From 47acd0938311f038e5fd7a0e157d9114b5001b76 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 29 Nov 2024 20:08:41 +0200 Subject: [PATCH 001/600] Spawn entities with a delay when pasting schematics (#2284) --- .../world/schematic/impl/SuperiorSchematic.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java index 85c14aa556..6a694e7926 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java @@ -286,11 +286,12 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long if (island.getOwner().isOnline()) finishTasks.forEach(Runnable::run); - Log.debugResult(Debug.PASTE_SCHEMATIC, "Spawning Entities", ""); - - for (SchematicEntity entity : this.data.entities) { - entity.spawnEntity(min); - } + // We spawn the entities with a delay, waiting for players to teleport to the island first. + BukkitExecutor.sync(() -> { + for (SchematicEntity entity : this.data.entities) { + entity.spawnEntity(min); + } + }, 20L); Log.debugResult(Debug.PASTE_SCHEMATIC, "Finished Schematic Placement", ""); From 8bbaeae29fae131aca1d6f5928bcfe0bbdee3fca Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 1 Dec 2024 21:49:01 +0200 Subject: [PATCH 002/600] Do not use String#replace in MessageComponent for better performance --- .../service/message/IMessageComponent.java | 12 +- .../core/messages/Message.java | 4 +- .../core/messages/MessageContent.java | 128 +++++++++++++++ .../component/MultipleComponents.java | 6 + .../component/impl/ActionBarComponent.java | 17 +- .../component/impl/BossBarComponent.java | 21 +-- .../impl/ComplexMessageComponent.java | 146 ++++++++++++++---- .../component/impl/RawMessageComponent.java | 15 +- .../component/impl/TitleComponent.java | 25 +-- .../superiorskyblock/island/SIsland.java | 2 +- 10 files changed, 310 insertions(+), 66 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/message/IMessageComponent.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/message/IMessageComponent.java index 9191b950dc..2e3042d4b0 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/message/IMessageComponent.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/message/IMessageComponent.java @@ -11,9 +11,19 @@ public interface IMessageComponent { /** * Get the raw message of this component. + * + * @deprecated See {@link #getMessage(Object...)} */ + @Deprecated String getMessage(); + /** + * Get the raw message of this component. + */ + default String getMessage(Object... args) { + return getMessage(); + } + /** * Send this message to a {@link CommandSender}. * @@ -21,7 +31,7 @@ public interface IMessageComponent { * @param args The arguments of the message. */ void sendMessage(CommandSender sender, Object... args); - + enum Type { /** diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 3ba143677d..0469e31cab 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -940,8 +940,8 @@ public IMessageComponent getComponent(Locale locale) { } @Nullable - public String getMessage(Locale locale, Object... objects) { - return isEmpty(locale) ? defaultMessage : replaceArgs(messages.get(locale).getMessage(), objects).orElse(null); + public String getMessage(Locale locale, Object... args) { + return isEmpty(locale) ? defaultMessage : messages.get(locale).getMessage(args); } public final void send(SuperiorPlayer superiorPlayer, Object... args) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java new file mode 100644 index 0000000000..c37be3a110 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java @@ -0,0 +1,128 @@ +package com.bgsoftware.superiorskyblock.core.messages; + +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; + +import java.math.BigDecimal; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MessageContent { + + public static final MessageContent EMPTY = new MessageContent(Collections.emptyList()) { + @Override + public Optional getContent(Object... arguments) { + return Optional.empty(); + } + }; + + private static final Pattern DEFAULT_PLACEHOLDER_PATTERN = Pattern.compile("\\{(\\d+)}"); + + private final List contentParts = new LinkedList<>(); + + public static List parse(List contents) { + List messageContentsList = new LinkedList<>(); + for (String content : contents) + messageContentsList.add(parse(content)); + return messageContentsList; + } + + public static MessageContent parse(String content) { + Matcher matcher = DEFAULT_PLACEHOLDER_PATTERN.matcher(content); + + List parts = new LinkedList<>(); + int lastPartIdx = 0; + + while (matcher.find()) { + StringBuilder previousPart = new StringBuilder(content.substring(lastPartIdx, matcher.start())); + + ArgumentPart argumentPart = null; + + try { + int argumentIndex = Integer.parseInt(matcher.group(1)); + argumentPart = ArgumentPart.fromIndex(argumentIndex); + } catch (NumberFormatException error) { + previousPart.append(matcher.group()); + } + + if (previousPart.length() > 0) + parts.add(new StaticPart(previousPart.toString())); + if (argumentPart != null) + parts.add(argumentPart); + + lastPartIdx = matcher.end(); + } + + if (lastPartIdx < content.length()) + parts.add(new StaticPart(content.substring(lastPartIdx))); + + return new MessageContent(parts); + } + + private MessageContent(List contentParts) { + this.contentParts.addAll(contentParts); + } + + public Optional getContent(Object... arguments) { + StringBuilder content = new StringBuilder(); + for (IPart part : contentParts) { + if (part instanceof StaticPart) { + content.append(((StaticPart) part).content); + } else { + int argumentIndex = ((ArgumentPart) part).argumentIndex; + if (argumentIndex >= 0 && argumentIndex < arguments.length) { + content.append(getArgumentString(arguments[argumentIndex])); + } else { + content.append("{").append(argumentIndex).append("}"); + } + } + } + + return content.length() == 0 ? Optional.empty() : Optional.of(content.toString()); + } + + private static String getArgumentString(Object argument) { + return argument instanceof BigDecimal ? + Formatters.NUMBER_FORMATTER.format((BigDecimal) argument) : + String.valueOf(argument); + } + + private interface IPart { + + } + + private static class StaticPart implements IPart { + + private final String content; + + StaticPart(String content) { + this.content = content; + } + + } + + private static class ArgumentPart implements IPart { + + private static final ArgumentPart[] CACHED_PARTS = new ArgumentPart[]{ + new ArgumentPart(0), + new ArgumentPart(1), + new ArgumentPart(2), + new ArgumentPart(3) + }; + + private final int argumentIndex; + + static ArgumentPart fromIndex(int index) { + return index >= 0 && index < CACHED_PARTS.length ? CACHED_PARTS[index] : new ArgumentPart(index); + } + + ArgumentPart(int argumentIndex) { + this.argumentIndex = argumentIndex; + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java index 5d9978c65f..0152c81c48 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java @@ -91,10 +91,16 @@ public Type getType() { } @Override + @Deprecated public String getMessage() { return messageComponents.isEmpty() ? "" : messageComponents.get(0).getMessage(); } + @Override + public String getMessage(Object... args) { + return messageComponents.isEmpty() ? "" : messageComponents.get(0).getMessage(args); + } + @Override public void sendMessage(CommandSender sender, Object... args) { this.messageComponents.forEach(messageComponent -> messageComponent.sendMessage(sender, args)); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ActionBarComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ActionBarComponent.java index a072901de9..26dc0a1222 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ActionBarComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ActionBarComponent.java @@ -4,7 +4,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -13,14 +13,14 @@ public class ActionBarComponent implements IMessageComponent { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private final String message; + private final MessageContent content; public static IMessageComponent of(@Nullable String message) { return Text.isBlank(message) ? EmptyMessageComponent.getInstance() : new ActionBarComponent(message); } - private ActionBarComponent(String message) { - this.message = message; + private ActionBarComponent(String content) { + this.content = MessageContent.parse(content); } @Override @@ -30,12 +30,17 @@ public Type getType() { @Override public String getMessage() { - return this.message; + return this.content.getContent().orElse(""); + } + + @Override + public String getMessage(Object... args) { + return this.content.getContent(args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { - Message.replaceArgs(this.message, args).ifPresent(message -> + this.content.getContent(args).ifPresent(message -> plugin.getNMSPlayers().sendActionBar((Player) sender, message)); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/BossBarComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/BossBarComponent.java index 1c16d948ee..3e808a019c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/BossBarComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/BossBarComponent.java @@ -7,8 +7,7 @@ import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBarsService; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.core.LazyReference; -import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; -import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import org.apache.logging.log4j.util.Strings; import org.bukkit.command.CommandSender; @@ -24,7 +23,7 @@ protected BossBarsService create() { } }; - private final String message; + private final MessageContent content; private final BossBar.Color color; private final int ticksToRun; @@ -32,8 +31,8 @@ public static IMessageComponent of(@Nullable String message, BossBar.Color color return ticks <= 0 || Strings.isBlank(message) ? EmptyMessageComponent.getInstance() : new BossBarComponent(message, color, ticks); } - private BossBarComponent(String message, BossBar.Color color, int ticks) { - this.message = message; + private BossBarComponent(String content, BossBar.Color color, int ticks) { + this.content = MessageContent.parse(content); this.color = color; this.ticksToRun = ticks; } @@ -45,15 +44,19 @@ public Type getType() { @Override public String getMessage() { - return this.message; + return this.content.getContent().orElse(""); + } + + @Override + public String getMessage(Object... args) { + return this.content.getContent(args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { if (sender instanceof Player) { - Message.replaceArgs(this.message, args).ifPresent(message -> { - bossBarsService.get().createBossBar((Player) sender, message, this.color, this.ticksToRun); - }); + this.content.getContent(args).ifPresent(message -> + bossBarsService.get().createBossBar((Player) sender, message, this.color, this.ticksToRun)); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java index a152ba3ee8..9873bc07cd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java @@ -3,7 +3,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.HoverEvent; @@ -14,8 +14,8 @@ public class ComplexMessageComponent implements IMessageComponent { - private final BaseComponent[] baseComponents; - private final TextComponent textComponent; + private final IWrappedComponent[] components; + private final MessageContent content; public static IMessageComponent of(@Nullable BaseComponent[] baseComponents) { if (baseComponents == null || baseComponents.length == 0) @@ -34,8 +34,34 @@ public static IMessageComponent of(@Nullable BaseComponent[] baseComponents) { } private ComplexMessageComponent(BaseComponent[] baseComponents) { - this.baseComponents = baseComponents; - this.textComponent = findTextComponent(baseComponents); + this.components = parseComponents(baseComponents); + this.content = findTextComponentContent(baseComponents); + } + + private static IWrappedComponent[] parseComponents(BaseComponent[] baseComponents) { + IWrappedComponent[] components = new IWrappedComponent[baseComponents.length]; + for (int i = 0; i < components.length; ++i) { + BaseComponent curr = baseComponents[i]; + IWrappedComponent wrappedComponent; + if (curr instanceof TextComponent) { + wrappedComponent = new ContentComponent((TextComponent) curr); + } else if (curr.getHoverEvent() != null) { + wrappedComponent = new HoverEventComponent(curr); + } else { + wrappedComponent = new ComponentHolder(curr); + } + components[i] = wrappedComponent; + } + return components; + } + + private static MessageContent findTextComponentContent(BaseComponent[] baseComponents) { + for (BaseComponent baseComponent : baseComponents) { + if (baseComponent instanceof TextComponent) + return MessageContent.parse(((TextComponent) baseComponent).getText()); + } + + return MessageContent.EMPTY; } @Override @@ -45,47 +71,105 @@ public Type getType() { @Override public String getMessage() { - return this.textComponent.getText(); + return this.content.getContent().orElse(""); + } + + @Override + public String getMessage(Object... args) { + return this.content.getContent(args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { if (!(sender instanceof Player)) { - String rawMessage = getMessage(); - if (rawMessage != null && !rawMessage.isEmpty()) - sender.sendMessage(rawMessage); - } else { - BaseComponent[] duplicate = replaceArgs(this.baseComponents, args); - if (duplicate.length > 0) - ((Player) sender).spigot().sendMessage(duplicate); + this.content.getContent(args).ifPresent(sender::sendMessage); + } else if (components.length > 0) { + BaseComponent[] components = new BaseComponent[this.components.length]; + for (int i = 0; i < this.components.length; ++i) + components[i] = this.components[i].parse(args); + ((Player) sender).spigot().sendMessage(components); } } - private static BaseComponent[] replaceArgs(BaseComponent[] textComponents, Object... objects) { - BaseComponent[] duplicate = new BaseComponent[textComponents.length]; + private interface IWrappedComponent { - for (int i = 0; i < textComponents.length; i++) { - duplicate[i] = textComponents[i].duplicate(); - if (duplicate[i] instanceof TextComponent) { - TextComponent textComponent = (TextComponent) duplicate[i]; - textComponent.setText(Message.replaceArgs(textComponent.getText(), objects).orElse("")); - } - HoverEvent hoverEvent = duplicate[i].getHoverEvent(); - if (hoverEvent != null) - duplicate[i].setHoverEvent(new HoverEvent(hoverEvent.getAction(), replaceArgs(hoverEvent.getValue(), objects))); + BaseComponent parse(Object... args); + + } + + private static class ComponentHolder implements IWrappedComponent { + + private final BaseComponent handle; + + ComponentHolder(BaseComponent handle) { + this.handle = handle; + } + + @Override + public BaseComponent parse(Object... args) { + return this.handle; } - return duplicate; } - @Nullable - private static TextComponent findTextComponent(BaseComponent[] baseComponents) { - for (BaseComponent baseComponent : baseComponents) { - if (baseComponent instanceof TextComponent) - return (TextComponent) baseComponent; + private static class ContentComponent implements IWrappedComponent { + + private final MessageContent content; + @Nullable + private final HoverEventContents hoverEventContents; + + ContentComponent(TextComponent textComponent) { + this.content = MessageContent.parse(textComponent.getText()); + this.hoverEventContents = textComponent.getHoverEvent() == null ? null : + new HoverEventContents(textComponent.getHoverEvent()); + } + + @Override + public BaseComponent parse(Object... args) { + TextComponent textComponent = new TextComponent(this.content.getContent(args).orElse("")); + if (this.hoverEventContents != null) + textComponent.setHoverEvent(this.hoverEventContents.parse(args)); + + return textComponent; + } + } + + private static class HoverEventComponent implements IWrappedComponent { + + private final BaseComponent baseComponent; + private final HoverEventContents hoverEventContents; + + HoverEventComponent(BaseComponent baseComponent) { + this.baseComponent = baseComponent; + this.hoverEventContents = new HoverEventContents(baseComponent.getHoverEvent()); + } + + @Override + public BaseComponent parse(Object... args) { + BaseComponent newComponent = this.baseComponent.duplicate(); + newComponent.setHoverEvent(this.hoverEventContents.parse(args)); + return newComponent; + } + + } + + private static class HoverEventContents { + + private final HoverEvent.Action action; + private final IWrappedComponent[] components; + + HoverEventContents(HoverEvent hoverEvent) { + this.action = hoverEvent.getAction(); + this.components = parseComponents(hoverEvent.getValue()); + } + + HoverEvent parse(Object... args) { + BaseComponent[] components = new BaseComponent[this.components.length]; + for (int i = 0; i < components.length; ++i) + components[i] = this.components[i].parse(args); + return new HoverEvent(this.action, components); } - return null; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/RawMessageComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/RawMessageComponent.java index b59eab4486..13fd276d91 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/RawMessageComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/RawMessageComponent.java @@ -3,20 +3,20 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import org.bukkit.command.CommandSender; public class RawMessageComponent implements IMessageComponent { - private final String message; + private final MessageContent content; public static IMessageComponent of(@Nullable String message) { return Text.isBlank(message) ? EmptyMessageComponent.getInstance() : new RawMessageComponent(message); } private RawMessageComponent(String message) { - this.message = message; + this.content = MessageContent.parse(message); } @Override @@ -26,12 +26,17 @@ public Type getType() { @Override public String getMessage() { - return this.message; + return this.content.getContent().orElse(""); + } + + @Override + public String getMessage(Object... args) { + return this.content.getContent(args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { - Message.replaceArgs(this.message, args).ifPresent(sender::sendMessage); + this.content.getContent(args).ifPresent(sender::sendMessage); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java index 41ab9e4161..9f5451fe37 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java @@ -5,7 +5,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -14,8 +14,8 @@ public class TitleComponent implements IMessageComponent { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private final String titleMessage; - private final String subtitleMessage; + private final MessageContent titleMessage; + private final MessageContent subtitleMessage; private final int fadeIn; private final int duration; private final int fadeOut; @@ -27,8 +27,8 @@ public static IMessageComponent of(@Nullable String titleMessage, @Nullable Stri } private TitleComponent(String titleMessage, String subtitleMessage, int fadeIn, int duration, int fadeOut) { - this.titleMessage = titleMessage; - this.subtitleMessage = subtitleMessage; + this.titleMessage = MessageContent.parse(titleMessage); + this.subtitleMessage = MessageContent.parse(subtitleMessage); this.fadeIn = fadeIn; this.duration = duration; this.fadeOut = fadeOut; @@ -41,18 +41,21 @@ public Type getType() { @Override public String getMessage() { - return this.titleMessage; + return this.titleMessage.getContent().orElse(""); } @Override - public void sendMessage(CommandSender sender, Object... args) { - String titleMessage = Message.replaceArgs(this.titleMessage, args).orElse(null); - String subtitleMessage = Message.replaceArgs(this.subtitleMessage, args).orElse(null); + public String getMessage(Object... args) { + return this.titleMessage.getContent(args).orElse(""); + } - if (titleMessage != null || subtitleMessage != null) { + @Override + public void sendMessage(CommandSender sender, Object... args) { + String titleMessage = this.titleMessage.getContent(args).orElse(null); + String subtitleMessage = this.subtitleMessage.getContent(args).orElse(null); + if (titleMessage != null && subtitleMessage != null) plugin.getNMSPlayers().sendTitle((Player) sender, titleMessage, subtitleMessage, this.fadeIn, this.duration, this.fadeOut); - } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 776364620d..87bd4e8ff5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -2067,7 +2067,7 @@ public void sendMessage(IMessageComponent messageComponent, List ignoredMe Preconditions.checkNotNull(messageComponent, "messageComponent parameter cannot be null."); Preconditions.checkNotNull(ignoredMembers, "ignoredMembers parameter cannot be null."); - Log.debug(Debug.SEND_MESSAGE, owner.getName(), messageComponent.getMessage(), ignoredMembers, Arrays.asList(args)); + Log.debug(Debug.SEND_MESSAGE, owner.getName(), messageComponent.getMessage(args), ignoredMembers, Arrays.asList(args)); forEachIslandMember(ignoredMembers, false, islandMember -> messageComponent.sendMessage(islandMember.asPlayer(), args)); } From 600b3f1798d716f437883debd9f375a78478ad86 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 2 Dec 2024 11:14:25 +0200 Subject: [PATCH 003/600] Spawn entities only after the player was teleported to the island (#2284) --- .../schematic/impl/WorldEditSchematic.java | 5 +++ .../island/GridManagerImpl.java | 5 +++ .../world/schematic/BaseSchematic.java | 5 ++- .../schematic/impl/SuperiorSchematic.java | 43 ++++++++++++++----- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/Hooks/FastAsyncWorldEdit/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/WorldEditSchematic.java b/Hooks/FastAsyncWorldEdit/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/WorldEditSchematic.java index 6784f5866d..722444b673 100644 --- a/Hooks/FastAsyncWorldEdit/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/WorldEditSchematic.java +++ b/Hooks/FastAsyncWorldEdit/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/WorldEditSchematic.java @@ -107,6 +107,11 @@ public List getAffectedChunks() { return Collections.emptyList(); } + @Override + public Runnable onTeleportCallback() { + return null; + } + private void readBlocks() { BlockArrayClipboard clipboard = (BlockArrayClipboard) schematic.getClipboard(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index 77714d9745..8597a403cb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -319,6 +319,8 @@ private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Bi List affectedChunks = schematic instanceof BaseSchematic ? ((BaseSchematic) schematic).getAffectedChunks() : null; + Runnable onTeleportCallback = schematic instanceof BaseSchematic ? + ((BaseSchematic) schematic).onTeleportCallback() : null; Log.debugResult(Debug.CREATE_ISLAND, "Creation Callback", "Registering new island"); @@ -383,6 +385,9 @@ private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Bi } plugin.getEventsBus().callPostIslandCreateEvent(builder.owner, island); + + if (onTeleportCallback != null) + onTeleportCallback.run(); } }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java index 6a776e502a..53c4ecef35 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.world.schematic; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; @@ -12,7 +13,6 @@ import java.util.List; import java.util.Map; -@SuppressWarnings("WeakerAccess") public abstract class BaseSchematic implements Schematic { protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @@ -42,4 +42,7 @@ public Map getBlockCounts() { public abstract List getAffectedChunks(); + @Nullable + public abstract Runnable onTeleportCallback(); + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java index 6a694e7926..b5d3c2b819 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java @@ -53,6 +53,7 @@ public class SuperiorSchematic extends BaseSchematic implements Schematic { private final Data data; private List affectedChunks = null; + private Runnable onTeleportCallback = null; public SuperiorSchematic(String name, CompoundTag compoundTag) { super(name); @@ -286,13 +287,6 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long if (island.getOwner().isOnline()) finishTasks.forEach(Runnable::run); - // We spawn the entities with a delay, waiting for players to teleport to the island first. - BukkitExecutor.sync(() -> { - for (SchematicEntity entity : this.data.entities) { - entity.spawnEntity(min); - } - }, 20L); - Log.debugResult(Debug.PASTE_SCHEMATIC, "Finished Schematic Placement", ""); island.handleBlocksPlace(cachedCounts); @@ -300,10 +294,15 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long plugin.getEventsBus().callIslandSchematicPasteEvent(island, name, location); Profiler.end(profiler); - - this.affectedChunks = new LinkedList<>(affectedChunks); - callback.run(); - this.affectedChunks = null; + + synchronized (this) { + try { + prepareCallback(affectedChunks, min); + callback.run(); + } finally { + finishCallback(); + } + } } catch (Throwable error2) { Log.debugResult(Debug.PASTE_SCHEMATIC, "Failed Finishing Placement", error2); Profiler.end(profiler); @@ -326,6 +325,11 @@ public List getAffectedChunks() { return affectedChunks == null ? Collections.emptyList() : Collections.unmodifiableList(affectedChunks); } + @Override + public Runnable onTeleportCallback() { + return this.onTeleportCallback; + } + public SuperiorSchematic copy(String newName) { return new SuperiorSchematic(newName, this.data, this.cachedCounts); } @@ -335,6 +339,23 @@ private void readBlock(SchematicBlockData block) { cachedCounts.put(key, cachedCounts.getRaw(key, 0) + 1); } + private void prepareCallback(List affectedChunks, Location min) { + this.affectedChunks = new LinkedList<>(affectedChunks); + // We spawn the entities with a delay, waiting for players to teleport to the island first. + this.onTeleportCallback = () -> { + BukkitExecutor.sync(() -> { + for (SchematicEntity entity : data.entities) { + entity.spawnEntity(min); + } + }, 20L); + }; + } + + private void finishCallback() { + this.affectedChunks = null; + this.onTeleportCallback = null; + } + private static class Data { private final BlockOffset offset; From d193479ff0fc2996afa3f5c9181a52675dc55d1b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 7 Dec 2024 12:41:09 +0200 Subject: [PATCH 004/600] Adds support to 1.21.4 --- NMS/v1_21_4/build.gradle | 38 ++ .../nms/v1_21_4/NMSAlgorithmsImpl.java | 266 ++++++++ .../nms/v1_21_4/NMSChunksImpl.java | 574 ++++++++++++++++++ .../nms/v1_21_4/NMSDragonFightImpl.java | 118 ++++ .../nms/v1_21_4/NMSEntitiesImpl.java | 43 ++ .../nms/v1_21_4/NMSHologramsImpl.java | 188 ++++++ .../nms/v1_21_4/NMSPlayersImpl.java | 169 ++++++ .../nms/v1_21_4/NMSTagsImpl.java | 209 +++++++ .../nms/v1_21_4/NMSUtils.java | 485 +++++++++++++++ .../nms/v1_21_4/NMSWorldImpl.java | 411 +++++++++++++ .../nms/v1_21_4/chunks/CropsBlockEntity.java | 141 +++++ .../chunks/CropsTickingBlockEntity.java | 30 + .../nms/v1_21_4/dragon/DragonUtils.java | 37 ++ .../dragon/EndWorldEndDragonFightHandler.java | 47 ++ .../v1_21_4/dragon/IslandEndDragonFight.java | 205 +++++++ .../dragon/IslandEntityEnderDragon.java | 81 +++ .../nms/v1_21_4/dragon/SpikesCache.java | 189 ++++++ .../v1_21_4/enchantment/GlowEnchantment.java | 113 ++++ .../generator/IslandsGeneratorImpl.java | 67 ++ .../menu/MenuBrewingStandBlockEntity.java | 24 + .../menu/MenuDispenserBlockEntity.java | 24 + .../v1_21_4/menu/MenuFurnaceBlockEntity.java | 24 + .../v1_21_4/menu/MenuHopperBlockEntity.java | 26 + .../TickingSpawnerBlockEntityNotifier.java | 57 ++ .../nms/v1_21_4/world/KeyBlocksCache.java | 32 + .../nms/v1_21_4/world/PropertiesMapper.java | 85 +++ .../v1_21_4/world/WorldEditSessionImpl.java | 327 ++++++++++ build.gradle | 2 +- settings.gradle | 3 +- 29 files changed, 4013 insertions(+), 2 deletions(-) create mode 100644 NMS/v1_21_4/build.gradle create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSDragonFightImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSHologramsImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsBlockEntity.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsTickingBlockEntity.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/DragonUtils.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndWorldEndDragonFightHandler.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEndDragonFight.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/SpikesCache.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/generator/IslandsGeneratorImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuBrewingStandBlockEntity.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuDispenserBlockEntity.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuFurnaceBlockEntity.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuHopperBlockEntity.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/spawners/TickingSpawnerBlockEntityNotifier.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapper.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java diff --git a/NMS/v1_21_4/build.gradle b/NMS/v1_21_4/build.gradle new file mode 100644 index 0000000000..5dcad64f7b --- /dev/null +++ b/NMS/v1_21_4/build.gradle @@ -0,0 +1,38 @@ +plugins { + id("io.papermc.paperweight.userdev") version "1.7.1" +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } +} + +group 'NMS:v1_21_4' + +dependencies { + paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.21.4-R0.1-SNAPSHOT") + compileOnly project(":NMS:Spigot-1_20_3") + compileOnly project(":NMS:Paper-1_20_3") + compileOnly project(":API") + compileOnly rootProject +} + +shadowJar { + archiveFileName = "${project.name}-exclude.jar" +} + +assemble { + dependsOn(reobfJar) +} + +tasks { + reobfJar { + File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") + outputJar.set(layout.buildDirectory.file(outputFile.getPath())) + } +} + +if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java new file mode 100644 index 0000000000..249d590bca --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -0,0 +1,266 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; +import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; +import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.enchantment.GlowEnchantment; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuBrewingStandBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuDispenserBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuFurnaceBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; +import io.papermc.paper.chat.ChatRenderer; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.TextReplacementConfig; +import net.minecraft.SharedConstants; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.Container; +import net.minecraft.world.entity.item.FallingBlockEntity; +import net.minecraft.world.entity.vehicle.AbstractMinecart; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.command.defaults.BukkitCommand; +import org.bukkit.craftbukkit.CraftRegistry; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftFallingBlock; +import org.bukkit.craftbukkit.entity.CraftMinecart; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffect; +import org.jetbrains.annotations.NotNull; + +import java.util.EnumMap; +import java.util.Map; +import java.util.function.BiFunction; + +public class NMSAlgorithmsImpl implements NMSAlgorithms { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final ReflectField> REGISTRY_CACHE = + new ReflectField<>(CraftRegistry.class, Map.class, "cache"); + + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); + + static { + MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); + } + + private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { + @Override + public byte[] processClass(byte[] classBytes, String path) { + return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); + } + }; + + @Override + public void registerCommand(BukkitCommand command) { + ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); + } + + @Override + public String parseSignLine(String original) { + return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); + } + + @Override + public int getCombinedId(Location location) { + org.bukkit.World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return 0; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockState blockState = serverLevel.getBlockState(blockPos); + return Block.getId(blockState); + } + + @Override + public int getCombinedId(Material material, byte data) { + BlockState blockState; + + if (data == 0) { + Block block = CraftMagicNumbers.getBlock(material); + if (block == null) + return -1; + blockState = block.defaultBlockState(); + } else { + blockState = CraftMagicNumbers.getBlock(material, data); + } + + return blockState == null ? -1 : Block.getId(blockState); + } + + @Override + public int compareMaterials(Material o1, Material o2) { + int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); + int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); + return Integer.compare(firstMaterial, secondMaterial); + } + + @Override + public Key getBlockKey(int combinedId) { + Block block = Block.stateById(combinedId).getBlock(); + return KeyBlocksCache.getBlockKey(block); + } + + @Override + public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { + AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); + Block block = minecart.getDisplayBlockState().getBlock(); + return KeyBlocksCache.getBlockKey(block); + } + + @Override + public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { + FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); + Block block = fallingBlock.getBlockState().getBlock(); + return KeyBlocksCache.getBlockKey(block); + } + + @Override + public void setCustomModel(ItemMeta itemMeta, int customModel) { + itemMeta.setCustomModelData(customModel); + } + + @Override + public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { + if (!potionMeta.hasCustomEffects()) + potionMeta.setColor(potionEffect.getType().getColor()); + potionMeta.addCustomEffect(potionEffect, true); + } + + @Override + public String getMinecraftKey(ItemStack itemStack) { + return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); + } + + @Override + public Enchantment getGlowEnchant() { + return new GlowEnchantment(); + } + + @Override + public Enchantment createGlowEnchantment() { + Enchantment enchantment = getGlowEnchant(); + + Map registryCache = REGISTRY_CACHE.get(Registry.ENCHANTMENT); + + registryCache.put(enchantment.getKey(), enchantment); + + return enchantment; + } + + @Nullable + @Override + public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { + MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); + return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); + } + + @Override + public int getMaxWorldSize() { + return Bukkit.getMaxWorldSize(); + } + + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + + @Override + public int getDataVersion() { + return SharedConstants.getCurrentVersion().getDataVersion().getVersion(); + } + + @Override + public ClassProcessor getClassProcessor() { + return CLASS_PROCESSOR; + } + + @Override + public void handlePaperChatRenderer(Object event) { + if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) + return; + + ChatRenderer originalRenderer = asyncChatEvent.renderer(); + asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); + } + + private interface MenuCreator extends BiFunction { + } + + private static class ChatRendererWrapper { + + private static final String MESSAGE_PLACEHOLDER = "{message}"; + private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = + net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); + + private final ChatRenderer renderer = new ChatRenderer() { + @Override + public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, + net.kyori.adventure.text.@NotNull Component sourceDisplayName, + net.kyori.adventure.text.@NotNull Component message, + @NotNull Audience viewer) { + String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer + .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); + Island island = superiorPlayer.getIsland(); + + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( + Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) + .replaceText(TextReplacementConfig.builder() + .matchLiteral(MESSAGE_PLACEHOLDER) + .replacement(message) + .build()); + } + }; + + private final ChatRenderer originalRenderer; + + public ChatRendererWrapper(ChatRenderer originalRenderer) { + this.originalRenderer = originalRenderer; + } + + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java new file mode 100644 index 0000000000..cd7afb2776 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -0,0 +1,574 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.core.CalculatedChunk; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Counter; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.bgsoftware.superiorskyblock.nms.NMSChunks; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.chunks.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; +import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.BitStorage; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.SlabType; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.phys.AABB; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.entity.CraftEntityType; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.generator.ChunkGenerator; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +public class NMSChunksImpl implements NMSChunks { + + private final SuperiorSkyblockPlugin plugin; + + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + KeyBlocksCache.cacheAllBlocks(); + } + + @Override + public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, + Collection playersToUpdate) { + if (chunkPositions.isEmpty()) + return; + + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); + + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); + + ChunkPos chunkPos = levelChunk.getPos(); + + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + LevelChunkSection currentSection = chunkSections[i]; + if (currentSection != null) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); + } + } + + levelChunk.markUnsaved(); + + ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); + ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( + levelChunk, levelChunk.level.getLightEngine(), null, null); + + playersToUpdate.forEach(player -> { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + serverPlayer.connection.send(forgetLevelChunkPacket); + serverPlayer.connection.send(mapChunkPacket); + }); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + + Codec>> biomesCodec = PalettedContainer.codecRW( + biomesRegistry.asHolderIdMap(), + biomesRegistry.holderByNameCodec(), + PalettedContainer.Strategy.SECTION_BIOMES, + biomesRegistry.getOrThrow(Biomes.PLAINS) + ); + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); + Tag biomesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = unloadedChunkCompound.getSections(); + + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).put("biomes", biomesCompound); + } + + @Override + public void onFinish() { + // Do nothing. + } + }); + } + + @Override + public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { + if (chunkPositions.isEmpty()) + return; + + chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), + chunkPosition.getX(), chunkPosition.getZ(), false)); + + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); + + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + chunkSections[i] = new LevelChunkSection(biomesRegistry); + } + + removeEntities(levelChunk); + removeBlockEntities(levelChunk); + removeBlocks(levelChunk); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + Codec> blocksCodec = PalettedContainer.codecRW( + Block.BLOCK_STATE_REGISTRY, + BlockState.CODEC, + PalettedContainer.Strategy.SECTION_STATES, + Blocks.AIR.defaultBlockState()); + + ListTag tileEntities = new ListTag(); + + unloadedChunkCompound.setEntities(new ListTag()); + unloadedChunkCompound.setBlockEntities(tileEntities); + + if (serverLevel.generator instanceof IslandsGenerator) { + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); + Tag blockStatesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = unloadedChunkCompound.getSections(); + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).put("block_states", blockStatesCompound); + } else { + ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); + + try { + NMSUtils.buildSurfaceForChunk(serverLevel, protoChunk); + } catch (Exception ignored) { + } + + Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + Codec>> biomesCodec = PalettedContainer.codecRO( + biomesRegistry.asHolderIdMap(), + biomesRegistry.holderByNameCodec(), + PalettedContainer.Strategy.SECTION_BIOMES, + biomesRegistry.getOrThrow(Biomes.PLAINS) + ); + + LevelLightEngine lightEngine = serverLevel.getLightEngine(); + LevelChunkSection[] chunkSections = protoChunk.getSections(); + + ListTag sectionsList = new ListTag(); + + // Save blocks + for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { + int chunkSectionIndex = serverLevel.getSectionIndex(i); + + CompoundTag sectionCompound = new CompoundTag(); + + if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { + LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; + + { + DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); + sectionCompound.put("block_states", dataResult.getOrThrow()); + } + + { + DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); + sectionCompound.put("biomes", dataResult.getOrThrow()); + } + } + + if (!sectionCompound.isEmpty()) { + sectionCompound.putByte("Y", (byte) i); + sectionsList.add(sectionCompound); + } + } + + for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { + CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, + MinecraftServer.getServer().registryAccess()); + if (blockEntityCompound != null) + tileEntities.add(blockEntityCompound); + } + + unloadedChunkCompound.setSections(sectionsList); + } + } + + @Override + public void onFinish() { + if (onFinish != null) + onFinish.run(); + } + }); + } + + @Override + public CompletableFuture> calculateChunks(List chunkPositions, + Synchronized> unloadedChunksCache) { + List allCalculatedChunks = new LinkedList<>(); + List chunkPositionsToCalculate = new LinkedList<>(); + + Iterator chunkPositionsIterator = chunkPositions.iterator(); + while (chunkPositionsIterator.hasNext()) { + ChunkPosition chunkPosition = chunkPositionsIterator.next(); + CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); + if (cachedCalculatedChunk != null) { + allCalculatedChunks.add(cachedCalculatedChunk); + chunkPositionsIterator.remove(); + } else { + chunkPositionsToCalculate.add(chunkPosition); + } + } + + if (chunkPositions.isEmpty()) + return CompletableFuture.completedFuture(allCalculatedChunks); + + CompletableFuture> completableFuture = new CompletableFuture<>(); + + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z); + allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + + Codec> blocksCodec = PalettedContainer.codecRW( + Block.BLOCK_STATE_REGISTRY, + BlockState.CODEC, + PalettedContainer.Strategy.SECTION_STATES, + Blocks.AIR.defaultBlockState() + ); + Codec>> biomesCodec = PalettedContainer.codecRW( + biomesRegistry.asHolderIdMap(), + biomesRegistry.holderByNameCodec(), + PalettedContainer.Strategy.SECTION_BIOMES, + biomesRegistry.getOrThrow(Biomes.PLAINS) + ); + + LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; + + ListTag sectionsList = unloadedChunkCompound.getSections(); + for (int i = 0; i < sectionsList.size(); ++i) { + CompoundTag sectionCompound = sectionsList.getCompound(i); + byte yPosition = sectionCompound.getByte("Y"); + int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); + + if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { + PalettedContainer blocksDataPalette; + if (sectionCompound.contains("block_states", 10)) { + DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, + sectionCompound.getCompound("block_states")).promotePartial((sx) -> { + }); + blocksDataPalette = dataResult.getOrThrow(); + } else { + blocksDataPalette = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + } + + PalettedContainer> biomesDataPalette; + if (sectionCompound.contains("biomes", 10)) { + DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, + sectionCompound.getCompound("biomes")).promotePartial((sx) -> { + }); + biomesDataPalette = dataResult.getOrThrow(); + } else { + biomesDataPalette = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); + } + + chunkSections[sectionIndex] = new LevelChunkSection(blocksDataPalette, biomesDataPalette); + } + + } + + CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + allCalculatedChunks.add(calculatedChunk); + unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + } + + @Override + public void onFinish() { + completableFuture.complete(allCalculatedChunks); + } + }); + + return completableFuture; + } + + @Override + public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { + CompletableFuture> completableFuture = new CompletableFuture<>(); + + KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + List unloadedChunkCompounds = new LinkedList<>(); + + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { + if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) + chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); + } + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + unloadedChunkCompounds.add(unloadedChunkCompound); + } + + @Override + public void onFinish() { + BukkitExecutor.ensureMain(() -> { + for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + for (Tag entityTag : unloadedChunkCompound.getEntities()) { + EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); + if (entityType == null) + continue; + + Entity fakeEntity = EntityType.create((CompoundTag) entityTag, serverLevel, EntitySpawnReason.NATURAL).orElse(null); + if (fakeEntity != null) { + fakeEntity.valid = false; + if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) + continue; + } + + Key entityKey = Keys.of(CraftEntityType.minecraftToBukkit(entityType)); + chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); + } + } + + completableFuture.complete(chunkEntities); + }); + } + }); + + return completableFuture; + } + + @Override + public void injectChunkSections(Chunk chunk) { + // No implementation + } + + @Override + public boolean isChunkEmpty(Chunk bukkitChunk) { + LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); + return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> + chunkSection == null || chunkSection.hasOnlyAir()); + } + + @Override + public Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); + return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; + } + + @Override + public void startTickingChunk(Island island, Chunk chunk, boolean stop) { + if (plugin.getSettings().getCropsInterval() <= 0) + return; + + if (stop) { + CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); + if (cropsBlockEntity != null) + cropsBlockEntity.remove(); + } else { + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); + CropsBlockEntity.create(island, levelChunk); + } + } + + @Override + public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { + if (chunkPositions.isEmpty()) return; + CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> + cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); + } + + @Override + public void shutdown() { + List> pendingTasks = NMSUtils.getPendingChunkActions(); + + if (pendingTasks.isEmpty()) + return; + + Log.info("Waiting for chunk tasks to complete."); + + CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); + } + + @Override + public List getBlockEntities(Chunk chunk) { + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); + List blockEntities = new LinkedList<>(); + + World bukkitWorld = chunk.getWorld(); + + levelChunk.getBlockEntities().keySet().forEach(blockPos -> + blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); + + return blockEntities; + } + + private static final ReflectField PALETTED_CONTAINER_DATA = new ReflectField<>( + PalettedContainer.class, Object.class, "d"); + + private static final ReflectField PALETTED_CONTAINER_DATA_STORAGE = new ReflectField<>( + PalettedContainer.class, BitStorage.class, "b"); + + private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { + KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); + List spawnersLocations = new LinkedList<>(); + + for (int i = 0; i < chunkSections.length; ++i) { + LevelChunkSection levelChunkSection = chunkSections[i]; + if (levelChunkSection != null && !levelChunkSection.hasOnlyAir()) { + int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4; + for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { + BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); + calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, + sectionBottomY, blockCounts, spawnersLocations); + } + } + } + + return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); + } + + private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, + int sectionBottomY, KeyMap blockCounts, + List spawnersLocations) { + Block block = blockState.getBlock(); + + if (block == Blocks.AIR) + return; + + Location location = new Location(chunkPosition.getWorld(), + (chunkPosition.getX() << 4) + x, + sectionBottomY + y, + (chunkPosition.getZ() << 4) + z); + + int blockAmount = 1; + + if (NMSUtils.isDoubleBlock(block, blockState)) { + blockAmount = 2; + blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); + } + + Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); + blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); + if (block == Blocks.SPAWNER) { + spawnersLocations.add(location); + } + } + + private static void removeEntities(ChunkAccess chunk) { + ChunkPos chunkPos = chunk.getPos(); + ServerLevel serverLevel = ((LevelChunk) chunk).level; + + int chunkWorldCoordX = chunkPos.x << 4; + int chunkWorldCoordZ = chunkPos.z << 4; + + AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinY(), chunkWorldCoordZ, + chunkWorldCoordX + 15, serverLevel.getMaxY(), chunkWorldCoordZ + 15); + + List worldEntities = new LinkedList<>(); + serverLevel.getEntities().get(chunkBounds, worldEntities::add); + + worldEntities.forEach(nmsEntity -> { + if (!(nmsEntity instanceof Player)) + nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); + }); + } + + private static void removeBlockEntities(ChunkAccess chunk) { + chunk.blockEntities.values().forEach(BlockEntity::setRemoved); + chunk.blockEntities.clear(); + } + + private static void removeBlocks(ChunkAccess chunk) { + ServerLevel serverLevel = ((LevelChunk) chunk).level; + + ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); + + if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { + NMSUtils.buildSurfaceForChunk(serverLevel, chunk); + } + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSDragonFightImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSDragonFightImpl.java new file mode 100644 index 0000000000..41a01f1cc2 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSDragonFightImpl.java @@ -0,0 +1,118 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.EndWorldEndDragonFightHandler; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.IslandEndDragonFight; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.IslandEntityEnderDragon; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.SpikesCache; +import com.google.common.cache.LoadingCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.levelgen.feature.SpikeFeature; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.advancement.Advancement; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.entity.Player; + +import java.lang.reflect.Modifier; +import java.util.List; + +public class NMSDragonFightImpl implements NMSDragonFight { + + private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( + EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) + .removeFinal(); + + private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField<>( + ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE, 1); + + private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( + SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) + .removeFinal(); + + private static boolean firstWorldPreparation = true; + + static { + ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); + } + + @Override + public void prepareEndWorld(World bukkitWorld) { + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); + + if (firstWorldPreparation) { + firstWorldPreparation = false; + SPIKE_CACHE.set(null, SpikesCache.getInstance()); + } + } + + @Nullable + @Override + public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { + World bukkitWorld = island.getCenter(dimension).getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + return null; + + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); + } + + @Override + public void startDragonBattle(Island island, Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + return; + + dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + } + + @Override + public void removeDragonBattle(Island island, Dimension dimension) { + World bukkitWorld = island.getCenter(dimension).getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + return; + + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + + if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { + islandEndDragonFight.removeBattlePlayers(); + islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); + } + } + + @Override + public void awardTheEndAchievement(Player player) { + Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); + if (advancement != null) + player.getAdvancementProgress(advancement).awardCriteria(""); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java new file mode 100644 index 0000000000..6ac72430e4 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java @@ -0,0 +1,43 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4; + +import com.bgsoftware.superiorskyblock.nms.NMSEntities; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PortalProcessor; +import org.bukkit.Material; +import org.bukkit.craftbukkit.entity.CraftAnimals; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Animals; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.ItemStack; + +public class NMSEntitiesImpl implements NMSEntities { + + @Override + public ItemStack[] getEquipment(EntityEquipment entityEquipment) { + ItemStack[] itemStacks = new ItemStack[7]; + + itemStacks[0] = new ItemStack(Material.ARMOR_STAND); + itemStacks[1] = entityEquipment.getItemInMainHand(); + itemStacks[2] = entityEquipment.getItemInOffHand(); + itemStacks[3] = entityEquipment.getHelmet(); + itemStacks[4] = entityEquipment.getChestplate(); + itemStacks[5] = entityEquipment.getLeggings(); + itemStacks[6] = entityEquipment.getBoots(); + + return itemStacks; + } + + @Override + public boolean isAnimalFood(ItemStack itemStack, Animals animals) { + return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); + } + + @Override + public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { + Entity entity = ((CraftEntity) bukkitEntity).getHandle(); + PortalProcessor portalProcessor = entity.portalProcess; + return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSHologramsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSHologramsImpl.java new file mode 100644 index 0000000000..58ec1f184d --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSHologramsImpl.java @@ -0,0 +1,188 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4; + +import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; +import com.bgsoftware.superiorskyblock.nms.NMSHolograms; +import com.google.common.base.Preconditions; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftArmorStand; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.entity.Entity; + +@SuppressWarnings("unused") +public class NMSHologramsImpl implements NMSHolograms { + + @Override + public Hologram createHologram(Location location) { + Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); + serverLevel.addFreshEntity(entityHologram); + return entityHologram; + } + + @Override + public boolean isHologram(Entity entity) { + return ((CraftEntity) entity).getHandle() instanceof Hologram; + } + + public static class EntityHologram extends ArmorStand implements Hologram { + + private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); + + private CraftEntity bukkitEntity; + + EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + + setInvisible(true); + setSmall(true); + setShowArms(false); + setNoGravity(true); + setNoBasePlate(true); + setMarker(true); + forceSetBoundingBox(EMPTY_BOUND); + + super.collides = false; + super.setCustomNameVisible(true); + } + + @Override + public void setHologramName(String name) { + super.setCustomName(CraftChatMessage.fromStringOrNull(name)); + } + + @Override + public void removeHologram() { + super.remove(RemovalReason.DISCARDED); + } + + @Override + public org.bukkit.entity.ArmorStand getHandle() { + return this.getBukkitEntity(); + } + + @Override + public void inactiveTick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + @Override + public boolean repositionEntityAfterLoad() { + return false; + } + + @Override + public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { + // Prevent stand being equipped + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + + @Override + public void tick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + public void forceSetBoundingBox(AABB boundingBox) { + super.setBoundingBox(boundingBox); + } + + @Override + public CraftArmorStand getBukkitEntity() { + if (bukkitEntity == null) { + bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); + } + return (CraftArmorStand) bukkitEntity; + } + + @Override + public void remove(RemovalReason removalReason) { + // Prevent being killed. + } + + @Override + public void playSound(SoundEvent soundEvent, float volume, float pitch) { + // Remove sounds. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean isInvulnerableTo(ServerLevel serverLevel, DamageSource damageSource) { + /* + * The field Entity.invulnerable is private. + * It's only used while saving NBTTags, but since the entity would be killed + * on chunk unload, we prefer to override isInvulnerable(). + */ + return true; + } + + @Override + public void setCustomName(Component component) { + // Locks the custom name. + } + + @Override + public void setCustomNameVisible(boolean isCustomNameVisible) { + // Locks the custom name. + } + + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java new file mode 100644 index 0000000000..aafe5a9e31 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java @@ -0,0 +1,169 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.player.PlayerLocales; +import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; +import com.bgsoftware.superiorskyblock.world.Dimensions; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarStyle; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; + +import java.util.Locale; +import java.util.Optional; + +public class NMSPlayersImpl implements NMSPlayers { + + private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); + + private final SuperiorSkyblockPlugin plugin; + + public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void clearInventory(OfflinePlayer offlinePlayer) { + if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { + Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); + assert player != null; + player.getInventory().clear(); + player.getEnderChest().clear(); + return; + } + + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); + Player targetPlayer = serverPlayer.getBukkitEntity(); + + targetPlayer.loadData(); + + clearInventory(targetPlayer); + + //Setting the entity to the spawn location + Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); + + if (spawnLocation != null) { + serverPlayer.setLevel(serverLevel); + serverPlayer.absMoveTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), + spawnLocation.getYaw(), spawnLocation.getPitch()); + } + + targetPlayer.saveData(); + } + + @Override + public void setSkinTexture(SuperiorPlayer superiorPlayer) { + Player player = superiorPlayer.asPlayer(); + + if (player == null) + return; + + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() + .ifPresent(property -> setSkinTexture(superiorPlayer, property)); + } + + @Override + public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { + superiorPlayer.setTextureValue(property.value()); + } + + @SuppressWarnings("deprecation") + @Override + public void sendActionBar(Player player, String message) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); + } + + @Override + public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { + BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); + bossBar.addPlayer(player); + return bossBar; + } + + @SuppressWarnings("deprecation") + @Override + public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { + player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); + } + + @Override + public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { + return superiorPlayer.getUniqueId().equals(item.getThrower()); + } + + @Nullable + @Override + public Locale getPlayerLocale(Player player) { + if (PLAYER_LOCALE.isValid()) { + return player.locale(); + } else try { + //noinspection deprecation + return PlayerLocales.getLocale(player.getLocale()); + } catch (IllegalArgumentException error) { + return null; + } + } + + private static class BossBarImpl implements BossBar { + + private final org.bukkit.boss.BossBar bossBar; + private final BossBarTask bossBarTask; + + public BossBarImpl(String message, BarColor color, double ticksToRun) { + bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); + this.bossBarTask = BossBarTask.create(this, ticksToRun); + } + + @Override + public void addPlayer(Player player) { + this.bossBar.addPlayer(player); + this.bossBarTask.registerTask(player); + } + + @Override + public void removeAll() { + this.bossBar.removeAll(); + this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); + } + + @Override + public void setProgress(double progress) { + this.bossBar.setProgress(progress); + } + + @Override + public double getProgress() { + return this.bossBar.getProgress(); + } + + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java new file mode 100644 index 0000000000..c311e718e2 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java @@ -0,0 +1,209 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4; + +import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.nms.NMSTags; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.tag.ListTag; +import com.bgsoftware.superiorskyblock.tag.Tag; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.serialization.Dynamic; +import net.minecraft.SharedConstants; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.ByteArrayTag; +import net.minecraft.nbt.IntArrayTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.NumericTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ResolvableProfile; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.inventory.CraftItemStack; + +import java.util.Optional; +import java.util.Set; + +@SuppressWarnings({"unused"}) +public class NMSTagsImpl implements NMSTags { + + @Override + public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) + itemStack.save(MinecraftServer.getServer().registryAccess()); + tagCompound.putInt("DataVersion", SharedConstants.getCurrentVersion().getDataVersion().getVersion()); + + return CompoundTag.fromNBT(tagCompound); + } + + @Override + public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { + if (compoundTag.containsKey("NBT")) { + // Old compound version, deserialize it accordingly + return deserializeItemOld(compoundTag); + } + + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); + + int currentVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); + int itemVersion = tagCompound.getInt("DataVersion"); + if (itemVersion < currentVersion) { + tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, + new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); + } + + ItemStack itemStack = ItemStack.parse(MinecraftServer.getServer().registryAccess(), tagCompound).orElseThrow(); + + return CraftItemStack.asCraftMirror(itemStack); + } + + private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + Material type = Material.valueOf(typeName); + int amount = compoundTag.getInt("amount"); + short data = compoundTag.getShort("data"); + CompoundTag nbtData = compoundTag.getCompound("NBT"); + + org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); + + return CraftItemStack.asCraftMirror(itemStack); + } + + @Override + public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + PropertyMap propertyMap = new PropertyMap(); + propertyMap.put("textures", new Property("textures", texture)); + + ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap); + + itemStack.set(DataComponents.PROFILE, resolvableProfile); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + public CompoundTag getNBTTag(org.bukkit.entity.Entity bukkitEntity) { + Entity entity = ((CraftEntity) bukkitEntity).getHandle(); + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + compoundTag.putFloat("Yaw", entity.getYRot()); + compoundTag.putFloat("Pitch", entity.getXRot()); + return CompoundTag.fromNBT(compoundTag); + } + + @Override + @SuppressWarnings("ConstantConditions") + public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { + net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); + + if (compoundTag == null) + compoundTag = new net.minecraft.nbt.CompoundTag(); + + if (!compoundTag.contains("id")) + //noinspection deprecation + compoundTag.putString("id", entityType.getName()); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { + entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); + return !serverLevel.addWithUUID(entity) ? null : entity; + }); + } + + @Override + public byte[] getNBTByteArrayValue(Object object) { + return ((ByteArrayTag) object).getAsByteArray(); + } + + @Override + public byte getNBTByteValue(Object object) { + return ((NumericTag) object).getAsByte(); + } + + @Override + public Set getNBTCompoundValue(Object object) { + return ((net.minecraft.nbt.CompoundTag) object).getAllKeys(); + } + + @Override + public double getNBTDoubleValue(Object object) { + return ((NumericTag) object).getAsDouble(); + } + + @Override + public float getNBTFloatValue(Object object) { + return ((NumericTag) object).getAsFloat(); + } + + @Override + public int[] getNBTIntArrayValue(Object object) { + return ((IntArrayTag) object).getAsIntArray(); + } + + @Override + public int getNBTIntValue(Object object) { + return ((NumericTag) object).getAsInt(); + } + + @Override + public Object getNBTListIndexValue(Object object, int index) { + return ((net.minecraft.nbt.ListTag) object).get(index); + } + + @Override + public long getNBTLongValue(Object object) { + return ((NumericTag) object).getAsLong(); + } + + @Override + public short getNBTShortValue(Object object) { + return ((NumericTag) object).getAsShort(); + } + + @Override + public String getNBTStringValue(Object object) { + return ((StringTag) object).getAsString(); + } + + @Override + public Object parseList(ListTag listTag) { + net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); + + for (Tag tag : listTag) + nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); + + return nbtTagList; + } + + @Override + public Object getNBTCompoundTag(Object object, String key) { + return ((net.minecraft.nbt.CompoundTag) object).get(key); + } + + @Override + public void setNBTCompoundTagValue(Object object, String key, Object value) { + ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); + } + + @Override + public int getNBTTagListSize(Object object) { + return ((net.minecraft.nbt.ListTag) object).size(); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java new file mode 100644 index 0000000000..3b893058d9 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java @@ -0,0 +1,485 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.PropertiesMapper; +import com.bgsoftware.superiorskyblock.tag.ByteTag; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.tag.IntArrayTag; +import com.bgsoftware.superiorskyblock.tag.StringTag; +import com.bgsoftware.superiorskyblock.tag.Tag; +import com.google.common.base.Suppliers; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.BedBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.block.state.properties.SlabType; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +public class NMSUtils { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final ReflectMethod SEND_PACKETS_TO_RELEVANT_PLAYERS = new ReflectMethod<>( + ChunkHolder.class, 1, Packet.class, boolean.class); + private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( + ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); + private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( + ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( + EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + + private NMSUtils() { + + } + + public static void runActionOnEntityChunks(Collection chunksCoords, + ChunkCallback chunkCallback) { + runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> + runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); + } + + public static void runActionOnChunks(Collection chunksCoords, + boolean saveChunks, ChunkCallback chunkCallback) { + runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> + runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); + } + + private static void runActionOnChunksInternal(Collection chunksCoords, + ChunkCallback chunkCallback, + Consumer> onUnloadChunkAction) { + List unloadedChunks = new LinkedList<>(); + List loadedChunks = new LinkedList<>(); + + chunksCoords.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + ChunkAccess chunkAccess; + + try { + chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); + } catch (Throwable ex) { + chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); + } + + if (chunkAccess instanceof LevelChunk levelChunk) { + loadedChunks.add(levelChunk); + } else { + unloadedChunks.add(chunkPosition); + } + }); + + boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); + + if (!loadedChunks.isEmpty()) + runActionOnLoadedChunks(loadedChunks, chunkCallback); + + if (hasUnloadedChunks) { + onUnloadChunkAction.accept(unloadedChunks); + } else { + chunkCallback.onFinish(); + } + } + + private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { + chunks.forEach(chunkCallback::onLoadedChunk); + } + + private static void runActionOnUnloadedChunks(Collection chunks, + boolean saveChunks, ChunkCallback chunkCallback) { + if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { + Iterator chunksIterator = chunks.iterator(); + while (chunksIterator.hasNext()) { + ChunkPosition chunkPosition = chunksIterator.next(); + + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( + chunkPosition.getX(), chunkPosition.getZ()); + + if (cachedUnloadedChunk != null) { + chunkCallback.onLoadedChunk(cachedUnloadedChunk); + chunksIterator.remove(); + } + } + + if (chunks.isEmpty()) { + chunkCallback.onFinish(); + return; + } + } + + CompletableFuture pendingTask = new CompletableFuture<>(); + PENDING_CHUNK_ACTIONS.add(pendingTask); + + BukkitExecutor.createTask().runAsync(v -> { + List chunkCompounds = new LinkedList<>(); + + chunks.forEach(chunkPosition -> { + try { + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + + net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); + + if (chunkCompound == null) { + chunkCallback.onChunkNotExist(chunkPosition); + return; + } + + net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), + Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, + Optional.empty(), chunkPos, serverLevel); + + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + + if (saveChunks) + chunkCompounds.add(unloadedChunkCompound); + } catch (Exception error) { + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + + return chunkCompounds; + }).runSync(chunkCompounds -> { + chunkCompounds.forEach(unloadedChunkCompound -> { + + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + + ChunkPos chunkPos = unloadedChunkCompound.chunkPos(); + + try { + chunkMap.write(chunkPos, () -> unloadedChunkCompound.chunkCompound); + } catch (Exception error) { + Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); + } + }); + + chunkCallback.onFinish(); + + pendingTask.complete(null); + PENDING_CHUNK_ACTIONS.remove(pendingTask); + }); + } + + private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + CompletableFutureList readChunksTasksList = new CompletableFutureList<>(-1); + + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + CompletableFuture readTask = new CompletableFuture<>(); + readChunksTasksList.add(readTask); + + regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + readTask.completeExceptionally(error); + } else { + entityDataOptional.ifPresent(entityData -> { + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + }); + + readTask.complete(null); + } + }); + }); + + BukkitExecutor.createTask().runAsync(v -> { + readChunksTasksList.forEachCompleted(p -> { + // Wait for all chunks to load. + }, error -> { + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk:"); + }); + }).runSync(v -> { + chunkCallback.onFinish(); + }); + } else { + BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + MoonriseRegionFileIO.RegionDataController regionDataController = + serverLevel.moonrise$getEntityChunkDataController(); + int chunkX = chunkPosition.getX(); + int chunkZ = chunkPosition.getZ(); + MoonriseRegionFileIO.RegionDataController.ReadData readData = + regionDataController.readData(chunkX, chunkZ); + if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { + net.minecraft.nbt.CompoundTag entityData = readData.syncRead(); + if (entityData != null) { + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + } catch (IOException error) { + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }).runSync(v -> { + chunkCallback.onFinish(); + }); + } + } + + public static List> getPendingChunkActions() { + return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), + null); + } + + public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chunkX, int chunkZ, Packet packet) { + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); + ChunkHolder chunkHolder; + + try { + chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); + } catch (Throwable ex) { + chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); + } + + if (chunkHolder != null) { + if (SEND_PACKETS_TO_RELEVANT_PLAYERS.isValid()) { + SEND_PACKETS_TO_RELEVANT_PLAYERS.invoke(chunkHolder, packet, false); + } else { + chunkHolder.playerProvider.getPlayers(chunkPos, false).forEach(serverPlayer -> + serverPlayer.connection.send(packet)); + } + } + } + + public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, + CompoundTag statesTag, CompoundTag tileEntity) { + ServerLevel serverLevel = levelChunk.level; + + if (!isValidPosition(serverLevel, blockPos)) + return; + + BlockState blockState = Block.stateById(combinedId); + + if (statesTag != null) { + for (Map.Entry> entry : statesTag.entrySet()) { + try { + // noinspection rawtypes + Property property = PropertiesMapper.getProperty(entry.getKey()); + if (property != null) { + if (entry.getValue() instanceof ByteTag) { + // noinspection unchecked + blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); + } else if (entry.getValue() instanceof IntArrayTag) { + int[] data = ((IntArrayTag) entry.getValue()).getValue(); + // noinspection unchecked + blockState = blockState.setValue(property, data[0]); + } else if (entry.getValue() instanceof StringTag) { + String data = ((StringTag) entry.getValue()).getValue(); + // noinspection unchecked + blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); + } + } + } catch (Exception ignored) { + } + } + } + + if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || + blockState.getBlock() instanceof BedBlock) { + serverLevel.setBlock(blockPos, blockState, 3); + return; + } + + int indexY = serverLevel.getSectionIndex(blockPos.getY()); + + LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; + + int blockX = blockPos.getX() & 15; + int blockY = blockPos.getY(); + int blockZ = blockPos.getZ() & 15; + + boolean isOriginallyChunkSectionEmpty = levelChunkSection.hasOnlyAir(); + + levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); + + levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); + levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); + levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); + levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); + + levelChunk.markUnsaved(); + + boolean isChunkSectionEmpty = levelChunkSection.hasOnlyAir(); + + if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) + serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); + + serverLevel.getLightEngine().checkBlock(blockPos); + + if (tileEntity != null) { + net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); + if (tileEntityCompound != null) { + tileEntityCompound.putInt("x", blockPos.getX()); + tileEntityCompound.putInt("y", blockPos.getY()); + tileEntityCompound.putInt("z", blockPos.getZ()); + BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); + if (worldBlockEntity != null) + worldBlockEntity.loadWithComponents(tileEntityCompound, MinecraftServer.getServer().registryAccess()); + } + } + } + + public static boolean isDoubleBlock(Block block, BlockState blockState) { + return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && + blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; + } + + @Nullable + public static LevelChunk getCraftChunkHandle(CraftChunk craftChunk) { + ServerLevel serverLevel = craftChunk.getCraftWorld().getHandle(); + LevelChunk loadedChunk = serverLevel.getChunkIfLoaded(craftChunk.getX(), craftChunk.getZ()); + if (loadedChunk != null) + return loadedChunk; + + return (LevelChunk) serverLevel.getChunk(craftChunk.getX(), craftChunk.getZ(), ChunkStatus.FULL, true); + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkAccess chunkAccess) { + CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), serverLevel.generator); + + ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); + + // Unsafe: we do not provide chunks cache, even tho it is required. + // Should be fine in normal flow, as the only method that access the chunsk cache + // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 + WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); + + customChunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public record UnloadedChunkCompound(ChunkPosition chunkPosition, + net.minecraft.nbt.CompoundTag chunkCompound) { + + public ListTag getSections() { + return chunkCompound.getList("sections", 10); + } + + public ListTag getEntities() { + return chunkCompound.getList("Entities", 10); + } + + public void setSections(ListTag sectionsList) { + chunkCompound.put("sections", sectionsList); + } + + public void setEntities(ListTag entitiesList) { + chunkCompound.put("entities", entitiesList); + } + + public void setBlockEntities(ListTag blockEntitiesList) { + chunkCompound.put("block_entities", blockEntitiesList); + } + + public ServerLevel serverLevel() { + return ((CraftWorld) chunkPosition.getWorld()).getHandle(); + } + + public ChunkPos chunkPos() { + return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + } + + } + + private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { + return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && + blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && + blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); + } + + public interface ChunkCallback { + + void onLoadedChunk(LevelChunk levelChunk); + + void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + + default void onChunkNotExist(ChunkPosition chunkPosition) { + + } + + void onFinish(); + + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java new file mode 100644 index 0000000000..5eee65ef73 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -0,0 +1,411 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; +import com.bgsoftware.superiorskyblock.nms.ICachedBlock; +import com.bgsoftware.superiorskyblock.nms.NMSWorld; +import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.generator.IslandsGeneratorImpl; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.PropertiesMapper; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.block.entity.SpawnerBlockEntity; +import net.minecraft.world.level.block.entity.TickingBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Bukkit; +import org.bukkit.ChunkSnapshot; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.block.CraftSign; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.block.SignChangeEvent; + +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.function.IntFunction; + +public class NMSWorldImpl implements NMSWorld { + + private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); + private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( + Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PUBLIC = new ReflectField<>( + Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + + private final SuperiorSkyblockPlugin plugin; + + public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + } + + @Override + public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); + Location location = new Location( + Bukkit.getWorld(chunkSnapshot.getWorldName()), + (chunkSnapshot.getX() << 4) + x, + y, + (chunkSnapshot.getZ() << 4) + z + ); + + return Keys.of(KeyBlocksCache.getBlockKey(block), location); + } + + @Override + public void listenSpawner(Location location, IntFunction delayChangeCallback) { + World world = location.getWorld(); + + if (world == null) + return; + + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + + if (!(blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity)) + return; + + List blockEntityTickers; + + if (LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.isValid()) { + blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.get(serverLevel); + } else { + blockEntityTickers = serverLevel.blockEntityTickers; + } + + Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); + List tickersToAdd = new ArrayList<>(); + + while (blockEntityTickersIterator.hasNext()) { + TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); + if (tickingBlockEntity.getPos().equals(blockPos) && + !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { + blockEntityTickersIterator.remove(); + tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); + } + } + + if (!tickersToAdd.isEmpty()) + blockEntityTickers.addAll(tickersToAdd); + } + + @Override + public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { + if (!plugin.getSettings().isWorldBorders()) + return; + + Player player = superiorPlayer.asPlayer(); + World world = superiorPlayer.getWorld(); + + if (world == null || player == null) + return; + + int islandSize = island == null ? 0 : island.getIslandSize(); + + boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; + + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + + WorldBorder worldBorder; + + if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { + worldBorder = serverLevel.getWorldBorder(); + } else { + Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); + if (dimension == null) + return; + + Location center = island.getCenter(dimension); + + worldBorder = new WorldBorder(); + worldBorder.world = serverLevel; + worldBorder.setWarningBlocks(0); + worldBorder.setCenter(center.getX(), center.getZ()); + + switch (superiorPlayer.getBorderColor()) { + case BLUE -> { + worldBorder.setSize((islandSize * 2) + 1D); + } + case GREEN -> { + worldBorder.setSize((islandSize * 2) + 1.001D); + worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); + } + case RED -> { + worldBorder.setSize((islandSize * 2) + 1D); + worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); + } + } + } + + ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); + ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); + } + + @Override + public Object getBlockData(org.bukkit.block.Block block) { + return block.getBlockData(); + } + + @Override + public void setBlock(Location location, int combinedId) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); + NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + } + + @Override + public ICachedBlock cacheBlock(org.bukkit.block.Block block) { + return new NMSCachedBlock(block); + } + + @Override + public CompoundTag readBlockStates(Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockState blockState = serverLevel.getBlockState(blockPos); + + if (blockState.getValues().isEmpty()) + return null; + + CompoundTag compoundTag = new CompoundTag(); + + blockState.getValues().forEach((property, value) -> { + String name = PropertiesMapper.getPropertyName(property); + + if (property instanceof BooleanProperty) { + compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); + } else if (property instanceof IntegerProperty integerProperty) { + compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); + } else if (property instanceof EnumProperty) { + compoundTag.setString(name, ((Enum) value).name()); + } + }); + + return compoundTag; + } + + @Override + public byte[] getLightLevels(Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return new byte[0]; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + + LevelLightEngine lightEngine = serverLevel.getLightEngine(); + return new byte[]{ + location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : + (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), + (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) + }; + } + + @Override + public CompoundTag readTileEntity(Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + + if (blockEntity == null) + return null; + + net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + + compoundTag.remove("x"); + compoundTag.remove("y"); + compoundTag.remove("z"); + + return CompoundTag.fromNBT(compoundTag); + } + + @Override + public boolean isWaterLogged(org.bukkit.block.Block block) { + if (Materials.isWater(block.getType())) + return true; + + BlockData blockData = block.getBlockData(); + + return blockData instanceof BubbleColumn || + (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); + } + + @Override + public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { + BlockState blockState = ((CraftBlock) block).getNMS(); + return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; + } + + @Override + public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { + return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); + } + + @Override + public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { + return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); + } + + private int getDefaultAmount(BlockState blockState) { + Block block = blockState.getBlock(); + return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; + } + + @Override + public void placeSign(Island island, Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + + if (!(blockEntity instanceof SignBlockEntity signBlockEntity)) + return; + + String[] lines = new String[4]; + Component[] messages = signBlockEntity.getFrontText().getMessages(false); + System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length); + String[] strippedLines = new String[4]; + for (int i = 0; i < 4; i++) + strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); + + Component[] newLines; + + IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); + if (result.isCancelEvent()) { + newLines = CraftSign.sanitizeLines(strippedLines); + } else { + newLines = CraftSign.sanitizeLines(lines); + } + + System.arraycopy(newLines, 0, messages, 0, 4); + } + + @SuppressWarnings("deprecation") + @Override + public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { + if (LINES_SIGN_CHANGE_EVENT.isValid()) { + for (int i = 0; i < lines.length; i++) + signChangeEvent.setLine(i, lines[i]); + } + } + + @Override + public void playGeneratorSound(Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + serverLevel.levelEvent(1501, blockPos, 0); + } + + @Override + public void playBreakAnimation(org.bukkit.block.Block block) { + ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); + BlockPos blockPos = new BlockPos(block.getX(), block.getY(), block.getZ()); + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + } + + @Override + public void playPlaceSound(Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); + + serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, + (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } + + @Override + public int getMinHeight(World world) { + return world.getMinHeight(); + } + + @Override + public void removeAntiXray(World bukkitWorld) { + // Doesn't exist in this version. + } + + @Override + public IslandsGenerator createGenerator(Dimension dimension) { + return new IslandsGeneratorImpl(dimension); + } + + @Override + public WorldEditSession createEditSession(World world) { + return new WorldEditSessionImpl(((CraftWorld) world).getHandle()); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsBlockEntity.java new file mode 100644 index 0000000000..f89d0bc82b --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsBlockEntity.java @@ -0,0 +1,141 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.chunks; + +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; + +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Consumer; + +public class CropsBlockEntity extends BlockEntity { + + private static final ReflectMethod BLOCK_IS_RANDOMLY_TICKING = new ReflectMethod<>( + BlockBehaviour.class, boolean.class, "f", BlockState.class); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); + private static int random = ThreadLocalRandom.current().nextInt(); + + private final WeakReference island; + private final WeakReference chunk; + private final int chunkX; + private final int chunkZ; + + private int currentTick = 0; + + private double cachedCropGrowthMultiplier; + + private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { + super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); + this.island = new WeakReference<>(island); + this.chunk = new WeakReference<>(levelChunk); + ChunkPos chunkPos = levelChunk.getPos(); + this.chunkX = chunkPos.x; + this.chunkZ = chunkPos.z; + setLevel(levelChunk.level); + levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); + this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; + } + + public static void create(Island island, LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + long chunkPair = chunkPos.toLong(); + tickingChunks.computeIfAbsent(chunkPair, p -> { + BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); + return new CropsBlockEntity(island, levelChunk, blockPos); + }); + } + + public static CropsBlockEntity remove(long chunkPos) { + return tickingChunks.remove(chunkPos); + } + + public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { + if (tickingChunks.isEmpty()) + return; + + chunkPositions.forEach(chunkPosition -> { + long chunkKey = chunkPosition.asPair(); + CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); + if (cropsBlockEntity != null) + cropsBlockEntityConsumer.accept(cropsBlockEntity); + }); + } + + @Override + public boolean isValidBlockState(BlockState state) { + return true; + } + + public void remove() { + this.remove = true; + } + + public void tick() { + if (++currentTick <= plugin.getSettings().getCropsInterval()) + return; + + LevelChunk levelChunk = this.chunk.get(); + Island island = this.island.get(); + ServerLevel serverLevel = (ServerLevel) getLevel(); + + if (levelChunk == null || island == null || serverLevel == null) { + remove(); + return; + } + + currentTick = 0; + + int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); + + int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); + + if (chunkRandomTickSpeed > 0) { + LevelChunkSection[] sections = levelChunk.getSections(); + for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; + if (levelChunkSection != null && levelChunkSection.isRandomlyTicking()) { + for (int i = 0; i < chunkRandomTickSpeed; i++) { + random = random * 3 + 1013904223; + int factor = random >> 2; + int x = factor & 15; + int z = factor >> 8 & 15; + int y = factor >> 16 & 15; + BlockState blockState = levelChunkSection.getBlockState(x, y, z); + Block block = blockState.getBlock(); + if (BLOCK_IS_RANDOMLY_TICKING.invoke(block, blockState) && plugin.getSettings().getCropsToGrow().contains( + CraftMagicNumbers.getMaterial(block).name())) { + BlockPos blockPos = new BlockPos(x + (chunkX << 4), y + sectionBottomY, z + (chunkZ << 4)); + blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); + } + } + } + + } + } + } + + public void setCropGrowthMultiplier(double cropGrowthMultiplier) { + this.cachedCropGrowthMultiplier = cropGrowthMultiplier; + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsTickingBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsTickingBlockEntity.java new file mode 100644 index 0000000000..2cc80b2172 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsTickingBlockEntity.java @@ -0,0 +1,30 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.chunks; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.TickingBlockEntity; + +public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { + + + @Override + public void tick() { + cropsBlockEntity.tick(); + } + + @Override + public boolean isRemoved() { + return cropsBlockEntity.isRemoved(); + } + + @Override + public BlockPos getPos() { + return cropsBlockEntity.getBlockPos(); + } + + @Override + public String getType() { + return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/DragonUtils.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/DragonUtils.java new file mode 100644 index 0000000000..ce1e97f4b0 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/DragonUtils.java @@ -0,0 +1,37 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; + +import com.bgsoftware.common.reflection.ReflectField; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; + +import java.lang.reflect.Modifier; + +public class DragonUtils { + + private static final ReflectField END_PODIUM_LOCATION = new ReflectField( + EndPodiumFeature.class, BlockPos.class, + Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) + .removeFinal(); + + private static BlockPos currentPodiumPosition = BlockPos.ZERO; + + private DragonUtils() { + + } + + public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { + try { + END_PODIUM_LOCATION.set(null, podiumPosition); + currentPodiumPosition = podiumPosition; + runnable.run(); + } finally { + END_PODIUM_LOCATION.set(null, BlockPos.ZERO); + currentPodiumPosition = BlockPos.ZERO; + } + } + + public static BlockPos getCurrentPodiumPosition() { + return currentPodiumPosition; + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndWorldEndDragonFightHandler.java new file mode 100644 index 0000000000..e78f27aa4e --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndWorldEndDragonFightHandler.java @@ -0,0 +1,47 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; + +import com.bgsoftware.common.annotations.Nullable; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class EndWorldEndDragonFightHandler extends EndDragonFight { + + private final Map worldDragonFightsMap = new HashMap<>(); + private final List worldDragonFightsList = new LinkedList<>(); + + public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + this.worldDragonFightsList.forEach(EndDragonFight::tick); + } + + public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + if (oldDragonFight != null) + this.worldDragonFightsList.remove(oldDragonFight); + this.worldDragonFightsList.add(endDragonFight); + } + + @Nullable + public IslandEndDragonFight getDragonFight(UUID uuid) { + return this.worldDragonFightsMap.get(uuid); + } + + @Nullable + public IslandEndDragonFight removeDragonFight(UUID uuid) { + IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + if (endDragonFight != null) + this.worldDragonFightsList.remove(endDragonFight); + return endDragonFight; + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEndDragonFight.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEndDragonFight.java new file mode 100644 index 0000000000..90145d5df6 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEndDragonFight.java @@ -0,0 +1,205 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; +import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; +import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; +import net.minecraft.world.level.block.state.pattern.BlockInWorld; +import net.minecraft.world.level.block.state.pattern.BlockPattern; +import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; +import net.minecraft.world.level.block.state.predicate.BlockPredicate; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public class IslandEndDragonFight extends EndDragonFight { + + private static final ReflectField DRAGON_BATTLE = new ReflectField( + EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) + .removeFinal(); + private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( + EndDragonFight.class, boolean.class, Modifier.PRIVATE, 4); + private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( + EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); + + private static final ReflectField TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>( + EndDragonFight.class, int.class, Modifier.PRIVATE, 4); + private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( + DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); + + private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() + .aisle(" ", " ", " ", " # ", " ", " ", " ") + .aisle(" ", " ", " ", " # ", " ", " ", " ") + .aisle(" ", " ", " ", " # ", " ", " ", " ") + .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") + .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") + .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) + .build(); + + private final Island island; + private final BlockPos islandBlockPos; + private final Vec3 islandBlockVectored; + private final ServerLevel serverLevel; + private final IslandEntityEnderDragon entityEnderDragon; + + private byte currentTick = 0; + + public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { + this(island, serverLevel, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), null); + } + + public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, + @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + + this.island = island; + this.islandBlockPos = islandBlockPos; + this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); + this.serverLevel = serverLevel; + this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; + + SCAN_FOR_LEGACY_PORTALS.set(this, false); + WAS_DRAGON_KILLED.set(this, false); + DRAGON_BATTLE.set(this.entityEnderDragon, this); + + TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); + } + + @Override + public void tick() { + // doServerTick + + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); + + DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); + if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { + LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); + } + + if (++currentTick >= 20) { + updateBattlePlayers(); + currentTick = 0; + TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); + } + } + + @Nullable + @Override + public BlockPattern.BlockPatternMatch findExitPortal() { + int chunkX = this.islandBlockPos.getX() >> 4; + int chunkZ = this.islandBlockPos.getZ() >> 4; + + for (int x = -8; x <= 8; ++x) { + for (int z = -8; z <= 8; ++z) { + LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); + + for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { + if (blockEntity instanceof TheEndPortalBlockEntity) { + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( + this.serverLevel, blockEntity.getBlockPos()); + + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + + return blockPatternMatch; + } + } + } + } + } + + int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); + + for (int y = highestBlock; y >= this.serverLevel.getMinY(); --y) { + BlockPos currentPosition = new BlockPos(this.islandBlockPos.getX(), y, this.islandBlockPos.getZ()); + + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); + + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + + return blockPatternMatch; + } + } + + return null; + } + + @Override + public void resetSpikeCrystals() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); + } + + public void removeBattlePlayers() { + List dragonEventPlayers = new SequentialListBuilder() + .build(this.dragonEvent.getPlayers()); + for (ServerPlayer serverPlayer : dragonEventPlayers) + this.dragonEvent.removePlayer(serverPlayer); + } + + public IslandEntityEnderDragon getEnderDragon() { + return this.entityEnderDragon; + } + + private void updateBattlePlayers() { + Set nearbyPlayers = new HashSet<>(); + + for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { + Player bukkitPlayer = superiorPlayer.asPlayer(); + if (bukkitPlayer != null) { + ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); + if (serverPlayer.serverLevel().equals(this.serverLevel)) { + this.dragonEvent.addPlayer(serverPlayer); + nearbyPlayers.add(serverPlayer.getUUID()); + } + } + } + + List dragonEventPlayers = new SequentialListBuilder() + .build(this.dragonEvent.getPlayers()); + + dragonEventPlayers.stream() + .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) + .forEach(this.dragonEvent::removePlayer); + } + + private IslandEntityEnderDragon spawnEnderDragon() { + IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); + + entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); + entityEnderDragon.absMoveTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), + this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); + + this.serverLevel.addFreshEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); + + this.dragonUUID = entityEnderDragon.getUUID(); + this.resetSpikeCrystals(); + + return entityEnderDragon; + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java new file mode 100644 index 0000000000..e5e6bcec7b --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java @@ -0,0 +1,81 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.config.SettingsManager; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.level.Level; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftEnderDragon; + +public class IslandEntityEnderDragon extends EnderDragon { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + @NotNull + public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { + return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : + new EnderDragon(entityTypes, level); + } + + private final ServerLevel serverLevel; + private final Dimension dimension; + private BlockPos islandBlockPos; + + public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { + this(level); + this.islandBlockPos = islandBlockPos; + } + + private IslandEntityEnderDragon(Level level) { + super(EntityType.ENDER_DRAGON, level); + this.serverLevel = (ServerLevel) level; + this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + } + + @Override + public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { + // loadData + + super.readAdditionalSaveData(compoundTag); + + if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) + return; + + Location entityLocation = getBukkitEntity().getLocation(); + Island island = plugin.getGrid().getIslandAt(entityLocation); + + if (island == null) + return; + + Location middleBlock = island.getCenter(dimension); + + SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); + if (dimensionConfig instanceof SettingsManager.Worlds.End) { + middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); + } + + this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); + + IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); + dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + } + + @Override + public void aiStep() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); + } + + @Override + @NotNull + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/SpikesCache.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/SpikesCache.java new file mode 100644 index 0000000000..1e3108407b --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/SpikesCache.java @@ -0,0 +1,189 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; + + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.CacheStats; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.level.levelgen.feature.SpikeFeature; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class SpikesCache implements LoadingCache> { + + private static final SpikesCache INSTANCE = new SpikesCache(); + + private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() + .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); + + private long worldSeed; + + public static SpikesCache getInstance() { + return INSTANCE; + } + + private SpikesCache() { + + } + + @Override + public @NotNull + List get(@NotNull Long worldSeed) throws ExecutionException { + try { + this.worldSeed = worldSeed; + return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); + } finally { + this.worldSeed = 0; + } + } + + @Override + public @NotNull + List getUnchecked(@NotNull Long worldSeed) { + try { + this.worldSeed = worldSeed; + return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); + } finally { + this.worldSeed = 0; + } + } + + @Override + public @NotNull + ImmutableMap> getAll(@NotNull Iterable keys) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public List apply(@NotNull Long worldSeed) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public void refresh(@NotNull Long worldSeed) { + try { + this.worldSeed = worldSeed; + cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); + } finally { + this.worldSeed = 0; + } + } + + @Override + public @NotNull + ConcurrentMap> asMap() { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Nullable + @Override + public List getIfPresent(@NotNull Object worldSeed) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public @NotNull + List get(@NotNull Long worldSeed, + @NotNull Callable> loader) throws ExecutionException { + try { + this.worldSeed = worldSeed; + return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); + } finally { + this.worldSeed = 0; + } + } + + @Override + public @NotNull + ImmutableMap> getAllPresent(@NotNull Iterable keys) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public void put(@NotNull Long worldSeed, @NotNull List spikes) { + try { + this.worldSeed = worldSeed; + cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); + } finally { + this.worldSeed = 0; + } + } + + @Override + public void putAll(Map> spikesMap) { + spikesMap.forEach(this::put); + } + + @Override + public void invalidate(@NotNull Object worldSeed) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public void invalidateAll(@NotNull Iterable keys) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public void invalidateAll() { + this.cachedSpikes.invalidateAll(); + } + + @Override + public long size() { + return this.cachedSpikes.size(); + } + + @Override + public @NotNull + CacheStats stats() { + return this.cachedSpikes.stats(); + } + + @Override + public void cleanUp() { + this.cachedSpikes.cleanUp(); + } + + private class InternalCacheLoader extends CacheLoader> { + + @Override + public @NotNull + List load(@NotNull BlockPos blockPos) { + List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); + + Collections.shuffle(list, new Random(worldSeed)); + List spikesList = Lists.newArrayList(); + + for (int i = 0; i < 10; ++i) { + int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); + int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); + int l = list.get(i); + int radius = 2 + l / 3; + int height = 76 + l * 3; + boolean guarded = l == 1 || l == 2; + + spikesList.add(new SpikeFeature.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded)); + } + + return spikesList; + } + + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java new file mode 100644 index 0000000000..96e07d945c --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java @@ -0,0 +1,113 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.enchantment; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.common.reflection.ReflectMethod; +import net.minecraft.core.HolderSet; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.Registry; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.enchantment.Enchantment; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.enchantments.CraftEnchantment; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Map; + +public class GlowEnchantment extends CraftEnchantment { + + private static final ReflectField REGISTRY_FROZEN = new ReflectField<>( + MappedRegistry.class, boolean.class, Modifier.PRIVATE, 1); + + private static final ReflectField REGISTRY_ALL_TAGS = new ReflectField<>( + MappedRegistry.class, Object.class, "k"); + + private static final ReflectField, HolderSet.Named>> REGISTRY_FROZEN_TAGS = new ReflectField<>( + MappedRegistry.class, Map.class, Modifier.PRIVATE | Modifier.FINAL, 6); + + private static final ReflectMethod REGISTRY_TAG_SET_UNBOUND; + + static { + Class tagSetClass = MappedRegistry.class.getDeclaredClasses()[0]; + if (!tagSetClass.isInterface()) + throw new IllegalStateException("TagSet was not found, but " + tagSetClass); + + REGISTRY_TAG_SET_UNBOUND = new ReflectMethod<>(tagSetClass, tagSetClass, 1, new Class[0]); + } + + private static final String GLOW_ENCHANTMENT_NAME = "superiorskyblock_glowing_enchant"; + + private static final Enchantment HANDLE = initializeHandle(); + + private static Enchantment initializeHandle() { + Enchantment handle = new Enchantment( + Component.empty(), + Enchantment.definition( + HolderSet.empty(), + 1, + 1, + Enchantment.constantCost(0), + Enchantment.constantCost(0), + 0), + HolderSet.empty(), + DataComponentMap.EMPTY + ); + + MinecraftServer.getServer().registryAccess().lookup(Registries.ENCHANTMENT).ifPresent(registry -> { + try { + REGISTRY_FROZEN.set(registry, false); + try { + // This may throw IllegalStateException which we don't care about. + registry.createIntrusiveHolder(handle); + } catch (Throwable ignored) { + } + Registry.register(registry, ResourceLocation.withDefaultNamespace(GLOW_ENCHANTMENT_NAME), handle); + } finally { + freezeRegistry(registry); + } + }); + + return handle; + } + + private static void freezeRegistry(Registry registry) { + try { + freezeRegistryUnsafe(registry); + } catch (Throwable error) { + throw new RuntimeException(error); + } + } + + private static void freezeRegistryUnsafe(Registry registry) throws Exception { + Object allTags = REGISTRY_ALL_TAGS.get(registry); + + Field tagSetMapsField = allTags.getClass().getDeclaredFields()[0]; + tagSetMapsField.setAccessible(true); + + Map, HolderSet.Named> tagsMap = + (Map, HolderSet.Named>) tagSetMapsField.get(allTags); + Map, HolderSet.Named> frozenTags = REGISTRY_FROZEN_TAGS.get(registry); + + tagsMap.forEach(frozenTags::putIfAbsent); + + Object unboundTagSet = REGISTRY_TAG_SET_UNBOUND.invoke(registry); + REGISTRY_ALL_TAGS.set(registry, unboundTagSet); + + registry.freeze(); + + frozenTags.forEach(tagsMap::putIfAbsent); + + tagSetMapsField.set(allTags, tagsMap); + REGISTRY_ALL_TAGS.set(registry, allTags); + } + + public GlowEnchantment() { + super(NamespacedKey.minecraft(GLOW_ENCHANTMENT_NAME), HANDLE); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/generator/IslandsGeneratorImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/generator/IslandsGeneratorImpl.java new file mode 100644 index 0000000000..c896500ee1 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/generator/IslandsGeneratorImpl.java @@ -0,0 +1,67 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.generator; + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.WorldInfo; + +import java.util.Collections; +import java.util.List; +import java.util.Random; + +@SuppressWarnings({"unused", "NullableProblems"}) +public class IslandsGeneratorImpl extends IslandsGenerator { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Dimension dimension; + + public IslandsGeneratorImpl(Dimension dimension) { + this.dimension = dimension; + } + + @Override + public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, + @NotNull ChunkData chunkData) { + if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { + chunkData.setBlock(0, 99, 0, Material.BEDROCK); + } + } + + @Override + public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { + return new BiomeProvider() { + @Override + public @NotNull + Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { + return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension); + } + + @Override + public @NotNull + List getBiomes(@NotNull WorldInfo worldInfo) { + return IslandUtils.getDefaultWorldBiomes(); + } + + }; + } + + @Override + public List getDefaultPopulators(World world) { + return Collections.emptyList(); + } + + @Override + public Location getFixedSpawnLocation(World world, Random random) { + return new Location(world, 0, 100, 0); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuBrewingStandBlockEntity.java new file mode 100644 index 0000000000..04d3a730f6 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuBrewingStandBlockEntity.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.menu; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; +import org.bukkit.inventory.InventoryHolder; + +public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { + + private final InventoryHolder holder; + + public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { + super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); + this.holder = holder; + this.name = Component.nullToEmpty(title); + } + + @Override + public InventoryHolder getOwner() { + return holder; + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuDispenserBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuDispenserBlockEntity.java new file mode 100644 index 0000000000..bbf1632899 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuDispenserBlockEntity.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.menu; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.DispenserBlockEntity; +import org.bukkit.inventory.InventoryHolder; + +public class MenuDispenserBlockEntity extends DispenserBlockEntity { + + private final InventoryHolder holder; + + public MenuDispenserBlockEntity(InventoryHolder holder, String title) { + super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); + this.holder = holder; + this.name = Component.nullToEmpty(title); + } + + @Override + public InventoryHolder getOwner() { + return holder; + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuFurnaceBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuFurnaceBlockEntity.java new file mode 100644 index 0000000000..77a85ea54d --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuFurnaceBlockEntity.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.menu; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.FurnaceBlockEntity; +import org.bukkit.inventory.InventoryHolder; + +public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { + + private final InventoryHolder holder; + + public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { + super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); + this.holder = holder; + this.name = Component.nullToEmpty(title); + } + + @Override + public InventoryHolder getOwner() { + return holder; + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuHopperBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuHopperBlockEntity.java new file mode 100644 index 0000000000..4f02ec085e --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuHopperBlockEntity.java @@ -0,0 +1,26 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.menu; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.HopperBlock; +import net.minecraft.world.level.block.entity.HopperBlockEntity; +import org.bukkit.inventory.InventoryHolder; + +public class MenuHopperBlockEntity extends HopperBlockEntity { + + private final InventoryHolder holder; + + public MenuHopperBlockEntity(InventoryHolder holder, String title) { + super(BlockPos.ZERO, Blocks.HOPPER.defaultBlockState().setValue(HopperBlock.FACING, Direction.DOWN)); + this.holder = holder; + this.name = Component.nullToEmpty(title); + } + + @Override + public InventoryHolder getOwner() { + return holder; + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/spawners/TickingSpawnerBlockEntityNotifier.java new file mode 100644 index 0000000000..31fd354396 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/spawners/TickingSpawnerBlockEntityNotifier.java @@ -0,0 +1,57 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.spawners; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BaseSpawner; +import net.minecraft.world.level.block.entity.SpawnerBlockEntity; +import net.minecraft.world.level.block.entity.TickingBlockEntity; + +import java.util.function.IntFunction; + +public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { + + private final SpawnerBlockEntity spawnerBlockEntity; + private final TickingBlockEntity tickingBlockEntity; + private final IntFunction delayChangeCallback; + + public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, + IntFunction delayChangeCallback) { + this.spawnerBlockEntity = spawnerBlockEntity; + this.tickingBlockEntity = tickingBlockEntity; + this.delayChangeCallback = delayChangeCallback; + updateDelay(); + } + + @Override + public void tick() { + BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); + int startDelay = baseSpawner.spawnDelay; + try { + tickingBlockEntity.tick(); + } finally { + int newDelay = baseSpawner.spawnDelay; + if (newDelay > startDelay) + updateDelay(); + } + } + + @Override + public boolean isRemoved() { + return tickingBlockEntity.isRemoved(); + } + + @Override + public BlockPos getPos() { + return tickingBlockEntity.getPos(); + } + + @Override + public String getType() { + return tickingBlockEntity.getType(); + } + + public void updateDelay() { + BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); + baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java new file mode 100644 index 0000000000..613b7b40b1 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java @@ -0,0 +1,32 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; + +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.level.block.Block; +import org.bukkit.Material; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class KeyBlocksCache { + + private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); + + private KeyBlocksCache() { + + } + + public static Key getBlockKey(Block block) { + return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { + Material blockType = CraftMagicNumbers.getMaterial(block); + return blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); + }); + } + + public static void cacheAllBlocks() { + BuiltInRegistries.BLOCK.forEach(KeyBlocksCache::getBlockKey); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapper.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapper.java new file mode 100644 index 0000000000..b614485ebc --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapper.java @@ -0,0 +1,85 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; + +import com.bgsoftware.superiorskyblock.core.logging.Log; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.Property; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Map; + +public class PropertiesMapper { + + private static final Map> nameToProperty = new HashMap<>(); + private static final Map, String> propertyToName = new HashMap<>(); + + static { + Map fieldsToNames = new IdentityHashMap<>(); + + fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); + fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); + fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); + fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); + fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); + fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); + fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); + fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); + fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); + fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); + fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); + fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); + fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); + fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); + fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); + fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); + fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); + fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); + fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); + fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); + fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); + fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); + fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); + fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); + fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); + fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); + fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); + fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); + fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); + fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); + + try { + for (Field field : BlockStateProperties.class.getFields()) { + field.setAccessible(true); + Object value = field.get(null); + if (value instanceof Property) { + Property property = (Property) value; + register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); + } + } + } catch (Exception error) { + Log.error(error, "An unexpected error occurred while loading properties mapper:"); + } + + } + + private static void register(String key, String fieldName, Property property) { + if (nameToProperty.containsKey(key)) { + Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); + } else { + nameToProperty.put(key, property); + propertyToName.put(property, key); + } + } + + public static Property getProperty(String name) { + return nameToProperty.get(name); + } + + public static String getPropertyName(Property property) { + return propertyToName.get(property); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java new file mode 100644 index 0000000000..9e28acd363 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java @@ -0,0 +1,327 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.ByteTag; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.tag.IntArrayTag; +import com.bgsoftware.superiorskyblock.tag.StringTag; +import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.BedBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.generator.ChunkGenerator; + +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionImpl implements WorldEditSession { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); + private final ServerLevel serverLevel; + private final Dimension dimension; + + public WorldEditSessionImpl(ServerLevel serverLevel) { + this.serverLevel = serverLevel; + this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + } + + @Override + public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, + @Nullable CompoundTag blockEntityData) { + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + + if (!isValidPosition(blockPos)) + return; + + BlockState blockState = Block.stateById(combinedId); + + if (statesTag != null) { + for (Map.Entry> entry : statesTag.entrySet()) { + try { + // noinspection rawtypes + Property property = PropertiesMapper.getProperty(entry.getKey()); + if (property != null) { + if (entry.getValue() instanceof ByteTag) { + // noinspection unchecked + blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); + } else if (entry.getValue() instanceof IntArrayTag) { + int[] data = ((IntArrayTag) entry.getValue()).getValue(); + // noinspection unchecked + blockState = blockState.setValue(property, data[0]); + } else if (entry.getValue() instanceof StringTag) { + String data = ((StringTag) entry.getValue()).getValue(); + // noinspection unchecked + blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); + } + } + } catch (Exception ignored) { + } + } + } + + if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || + blockState.getBlock() instanceof BedBlock) { + blocksToUpdate.add(new Pair<>(blockPos, blockState)); + return; + } + + ChunkPos chunkPos = new ChunkPos(blockPos); + + if (blockEntityData != null) + blockEntities.add(new Pair<>(blockPos, blockEntityData)); + + ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); + + if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) + chunkData.lights.add(blockPos); + + LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + + int blockX = blockPos.getX() & 15; + int blockY = blockPos.getY(); + int blockZ = blockPos.getZ() & 15; + + levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); + + chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); + chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); + chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); + chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); + } + + @Override + public List getAffectedChunks() { + List chunkPositions = new LinkedList<>(); + World bukkitWorld = serverLevel.getWorld(); + LongIterator iterator = chunks.keyIterator(); + while (iterator.hasNext()) { + long chunkKey = iterator.next(); + ChunkPos chunkPos = new ChunkPos(chunkKey); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkPos.x, chunkPos.z)); + } + return chunkPositions; + } + + @Override + public void applyBlocks(Chunk bukkitChunk) { + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); + ChunkPos chunkPos = levelChunk.getPos(); + + long chunkKey = chunkPos.toLong(); + ChunkData chunkData = this.chunks.remove(chunkKey); + + if (chunkData == null) + return; + + int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); + for (int i = 0; i < chunkSectionsCount; ++i) { + levelChunk.getSections()[i] = chunkData.chunkSections[i]; + } + + chunkData.heightmaps.forEach(((type, heightmap) -> { + levelChunk.setHeightmap(type, heightmap.getRawData()); + })); + + if (plugin.getSettings().isLightsUpdate()) { + if (isStarLightInterface) { + this.lightenChunks.add(chunkPos); + } else { + ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); + chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); + // Queues chunk light for this chunk. + threadedLevelLightEngine.lightChunk(levelChunk, false); + } + } + + levelChunk.markUnsaved(); + } + + @Override + public void finish(Island island) { + // Update blocks + blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); + + // Update block entities + blockEntities.forEach(data -> { + net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); + if (blockEntityCompound != null) { + BlockPos blockPos = data.getKey(); + blockEntityCompound.putInt("x", blockPos.getX()); + blockEntityCompound.putInt("y", blockPos.getY()); + blockEntityCompound.putInt("z", blockPos.getZ()); + + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + + BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); + if (worldBlockEntity != null) + worldBlockEntity.loadWithComponents(blockEntityCompound, MinecraftServer.getServer().registryAccess()); + } + }); + + if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { + ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); + threadedLevelLightEngine.starlight$serverRelightChunks(lightenChunks, chunkCallback -> { + }, completeCallback -> { + }); + this.lightenChunks.clear(); + } + + } + + private boolean isValidPosition(BlockPos blockPos) { + return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && + blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && + blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); + } + + private class ChunkData { + private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; + private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); + private final List lights = isStarLightInterface ? Collections.emptyList() : new LinkedList<>(); + + public ChunkData(long chunkKey) { + ChunkPos chunkPos = new ChunkPos(chunkKey); + + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + + createChunkSections(biomesRegistry); + + ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), serverLevel, biomesRegistry, null); + + createHeightmaps(tempChunk); + runCustomWorldGenerator(tempChunk); + } + + private void createChunkSections(Registry biomesRegistry) { + Holder biome = CraftBiome.bukkitToMinecraftHolder( + IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); + + for (int i = 0; i < this.chunkSections.length; ++i) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + + this.chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + private void runCustomWorldGenerator(ProtoChunk tempChunk) { + ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); + + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; + + NMSUtils.buildSurfaceForChunk(serverLevel, tempChunk); + + // We want to copy the level chunk sections back + LevelChunkSection[] tempChunkSections = tempChunk.getSections(); + for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { + LevelChunkSection chunkSection = tempChunkSections[i]; + if (chunkSection != null) + this.chunkSections[i] = chunkSection; + } + } + + private void createHeightmaps(ProtoChunk tempChunk) { + for (Heightmap.Types heightmapType : Heightmap.Types.values()) { + if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { + this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); + } + } + } + + } + + +} diff --git a/build.gradle b/build.gradle index 698a759c78..69f10aecd2 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b8' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b9' implementation 'com.zaxxer:HikariCP:4.0.3' implementation 'org.slf4j:slf4j-api:2.0.5' diff --git a/settings.gradle b/settings.gradle index 1900e3de3c..9a8fecb0bb 100644 --- a/settings.gradle +++ b/settings.gradle @@ -61,4 +61,5 @@ include 'NMS:v1_19' include 'NMS:v1_20_3' include 'NMS:v1_20_4' include 'NMS:v1_21' -include 'NMS:v1_21_3' \ No newline at end of file +include 'NMS:v1_21_3' +include 'NMS:v1_21_4' \ No newline at end of file From 1abce2ef9e6ead08539739a5777620981de7e79e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 13 Dec 2024 17:45:54 +0200 Subject: [PATCH 005/600] Fixed errors from EntityDeathEvent in 1.21+ (#2289) --- .../upgrades/type/UpgradeTypeMobDrops.java | 62 ++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java index 97a433268f..9082bf0abf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java @@ -29,9 +29,11 @@ public class UpgradeTypeMobDrops implements IUpgradeType { new CmdAdminSetMobDrops()); private final SuperiorSkyblockPlugin plugin; + private final boolean isWildStackerInstalled; public UpgradeTypeMobDrops(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; + isWildStackerInstalled = Bukkit.getPluginManager().isPluginEnabled("WildStacker"); } @Override @@ -83,47 +85,51 @@ public void onEntityDeath(EntityDeathEvent e) { return; } + BukkitEntities.clearEntityEquipment(e.getEntity()); + double mobDropsMultiplier = island.getMobDropsMultiplier(); + if (mobDropsMultiplier <= 1) + return; - if (mobDropsMultiplier != 1 && mobDropsMultiplier > 0) { - for (ItemStack itemStack : new LinkedList<>(e.getDrops())) { - if (itemStack != null && !BukkitEntities.isEquipment(e.getEntity(), itemStack) && - !plugin.getNMSTags().serializeItem(itemStack).containsKey("WildChests")) { - int newAmount = (int) Math.floor(itemStack.getAmount() * mobDropsMultiplier); + List dropsToAdd = isWildStackerInstalled ? null : new LinkedList<>(); - if (Bukkit.getPluginManager().isPluginEnabled("WildStacker")) { - itemStack.setAmount(newAmount); - } else { - int stackAmounts = newAmount / itemStack.getMaxStackSize(); - int leftOvers = newAmount % itemStack.getMaxStackSize(); - boolean usedOriginal = false; + for (ItemStack itemStack : e.getDrops()) { + if (itemStack != null && !BukkitEntities.isEquipment(e.getEntity(), itemStack)) { + int newAmount = (int) Math.floor(itemStack.getAmount() * mobDropsMultiplier); - if (stackAmounts > 0) { - itemStack.setAmount(itemStack.getMaxStackSize()); - usedOriginal = true; + if (isWildStackerInstalled) { + itemStack.setAmount(newAmount); + } else { + int stackAmounts = newAmount / itemStack.getMaxStackSize(); + int leftOvers = newAmount % itemStack.getMaxStackSize(); + boolean usedOriginal = false; - ItemStack stackItem = itemStack.clone(); - stackItem.setAmount(itemStack.getMaxStackSize()); + if (stackAmounts > 0) { + itemStack.setAmount(itemStack.getMaxStackSize()); + usedOriginal = true; - for (int i = 0; i < stackAmounts - 1; i++) - e.getDrops().add(itemStack.clone()); - } + ItemStack stackItem = itemStack.clone(); + stackItem.setAmount(itemStack.getMaxStackSize()); - if (leftOvers > 0) { - if (usedOriginal) { - ItemStack leftOversItem = itemStack.clone(); - leftOversItem.setAmount(leftOvers); - e.getDrops().add(leftOversItem); - } else { - itemStack.setAmount(leftOvers); - } + for (int i = 0; i < stackAmounts - 1; i++) + dropsToAdd.add(itemStack.clone()); + } + + if (leftOvers > 0) { + if (usedOriginal) { + ItemStack leftOversItem = itemStack.clone(); + leftOversItem.setAmount(leftOvers); + dropsToAdd.add(leftOversItem); + } else { + itemStack.setAmount(leftOvers); } } } } } - BukkitEntities.clearEntityEquipment(e.getEntity()); + if (dropsToAdd != null) + e.getDrops().addAll(dropsToAdd); } } From 7cf5971a951d4e28360446b09f397f5483a7d060 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 13 Dec 2024 18:04:34 +0200 Subject: [PATCH 006/600] Do not cancel raids outside of island worlds (#2291) --- .../superiorskyblock/listener/ProtectionListener.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index a8d3d489be..3556e91d07 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -621,6 +621,9 @@ private class RaidTriggerListener implements Listener { @EventHandler public void onRaidTrigger(RaidTriggerEvent e) { + if (!plugin.getGrid().isIslandsWorld(e.getWorld())) + return; + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); Location location = e.getRaid().getLocation(); From a3dc9eef83400e8ae0c3fa2d3b744163adc30f41 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 13 Dec 2024 22:00:22 +0200 Subject: [PATCH 007/600] Fix stacked blocks holograms do not show up in some cases (#2293) --- .../superiorskyblock/listener/ChunksListener.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java index 7e231e18db..0471449ebc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java @@ -151,7 +151,11 @@ private void handleIslandChunkLoad(Island island, Chunk chunk, boolean isNewChun recalculateEntities.set(true); } - plugin.getStackedBlocks().updateStackedBlockHolograms(chunk); + BukkitExecutor.sync(() -> { + if (chunk.isLoaded()) + // Update holograms of stacked blocks in delay so the chunk is entirely loaded. + plugin.getStackedBlocks().updateStackedBlockHolograms(chunk); + }, 10L); BukkitExecutor.sync(() -> { if (!pendingLoadedChunksForIsland.remove(chunk) || !chunk.isLoaded()) From d5ca6163384dd258d65bbcd170ce8f6fb1ad55b6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 14 Dec 2024 14:01:54 +0200 Subject: [PATCH 008/600] Optimized crops growth multiplier on Paper servers --- .../nms/v1_16_R3/NMSChunksImpl.java | 3 +- .../v1_16_R3/crops/CropsTickingMethod.java | 122 +++++++++++++++ .../CropsTickingTileEntity.java | 39 +---- .../nms/v1_17/NMSChunksImpl.java | 2 +- .../{chunks => crops}/CropsBlockEntity.java | 36 +---- .../v1_17/crops}/CropsTickingBlockEntity.java | 2 +- .../nms/v1_17/crops/CropsTickingMethod.java | 132 ++++++++++++++++ .../nms/v1_18/NMSChunksImpl.java | 2 +- .../nms/v1_18/crops}/CropsBlockEntity.java | 46 +----- .../v1_18/crops}/CropsTickingBlockEntity.java | 2 +- .../nms/v1_18/crops/CropsTickingMethod.java | 132 ++++++++++++++++ .../nms/v1_19/NMSChunksImpl.java | 2 +- .../nms/v1_19/crops/CropsBlockEntity.java | 96 ++++++++++++ .../CropsTickingBlockEntity.java | 2 +- .../nms/v1_19/crops/CropsTickingMethod.java | 132 ++++++++++++++++ .../nms/v1_20_3/NMSChunksImpl.java | 2 +- .../nms/v1_20_3/crops/CropsBlockEntity.java | 96 ++++++++++++ .../crops}/CropsTickingBlockEntity.java | 2 +- .../nms/v1_20_3/crops/CropsTickingMethod.java | 132 ++++++++++++++++ .../nms/v1_20_4/NMSChunksImpl.java | 2 +- .../nms/v1_20_4/crops/CropsBlockEntity.java | 96 ++++++++++++ .../crops}/CropsTickingBlockEntity.java | 2 +- .../nms/v1_20_4/crops/CropsTickingMethod.java | 131 ++++++++++++++++ .../nms/v1_21/NMSChunksImpl.java | 2 +- .../nms/v1_21/chunks/CropsBlockEntity.java | 141 ------------------ .../nms/v1_21/crops}/CropsBlockEntity.java | 42 +----- .../CropsTickingBlockEntity.java | 2 +- .../nms/v1_21/crops/CropsTickingMethod.java | 139 +++++++++++++++++ .../nms/v1_21_3/NMSChunksImpl.java | 2 +- .../nms/v1_21_3/chunks/CropsBlockEntity.java | 141 ------------------ .../chunks/CropsTickingBlockEntity.java | 30 ---- .../nms/v1_21_3/crops}/CropsBlockEntity.java | 42 +----- .../crops/CropsTickingBlockEntity.java | 30 ++++ .../nms/v1_21_3/crops/CropsTickingMethod.java | 134 +++++++++++++++++ .../nms/v1_21_4/NMSChunksImpl.java | 2 +- .../nms/v1_21_4/chunks/CropsBlockEntity.java | 141 ------------------ .../chunks/CropsTickingBlockEntity.java | 30 ---- .../nms/v1_21_4/crops}/CropsBlockEntity.java | 45 +----- .../crops/CropsTickingBlockEntity.java | 30 ++++ .../nms/v1_21_4/crops/CropsTickingMethod.java | 134 +++++++++++++++++ 40 files changed, 1586 insertions(+), 714 deletions(-) create mode 100644 NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java rename NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/{chunks => crops}/CropsTickingTileEntity.java (67%) rename NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/{chunks => crops}/CropsBlockEntity.java (67%) rename NMS/{v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/chunks => v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops}/CropsTickingBlockEntity.java (92%) create mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java rename NMS/{v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/chunks => v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops}/CropsBlockEntity.java (60%) rename NMS/{v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/chunks => v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops}/CropsTickingBlockEntity.java (92%) create mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsBlockEntity.java rename NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/{chunks => crops}/CropsTickingBlockEntity.java (92%) create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsBlockEntity.java rename NMS/{v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/chunks => v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops}/CropsTickingBlockEntity.java (91%) create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsBlockEntity.java rename NMS/{v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/chunks => v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops}/CropsTickingBlockEntity.java (91%) create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/chunks/CropsBlockEntity.java rename NMS/{v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/chunks => v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops}/CropsBlockEntity.java (67%) rename NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/{chunks => crops}/CropsTickingBlockEntity.java (92%) create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/chunks/CropsBlockEntity.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/chunks/CropsTickingBlockEntity.java rename NMS/{v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/chunks => v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops}/CropsBlockEntity.java (67%) create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingBlockEntity.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsBlockEntity.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsTickingBlockEntity.java rename NMS/{v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/chunks => v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops}/CropsBlockEntity.java (65%) create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingBlockEntity.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java index 897d7bbbfa..085c4f21e2 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java @@ -17,7 +17,7 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_16_R3.chunks.CropsTickingTileEntity; +import com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops.CropsTickingTileEntity; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -63,7 +63,6 @@ import java.util.Arrays; import java.util.Collection; -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java new file mode 100644 index 0000000000..a8c354741c --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java @@ -0,0 +1,122 @@ +package com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import net.minecraft.server.v1_16_R3.Block; +import net.minecraft.server.v1_16_R3.BlockPosition; +import net.minecraft.server.v1_16_R3.Chunk; +import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; +import net.minecraft.server.v1_16_R3.ChunkSection; +import net.minecraft.server.v1_16_R3.IBlockData; +import net.minecraft.server.v1_16_R3.WorldServer; +import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; + +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +public abstract class CropsTickingMethod { + + private static final ReflectField WORLD_SERVER_RANDOM_TICK_RANDOM = new ReflectField<>( + WorldServer.class, Random.class, "randomTickRandom"); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final BlockPosition.MutableBlockPosition chunkTickMutablePosition = new BlockPosition.MutableBlockPosition(); + + private static final CropsTickingMethod INSTANCE = WORLD_SERVER_RANDOM_TICK_RANDOM.isValid() ? + new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); + + + protected CropsTickingMethod() { + + } + + public static void tick(Chunk chunk, int tickSpeed) { + INSTANCE.doTick(chunk, tickSpeed); + } + + protected abstract void doTick(Chunk chunk, int tickSpeed); + + private static class PaperCropsTickingMethod extends CropsTickingMethod { + + @Override + protected void doTick(Chunk chunk, int tickSpeed) { + WorldServer worldServer = chunk.world; + + ChunkCoordIntPair chunkCoord = chunk.getPos(); + int chunkOffsetX = chunkCoord.x << 4; + int chunkOffsetZ = chunkCoord.z << 4; + + Random randomTickRandom = WORLD_SERVER_RANDOM_TICK_RANDOM.get(worldServer); + + ChunkSection[] sections = chunk.getSections(); + for (int sectionIndex = 0; sectionIndex < 16; ++sectionIndex) { + ChunkSection chunkSection = sections[sectionIndex]; + if (chunkSection == null || chunkSection == Chunk.a) + continue; + + int tickingBlocks = chunkSection.tickingList.size(); + if (tickingBlocks <= 0) + continue; + + int offsetY = sectionIndex << 4; + + for (int i = 0; i < tickSpeed; ++i) { + int index = randomTickRandom.nextInt(4096); + if (index >= tickingBlocks) + continue; + + long raw = chunkSection.tickingList.getRaw(index); + int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); + IBlockData blockData = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); + Block block = blockData.getBlock(); + if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + continue; + + chunkTickMutablePosition.setValues((location & 15) | chunkOffsetX, + ((location >>> 8) & 255) | offsetY, + ((location >>> 4) & 15) | chunkOffsetZ); + + blockData.b(worldServer, chunkTickMutablePosition, randomTickRandom); + } + + } + + } + + } + + private static class SpigotCropsTickingMethod extends CropsTickingMethod { + + private static int random = ThreadLocalRandom.current().nextInt(); + + @Override + protected void doTick(Chunk chunk, int tickSpeed) { + WorldServer worldServer = chunk.world; + + ChunkCoordIntPair chunkCoord = chunk.getPos(); + int chunkOffsetX = chunkCoord.x << 4; + int chunkOffsetZ = chunkCoord.z << 4; + + for (ChunkSection chunkSection : chunk.getSections()) { + if (chunkSection != Chunk.a && chunkSection.d()) { + for (int i = 0; i < tickSpeed; i++) { + random = random * 3 + 1013904223; + int factor = random >> 2; + int x = factor & 15; + int z = factor >> 8 & 15; + int y = factor >> 16 & 15; + IBlockData blockData = chunkSection.getType(x, y, z); + Block block = blockData.getBlock(); + if (blockData.isTicking() && + plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + chunkTickMutablePosition.setValues(x + chunkOffsetX, y + chunkSection.getYPosition(), z + chunkOffsetZ); + blockData.b(worldServer, chunkTickMutablePosition, worldServer.random); + } + } + } + } + } + } + +} diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/chunks/CropsTickingTileEntity.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java similarity index 67% rename from NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/chunks/CropsTickingTileEntity.java rename to NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java index 8ced7c027c..1a7173b3f5 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/chunks/CropsTickingTileEntity.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java @@ -1,26 +1,20 @@ -package com.bgsoftware.superiorskyblock.nms.v1_16_R3.chunks; +package com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.Chunk; import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; -import net.minecraft.server.v1_16_R3.ChunkSection; import net.minecraft.server.v1_16_R3.GameRules; -import net.minecraft.server.v1_16_R3.IBlockData; import net.minecraft.server.v1_16_R3.ITickable; import net.minecraft.server.v1_16_R3.TileEntity; import net.minecraft.server.v1_16_R3.TileEntityTypes; -import net.minecraft.server.v1_16_R3.WorldServer; -import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; import java.lang.ref.WeakReference; import java.util.List; -import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; public class CropsTickingTileEntity extends TileEntity implements ITickable { @@ -28,12 +22,9 @@ public class CropsTickingTileEntity extends TileEntity implements ITickable { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - private static int random = ThreadLocalRandom.current().nextInt(); private final WeakReference island; private final WeakReference chunk; - private final int chunkX; - private final int chunkZ; private int currentTick = 0; @@ -43,9 +34,8 @@ private CropsTickingTileEntity(Island island, Chunk chunk) { super(TileEntityTypes.COMMAND_BLOCK); this.island = new WeakReference<>(island); this.chunk = new WeakReference<>(chunk); - this.chunkX = chunk.getPos().x; - this.chunkZ = chunk.getPos().z; - setLocation(chunk.getWorld(), new BlockPosition(chunkX << 4, 1, chunkZ << 4)); + ChunkCoordIntPair chunkCoord = chunk.getPos(); + setLocation(chunk.getWorld(), new BlockPosition(chunkCoord.x << 4, 1, chunkCoord.z << 4)); try { // Not a method of Spigot - fixes https://github.com/OmerBenGera/SuperiorSkyblock2/issues/5 @@ -98,28 +88,9 @@ public void tick() { currentTick = 0; int worldRandomTick = world.getGameRules().getInt(GameRules.RANDOM_TICK_SPEED); - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - - if (chunkRandomTickSpeed > 0) { - for (ChunkSection chunkSection : chunk.getSections()) { - if (chunkSection != Chunk.a && chunkSection.d()) { - for (int i = 0; i < chunkRandomTickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - IBlockData blockData = chunkSection.getType(x, y, z); - Block block = blockData.getBlock(); - if (block.isTicking(blockData) && plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { - blockData.b((WorldServer) world, new BlockPosition(x + (chunkX << 4), y + chunkSection.getYPosition(), z + (chunkZ << 4)), ThreadLocalRandom.current()); - } - } - } - } - } - + if (chunkRandomTickSpeed > 0) + CropsTickingMethod.tick(chunk, chunkRandomTickSpeed); } @Override diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java index 0e5b760261..830badf7b0 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java @@ -19,7 +19,7 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_17.chunks.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_17.crops.CropsBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_17.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/chunks/CropsBlockEntity.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsBlockEntity.java similarity index 67% rename from NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/chunks/CropsBlockEntity.java rename to NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsBlockEntity.java index bbff658297..fa2d74dc36 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/chunks/CropsBlockEntity.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.chunks; +package com.bgsoftware.superiorskyblock.nms.v1_17.crops; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -9,17 +9,12 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; import java.lang.ref.WeakReference; import java.util.List; -import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; public class CropsBlockEntity extends BlockEntity { @@ -27,12 +22,9 @@ public class CropsBlockEntity extends BlockEntity { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - private static int random = ThreadLocalRandom.current().nextInt(); private final WeakReference island; private final WeakReference chunk; - private final int chunkX; - private final int chunkZ; private int currentTick = 0; @@ -42,9 +34,6 @@ private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.getLevel().getBlockState(blockPos)); this.island = new WeakReference<>(island); this.chunk = new WeakReference<>(levelChunk); - ChunkPos chunkPos = levelChunk.getPos(); - this.chunkX = chunkPos.x; - this.chunkZ = chunkPos.z; setLevel(levelChunk.getLevel()); levelChunk.getLevel().addBlockEntityTicker(new CropsTickingBlockEntity(this)); this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; @@ -95,28 +84,9 @@ public void tick() { currentTick = 0; int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - - if (chunkRandomTickSpeed > 0) { - for (LevelChunkSection levelChunkSection : levelChunk.getSections()) { - if (levelChunkSection != LevelChunk.EMPTY_SECTION && levelChunkSection.isRandomlyTicking()) { - for (int i = 0; i < chunkRandomTickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (block.isRandomlyTicking(blockState) && plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { - BlockPos blockPos = new BlockPos(x + (chunkX << 4), y + levelChunkSection.bottomBlockY(), z + (chunkZ << 4)); - blockState.randomTick(serverLevel, blockPos, ThreadLocalRandom.current()); - } - } - } - } - } + if (chunkRandomTickSpeed > 0) + CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); } public void setCropGrowthMultiplier(double cropGrowthMultiplier) { diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/chunks/CropsTickingBlockEntity.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingBlockEntity.java similarity index 92% rename from NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/chunks/CropsTickingBlockEntity.java rename to NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingBlockEntity.java index 0eaf4ffc3f..3c1d933f4b 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/chunks/CropsTickingBlockEntity.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.chunks; +package com.bgsoftware.superiorskyblock.nms.v1_17.crops; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntityType; diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java new file mode 100644 index 0000000000..668cd425c0 --- /dev/null +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java @@ -0,0 +1,132 @@ +package com.bgsoftware.superiorskyblock.nms.v1_17.crops; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; + +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +public abstract class CropsTickingMethod { + + private static final ReflectField SERVER_LEVEL_RANDOM_TICK_RANDOM = new ReflectField<>( + ServerLevel.class, Random.class, "randomTickRandom"); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); + + private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? + new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); + + + protected CropsTickingMethod() { + + } + + public static void tick(LevelChunk levelChunk, int tickSpeed) { + INSTANCE.doTick(levelChunk, tickSpeed); + } + + protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + + private static class PaperCropsTickingMethod extends CropsTickingMethod { + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + ServerLevel serverLevel = levelChunk.level; + LevelChunkSection[] sections = levelChunk.getSections(); + + int minSection = serverLevel.getMinSection(); + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + Random randomTickRandom = SERVER_LEVEL_RANDOM_TICK_RANDOM.get(serverLevel); + + for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int tickingBlocks = levelChunkSection.tickingList.size(); + if (tickingBlocks <= 0) { + continue; + } + + int offsetY = (sectionIndex + minSection) << 4; + + for (int i = 0; i < tickSpeed; ++i) { + int index = randomTickRandom.nextInt(0x1000); + + if (index >= tickingBlocks) { + continue; + } + + long raw = levelChunkSection.tickingList.getRaw(index); + int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); + BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); + Block block = blockState.getBlock(); + if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + continue; + + chunkTickMutablePosition.set((location & 15) | chunkOffsetX, + ((location >>> 8) & 255) | offsetY, + ((location >>> 4) & 15) | chunkOffsetZ); + + blockState.randomTick(serverLevel, chunkTickMutablePosition, randomTickRandom); + } + } + + } + + } + + private static class SpigotCropsTickingMethod extends CropsTickingMethod { + + private static int random = ThreadLocalRandom.current().nextInt(); + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + LevelChunkSection[] sections = levelChunk.getSections(); + ServerLevel serverLevel = levelChunk.level; + + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; + + for (int i = 0; i < tickSpeed; i++) { + random = random * 3 + 1013904223; + int factor = random >> 2; + int x = factor & 15; + int z = factor >> 8 & 15; + int y = factor >> 16 & 15; + BlockState blockState = levelChunkSection.getBlockState(x, y, z); + Block block = blockState.getBlock(); + if (blockState.isRandomlyTicking() && + plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); + blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); + } + } + } + } + } + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java index 47fd74a9e0..6a7be2fbd5 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java @@ -16,7 +16,7 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_18.chunks.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_18.crops.CropsBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_18.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/chunks/CropsBlockEntity.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsBlockEntity.java similarity index 60% rename from NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/chunks/CropsBlockEntity.java rename to NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsBlockEntity.java index 20ecd51f14..fa88f7dda7 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/chunks/CropsBlockEntity.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsBlockEntity.java @@ -1,6 +1,5 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.chunks; +package com.bgsoftware.superiorskyblock.nms.v1_18.crops; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ChunkPosition; @@ -10,34 +9,22 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.lang.ref.WeakReference; import java.util.List; -import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; public class CropsBlockEntity extends BlockEntity { - private static final ReflectMethod BLOCK_IS_RANDOMLY_TICKING = new ReflectMethod<>( - BlockBehaviour.class, boolean.class, "d_", BlockState.class); - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - private static int random = ThreadLocalRandom.current().nextInt(); private final WeakReference island; private final WeakReference chunk; - private final int chunkX; - private final int chunkZ; private int currentTick = 0; @@ -47,9 +34,6 @@ private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); this.island = new WeakReference<>(island); this.chunk = new WeakReference<>(levelChunk); - ChunkPos chunkPos = levelChunk.getPos(); - this.chunkX = chunkPos.x; - this.chunkZ = chunkPos.z; setLevel(levelChunk.level); levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; @@ -100,33 +84,9 @@ public void tick() { currentTick = 0; int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - - if (chunkRandomTickSpeed > 0) { - LevelChunkSection[] sections = levelChunk.getSections(); - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - if (levelChunkSection != null && levelChunkSection.isRandomlyTicking()) { - for (int i = 0; i < chunkRandomTickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (BLOCK_IS_RANDOMLY_TICKING.invoke(block, blockState) && plugin.getSettings().getCropsToGrow().contains( - CraftMagicNumbers.getMaterial(block).name())) { - BlockPos blockPos = new BlockPos(x + (chunkX << 4), y + sectionBottomY, z + (chunkZ << 4)); - blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); - } - } - } - - } - } + if (chunkRandomTickSpeed > 0) + CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); } public void setCropGrowthMultiplier(double cropGrowthMultiplier) { diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/chunks/CropsTickingBlockEntity.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingBlockEntity.java similarity index 92% rename from NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/chunks/CropsTickingBlockEntity.java rename to NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingBlockEntity.java index 101c7a35b4..96b1e92def 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/chunks/CropsTickingBlockEntity.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.chunks; +package com.bgsoftware.superiorskyblock.nms.v1_18.crops; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntityType; diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java new file mode 100644 index 0000000000..2288384e56 --- /dev/null +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java @@ -0,0 +1,132 @@ +package com.bgsoftware.superiorskyblock.nms.v1_18.crops; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; + +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; + +public abstract class CropsTickingMethod { + + private static final ReflectField SERVER_LEVEL_RANDOM_TICK_RANDOM = new ReflectField<>( + ServerLevel.class, Random.class, "randomTickRandom"); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); + + private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? + new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); + + + protected CropsTickingMethod() { + + } + + public static void tick(LevelChunk levelChunk, int tickSpeed) { + INSTANCE.doTick(levelChunk, tickSpeed); + } + + protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + + private static class PaperCropsTickingMethod extends CropsTickingMethod { + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + ServerLevel serverLevel = levelChunk.level; + LevelChunkSection[] sections = levelChunk.getSections(); + + int minSection = serverLevel.getMinSection(); + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + Random randomTickRandom = SERVER_LEVEL_RANDOM_TICK_RANDOM.get(serverLevel); + + for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int tickingBlocks = levelChunkSection.tickingList.size(); + if (tickingBlocks <= 0) { + continue; + } + + int offsetY = (sectionIndex + minSection) << 4; + + for (int i = 0; i < tickSpeed; ++i) { + int index = randomTickRandom.nextInt(0x1000); + + if (index >= tickingBlocks) { + continue; + } + + long raw = levelChunkSection.tickingList.getRaw(index); + int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); + BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); + Block block = blockState.getBlock(); + if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + continue; + + chunkTickMutablePosition.set((location & 15) | chunkOffsetX, + ((location >>> 8) & 255) | offsetY, + ((location >>> 4) & 15) | chunkOffsetZ); + + blockState.randomTick(serverLevel, chunkTickMutablePosition, randomTickRandom); + } + } + + } + + } + + private static class SpigotCropsTickingMethod extends CropsTickingMethod { + + private static int random = ThreadLocalRandom.current().nextInt(); + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + LevelChunkSection[] sections = levelChunk.getSections(); + ServerLevel serverLevel = levelChunk.level; + + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; + + for (int i = 0; i < tickSpeed; i++) { + random = random * 3 + 1013904223; + int factor = random >> 2; + int x = factor & 15; + int z = factor >> 8 & 15; + int y = factor >> 16 & 15; + BlockState blockState = levelChunkSection.getBlockState(x, y, z); + Block block = blockState.getBlock(); + if (blockState.isRandomlyTicking() && + plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); + blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); + } + } + } + } + } + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java index c7c58a4b52..c11ba230d4 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java @@ -17,7 +17,7 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_19.chunks.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_19.crops.CropsBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_19.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsBlockEntity.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsBlockEntity.java new file mode 100644 index 0000000000..2fd51021c9 --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsBlockEntity.java @@ -0,0 +1,96 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.crops; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.chunk.LevelChunk; + +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.function.Consumer; + +public class CropsBlockEntity extends BlockEntity { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); + + private final WeakReference island; + private final WeakReference chunk; + + private int currentTick = 0; + + private double cachedCropGrowthMultiplier; + + private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { + super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); + this.island = new WeakReference<>(island); + this.chunk = new WeakReference<>(levelChunk); + setLevel(levelChunk.level); + levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); + this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; + } + + public static void create(Island island, LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + long chunkPair = chunkPos.toLong(); + tickingChunks.computeIfAbsent(chunkPair, p -> { + BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); + return new CropsBlockEntity(island, levelChunk, blockPos); + }); + } + + public static CropsBlockEntity remove(long chunkPos) { + return tickingChunks.remove(chunkPos); + } + + public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { + if (tickingChunks.isEmpty()) + return; + + chunkPositions.forEach(chunkPosition -> { + long chunkKey = chunkPosition.asPair(); + CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); + if (cropsBlockEntity != null) + cropsBlockEntityConsumer.accept(cropsBlockEntity); + }); + } + + public void remove() { + this.remove = true; + } + + public void tick() { + if (++currentTick <= plugin.getSettings().getCropsInterval()) + return; + + LevelChunk levelChunk = this.chunk.get(); + Island island = this.island.get(); + ServerLevel serverLevel = (ServerLevel) getLevel(); + + if (levelChunk == null || island == null || serverLevel == null) { + remove(); + return; + } + + currentTick = 0; + + int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); + int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); + if (chunkRandomTickSpeed > 0) + CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); + } + + public void setCropGrowthMultiplier(double cropGrowthMultiplier) { + this.cachedCropGrowthMultiplier = cropGrowthMultiplier; + } + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/chunks/CropsTickingBlockEntity.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingBlockEntity.java similarity index 92% rename from NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/chunks/CropsTickingBlockEntity.java rename to NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingBlockEntity.java index 4723b7e0d9..0c7bfbfdc2 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/chunks/CropsTickingBlockEntity.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.chunks; +package com.bgsoftware.superiorskyblock.nms.v1_19.crops; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntityType; diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java new file mode 100644 index 0000000000..19dfd537a6 --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java @@ -0,0 +1,132 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.crops; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; + +import java.util.concurrent.ThreadLocalRandom; + +public abstract class CropsTickingMethod { + + private static final ReflectField SERVER_LEVEL_RANDOM_TICK_RANDOM = new ReflectField<>( + ServerLevel.class, RandomSource.class, "randomTickRandom"); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); + + private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? + new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); + + + protected CropsTickingMethod() { + + } + + public static void tick(LevelChunk levelChunk, int tickSpeed) { + INSTANCE.doTick(levelChunk, tickSpeed); + } + + protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + + private static class PaperCropsTickingMethod extends CropsTickingMethod { + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + ServerLevel serverLevel = levelChunk.level; + LevelChunkSection[] sections = levelChunk.getSections(); + + int minSection = serverLevel.getMinSection(); + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + RandomSource randomTickRandom = SERVER_LEVEL_RANDOM_TICK_RANDOM.get(serverLevel); + + for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int tickingBlocks = levelChunkSection.tickingList.size(); + if (tickingBlocks <= 0) { + continue; + } + + int offsetY = (sectionIndex + minSection) << 4; + + for (int i = 0; i < tickSpeed; ++i) { + int index = randomTickRandom.nextInt(0x1000); + + if (index >= tickingBlocks) { + continue; + } + + long raw = levelChunkSection.tickingList.getRaw(index); + int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); + BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); + Block block = blockState.getBlock(); + if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + continue; + + chunkTickMutablePosition.set((location & 15) | chunkOffsetX, + ((location >>> 8) & 255) | offsetY, + ((location >>> 4) & 15) | chunkOffsetZ); + + blockState.randomTick(serverLevel, chunkTickMutablePosition, randomTickRandom); + } + } + + } + + } + + private static class SpigotCropsTickingMethod extends CropsTickingMethod { + + private static int random = ThreadLocalRandom.current().nextInt(); + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + LevelChunkSection[] sections = levelChunk.getSections(); + ServerLevel serverLevel = levelChunk.level; + + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; + + for (int i = 0; i < tickSpeed; i++) { + random = random * 3 + 1013904223; + int factor = random >> 2; + int x = factor & 15; + int z = factor >> 8 & 15; + int y = factor >> 16 & 15; + BlockState blockState = levelChunkSection.getBlockState(x, y, z); + Block block = blockState.getBlock(); + if (blockState.isRandomlyTicking() && + plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); + blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); + } + } + } + } + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java index 26610d28f1..53d13f3fd9 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java @@ -18,7 +18,7 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.chunks.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.crops.CropsBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsBlockEntity.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsBlockEntity.java new file mode 100644 index 0000000000..b53aa44c98 --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsBlockEntity.java @@ -0,0 +1,96 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.crops; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.chunk.LevelChunk; + +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.function.Consumer; + +public class CropsBlockEntity extends BlockEntity { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); + + private final WeakReference island; + private final WeakReference chunk; + + private int currentTick = 0; + + private double cachedCropGrowthMultiplier; + + private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { + super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); + this.island = new WeakReference<>(island); + this.chunk = new WeakReference<>(levelChunk); + setLevel(levelChunk.level); + levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); + this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; + } + + public static void create(Island island, LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + long chunkPair = chunkPos.toLong(); + tickingChunks.computeIfAbsent(chunkPair, p -> { + BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); + return new CropsBlockEntity(island, levelChunk, blockPos); + }); + } + + public static CropsBlockEntity remove(long chunkPos) { + return tickingChunks.remove(chunkPos); + } + + public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { + if (tickingChunks.isEmpty()) + return; + + chunkPositions.forEach(chunkPosition -> { + long chunkKey = chunkPosition.asPair(); + CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); + if (cropsBlockEntity != null) + cropsBlockEntityConsumer.accept(cropsBlockEntity); + }); + } + + public void remove() { + this.remove = true; + } + + public void tick() { + if (++currentTick <= plugin.getSettings().getCropsInterval()) + return; + + LevelChunk levelChunk = this.chunk.get(); + Island island = this.island.get(); + ServerLevel serverLevel = (ServerLevel) getLevel(); + + if (levelChunk == null || island == null || serverLevel == null) { + remove(); + return; + } + + currentTick = 0; + + int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); + int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); + if (chunkRandomTickSpeed > 0) + CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); + } + + public void setCropGrowthMultiplier(double cropGrowthMultiplier) { + this.cachedCropGrowthMultiplier = cropGrowthMultiplier; + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/chunks/CropsTickingBlockEntity.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingBlockEntity.java similarity index 91% rename from NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/chunks/CropsTickingBlockEntity.java rename to NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingBlockEntity.java index 8160147ab8..898386068b 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/chunks/CropsTickingBlockEntity.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.chunks; +package com.bgsoftware.superiorskyblock.nms.v1_20_3.crops; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntityType; diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java new file mode 100644 index 0000000000..b86440f5cb --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java @@ -0,0 +1,132 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.crops; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; + +import java.util.concurrent.ThreadLocalRandom; + +public abstract class CropsTickingMethod { + + private static final ReflectField SERVER_LEVEL_RANDOM_TICK_RANDOM = new ReflectField<>( + ServerLevel.class, RandomSource.class, "randomTickRandom"); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); + + private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? + new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); + + + protected CropsTickingMethod() { + + } + + public static void tick(LevelChunk levelChunk, int tickSpeed) { + INSTANCE.doTick(levelChunk, tickSpeed); + } + + protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + + private static class PaperCropsTickingMethod extends CropsTickingMethod { + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + ServerLevel serverLevel = levelChunk.level; + LevelChunkSection[] sections = levelChunk.getSections(); + + int minSection = serverLevel.getMinSection(); + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + RandomSource randomTickRandom = SERVER_LEVEL_RANDOM_TICK_RANDOM.get(serverLevel); + + for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int tickingBlocks = levelChunkSection.tickingList.size(); + if (tickingBlocks <= 0) { + continue; + } + + int offsetY = (sectionIndex + minSection) << 4; + + for (int i = 0; i < tickSpeed; ++i) { + int index = randomTickRandom.nextInt(0x1000); + + if (index >= tickingBlocks) { + continue; + } + + long raw = levelChunkSection.tickingList.getRaw(index); + int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); + BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); + Block block = blockState.getBlock(); + if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + continue; + + chunkTickMutablePosition.set((location & 15) | chunkOffsetX, + ((location >>> 8) & 255) | offsetY, + ((location >>> 4) & 15) | chunkOffsetZ); + + blockState.randomTick(serverLevel, chunkTickMutablePosition, randomTickRandom); + } + } + + } + + } + + private static class SpigotCropsTickingMethod extends CropsTickingMethod { + + private static int random = ThreadLocalRandom.current().nextInt(); + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + LevelChunkSection[] sections = levelChunk.getSections(); + ServerLevel serverLevel = levelChunk.level; + + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; + + for (int i = 0; i < tickSpeed; i++) { + random = random * 3 + 1013904223; + int factor = random >> 2; + int x = factor & 15; + int z = factor >> 8 & 15; + int y = factor >> 16 & 15; + BlockState blockState = levelChunkSection.getBlockState(x, y, z); + Block block = blockState.getBlock(); + if (blockState.isRandomlyTicking() && + plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); + blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); + } + } + } + } + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java index 7090373f50..87c5a499a9 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java @@ -17,7 +17,7 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.chunks.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.crops.CropsBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsBlockEntity.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsBlockEntity.java new file mode 100644 index 0000000000..05432e1ad1 --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsBlockEntity.java @@ -0,0 +1,96 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.crops; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.chunk.LevelChunk; + +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.function.Consumer; + +public class CropsBlockEntity extends BlockEntity { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); + + private final WeakReference island; + private final WeakReference chunk; + + private int currentTick = 0; + + private double cachedCropGrowthMultiplier; + + private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { + super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); + this.island = new WeakReference<>(island); + this.chunk = new WeakReference<>(levelChunk); + setLevel(levelChunk.level); + levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); + this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; + } + + public static void create(Island island, LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + long chunkPair = chunkPos.toLong(); + tickingChunks.computeIfAbsent(chunkPair, p -> { + BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); + return new CropsBlockEntity(island, levelChunk, blockPos); + }); + } + + public static CropsBlockEntity remove(long chunkPos) { + return tickingChunks.remove(chunkPos); + } + + public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { + if (tickingChunks.isEmpty()) + return; + + chunkPositions.forEach(chunkPosition -> { + long chunkKey = chunkPosition.asPair(); + CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); + if (cropsBlockEntity != null) + cropsBlockEntityConsumer.accept(cropsBlockEntity); + }); + } + + public void remove() { + this.remove = true; + } + + public void tick() { + if (++currentTick <= plugin.getSettings().getCropsInterval()) + return; + + LevelChunk levelChunk = this.chunk.get(); + Island island = this.island.get(); + ServerLevel serverLevel = (ServerLevel) getLevel(); + + if (levelChunk == null || island == null || serverLevel == null) { + remove(); + return; + } + + currentTick = 0; + + int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); + int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); + if (chunkRandomTickSpeed > 0) + CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); + } + + public void setCropGrowthMultiplier(double cropGrowthMultiplier) { + this.cachedCropGrowthMultiplier = cropGrowthMultiplier; + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/chunks/CropsTickingBlockEntity.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingBlockEntity.java similarity index 91% rename from NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/chunks/CropsTickingBlockEntity.java rename to NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingBlockEntity.java index ed82388261..7ef4d1dd06 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/chunks/CropsTickingBlockEntity.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.chunks; +package com.bgsoftware.superiorskyblock.nms.v1_20_4.crops; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntityType; diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java new file mode 100644 index 0000000000..d0ef84c8ac --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java @@ -0,0 +1,131 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.crops; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; + +import java.util.concurrent.ThreadLocalRandom; + +public abstract class CropsTickingMethod { + + private static final ReflectField SERVER_LEVEL_RANDOM_TICK_RANDOM = new ReflectField<>( + ServerLevel.class, RandomSource.class, "randomTickRandom"); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); + + private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? + new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); + + protected CropsTickingMethod() { + + } + + public static void tick(LevelChunk levelChunk, int tickSpeed) { + INSTANCE.doTick(levelChunk, tickSpeed); + } + + protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + + private static class PaperCropsTickingMethod extends CropsTickingMethod { + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + ServerLevel serverLevel = levelChunk.level; + LevelChunkSection[] sections = levelChunk.getSections(); + + int minSection = serverLevel.getMinSection(); + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + RandomSource randomTickRandom = SERVER_LEVEL_RANDOM_TICK_RANDOM.get(serverLevel); + + for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int tickingBlocks = levelChunkSection.tickingList.size(); + if (tickingBlocks <= 0) { + continue; + } + + int offsetY = (sectionIndex + minSection) << 4; + + for (int i = 0; i < tickSpeed; ++i) { + int index = randomTickRandom.nextInt(0x1000); + + if (index >= tickingBlocks) { + continue; + } + + long raw = levelChunkSection.tickingList.getRaw(index); + int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); + BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); + Block block = blockState.getBlock(); + if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + continue; + + chunkTickMutablePosition.set((location & 15) | chunkOffsetX, + ((location >>> 8) & 255) | offsetY, + ((location >>> 4) & 15) | chunkOffsetZ); + + blockState.randomTick(serverLevel, chunkTickMutablePosition, randomTickRandom); + } + } + + } + + } + + private static class SpigotCropsTickingMethod extends CropsTickingMethod { + + private static int random = ThreadLocalRandom.current().nextInt(); + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + LevelChunkSection[] sections = levelChunk.getSections(); + ServerLevel serverLevel = levelChunk.level; + + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; + + for (int i = 0; i < tickSpeed; i++) { + random = random * 3 + 1013904223; + int factor = random >> 2; + int x = factor & 15; + int z = factor >> 8 & 15; + int y = factor >> 16 & 15; + BlockState blockState = levelChunkSection.getBlockState(x, y, z); + Block block = blockState.getBlock(); + if (blockState.isRandomlyTicking() && + plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); + blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); + } + } + } + } + } + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java index 8791eeb4b9..b8a738fe31 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java @@ -17,7 +17,7 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_21.chunks.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21.crops.CropsBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/chunks/CropsBlockEntity.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/chunks/CropsBlockEntity.java deleted file mode 100644 index a68e479df4..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/chunks/CropsBlockEntity.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.chunks; - -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.Consumer; - -public class CropsBlockEntity extends BlockEntity { - - private static final ReflectMethod BLOCK_IS_RANDOMLY_TICKING = new ReflectMethod<>( - BlockBehaviour.class, boolean.class, "d_", BlockState.class); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - private static int random = ThreadLocalRandom.current().nextInt(); - - private final WeakReference island; - private final WeakReference chunk; - private final int chunkX; - private final int chunkZ; - - private int currentTick = 0; - - private double cachedCropGrowthMultiplier; - - private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(levelChunk); - ChunkPos chunkPos = levelChunk.getPos(); - this.chunkX = chunkPos.x; - this.chunkZ = chunkPos.z; - setLevel(levelChunk.level); - levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; - } - - public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); - return new CropsBlockEntity(island, levelChunk, blockPos); - }); - } - - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); - } - - public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { - if (tickingChunks.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> { - long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); - if (cropsBlockEntity != null) - cropsBlockEntityConsumer.accept(cropsBlockEntity); - }); - } - - @Override - public boolean isValidBlockState(BlockState state) { - return true; - } - - public void remove() { - this.remove = true; - } - - public void tick() { - if (++currentTick <= plugin.getSettings().getCropsInterval()) - return; - - LevelChunk levelChunk = this.chunk.get(); - Island island = this.island.get(); - ServerLevel serverLevel = (ServerLevel) getLevel(); - - if (levelChunk == null || island == null || serverLevel == null) { - remove(); - return; - } - - currentTick = 0; - - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - - if (chunkRandomTickSpeed > 0) { - LevelChunkSection[] sections = levelChunk.getSections(); - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - if (levelChunkSection != null && levelChunkSection.isRandomlyTicking()) { - for (int i = 0; i < chunkRandomTickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (BLOCK_IS_RANDOMLY_TICKING.invoke(block, blockState) && plugin.getSettings().getCropsToGrow().contains( - CraftMagicNumbers.getMaterial(block).name())) { - BlockPos blockPos = new BlockPos(x + (chunkX << 4), y + sectionBottomY, z + (chunkZ << 4)); - blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); - } - } - } - - } - } - } - - public void setCropGrowthMultiplier(double cropGrowthMultiplier) { - this.cachedCropGrowthMultiplier = cropGrowthMultiplier; - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/chunks/CropsBlockEntity.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsBlockEntity.java similarity index 67% rename from NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/chunks/CropsBlockEntity.java rename to NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsBlockEntity.java index 111349a929..eb7f0db6de 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/chunks/CropsBlockEntity.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.chunks; +package com.bgsoftware.superiorskyblock.nms.v1_21.crops; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -9,17 +9,13 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; import java.lang.ref.WeakReference; import java.util.List; -import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; public class CropsBlockEntity extends BlockEntity { @@ -27,12 +23,9 @@ public class CropsBlockEntity extends BlockEntity { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - private static int random = ThreadLocalRandom.current().nextInt(); private final WeakReference island; private final WeakReference chunk; - private final int chunkX; - private final int chunkZ; private int currentTick = 0; @@ -42,9 +35,6 @@ private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); this.island = new WeakReference<>(island); this.chunk = new WeakReference<>(levelChunk); - ChunkPos chunkPos = levelChunk.getPos(); - this.chunkX = chunkPos.x; - this.chunkZ = chunkPos.z; setLevel(levelChunk.level); levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; @@ -75,6 +65,11 @@ public static void forEachChunk(List chunkPositions, Consumer 0) { - for (LevelChunkSection levelChunkSection : levelChunk.getSections()) { - if (levelChunkSection != null && levelChunkSection.isRandomlyTicking()) { - for (int i = 0; i < chunkRandomTickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (block.isRandomlyTicking(blockState) && plugin.getSettings().getCropsToGrow().contains( - CraftMagicNumbers.getMaterial(block).name())) { - BlockPos blockPos = new BlockPos(x + (chunkX << 4), - y + levelChunkSection.bottomBlockY(), z + (chunkZ << 4)); - blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); - } - } - } - } - } + if (chunkRandomTickSpeed > 0) + CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); } public void setCropGrowthMultiplier(double cropGrowthMultiplier) { diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/chunks/CropsTickingBlockEntity.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingBlockEntity.java similarity index 92% rename from NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/chunks/CropsTickingBlockEntity.java rename to NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingBlockEntity.java index acbef87fec..5e3376dd74 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/chunks/CropsTickingBlockEntity.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.chunks; +package com.bgsoftware.superiorskyblock.nms.v1_21.crops; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntityType; diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java new file mode 100644 index 0000000000..065da93ca1 --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java @@ -0,0 +1,139 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.crops; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Supplier; + +public abstract class CropsTickingMethod { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final CropsTickingMethod INSTANCE = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection"); + return new PaperCropsTickingMethod(); + } catch (Throwable error) { + return new SpigotCropsTickingMethod(); + } + }).get(); + + protected CropsTickingMethod() { + + } + + public static void tick(LevelChunk levelChunk, int tickSpeed) { + INSTANCE.doTick(levelChunk, tickSpeed); + } + + protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + + private static class PaperCropsTickingMethod extends CropsTickingMethod { + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + ServerLevel serverLevel = levelChunk.level; + LevelChunkSection[] sections = levelChunk.getSections(); + + int minSection = serverLevel.getMinSection(); + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + RandomSource simpleRandom = serverLevel.random; + + for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + + ca.spottedleaf.moonrise.common.list.IBlockDataList tickList = + levelChunkSection.moonrise$getTickingBlockList(); + int tickingBlocks = tickList.size(); + if (tickingBlocks <= 0) { + continue; + } + + PalettedContainer states = levelChunkSection.states; + + int offsetY = (sectionIndex + minSection) << 4; + + for (int i = 0; i < tickSpeed; ++i) { + int index = simpleRandom.nextInt() & 0xFFF; + + if (index >= tickingBlocks) { + continue; + } + + long raw = tickList.getRaw(index); + int location = ca.spottedleaf.moonrise.common.list.IBlockDataList.getLocationFromRaw(raw); + BlockState blockState = states.get(location); + Block block = blockState.getBlock(); + if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + continue; + + // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! + BlockPos blockPos = new BlockPos((location & 15) | chunkOffsetX, + ((location >>> 8) & 255) | offsetY, + ((location >>> 4) & 15) | chunkOffsetZ); + + blockState.randomTick(serverLevel, blockPos, simpleRandom); + } + } + + } + + } + + private static class SpigotCropsTickingMethod extends CropsTickingMethod { + + private static int random = ThreadLocalRandom.current().nextInt(); + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + LevelChunkSection[] sections = levelChunk.getSections(); + ServerLevel serverLevel = levelChunk.level; + + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; + + for (int i = 0; i < tickSpeed; i++) { + random = random * 3 + 1013904223; + int factor = random >> 2; + int x = factor & 15; + int z = factor >> 8 & 15; + int y = factor >> 16 & 15; + BlockState blockState = levelChunkSection.getBlockState(x, y, z); + Block block = blockState.getBlock(); + if (blockState.isRandomlyTicking() && + plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); + blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); + } + } + } + } + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java index 458b6464cb..cf6e04f64c 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java @@ -17,7 +17,7 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.chunks.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.crops.CropsBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/chunks/CropsBlockEntity.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/chunks/CropsBlockEntity.java deleted file mode 100644 index b6dac95a6d..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/chunks/CropsBlockEntity.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.chunks; - -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.Consumer; - -public class CropsBlockEntity extends BlockEntity { - - private static final ReflectMethod BLOCK_IS_RANDOMLY_TICKING = new ReflectMethod<>( - BlockBehaviour.class, boolean.class, "f", BlockState.class); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - private static int random = ThreadLocalRandom.current().nextInt(); - - private final WeakReference island; - private final WeakReference chunk; - private final int chunkX; - private final int chunkZ; - - private int currentTick = 0; - - private double cachedCropGrowthMultiplier; - - private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(levelChunk); - ChunkPos chunkPos = levelChunk.getPos(); - this.chunkX = chunkPos.x; - this.chunkZ = chunkPos.z; - setLevel(levelChunk.level); - levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; - } - - public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); - return new CropsBlockEntity(island, levelChunk, blockPos); - }); - } - - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); - } - - public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { - if (tickingChunks.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> { - long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); - if (cropsBlockEntity != null) - cropsBlockEntityConsumer.accept(cropsBlockEntity); - }); - } - - @Override - public boolean isValidBlockState(BlockState state) { - return true; - } - - public void remove() { - this.remove = true; - } - - public void tick() { - if (++currentTick <= plugin.getSettings().getCropsInterval()) - return; - - LevelChunk levelChunk = this.chunk.get(); - Island island = this.island.get(); - ServerLevel serverLevel = (ServerLevel) getLevel(); - - if (levelChunk == null || island == null || serverLevel == null) { - remove(); - return; - } - - currentTick = 0; - - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - - if (chunkRandomTickSpeed > 0) { - LevelChunkSection[] sections = levelChunk.getSections(); - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - if (levelChunkSection != null && levelChunkSection.isRandomlyTicking()) { - for (int i = 0; i < chunkRandomTickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (BLOCK_IS_RANDOMLY_TICKING.invoke(block, blockState) && plugin.getSettings().getCropsToGrow().contains( - CraftMagicNumbers.getMaterial(block).name())) { - BlockPos blockPos = new BlockPos(x + (chunkX << 4), y + sectionBottomY, z + (chunkZ << 4)); - blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); - } - } - } - - } - } - } - - public void setCropGrowthMultiplier(double cropGrowthMultiplier) { - this.cachedCropGrowthMultiplier = cropGrowthMultiplier; - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/chunks/CropsTickingBlockEntity.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/chunks/CropsTickingBlockEntity.java deleted file mode 100644 index faf9805810..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/chunks/CropsTickingBlockEntity.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.chunks; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { - - - @Override - public void tick() { - cropsBlockEntity.tick(); - } - - @Override - public boolean isRemoved() { - return cropsBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return cropsBlockEntity.getBlockPos(); - } - - @Override - public String getType() { - return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/chunks/CropsBlockEntity.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsBlockEntity.java similarity index 67% rename from NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/chunks/CropsBlockEntity.java rename to NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsBlockEntity.java index edd5276727..baea19acfb 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/chunks/CropsBlockEntity.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.chunks; +package com.bgsoftware.superiorskyblock.nms.v1_21_3.crops; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -9,17 +9,13 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; import java.lang.ref.WeakReference; import java.util.List; -import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; public class CropsBlockEntity extends BlockEntity { @@ -27,12 +23,9 @@ public class CropsBlockEntity extends BlockEntity { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - private static int random = ThreadLocalRandom.current().nextInt(); private final WeakReference island; private final WeakReference chunk; - private final int chunkX; - private final int chunkZ; private int currentTick = 0; @@ -42,9 +35,6 @@ private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); this.island = new WeakReference<>(island); this.chunk = new WeakReference<>(levelChunk); - ChunkPos chunkPos = levelChunk.getPos(); - this.chunkX = chunkPos.x; - this.chunkZ = chunkPos.z; setLevel(levelChunk.level); levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; @@ -75,6 +65,11 @@ public static void forEachChunk(List chunkPositions, Consumer 0) { - for (LevelChunkSection levelChunkSection : levelChunk.getSections()) { - if (levelChunkSection != null && levelChunkSection.isRandomlyTicking()) { - for (int i = 0; i < chunkRandomTickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (block.isRandomlyTicking(blockState) && plugin.getSettings().getCropsToGrow().contains( - CraftMagicNumbers.getMaterial(block).name())) { - BlockPos blockPos = new BlockPos(x + (chunkX << 4), - y + levelChunkSection.bottomBlockY(), z + (chunkZ << 4)); - blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); - } - } - } - } - } + if (chunkRandomTickSpeed > 0) + CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); } public void setCropGrowthMultiplier(double cropGrowthMultiplier) { diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingBlockEntity.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingBlockEntity.java new file mode 100644 index 0000000000..abfac14dd1 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingBlockEntity.java @@ -0,0 +1,30 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.crops; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.TickingBlockEntity; + +public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { + + + @Override + public void tick() { + cropsBlockEntity.tick(); + } + + @Override + public boolean isRemoved() { + return cropsBlockEntity.isRemoved(); + } + + @Override + public BlockPos getPos() { + return cropsBlockEntity.getBlockPos(); + } + + @Override + public String getType() { + return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java new file mode 100644 index 0000000000..ea7ecff4c2 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java @@ -0,0 +1,134 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.crops; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; + +import java.util.concurrent.ThreadLocalRandom; + +public abstract class CropsTickingMethod { + + private static final ReflectField SERVER_LEVEL_SIMPLE_RANDOM = new ReflectField<>( + ServerLevel.class, RandomSource.class, "simpleRandom"); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_SIMPLE_RANDOM.isValid() ? + new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); + + protected CropsTickingMethod() { + + } + + public static void tick(LevelChunk levelChunk, int tickSpeed) { + INSTANCE.doTick(levelChunk, tickSpeed); + } + + protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + + private static class PaperCropsTickingMethod extends CropsTickingMethod { + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + ServerLevel serverLevel = levelChunk.level; + LevelChunkSection[] sections = levelChunk.getSections(); + + int minSection = serverLevel.getMinSectionY(); + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + RandomSource simpleRandom = SERVER_LEVEL_SIMPLE_RANDOM.get(serverLevel); + + for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + ca.spottedleaf.moonrise.common.list.ShortList tickList = + levelChunkSection.moonrise$getTickingBlockList(); + int tickingBlocks = tickList.size(); + if (tickingBlocks <= 0) { + continue; + } + + PalettedContainer states = levelChunkSection.states; + + int offsetY = (sectionIndex + minSection) << 4; + + for (int i = 0; i < tickSpeed; ++i) { + int index = simpleRandom.nextInt() & 0xFFF; + + if (index >= tickingBlocks) { + continue; + } + + int location = (int) tickList.getRaw(index) & 0xFFFF; + BlockState blockState = states.get(location); + Block block = blockState.getBlock(); + if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + continue; + + // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! + BlockPos blockPos = new BlockPos((location & 15) | chunkOffsetX, + ((location >>> 8) & 15) | offsetY, + ((location >>> 4) & 15) | chunkOffsetZ); + + blockState.randomTick(serverLevel, blockPos, simpleRandom); + } + } + + } + + } + + private static class SpigotCropsTickingMethod extends CropsTickingMethod { + + private static int random = ThreadLocalRandom.current().nextInt(); + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + LevelChunkSection[] sections = levelChunk.getSections(); + ServerLevel serverLevel = levelChunk.level; + + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; + + for (int i = 0; i < tickSpeed; i++) { + random = random * 3 + 1013904223; + int factor = random >> 2; + int x = factor & 15; + int z = factor >> 8 & 15; + int y = factor >> 16 & 15; + BlockState blockState = levelChunkSection.getBlockState(x, y, z); + Block block = blockState.getBlock(); + if (blockState.isRandomlyTicking() && + plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); + blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); + } + } + } + } + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java index cd7afb2776..b32088286e 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -17,7 +17,7 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.chunks.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.crops.CropsBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsBlockEntity.java deleted file mode 100644 index f89d0bc82b..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsBlockEntity.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.chunks; - -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.Consumer; - -public class CropsBlockEntity extends BlockEntity { - - private static final ReflectMethod BLOCK_IS_RANDOMLY_TICKING = new ReflectMethod<>( - BlockBehaviour.class, boolean.class, "f", BlockState.class); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - private static int random = ThreadLocalRandom.current().nextInt(); - - private final WeakReference island; - private final WeakReference chunk; - private final int chunkX; - private final int chunkZ; - - private int currentTick = 0; - - private double cachedCropGrowthMultiplier; - - private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(levelChunk); - ChunkPos chunkPos = levelChunk.getPos(); - this.chunkX = chunkPos.x; - this.chunkZ = chunkPos.z; - setLevel(levelChunk.level); - levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; - } - - public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); - return new CropsBlockEntity(island, levelChunk, blockPos); - }); - } - - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); - } - - public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { - if (tickingChunks.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> { - long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); - if (cropsBlockEntity != null) - cropsBlockEntityConsumer.accept(cropsBlockEntity); - }); - } - - @Override - public boolean isValidBlockState(BlockState state) { - return true; - } - - public void remove() { - this.remove = true; - } - - public void tick() { - if (++currentTick <= plugin.getSettings().getCropsInterval()) - return; - - LevelChunk levelChunk = this.chunk.get(); - Island island = this.island.get(); - ServerLevel serverLevel = (ServerLevel) getLevel(); - - if (levelChunk == null || island == null || serverLevel == null) { - remove(); - return; - } - - currentTick = 0; - - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - - if (chunkRandomTickSpeed > 0) { - LevelChunkSection[] sections = levelChunk.getSections(); - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - if (levelChunkSection != null && levelChunkSection.isRandomlyTicking()) { - for (int i = 0; i < chunkRandomTickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (BLOCK_IS_RANDOMLY_TICKING.invoke(block, blockState) && plugin.getSettings().getCropsToGrow().contains( - CraftMagicNumbers.getMaterial(block).name())) { - BlockPos blockPos = new BlockPos(x + (chunkX << 4), y + sectionBottomY, z + (chunkZ << 4)); - blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); - } - } - } - - } - } - } - - public void setCropGrowthMultiplier(double cropGrowthMultiplier) { - this.cachedCropGrowthMultiplier = cropGrowthMultiplier; - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsTickingBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsTickingBlockEntity.java deleted file mode 100644 index 2cc80b2172..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/chunks/CropsTickingBlockEntity.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.chunks; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { - - - @Override - public void tick() { - cropsBlockEntity.tick(); - } - - @Override - public boolean isRemoved() { - return cropsBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return cropsBlockEntity.getBlockPos(); - } - - @Override - public String getType() { - return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/chunks/CropsBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsBlockEntity.java similarity index 65% rename from NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/chunks/CropsBlockEntity.java rename to NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsBlockEntity.java index 22f8142aa5..42d50d74aa 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/chunks/CropsBlockEntity.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.chunks; +package com.bgsoftware.superiorskyblock.nms.v1_21_4.crops; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -9,17 +9,13 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; import java.lang.ref.WeakReference; import java.util.List; -import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; public class CropsBlockEntity extends BlockEntity { @@ -27,12 +23,9 @@ public class CropsBlockEntity extends BlockEntity { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - private static int random = ThreadLocalRandom.current().nextInt(); private final WeakReference island; private final WeakReference chunk; - private final int chunkX; - private final int chunkZ; private int currentTick = 0; @@ -42,9 +35,6 @@ private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); this.island = new WeakReference<>(island); this.chunk = new WeakReference<>(levelChunk); - ChunkPos chunkPos = levelChunk.getPos(); - this.chunkX = chunkPos.x; - this.chunkZ = chunkPos.z; setLevel(levelChunk.level); levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; @@ -75,6 +65,11 @@ public static void forEachChunk(List chunkPositions, Consumer 0) { - LevelChunkSection[] sections = levelChunk.getSections(); - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - if (levelChunkSection != null && levelChunkSection.isRandomlyTicking()) { - for (int i = 0; i < chunkRandomTickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (block.isRandomlyTicking(blockState) && plugin.getSettings().getCropsToGrow().contains( - CraftMagicNumbers.getMaterial(block).name())) { - BlockPos blockPos = new BlockPos(x + (chunkX << 4), y + sectionBottomY, z + (chunkZ << 4)); - blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); - } - } - } - - } - } + if (chunkRandomTickSpeed > 0) + CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); } public void setCropGrowthMultiplier(double cropGrowthMultiplier) { diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingBlockEntity.java new file mode 100644 index 0000000000..265928a203 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingBlockEntity.java @@ -0,0 +1,30 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.crops; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.TickingBlockEntity; + +public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { + + + @Override + public void tick() { + cropsBlockEntity.tick(); + } + + @Override + public boolean isRemoved() { + return cropsBlockEntity.isRemoved(); + } + + @Override + public BlockPos getPos() { + return cropsBlockEntity.getBlockPos(); + } + + @Override + public String getType() { + return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java new file mode 100644 index 0000000000..9e11abf67b --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java @@ -0,0 +1,134 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.crops; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; + +import java.util.concurrent.ThreadLocalRandom; + +public abstract class CropsTickingMethod { + + private static final ReflectField SERVER_LEVEL_SIMPLE_RANDOM = new ReflectField<>( + ServerLevel.class, RandomSource.class, "simpleRandom"); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_SIMPLE_RANDOM.isValid() ? + new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); + + protected CropsTickingMethod() { + + } + + public static void tick(LevelChunk levelChunk, int tickSpeed) { + INSTANCE.doTick(levelChunk, tickSpeed); + } + + protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + + private static class PaperCropsTickingMethod extends CropsTickingMethod { + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + ServerLevel serverLevel = levelChunk.level; + LevelChunkSection[] sections = levelChunk.getSections(); + + int minSection = serverLevel.getMinSectionY(); + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + RandomSource simpleRandom = SERVER_LEVEL_SIMPLE_RANDOM.get(serverLevel); + + for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + ca.spottedleaf.moonrise.common.list.ShortList tickList = + levelChunkSection.moonrise$getTickingBlockList(); + int tickingBlocks = tickList.size(); + if (tickingBlocks <= 0) { + continue; + } + + PalettedContainer states = levelChunkSection.states; + + int offsetY = (sectionIndex + minSection) << 4; + + for (int i = 0; i < tickSpeed; ++i) { + int index = simpleRandom.nextInt() & 0xFFF; + + if (index >= tickingBlocks) { + continue; + } + + int location = (int) tickList.getRaw(index) & 0xFFFF; + BlockState blockState = states.get(location); + Block block = blockState.getBlock(); + if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + continue; + + // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! + BlockPos blockPos = new BlockPos((location & 15) | chunkOffsetX, + ((location >>> 8) & 15) | offsetY, + ((location >>> 4) & 15) | chunkOffsetZ); + + blockState.randomTick(serverLevel, blockPos, simpleRandom); + } + } + + } + + } + + private static class SpigotCropsTickingMethod extends CropsTickingMethod { + + private static int random = ThreadLocalRandom.current().nextInt(); + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + LevelChunkSection[] sections = levelChunk.getSections(); + ServerLevel serverLevel = levelChunk.level; + + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; + + for (int i = 0; i < tickSpeed; i++) { + random = random * 3 + 1013904223; + int factor = random >> 2; + int x = factor & 15; + int z = factor >> 8 & 15; + int y = factor >> 16 & 15; + BlockState blockState = levelChunkSection.getBlockState(x, y, z); + Block block = blockState.getBlock(); + if (blockState.isRandomlyTicking() && + plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); + blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); + } + } + } + } + } + +} From 1c6afa68cde8cc5a5114012e0f38ca004bdbf9f0 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 14 Dec 2024 15:57:46 +0200 Subject: [PATCH 009/600] Optimized settings runtime-lookups --- .../nms/v1_12_R1/NMSChunksImpl.java | 1 + .../chunks/CropsTickingTileEntity.java | 48 ++++++++-- .../nms/v1_16_R3/NMSChunksImpl.java | 2 + .../v1_16_R3/crops/CropsTickingMethod.java | 36 ++++++-- .../nms/v1_17/NMSChunksImpl.java | 2 + .../nms/v1_17/crops/CropsTickingMethod.java | 35 ++++++- .../nms/v1_18/NMSChunksImpl.java | 2 + .../nms/v1_18/crops/CropsTickingMethod.java | 35 ++++++- .../nms/v1_19/NMSChunksImpl.java | 2 + .../nms/v1_19/crops/CropsTickingMethod.java | 35 ++++++- .../nms/v1_20_3/NMSChunksImpl.java | 2 + .../nms/v1_20_3/crops/CropsTickingMethod.java | 35 ++++++- .../nms/v1_20_4/NMSChunksImpl.java | 2 + .../nms/v1_20_4/crops/CropsTickingMethod.java | 35 ++++++- .../nms/v1_21/NMSChunksImpl.java | 2 + .../nms/v1_21/crops/CropsTickingMethod.java | 35 ++++++- .../nms/v1_21_3/NMSChunksImpl.java | 2 + .../nms/v1_21_3/crops/CropsTickingMethod.java | 35 ++++++- .../nms/v1_21_4/NMSChunksImpl.java | 2 + .../nms/v1_21_4/crops/CropsTickingMethod.java | 35 ++++++- .../chunks/CropsTickingTileEntity.java | 56 +++++++++--- .../SuperiorSkyblockPlugin.java | 24 +++-- .../commands/CommandsMap.java | 23 ++++- .../config/SettingsContainer.java | 91 +++++++++++-------- .../config/SettingsManagerImpl.java | 3 + .../config/section/DefaultValuesSection.java | 7 +- .../core/events/CallbacksBus.java | 38 ++++++++ .../superiorskyblock/island/SIsland.java | 22 ++++- .../superiorskyblock/island/SpawnIsland.java | 31 ++++++- .../island/upgrade/DefaultUpgradeLevel.java | 2 +- .../island/warp/SignWarp.java | 32 ++++--- .../region/RegionManagerServiceImpl.java | 33 ++++++- 32 files changed, 600 insertions(+), 145 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java index b92c42238d..95e029a184 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java @@ -63,6 +63,7 @@ public class NMSChunksImpl implements NMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); + CropsTickingTileEntity.register(); } @Override diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java index d36214e185..d3d02e95d8 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java @@ -2,9 +2,13 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.Chunk; @@ -16,7 +20,9 @@ import org.bukkit.craftbukkit.v1_12_R1.util.CraftMagicNumbers; import java.lang.ref.WeakReference; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; @@ -24,6 +30,12 @@ public class CropsTickingTileEntity extends TileEntity implements ITickable { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingTileEntity::onSettingsUpdate); + } + private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); private static int random = ThreadLocalRandom.current().nextInt(); @@ -36,15 +48,8 @@ public class CropsTickingTileEntity extends TileEntity implements ITickable { private double cachedCropGrowthMultiplier; - private CropsTickingTileEntity(Island island, Chunk chunk) { - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(chunk); - this.chunkX = chunk.locX; - this.chunkZ = chunk.locZ; - a(chunk.getWorld()); - setPosition(new BlockPosition(chunkX << 4, 1, chunkZ << 4)); - world.tileEntityListTick.add(this); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; + public static void register() { + // Calls the static initializer which registers the callback. } public static void create(Island island, Chunk chunk) { @@ -68,6 +73,17 @@ public static void forEachChunk(List chunkPositions, Consumer(island); + this.chunk = new WeakReference<>(chunk); + this.chunkX = chunk.locX; + this.chunkZ = chunk.locZ; + a(chunk.getWorld()); + setPosition(new BlockPosition(chunkX << 4, 1, chunkZ << 4)); + world.tileEntityListTick.add(this); + this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; + } + @Override public void e() { if (++currentTick <= plugin.getSettings().getCropsInterval()) @@ -98,7 +114,7 @@ public void e() { int y = factor >> 16 & 15; IBlockData blockData = chunkSection.getType(x, y, z); Block block = blockData.getBlock(); - if (block.isTicking() && plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + if (block.isTicking() && CROPS_TO_GROW_CACHE.contains(block)) { block.a(world, new BlockPosition(x + (chunkX << 4), y + chunkSection.getYPosition(), z + (chunkZ << 4)), blockData, ThreadLocalRandom.current()); } @@ -113,4 +129,16 @@ public void setCropGrowthMultiplier(double cropGrowthMultiplier) { this.cachedCropGrowthMultiplier = cropGrowthMultiplier; } + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey) { + Block block = CraftMagicNumbers.getBlock(((MaterialKey) key).getMaterial()); + if (block != null && block.isTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java index 085c4f21e2..adc2432df2 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java @@ -17,6 +17,7 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; +import com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops.CropsTickingTileEntity; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; @@ -82,6 +83,7 @@ public class NMSChunksImpl implements NMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); + CropsTickingMethod.register(); } @Override diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java index a8c354741c..16b1a7f429 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java @@ -2,6 +2,10 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.Chunk; @@ -11,7 +15,9 @@ import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; +import java.util.HashSet; import java.util.Random; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; public abstract class CropsTickingMethod { @@ -21,22 +27,43 @@ public abstract class CropsTickingMethod { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + } + private static final BlockPosition.MutableBlockPosition chunkTickMutablePosition = new BlockPosition.MutableBlockPosition(); private static final CropsTickingMethod INSTANCE = WORLD_SERVER_RANDOM_TICK_RANDOM.isValid() ? new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); - protected CropsTickingMethod() { } + public static void register() { + // Calls the static initializer which registers the callback. + } + public static void tick(Chunk chunk, int tickSpeed) { INSTANCE.doTick(chunk, tickSpeed); } protected abstract void doTick(Chunk chunk, int tickSpeed); + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey) { + Block block = CraftMagicNumbers.getBlock(((MaterialKey) key).getMaterial()); + if (block != null && block.getBlockData().isTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + private static class PaperCropsTickingMethod extends CropsTickingMethod { @Override @@ -69,8 +96,7 @@ protected void doTick(Chunk chunk, int tickSpeed) { long raw = chunkSection.tickingList.getRaw(index); int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); IBlockData blockData = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); - Block block = blockData.getBlock(); - if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + if (!CROPS_TO_GROW_CACHE.contains(blockData.getBlock())) continue; chunkTickMutablePosition.setValues((location & 15) | chunkOffsetX, @@ -107,9 +133,7 @@ protected void doTick(Chunk chunk, int tickSpeed) { int z = factor >> 8 & 15; int y = factor >> 16 & 15; IBlockData blockData = chunkSection.getType(x, y, z); - Block block = blockData.getBlock(); - if (blockData.isTicking() && - plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + if (blockData.isTicking() && CROPS_TO_GROW_CACHE.contains(blockData.getBlock())) { chunkTickMutablePosition.setValues(x + chunkOffsetX, y + chunkSection.getYPosition(), z + chunkOffsetZ); blockData.b(worldServer, chunkTickMutablePosition, worldServer.random); } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java index 830badf7b0..2a739ec661 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java @@ -20,6 +20,7 @@ import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.v1_17.crops.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_17.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_17.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -88,6 +89,7 @@ public class NMSChunksImpl implements NMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); + CropsTickingMethod.register(); } @Override diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java index 668cd425c0..1acaaaeaa5 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java @@ -2,6 +2,10 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; @@ -11,7 +15,9 @@ import net.minecraft.world.level.chunk.LevelChunkSection; import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; +import java.util.HashSet; import java.util.Random; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; public abstract class CropsTickingMethod { @@ -21,6 +27,12 @@ public abstract class CropsTickingMethod { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + } + private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? @@ -31,12 +43,28 @@ protected CropsTickingMethod() { } + public static void register() { + // Calls the static initializer which registers the callback. + } + public static void tick(LevelChunk levelChunk, int tickSpeed) { INSTANCE.doTick(levelChunk, tickSpeed); } protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey materialKey) { + Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); + if (block != null && block.defaultBlockState().isRandomlyTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + private static class PaperCropsTickingMethod extends CropsTickingMethod { @Override @@ -74,8 +102,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { long raw = levelChunkSection.tickingList.getRaw(index); int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); - Block block = blockState.getBlock(); - if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) continue; chunkTickMutablePosition.set((location & 15) | chunkOffsetX, @@ -118,9 +145,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { int z = factor >> 8 & 15; int y = factor >> 16 & 15; BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (blockState.isRandomlyTicking() && - plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java index 6a7be2fbd5..a59f820338 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java @@ -17,6 +17,7 @@ import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.v1_18.crops.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_18.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_18.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -83,6 +84,7 @@ public class NMSChunksImpl implements NMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); + CropsTickingMethod.register(); } @Override diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java index 2288384e56..0a5c4db0d0 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java @@ -2,6 +2,10 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; @@ -11,7 +15,9 @@ import net.minecraft.world.level.chunk.LevelChunkSection; import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; +import java.util.HashSet; import java.util.Random; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; public abstract class CropsTickingMethod { @@ -21,6 +27,12 @@ public abstract class CropsTickingMethod { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + } + private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? @@ -31,12 +43,28 @@ protected CropsTickingMethod() { } + public static void register() { + // Calls the static initializer which registers the callback. + } + public static void tick(LevelChunk levelChunk, int tickSpeed) { INSTANCE.doTick(levelChunk, tickSpeed); } protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey materialKey) { + Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); + if (block != null && block.defaultBlockState().isRandomlyTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + private static class PaperCropsTickingMethod extends CropsTickingMethod { @Override @@ -74,8 +102,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { long raw = levelChunkSection.tickingList.getRaw(index); int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); - Block block = blockState.getBlock(); - if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) continue; chunkTickMutablePosition.set((location & 15) | chunkOffsetX, @@ -118,9 +145,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { int z = factor >> 8 & 15; int y = factor >> 16 & 15; BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (blockState.isRandomlyTicking() && - plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java index c11ba230d4..0a9cf60931 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.v1_19.crops.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_19.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_19.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -87,6 +88,7 @@ public class NMSChunksImpl implements NMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); + CropsTickingMethod.register(); } @Override diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java index 19dfd537a6..f5f1e95ad7 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java @@ -2,6 +2,10 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; @@ -12,6 +16,8 @@ import net.minecraft.world.level.chunk.LevelChunkSection; import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; public abstract class CropsTickingMethod { @@ -21,6 +27,12 @@ public abstract class CropsTickingMethod { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + } + private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? @@ -31,12 +43,28 @@ protected CropsTickingMethod() { } + public static void register() { + // Calls the static initializer which registers the callback. + } + public static void tick(LevelChunk levelChunk, int tickSpeed) { INSTANCE.doTick(levelChunk, tickSpeed); } protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey materialKey) { + Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); + if (block != null && block.defaultBlockState().isRandomlyTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + private static class PaperCropsTickingMethod extends CropsTickingMethod { @Override @@ -74,8 +102,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { long raw = levelChunkSection.tickingList.getRaw(index); int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); - Block block = blockState.getBlock(); - if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) continue; chunkTickMutablePosition.set((location & 15) | chunkOffsetX, @@ -118,9 +145,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { int z = factor >> 8 & 15; int y = factor >> 16 & 15; BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (blockState.isRandomlyTicking() && - plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java index 53d13f3fd9..ba7709c4dd 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java @@ -19,6 +19,7 @@ import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.v1_20_3.crops.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -97,6 +98,7 @@ public class NMSChunksImpl implements NMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); + CropsTickingMethod.register(); } @Override diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java index b86440f5cb..02ca6bea8a 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java @@ -2,6 +2,10 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; @@ -12,6 +16,8 @@ import net.minecraft.world.level.chunk.LevelChunkSection; import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; public abstract class CropsTickingMethod { @@ -21,6 +27,12 @@ public abstract class CropsTickingMethod { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + } + private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? @@ -31,12 +43,28 @@ protected CropsTickingMethod() { } + public static void register() { + // Calls the static initializer which registers the callback. + } + public static void tick(LevelChunk levelChunk, int tickSpeed) { INSTANCE.doTick(levelChunk, tickSpeed); } protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey materialKey) { + Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); + if (block != null && block.defaultBlockState().isRandomlyTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + private static class PaperCropsTickingMethod extends CropsTickingMethod { @Override @@ -74,8 +102,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { long raw = levelChunkSection.tickingList.getRaw(index); int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); - Block block = blockState.getBlock(); - if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) continue; chunkTickMutablePosition.set((location & 15) | chunkOffsetX, @@ -118,9 +145,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { int z = factor >> 8 & 15; int y = factor >> 16 & 15; BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (blockState.isRandomlyTicking() && - plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java index 87c5a499a9..db0017b3f7 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.v1_20_4.crops.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -89,6 +90,7 @@ public class NMSChunksImpl implements NMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); + CropsTickingMethod.register(); } @Override diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java index d0ef84c8ac..0944a3ca39 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java @@ -2,6 +2,10 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; @@ -12,6 +16,8 @@ import net.minecraft.world.level.chunk.LevelChunkSection; import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; public abstract class CropsTickingMethod { @@ -21,6 +27,12 @@ public abstract class CropsTickingMethod { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + } + private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? @@ -30,12 +42,28 @@ protected CropsTickingMethod() { } + public static void register() { + // Calls the static initializer which registers the callback. + } + public static void tick(LevelChunk levelChunk, int tickSpeed) { INSTANCE.doTick(levelChunk, tickSpeed); } protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey materialKey) { + Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); + if (block != null && block.defaultBlockState().isRandomlyTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + private static class PaperCropsTickingMethod extends CropsTickingMethod { @Override @@ -73,8 +101,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { long raw = levelChunkSection.tickingList.getRaw(index); int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); - Block block = blockState.getBlock(); - if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) continue; chunkTickMutablePosition.set((location & 15) | chunkOffsetX, @@ -117,9 +144,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { int z = factor >> 8 & 15; int y = factor >> 16 & 15; BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (blockState.isRandomlyTicking() && - plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java index b8a738fe31..ad42939afb 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.v1_21.crops.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_21.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -83,6 +84,7 @@ public class NMSChunksImpl implements NMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); + CropsTickingMethod.register(); } @Override diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java index 065da93ca1..dcaca12832 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java @@ -1,6 +1,10 @@ package com.bgsoftware.superiorskyblock.nms.v1_21.crops; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; @@ -12,6 +16,8 @@ import net.minecraft.world.level.chunk.PalettedContainer; import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; import java.util.function.Supplier; @@ -19,6 +25,12 @@ public abstract class CropsTickingMethod { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + } + private static final CropsTickingMethod INSTANCE = ((Supplier) () -> { try { Class.forName("ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection"); @@ -28,6 +40,10 @@ public abstract class CropsTickingMethod { } }).get(); + public static void register() { + // Calls the static initializer which registers the callback. + } + protected CropsTickingMethod() { } @@ -38,6 +54,18 @@ public static void tick(LevelChunk levelChunk, int tickSpeed) { protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey materialKey) { + Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); + if (block != null && block.defaultBlockState().isRandomlyTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + private static class PaperCropsTickingMethod extends CropsTickingMethod { @Override @@ -80,8 +108,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { long raw = tickList.getRaw(index); int location = ca.spottedleaf.moonrise.common.list.IBlockDataList.getLocationFromRaw(raw); BlockState blockState = states.get(location); - Block block = blockState.getBlock(); - if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) continue; // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! @@ -125,9 +152,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { int z = factor >> 8 & 15; int y = factor >> 16 & 15; BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (blockState.isRandomlyTicking() && - plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java index cf6e04f64c..3f14d9c784 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.v1_21_3.crops.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -84,6 +85,7 @@ public class NMSChunksImpl implements NMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); + CropsTickingMethod.register(); } @Override diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java index ea7ecff4c2..d19ef091a2 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java @@ -2,6 +2,10 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; @@ -13,6 +17,8 @@ import net.minecraft.world.level.chunk.PalettedContainer; import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; public abstract class CropsTickingMethod { @@ -22,6 +28,12 @@ public abstract class CropsTickingMethod { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + } + private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_SIMPLE_RANDOM.isValid() ? new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); @@ -29,12 +41,28 @@ protected CropsTickingMethod() { } + public static void register() { + // Calls the static initializer which registers the callback. + } + public static void tick(LevelChunk levelChunk, int tickSpeed) { INSTANCE.doTick(levelChunk, tickSpeed); } protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey materialKey) { + Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); + if (block != null && block.defaultBlockState().isRandomlyTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + private static class PaperCropsTickingMethod extends CropsTickingMethod { @Override @@ -75,8 +103,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { int location = (int) tickList.getRaw(index) & 0xFFFF; BlockState blockState = states.get(location); - Block block = blockState.getBlock(); - if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) continue; // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! @@ -120,9 +147,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { int z = factor >> 8 & 15; int y = factor >> 16 & 15; BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (blockState.isRandomlyTicking() && - plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java index b32088286e..1eac0cb3f5 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.v1_21_4.crops.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -84,6 +85,7 @@ public class NMSChunksImpl implements NMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); + CropsTickingMethod.register(); } @Override diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java index 9e11abf67b..66a1758608 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java @@ -2,6 +2,10 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; @@ -13,6 +17,8 @@ import net.minecraft.world.level.chunk.PalettedContainer; import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; public abstract class CropsTickingMethod { @@ -25,16 +31,38 @@ public abstract class CropsTickingMethod { private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_SIMPLE_RANDOM.isValid() ? new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + } + protected CropsTickingMethod() { } + public static void register() { + // Calls the static initializer which registers the callback. + } + public static void tick(LevelChunk levelChunk, int tickSpeed) { INSTANCE.doTick(levelChunk, tickSpeed); } protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey materialKey) { + Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); + if (block != null && block.defaultBlockState().isRandomlyTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + private static class PaperCropsTickingMethod extends CropsTickingMethod { @Override @@ -75,8 +103,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { int location = (int) tickList.getRaw(index) & 0xFFFF; BlockState blockState = states.get(location); - Block block = blockState.getBlock(); - if (!plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) + if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) continue; // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! @@ -120,9 +147,7 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { int z = factor >> 8 & 15; int y = factor >> 16 & 15; BlockState blockState = levelChunkSection.getBlockState(x, y, z); - Block block = blockState.getBlock(); - if (blockState.isRandomlyTicking() && - plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); } diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java index f960bcccaa..f416c97604 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java @@ -2,9 +2,13 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockPosition; import net.minecraft.server.v1_8_R3.Chunk; @@ -16,7 +20,9 @@ import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; import java.lang.ref.WeakReference; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; @@ -24,6 +30,12 @@ public class CropsTickingTileEntity extends TileEntity implements IUpdatePlayerL private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingTileEntity::onSettingsUpdate); + } + private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); private static int random = ThreadLocalRandom.current().nextInt(); @@ -36,19 +48,8 @@ public class CropsTickingTileEntity extends TileEntity implements IUpdatePlayerL private double cachedCropGrowthMultiplier; - private CropsTickingTileEntity(Island island, Chunk chunk) { - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(chunk); - this.chunkX = chunk.locX; - this.chunkZ = chunk.locZ; - a(chunk.getWorld()); - a(new BlockPosition(chunkX << 4, 1, chunkZ << 4)); - try { - world.tileEntityList.add(this); - } catch (Throwable error) { - world.a(this); - } - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; + public static void register() { + // Calls the static initializer which registers the callback. } public static CropsTickingTileEntity remove(long chunkCoords) { @@ -72,6 +73,21 @@ public static void forEachChunk(List chunkPositions, Consumer(island); + this.chunk = new WeakReference<>(chunk); + this.chunkX = chunk.locX; + this.chunkZ = chunk.locZ; + a(chunk.getWorld()); + a(new BlockPosition(chunkX << 4, 1, chunkZ << 4)); + try { + world.tileEntityList.add(this); + } catch (Throwable error) { + world.a(this); + } + this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; + } + @Override public void c() { if (++currentTick <= plugin.getSettings().getCropsInterval()) @@ -102,7 +118,7 @@ public void c() { int y = factor >> 16 & 15; IBlockData blockData = chunkSection.getType(x, y, z); Block block = blockData.getBlock(); - if (block.isTicking() && plugin.getSettings().getCropsToGrow().contains(CraftMagicNumbers.getMaterial(block).name())) { + if (block.isTicking() && CROPS_TO_GROW_CACHE.contains(block)) { block.a(world, new BlockPosition(x + (chunkX << 4), y + chunkSection.getYPosition(), z + (chunkZ << 4)), blockData, ThreadLocalRandom.current()); } @@ -117,4 +133,16 @@ public void setCropGrowthMultiplier(double cropGrowthMultiplier) { this.cachedCropGrowthMultiplier = cropGrowthMultiplier; } + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey) { + Block block = CraftMagicNumbers.getBlock(((MaterialKey) key).getMaterial()); + if (block != null && block.isTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index a3f14391fa..6710ecadb0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -24,6 +24,7 @@ import com.bgsoftware.superiorskyblock.core.engine.EnginesFactory; import com.bgsoftware.superiorskyblock.core.engine.NashornEngineDownloader; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; import com.bgsoftware.superiorskyblock.core.events.EventsBus; import com.bgsoftware.superiorskyblock.core.factory.FactoriesManagerImpl; import com.bgsoftware.superiorskyblock.core.itemstack.GlowEnchantment; @@ -84,8 +85,6 @@ import org.bukkit.generator.ChunkGenerator; import org.bukkit.plugin.java.JavaPlugin; -import java.io.File; -import java.lang.reflect.Constructor; import java.util.Locale; import java.util.Optional; @@ -93,6 +92,13 @@ public class SuperiorSkyblockPlugin extends JavaPlugin implements SuperiorSkyblo private static SuperiorSkyblockPlugin plugin; + /* Global handlers */ + private final Updater updater = new Updater(this, "superiorskyblock2"); + private final EventsBus eventsBus = new EventsBus(this); + private final CallbacksBus callbacksBus = new CallbacksBus(); + private final BukkitListeners bukkitListeners = new BukkitListeners(this); + private IScriptEngine scriptEngine = EnginesFactory.createDefaultEngine(); + /* Managers */ private final DataManager dataHandler = new DataManager(this); private final FactoriesManagerImpl factoriesHandler = new FactoriesManagerImpl(); @@ -112,14 +118,6 @@ public class SuperiorSkyblockPlugin extends JavaPlugin implements SuperiorSkyblo private final ServicesHandler servicesHandler = new ServicesHandler(this); private final SettingsManagerImpl settingsHandler = new SettingsManagerImpl(this); - /* Global handlers */ - private final Updater updater = new Updater(this, "superiorskyblock2"); - private final EventsBus eventsBus = new EventsBus(this); - private final BukkitListeners bukkitListeners = new BukkitListeners(this); - private IScriptEngine scriptEngine = EnginesFactory.createDefaultEngine(); - @Nullable - private ChunkGenerator worldGenerator = null; - /* NMS */ @Nullable private NMSAlgorithms nmsAlgorithms; @@ -316,6 +314,8 @@ public void onEnable() { eventsBus.callPluginInitializedEvent(this); loadingStage = PluginLoadingStage.ENABLED; + + plugin.getCallbacksBus().notifyCallbacks(CallbacksBus.CallbackType.SETTINGS_UPDATE); } catch (Throwable error) { Log.error(error, "An unexpected error occurred while enabling the plugin:"); Bukkit.shutdown(); @@ -589,6 +589,10 @@ public EventsBus getEventsBus() { return eventsBus; } + public CallbacksBus getCallbacksBus() { + return callbacksBus; + } + public ServicesHandler getServices() { return servicesHandler; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java index 230d0c57e4..f42b2ee0a3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java @@ -4,19 +4,35 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; import com.google.common.base.Preconditions; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; public abstract class CommandsMap { + private static Set DISABLED_COMMANDS_CACHE; + private static boolean registeredCallback = false; + + private static void onSettingsUpdate() { + DISABLED_COMMANDS_CACHE = new HashSet<>(); + SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + plugin.getSettings().getDisabledCommands().forEach(commandLabel -> { + SuperiorCommand superiorCommand = plugin.getCommands().getCommand(commandLabel); + if (superiorCommand != null && !(superiorCommand instanceof IAdminIslandCommand)) + DISABLED_COMMANDS_CACHE.add(superiorCommand); + }); + } + private final Map subCommands = new LinkedHashMap<>(); private final Map aliasesToCommand = new HashMap<>(); @@ -24,6 +40,10 @@ public abstract class CommandsMap { protected CommandsMap(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; + if (!registeredCallback) { + registeredCallback = true; + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CommandsMap::onSettingsUpdate); + } } public abstract void loadDefaultCommands(); @@ -79,8 +99,7 @@ public List getSubCommands(boolean includeDisabled) { } private boolean isCommandEnabled(SuperiorCommand superiorCommand) { - return superiorCommand instanceof IAdminIslandCommand || superiorCommand.getAliases().stream() - .noneMatch(plugin.getSettings().getDisabledCommands()::contains); + return superiorCommand instanceof IAdminIslandCommand || !DISABLED_COMMANDS_CACHE.contains(superiorCommand); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 454d7035c0..d683dd4e4e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -48,7 +48,9 @@ import java.math.BigInteger; import java.util.Arrays; import java.util.Collections; +import java.util.EnumMap; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -231,15 +233,17 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config islandCommand = config.getString("island-command", "island,is,islands"); maxIslandSize = config.getInt("max-island-size", 200); defaultIslandSize = config.getInt("default-values.island-size", 20); - defaultBlockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); + KeyMap defaultBlockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); loadListOrSection(config, "default-values.block-limits", "block limit", (key, limit) -> { Key blockKey = Keys.ofMaterialAndData(key); defaultBlockLimits.put(blockKey, limit); plugin.getBlockValues().addCustomBlockKey(blockKey); }); - defaultEntityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + this.defaultBlockLimits = KeyMaps.unmodifiableKeyMap(defaultBlockLimits); + KeyMap defaultEntityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); loadListOrSection(config, "default-values.entity-limits", "entity limit", (entityType, limit) -> defaultEntityLimits.put(Keys.ofEntityType(entityType), limit)); + this.defaultEntityLimits = KeyMaps.unmodifiableKeyMap(defaultEntityLimits); defaultTeamLimit = config.getInt("default-values.team-limit", 4); defaultWarpsLimit = config.getInt("default-values.warps-limit", 3); defaultCoopLimit = config.getInt("default-values.coop-limit", 8); @@ -258,14 +262,15 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config islandsHeight = config.getInt("islands-height", 100); worldBordersEnabled = config.getBoolean("world-borders", true); stackedBlocksEnabled = config.getBoolean("stacked-blocks.enabled", true); - stackedBlocksDisabledWorlds = config.getStringList("stacked-blocks.disabled-worlds"); + stackedBlocksDisabledWorlds = Collections.unmodifiableList(config.getStringList("stacked-blocks.disabled-worlds")); whitelistedStackedBlocks = KeySets.createHashSet(KeyIndicator.MATERIAL, config.getStringList("stacked-blocks.whitelisted")); stackedBlocksName = Formatters.COLOR_FORMATTER.format(config.getString("stacked-blocks.custom-name")); - stackedBlocksLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); + KeyMap stackedBlocksLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); loadListOrSection(config, "stacked-blocks.limits", "stacked-block limit", (key, limit) -> { Key blockKey = Keys.ofMaterialAndData(key); stackedBlocksLimits.put(blockKey, limit); }); + this.stackedBlocksLimits = KeyMaps.unmodifiableKeyMap(stackedBlocksLimits); stackedBlocksAutoPickup = config.getBoolean("stacked-blocks.auto-collect", false); stackedBlocksMenuEnabled = config.getBoolean("stacked-blocks.deposit-menu.enabled", true); stackedBlocksMenuTitle = Formatters.COLOR_FORMATTER.format(config.getString("stacked-blocks.deposit-menu.title", "&lDeposit Blocks")); @@ -275,9 +280,10 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config coopMembers = config.getBoolean("coop-members", true); islandRolesSection = config.getConfigurationSection("island-roles"); signWarpLine = config.getString("sign-warp-line", "[IslandWarp]"); - signWarp = Formatters.formatList(config.getStringList("sign-warp"), Formatters.COLOR_FORMATTER); + List signWarp = Formatters.formatList(config.getStringList("sign-warp"), Formatters.COLOR_FORMATTER); while (signWarp.size() < 4) signWarp.add(""); + this.signWarp = Collections.unmodifiableList(signWarp); visitorsSignRequiredForVisit = config.getBoolean("visitors-sign.required-for-visit", true); visitorsSignLine = config.getString("visitors-sign.line", "[Welcome]"); visitorsSignActive = Formatters.COLOR_FORMATTER.format(config.getString("visitors-sign.active", "&a[Welcome]")); @@ -329,15 +335,15 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config worldsDifficulty = config.getString("worlds.difficulty", "EASY").toUpperCase(Locale.ENGLISH); spawnLocation = config.getString("spawn.location", "SuperiorWorld, 0, 100, 0, 0, 0"); spawnProtection = config.getBoolean("spawn.protection", true); - spawnSettings = config.getStringList("spawn.settings") - .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList()); - spawnPermissions = config.getStringList("spawn.permissions") - .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList()); + spawnSettings = Collections.unmodifiableList(new LinkedList<>(config.getStringList("spawn.settings") + .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList()))); + spawnPermissions = Collections.unmodifiableList(new LinkedList<>(config.getStringList("spawn.permissions") + .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList()))); spawnWorldBorder = config.getBoolean("spawn.world-border", false); spawnSize = config.getInt("spawn.size", 200); spawnDamage = config.getBoolean("spawn.players-damage", false); - worldPermissions = config.getStringList("world-permissions") - .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toSet()); + worldPermissions = Collections.unmodifiableSet(new LinkedHashSet<>(config.getStringList("world-permissions") + .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toSet()))); voidTeleportMembers = config.getBoolean("void-teleport.members", true); voidTeleportVisitors = config.getBoolean("void-teleport.visitors", true); interactables = loadInteractables(plugin); @@ -346,10 +352,10 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config coopDamage = config.getBoolean("coop-damage", true); disbandCount = config.getInt("disband-count", 5); islandTopIncludeLeader = config.getBoolean("island-top-include-leader", true); - defaultPlaceholders = config.getStringList("default-placeholders").stream().collect(Collectors.toMap( + defaultPlaceholders = Collections.unmodifiableMap(config.getStringList("default-placeholders").stream().collect(Collectors.toMap( line -> line.split(":")[0].replace("superior_", "").toLowerCase(Locale.ENGLISH), line -> line.split(":")[1] - )); + ))); banConfirm = config.getBoolean("ban-confirm"); disbandConfirm = config.getBoolean("disband-confirm"); kickConfirm = config.getBoolean("kick-confirm"); @@ -360,9 +366,9 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config islandNamesRequiredForCreation = config.getBoolean("island-names.required-for-creation", true); islandNamesMaxLength = config.getInt("island-names.max-length", 16); islandNamesMinLength = config.getInt("island-names.min-length", 3); - filteredIslandNames = config.getStringList("island-names.filtered-names").stream() + filteredIslandNames = Collections.unmodifiableList(config.getStringList("island-names.filtered-names").stream() .map(str -> str.toLowerCase(Locale.ENGLISH)) - .collect(Collectors.toList()); + .collect(Collectors.toList())); islandNamesColorSupport = config.getBoolean("island-names.color-support", true); islandNamesIslandTop = config.getBoolean("island-names.island-top", true); islandNamesPreventPlayerNames = config.getBoolean("island-names.prevent-player-names", true); @@ -370,8 +376,8 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config teleportOnKick = config.getBoolean("teleport-on-kick", false); clearOnJoin = config.getBoolean("clear-on-join", false); rateOwnIsland = config.getBoolean("rate-own-island", false); - defaultSettings = config.getStringList("default-settings") - .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList()); + defaultSettings = Collections.unmodifiableList(config.getStringList("default-settings") + .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList())); defaultGenerator = new KeyMap[Dimension.values().size()]; if (config.isConfigurationSection("default-values.generator")) { for (String env : config.getConfigurationSection("default-values.generator").getKeys(false)) { @@ -388,12 +394,13 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config disableRedstoneOffline = config.getBoolean("disable-redstone-offline", true); disableRedstoneAFK = config.getBoolean("afk-integrations.disable-redstone", false); disableSpawningAFK = config.getBoolean("afk-integrations.disable-spawning", true); - commandsCooldown = new HashMap<>(); + Map> commandsCooldown = new HashMap<>(); for (String subCommand : config.getConfigurationSection("commands-cooldown").getKeys(false)) { int cooldown = config.getInt("commands-cooldown." + subCommand + ".cooldown"); String permission = config.getString("commands-cooldown." + subCommand + ".bypass-permission"); commandsCooldown.put(subCommand, new Pair<>(cooldown, permission)); } + this.commandsCooldown = Collections.unmodifiableMap(commandsCooldown); upgradeCooldown = config.getLong("upgrade-cooldown", -1L); numberFormat = config.getString("number-format", "en-US"); NumberFormatter.setNumberFormatter(numberFormat); @@ -402,9 +409,9 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config skipOneItemMenus = config.getBoolean("skip-one-item-menus", false); teleportOnPVPEnable = config.getBoolean("teleport-on-pvp-enable", true); immuneToPVPWhenTeleport = config.getBoolean("immune-to-pvp-when-teleport", true); - blockedVisitorsCommands = config.getStringList("blocked-visitors-commands"); + blockedVisitorsCommands = Collections.unmodifiableList(config.getStringList("blocked-visitors-commands")); defaultContainersEnabled = config.getBoolean("default-containers.enabled", false); - defaultContainersContents = new HashMap<>(); + Map defaultContainersContents = new EnumMap<>(InventoryType.class); if (config.contains("default-containers.containers")) { for (String container : config.getConfigurationSection("default-containers.containers").getKeys(false)) { try { @@ -438,22 +445,25 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config } } } - defaultSignLines = Formatters.formatList(config.getStringList("default-signs"), Formatters.COLOR_FORMATTER); - eventCommands = new HashMap<>(); + this.defaultContainersContents = Collections.unmodifiableMap(defaultContainersContents); + defaultSignLines = Collections.unmodifiableList( + Formatters.formatList(config.getStringList("default-signs"), Formatters.COLOR_FORMATTER)); + Map> eventCommands = new HashMap<>(); if (config.contains("event-commands")) { for (String eventName : config.getConfigurationSection("event-commands").getKeys(false)) { eventCommands.put(eventName.toLowerCase(Locale.ENGLISH), config.getStringList("event-commands." + eventName)); } } + this.eventCommands = Collections.unmodifiableMap(eventCommands); warpsWarmup = config.getLong("warps-warmup", 0); homeWarmup = config.getLong("home-warmup", 0); visitWarmup = config.getLong("visit-warmup", 0); liquidUpdate = config.getBoolean("liquid-update", false); lightsUpdate = config.getBoolean("lights-update", false); - pvpWorlds = config.getStringList("pvp-worlds"); + pvpWorlds = Collections.unmodifiableList(config.getStringList("pvp-worlds")); stopLeaving = config.getBoolean("stop-leaving", false); valuesMenu = config.getBoolean("values-menu", true); - cropsToGrow = config.getStringList("crops-to-grow"); + cropsToGrow = Collections.unmodifiableList(config.getStringList("crops-to-grow")); cropsInterval = config.getInt("crops-interval", 5); onlyBackButton = config.getBoolean("only-back-button", false); buildOutsideIsland = config.getBoolean("build-outside-island", false); @@ -467,24 +477,26 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config syncWorth = BlockValuesManagerImpl.SyncWorthStatus.of(config.getString("sync-worth", "NONE")); negativeWorth = config.getBoolean("negative-worth", true); negativeLevel = config.getBoolean("negative-level", true); - disabledEvents = config.getStringList("disabled-events") - .stream().map(str -> str.toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()); - disabledCommands = config.getStringList("disabled-commands") - .stream().map(str -> str.toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()); - disabledHooks = config.getStringList("disabled-hooks") - .stream().map(str -> str.toLowerCase(Locale.ENGLISH)).collect(Collectors.toList()); + disabledEvents = Collections.unmodifiableList(config.getStringList("disabled-events") + .stream().map(str -> str.toLowerCase(Locale.ENGLISH)).collect(Collectors.toList())); + disabledCommands = Collections.unmodifiableList(config.getStringList("disabled-commands") + .stream().map(str -> str.toLowerCase(Locale.ENGLISH)).collect(Collectors.toList())); + disabledHooks = Collections.unmodifiableList(config.getStringList("disabled-hooks") + .stream().map(str -> str.toLowerCase(Locale.ENGLISH)).collect(Collectors.toList())); schematicNameArgument = config.getBoolean("schematic-name-argument", true); islandChestTitle = Formatters.COLOR_FORMATTER.format(config.getString("island-chests.chest-title", "&4Island Chest")); islandChestsDefaultPage = config.getInt("island-chests.default-pages", 0); islandChestsDefaultSize = Math.min(6, Math.max(1, config.getInt("island-chests.default-size", 3))); - commandAliases = new HashMap<>(); + Map> commandAliases = new HashMap<>(); if (config.isConfigurationSection("command-aliases")) { for (String label : config.getConfigurationSection("command-aliases").getKeys(false)) { commandAliases.put(label.toLowerCase(Locale.ENGLISH), config.getStringList("command-aliases." + label)); } } - valuableBlocks = KeySets.createHashSet(KeyIndicator.MATERIAL, config.getStringList("valuable-blocks")); - islandPreviewLocations = new HashMap<>(); + this.commandAliases = Collections.unmodifiableMap(commandAliases); + valuableBlocks = KeySets.unmodifiableKeySet( + KeySets.createHashSet(KeyIndicator.MATERIAL, config.getStringList("valuable-blocks"))); + Map islandPreviewLocations = new HashMap<>(); if (config.isConfigurationSection("preview-islands")) { for (String schematic : config.getConfigurationSection("preview-islands").getKeys(false)) { try { @@ -495,6 +507,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config } } } + this.islandPreviewLocations = Collections.unmodifiableMap(islandPreviewLocations); tabCompleteHideVanished = config.getBoolean("tab-complete-hide-vanished", true); dropsUpgradePlayersMultiply = config.getBoolean("drops-upgrade-players-multiply", false); protectedMessageDelay = config.getLong("protected-message-delay", 60L); @@ -510,7 +523,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config .orElse(TopIslandMembersSorting.NAMES); bossBarLimit = config.getInt("bossbar-limit", 1); deleteUnsafeWarps = config.getBoolean("delete-unsafe-warps", true); - playerRespawnActions = new LinkedList<>(); + List playerRespawnActions = new LinkedList<>(); config.getStringList("player-respawn").forEach(respawnAction -> { try { playerRespawnActions.add(RespawnAction.getByName(respawnAction)); @@ -518,6 +531,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config Log.warnFromFile("config.yml", "Invalid respawn action ", respawnAction + ", skipping..."); } }); + this.playerRespawnActions = Collections.unmodifiableList(playerRespawnActions); blockCountsSaveThreshold = BigInteger.valueOf(config.getInt("block-counts-save-threshold", 100)); chatSigningSupport = config.getBoolean("chat-signing-support", true); } @@ -543,7 +557,7 @@ private List loadInteractables(SuperiorSkyblockPlugin plugin) { } } - return interactablesList; + return Collections.unmodifiableList(interactablesList); } private KeySet loadSafeBlocks(SuperiorSkyblockPlugin plugin) { @@ -572,15 +586,16 @@ private KeySet loadSafeBlocks(SuperiorSkyblockPlugin plugin) { } } - return KeySets.createHashSet(KeyIndicator.MATERIAL, safeBlocks); + return KeySets.unmodifiableKeySet(KeySets.createHashSet(KeyIndicator.MATERIAL, safeBlocks)); } private void loadGenerator(YamlConfiguration config, String path, int index) { - defaultGenerator[index] = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); + KeyMap defaultGenerator = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); loadListOrSection(config, path, "generator-rates", (key, percentage) -> { Key blockKey = Keys.ofMaterialAndData(key); - defaultGenerator[index].put(blockKey, percentage); + defaultGenerator.put(blockKey, percentage); }); + this.defaultGenerator[index] = KeyMaps.unmodifiableKeyMap(defaultGenerator); } private static void loadListOrSection(YamlConfiguration config, String path, String parseName, BiConsumer consumer) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index 787f45e67c..22e01f3ec2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.config.section.WorldsSection; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.Location; import org.bukkit.configuration.file.YamlConfiguration; @@ -81,6 +82,8 @@ public void loadData() throws ManagerLoadException { } loadContainerFromConfig(cfg); + + plugin.getCallbacksBus().notifyCallbacks(CallbacksBus.CallbackType.SETTINGS_UPDATE); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java index 45c2a48cfb..7d224c01e8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; import java.math.BigDecimal; +import java.util.Collections; import java.util.Map; public class DefaultValuesSection extends SettingsContainerHolder implements SettingsManager.DefaultValues { @@ -62,12 +63,16 @@ public BigDecimal getBankLimit() { @Override public Map[] getGenerators() { + return getGeneratorsUnsafe().clone(); + } + + public Map[] getGeneratorsUnsafe() { return getContainer().defaultGenerator; } @Override public Map getRoleLimits() { - return getContainer().defaultRoleLimits.asMap(); + return Collections.unmodifiableMap(getContainer().defaultRoleLimits.asMap()); } public Int2IntMapView getRoleLimitsAsView() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java new file mode 100644 index 0000000000..409806f7a9 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java @@ -0,0 +1,38 @@ +package com.bgsoftware.superiorskyblock.core.events; + +import com.bgsoftware.superiorskyblock.core.logging.Log; + +import java.util.EnumMap; +import java.util.LinkedList; +import java.util.List; + +public class CallbacksBus { + + private final EnumMap> CALLBACKS = new EnumMap<>(CallbackType.class); + + public CallbacksBus() { + } + + public void registerCallback(CallbackType callbackType, Runnable callback) { + CALLBACKS.computeIfAbsent(callbackType, c -> new LinkedList<>()).add(callback); + } + + public void notifyCallbacks(CallbackType callbackType) { + List callbacks = CALLBACKS.get(callbackType); + if (callbacks != null) + callbacks.forEach(callback -> { + try { + callback.run(); + } catch (Throwable error) { + Log.error(error, "An unexpected error occurred while running callback:"); + } + }); + } + + public enum CallbackType { + + SETTINGS_UPDATE + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 87bd4e8ff5..5c75b9e85b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -48,11 +48,11 @@ import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; import com.bgsoftware.superiorskyblock.core.events.EventResult; import com.bgsoftware.superiorskyblock.core.events.EventsBus; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.BaseKey; -import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; @@ -148,6 +148,12 @@ public class SIsland implements Island { private static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static EnumerateSet DEFAULT_FLAGS_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, SIsland::onSettingsUpdate); + } + private final DatabaseBridge databaseBridge; private final IslandBank islandBank; private final IslandCalculationAlgorithm calculationAlgorithm; @@ -3662,7 +3668,7 @@ public void removeRatings() { @Override public boolean hasSettingsEnabled(IslandFlag settings) { Preconditions.checkNotNull(settings, "settings parameter cannot be null."); - return islandFlags.getOrDefault(settings, (byte) (plugin.getSettings().getDefaultSettings().contains(settings.getName()) ? 1 : 0)) == 1; + return islandFlags.getOrDefault(settings, (byte) (DEFAULT_FLAGS_CACHE.contains(settings) ? 1 : 0)) == 1; } @Override @@ -4728,7 +4734,7 @@ private void updateOldUpgradeValues() { this.cobbleGeneratorValues.write(cobbleGeneratorValues -> { for (Dimension dimension : Dimension.values()) { - Map defaultGenerator = plugin.getSettings().getDefaultValues().getGenerators()[dimension.ordinal()]; + Map defaultGenerator = plugin.getSettings().getDefaultValues().getGeneratorsUnsafe()[dimension.ordinal()]; if (defaultGenerator != null) { KeyMap worldGeneratorRates = cobbleGeneratorValues.get(dimension); @@ -5012,6 +5018,16 @@ private void notifyCropGrowthChange(double newCropGrowth) { .values().forEach(chunkPositions -> plugin.getNMSChunks().updateCropsTicker(chunkPositions, newCropGrowthMultiplier)); } + private static void onSettingsUpdate() { + DEFAULT_FLAGS_CACHE = new EnumerateSet<>(IslandFlag.values()); + plugin.getSettings().getDefaultSettings().forEach(islandFlagName -> { + try { + DEFAULT_FLAGS_CACHE.add(IslandFlag.getByName(islandFlagName)); + } catch (Throwable ignored) { + } + }); + } + public static class UniqueVisitor { private final Pair pair; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 2dd36e1f2a..92deece482 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -37,8 +37,10 @@ import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.WorldInfoImpl; +import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.database.bridge.EmptyDatabaseBridge; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; import com.bgsoftware.superiorskyblock.core.key.KeyMaps; import com.bgsoftware.superiorskyblock.core.persistence.EmptyPersistentDataContainer; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; @@ -87,6 +89,31 @@ public class SpawnIsland implements Island { private static final IslandChest[] EMPTY_ISLAND_CHESTS = new IslandChest[0]; private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static EnumerateSet DEFAULT_SPAWN_FLAGS_CACHE; + private static EnumerateSet DEFAULT_SPAWN_PRIVILEGES_CACHE; + + static { + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, SpawnIsland::onSettingsUpdate); + } + + private static void onSettingsUpdate() { + DEFAULT_SPAWN_FLAGS_CACHE = new EnumerateSet<>(IslandFlag.values()); + plugin.getSettings().getSpawn().getSettings().forEach(flagName -> { + try { + DEFAULT_SPAWN_FLAGS_CACHE.add(IslandFlag.getByName(flagName)); + } catch (Throwable ignored) { + } + }); + + DEFAULT_SPAWN_PRIVILEGES_CACHE = new EnumerateSet<>(IslandPrivilege.values()); + plugin.getSettings().getSpawn().getPermissions().forEach(privilegeName -> { + try { + DEFAULT_SPAWN_PRIVILEGES_CACHE.add(IslandPrivilege.getByName(privilegeName)); + } catch (Throwable ignored) { + } + }); + } + private final PriorityQueue playersInside = new PriorityQueue<>(SortingComparators.PLAYER_NAMES_COMPARATOR); private final DirtyChunksContainer dirtyChunksContainer; @@ -890,7 +917,7 @@ public PrivilegeNodeAbstract getPermissionNode(SuperiorPlayer superiorPlayer) { @Override public PlayerRole getRequiredPlayerRole(IslandPrivilege islandPrivilege) { - return plugin.getSettings().getSpawn().getPermissions().contains(islandPrivilege.getName()) ? + return DEFAULT_SPAWN_PRIVILEGES_CACHE.contains(islandPrivilege) ? SPlayerRole.guestRole() : SPlayerRole.lastRole(); } @@ -1842,7 +1869,7 @@ public void removeRatings() { @Override public boolean hasSettingsEnabled(IslandFlag islandFlag) { - return plugin.getSettings().getSpawn().getSettings().contains(islandFlag.getName()); + return DEFAULT_SPAWN_FLAGS_CACHE.contains(islandFlag); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java index 15be8e3778..1e660901a9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java @@ -27,7 +27,7 @@ private DefaultUpgradeLevel() { IntValue.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getIslandSize()), (KeyMap) plugin.getSettings().getDefaultValues().getBlockLimits(), (KeyMap) plugin.getSettings().getDefaultValues().getEntityLimits(), - convertFromArray(plugin.getSettings().getDefaultValues().getGenerators()), + convertFromArray(plugin.getSettings().getDefaultValues().getGeneratorsUnsafe()), Collections.emptyMap(), Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getBankLimit()), plugin.getSettings().getDefaultValues().getRoleLimitsAsView() diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java index deb65b316b..074a4fa36d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.command.CommandSender; import org.bukkit.inventory.ItemStack; @@ -22,25 +23,28 @@ private SignWarp() { public static void trySignWarpBreak(IslandWarp islandWarp, CommandSender commandSender) { Block signBlock = islandWarp.getLocation().getBlock(); - // We check for a sign block at the warp's location. - if (signBlock.getState() instanceof Sign) { - Sign sign = (Sign) signBlock.getState(); + BlockState blockState = signBlock.getState(); - List configSignWarp = new ArrayList<>(plugin.getSettings().getSignWarp()); - configSignWarp.replaceAll(line -> line.replace("{0}", islandWarp.getName())); - String[] signLines = sign.getLines(); + // We check for a sign block at the warp's location. + if (!(blockState instanceof Sign)) + return; - for (int i = 0; i < signLines.length && i < configSignWarp.size(); ++i) { - if (!signLines[i].equals(configSignWarp.get(i))) - return; - } + Sign sign = (Sign) blockState; - // Detected warp sign - signBlock.setType(Material.AIR); - signBlock.getWorld().dropItemNaturally(signBlock.getLocation(), new ItemStack(Material.SIGN)); + List configSignWarp = new ArrayList<>(plugin.getSettings().getSignWarp()); + configSignWarp.replaceAll(line -> line.replace("{0}", islandWarp.getName())); + String[] signLines = sign.getLines(); - Message.DELETE_WARP_SIGN_BROKE.send(commandSender); + for (int i = 0; i < signLines.length && i < configSignWarp.size(); ++i) { + if (!signLines[i].equals(configSignWarp.get(i))) + return; } + + // Detected warp sign + signBlock.setType(Material.AIR); + signBlock.getWorld().dropItemNaturally(signBlock.getLocation(), new ItemStack(Material.SIGN)); + + Message.DELETE_WARP_SIGN_BROKE.send(commandSender); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 71ff82d167..3f17d1887b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -8,6 +8,8 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPreview; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.region.MoveResult; @@ -16,6 +18,10 @@ import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ServerVersion; +import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.KeySets; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -69,11 +75,30 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService @Nullable private static final EntityType AXOLOTL_TYPE = getSafeEntityType("AXOLOTL"); private static final int MAX_PICKUP_DISTANCE = 1; + private static EnumerateSet WORLD_PERMISSIONS_CACHE; + private static KeySet INTERACTABLES_CACHE; private final SuperiorSkyblockPlugin plugin; public RegionManagerServiceImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; + plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, this::onSettingsUpdate); + } + + private void onSettingsUpdate() { + WORLD_PERMISSIONS_CACHE = new EnumerateSet<>(IslandPrivilege.values()); + plugin.getSettings().getWorldPermissions().forEach(islandPrivilageName -> { + try { + WORLD_PERMISSIONS_CACHE.add(IslandPrivilege.getByName(islandPrivilageName)); + } catch (Throwable ignored) { + } + }); + + INTERACTABLES_CACHE = KeySets.createHashSet(KeyIndicator.MATERIAL); + plugin.getSettings().getInteractables().forEach(interactableName -> { + INTERACTABLES_CACHE.add(Keys.ofMaterialAndData(interactableName)); + }); + } @Override @@ -123,20 +148,20 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc Preconditions.checkNotNull(block, "block cannot be null"); Location blockLocation = block.getLocation(); - Material blockType = block.getType(); + Key blockKey = Keys.of(block); boolean isInteractableItem = BukkitItems.isInteractableItem(usedItem); int stackedBlockAmount = plugin.getStackedBlocks().getStackedBlockAmount(blockLocation); - if (!isInteractableItem && stackedBlockAmount <= 1 && - !plugin.getSettings().getInteractables().contains(blockType.name())) + if (!isInteractableItem && stackedBlockAmount <= 1 && !INTERACTABLES_CACHE.contains(blockKey)) return InteractionResult.SUCCESS; Island island = plugin.getGrid().getIslandAt(blockLocation); BlockState blockState = block.getState(); EntityType spawnType = usedItem == null ? EntityType.UNKNOWN : BukkitItems.getEntityType(usedItem); + Material blockType = block.getType(); IslandPrivilege islandPrivilege; @@ -364,7 +389,7 @@ private InteractionResult handleInteractionInternal(SuperiorPlayer superiorPlaye if (superiorPlayer.hasBypassModeEnabled()) return InteractionResult.SUCCESS; - if (checkIslandBoundaries && !plugin.getSettings().getWorldPermissions().contains(islandPrivilege.getName())) { + if (checkIslandBoundaries && !WORLD_PERMISSIONS_CACHE.contains(islandPrivilege)) { if (island == null && plugin.getGrid().isIslandsWorld(superiorPlayer.getWorld())) return InteractionResult.OUTSIDE_ISLAND; From aba698cf5685f80a2c1958ed3c7c92e44bab78e5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 14 Dec 2024 16:06:24 +0200 Subject: [PATCH 010/600] Patch dupe glitch with armor stands (#2295) --- .../upgrades/type/UpgradeTypeMobDrops.java | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java index 9082bf0abf..bb164d5752 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.world.BukkitEntities; import org.bukkit.Bukkit; import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -46,22 +47,25 @@ public List getCommands() { return commands; } + private static boolean canDupeDropsForEntity(Entity entity) { + return entity instanceof LivingEntity && !(entity instanceof Player) && !(entity instanceof ArmorStand); + } + private class MobDropsListener implements Listener { // Priority is set to HIGH for fixing detection with WildStacker // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/540 @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onLastDamageEntity(EntityDamageEvent e) { - if (!(e.getEntity() instanceof LivingEntity)) + if (!canDupeDropsForEntity(e.getEntity())) return; LivingEntity livingEntity = (LivingEntity) e.getEntity(); - if (!(livingEntity instanceof ArmorStand) && livingEntity.getHealth() - e.getFinalDamage() > 0) + if (livingEntity.getHealth() - e.getFinalDamage() > 0) return; Island island = plugin.getGrid().getIslandAt(livingEntity.getLocation()); - if (island == null) return; @@ -70,12 +74,11 @@ public void onLastDamageEntity(EntityDamageEvent e) { @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onEntityDeath(EntityDeathEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getEntity().getLocation()); - - if (island == null) + if (!canDupeDropsForEntity(e.getEntity())) return; - if (e.getEntity() instanceof Player) + Island island = plugin.getGrid().getIslandAt(e.getEntity().getLocation()); + if (island == null) return; if (plugin.getSettings().isDropsUpgradePlayersMultiply()) { @@ -85,16 +88,18 @@ public void onEntityDeath(EntityDeathEvent e) { return; } - BukkitEntities.clearEntityEquipment(e.getEntity()); - double mobDropsMultiplier = island.getMobDropsMultiplier(); - if (mobDropsMultiplier <= 1) - return; + if (mobDropsMultiplier > 1) + modifyEventDrops(e.getDrops(), e.getEntity(), mobDropsMultiplier); + + BukkitEntities.clearEntityEquipment(e.getEntity()); + } + private void modifyEventDrops(List drops, LivingEntity livingEntity, double mobDropsMultiplier) { List dropsToAdd = isWildStackerInstalled ? null : new LinkedList<>(); - for (ItemStack itemStack : e.getDrops()) { - if (itemStack != null && !BukkitEntities.isEquipment(e.getEntity(), itemStack)) { + for (ItemStack itemStack : drops) { + if (itemStack != null && !BukkitEntities.isEquipment(livingEntity, itemStack)) { int newAmount = (int) Math.floor(itemStack.getAmount() * mobDropsMultiplier); if (isWildStackerInstalled) { @@ -129,7 +134,7 @@ public void onEntityDeath(EntityDeathEvent e) { } if (dropsToAdd != null) - e.getDrops().addAll(dropsToAdd); + drops.addAll(dropsToAdd); } } From 48acd91b49a5e0e1c584eb827426dbdc449c3b13 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 14 Dec 2024 16:37:49 +0200 Subject: [PATCH 011/600] Fixed errors due to one of recent commits --- .../superiorskyblock/commands/CommandsMap.java | 9 ++++----- .../superiorskyblock/core/events/CallbacksBus.java | 8 ++++++++ .../com/bgsoftware/superiorskyblock/island/SIsland.java | 8 ++++---- .../bgsoftware/superiorskyblock/island/SpawnIsland.java | 4 ++-- .../service/region/RegionManagerServiceImpl.java | 8 ++++++-- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java index f42b2ee0a3..ae303c0507 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java @@ -21,7 +21,6 @@ public abstract class CommandsMap { private static Set DISABLED_COMMANDS_CACHE; - private static boolean registeredCallback = false; private static void onSettingsUpdate() { DISABLED_COMMANDS_CACHE = new HashSet<>(); @@ -33,6 +32,10 @@ private static void onSettingsUpdate() { }); } + public static void registerCallbacks(CallbacksBus bus) { + bus.registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CommandsMap::onSettingsUpdate); + } + private final Map subCommands = new LinkedHashMap<>(); private final Map aliasesToCommand = new HashMap<>(); @@ -40,10 +43,6 @@ private static void onSettingsUpdate() { protected CommandsMap(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registeredCallback) { - registeredCallback = true; - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CommandsMap::onSettingsUpdate); - } } public abstract void loadDefaultCommands(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java index 409806f7a9..5b67d091f2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java @@ -1,6 +1,10 @@ package com.bgsoftware.superiorskyblock.core.events; +import com.bgsoftware.superiorskyblock.commands.CommandsMap; import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.island.SIsland; +import com.bgsoftware.superiorskyblock.island.SpawnIsland; +import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; import java.util.EnumMap; import java.util.LinkedList; @@ -11,6 +15,10 @@ public class CallbacksBus { private final EnumMap> CALLBACKS = new EnumMap<>(CallbackType.class); public CallbacksBus() { + SIsland.registerCallbacks(this); + CommandsMap.registerCallbacks(this); + SpawnIsland.registerCallbacks(this); + RegionManagerServiceImpl.registerCallbacks(this); } public void registerCallback(CallbackType callbackType, Runnable callback) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 5c75b9e85b..96b0cbd891 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -150,10 +150,6 @@ public class SIsland implements Island { private static EnumerateSet DEFAULT_FLAGS_CACHE; - static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, SIsland::onSettingsUpdate); - } - private final DatabaseBridge databaseBridge; private final IslandBank islandBank; private final IslandCalculationAlgorithm calculationAlgorithm; @@ -5018,6 +5014,10 @@ private void notifyCropGrowthChange(double newCropGrowth) { .values().forEach(chunkPositions -> plugin.getNMSChunks().updateCropsTicker(chunkPositions, newCropGrowthMultiplier)); } + public static void registerCallbacks(CallbacksBus bus) { + bus.registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, SIsland::onSettingsUpdate); + } + private static void onSettingsUpdate() { DEFAULT_FLAGS_CACHE = new EnumerateSet<>(IslandFlag.values()); plugin.getSettings().getDefaultSettings().forEach(islandFlagName -> { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 92deece482..41c2ddc859 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -92,8 +92,8 @@ public class SpawnIsland implements Island { private static EnumerateSet DEFAULT_SPAWN_FLAGS_CACHE; private static EnumerateSet DEFAULT_SPAWN_PRIVILEGES_CACHE; - static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, SpawnIsland::onSettingsUpdate); + public static void registerCallbacks(CallbacksBus bus) { + bus.registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, SpawnIsland::onSettingsUpdate); } private static void onSettingsUpdate() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 3f17d1887b..11e83ebc29 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -82,10 +82,14 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService public RegionManagerServiceImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, this::onSettingsUpdate); } - private void onSettingsUpdate() { + public static void registerCallbacks(CallbacksBus bus) { + bus.registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, RegionManagerServiceImpl::onSettingsUpdate); + } + + private static void onSettingsUpdate() { + SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); WORLD_PERMISSIONS_CACHE = new EnumerateSet<>(IslandPrivilege.values()); plugin.getSettings().getWorldPermissions().forEach(islandPrivilageName -> { try { From 1384ff7f3226aa7b5bec4aa55eaf56ae3c9f831f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 14 Dec 2024 16:54:17 +0200 Subject: [PATCH 012/600] Actually fix the errors --- .../superiorskyblock/SuperiorSkyblockPlugin.java | 15 ++++++++------- .../core/events/CallbacksBus.java | 3 +++ .../superiorskyblock/island/SpawnIsland.java | 11 ++++++++--- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index 6710ecadb0..df72227687 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -92,13 +92,6 @@ public class SuperiorSkyblockPlugin extends JavaPlugin implements SuperiorSkyblo private static SuperiorSkyblockPlugin plugin; - /* Global handlers */ - private final Updater updater = new Updater(this, "superiorskyblock2"); - private final EventsBus eventsBus = new EventsBus(this); - private final CallbacksBus callbacksBus = new CallbacksBus(); - private final BukkitListeners bukkitListeners = new BukkitListeners(this); - private IScriptEngine scriptEngine = EnginesFactory.createDefaultEngine(); - /* Managers */ private final DataManager dataHandler = new DataManager(this); private final FactoriesManagerImpl factoriesHandler = new FactoriesManagerImpl(); @@ -118,6 +111,13 @@ public class SuperiorSkyblockPlugin extends JavaPlugin implements SuperiorSkyblo private final ServicesHandler servicesHandler = new ServicesHandler(this); private final SettingsManagerImpl settingsHandler = new SettingsManagerImpl(this); + /* Global handlers */ + private final Updater updater = new Updater(this, "superiorskyblock2"); + private final EventsBus eventsBus = new EventsBus(this); + private final CallbacksBus callbacksBus = new CallbacksBus(); + private final BukkitListeners bukkitListeners = new BukkitListeners(this); + private IScriptEngine scriptEngine = EnginesFactory.createDefaultEngine(); + /* NMS */ @Nullable private NMSAlgorithms nmsAlgorithms; @@ -138,6 +138,7 @@ public static SuperiorSkyblockPlugin getPlugin() { @Override public void onLoad() { plugin = this; + callbacksBus.registerDefaultCallbacks(); DependenciesManager.inject(this); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java index 5b67d091f2..c817cbe40a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java @@ -15,6 +15,9 @@ public class CallbacksBus { private final EnumMap> CALLBACKS = new EnumMap<>(CallbackType.class); public CallbacksBus() { + } + + public void registerDefaultCallbacks() { SIsland.registerCallbacks(this); CommandsMap.registerCallbacks(this); SpawnIsland.registerCallbacks(this); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 41c2ddc859..20cb805611 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -34,6 +34,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.IslandArea; +import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.WorldInfoImpl; @@ -84,8 +85,12 @@ public class SpawnIsland implements Island { private static final UUID spawnUUID = new UUID(0, 0); - private static final SSuperiorPlayer ownerPlayer = new SSuperiorPlayer((SuperiorPlayerBuilderImpl) - SuperiorPlayer.newBuilder().setUniqueId(spawnUUID)); + private static final LazyReference ownerPlayer = new LazyReference() { + @Override + protected SSuperiorPlayer create() { + return new SSuperiorPlayer((SuperiorPlayerBuilderImpl) SuperiorPlayer.newBuilder().setUniqueId(spawnUUID)); + } + }; private static final IslandChest[] EMPTY_ISLAND_CHESTS = new IslandChest[0]; private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @@ -162,7 +167,7 @@ public SpawnIsland() throws ManagerLoadException { @Override public SuperiorPlayer getOwner() { - return ownerPlayer; + return ownerPlayer.get(); } @Override From 6bb3e98c87cb5d906fc603c5325bd2e17258b9c7 Mon Sep 17 00:00:00 2001 From: Ome_R Date: Sat, 14 Dec 2024 18:35:12 +0200 Subject: [PATCH 013/600] Reuse objects whenever possible (#2296) --- .../api/island/DelegateIslandPreview.java | 5 + .../api/island/IslandPreview.java | 9 + .../api/island/warps/DelegateIslandWarp.java | 5 + .../api/island/warps/IslandWarp.java | 8 + .../api/player/DelegateSuperiorPlayer.java | 5 + .../api/wrappers/SuperiorPlayer.java | 9 + .../SpawnersProvider_AdvancedSpawners.java | 25 +- .../SpawnersProvider_CandcSilkSpawners.java | 13 +- .../external/CoreProtectHook.java | 45 +-- .../external/ItemsAdderHook.java | 10 +- .../SpawnersProvider_MergedSpawner.java | 13 +- .../superiorskyblock/external/OraxenHook.java | 10 +- .../SpawnersProvider_PvpingSpawners.java | 20 +- .../EntitiesProvider_RoseStacker.java | 8 +- .../StackedBlocksProvider_RoseStacker.java | 25 +- .../external/SlimefunHook.java | 5 +- .../external/TimbruSilkSpawnersHook.java | 7 +- .../SpawnersProvider_UltimateStacker.java | 11 +- .../SpawnersProvider_UltimateStacker3.java | 11 +- .../WildStackerSnapshotsContainer.java | 2 +- .../SpawnersProvider_WildStacker.java | 9 +- .../StackedBlocksProvider_WildStacker.java | 10 +- .../v1_20_3/algorithms/NMSCachedBlock.java | 21 +- .../nms/algorithms/NMSCachedBlock.java | 21 +- .../nms/v1_12_R1/NMSAlgorithmsImpl.java | 7 +- .../nms/v1_12_R1/NMSCachedBlock.java | 25 +- .../nms/v1_12_R1/NMSChunksImpl.java | 2 +- .../nms/v1_12_R1/NMSUtils.java | 25 +- .../nms/v1_12_R1/NMSWorldImpl.java | 150 +++++----- .../dragon/IslandEntityEnderDragon.java | 7 +- .../v1_12_R1/world/WorldEditSessionImpl.java | 39 ++- .../nms/v1_16_R3/NMSAlgorithmsImpl.java | 7 +- .../nms/v1_16_R3/NMSChunksImpl.java | 3 +- .../nms/v1_16_R3/NMSUtils.java | 24 ++ .../nms/v1_16_R3/NMSWorldImpl.java | 143 +++++----- .../dragon/IslandEnderDragonBattle.java | 20 +- .../dragon/IslandEntityEnderDragon.java | 7 +- .../v1_16_R3/world/WorldEditSessionImpl.java | 38 ++- .../nms/v1_17/NMSAlgorithmsImpl.java | 8 +- .../nms/v1_17/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_17/NMSUtils.java | 25 ++ .../nms/v1_17/NMSWorldImpl.java | 113 ++++---- .../v1_17/dragon/IslandEndDragonFight.java | 20 +- .../v1_17/dragon/IslandEntityEnderDragon.java | 7 +- .../nms/v1_17/world/WorldEditSessionImpl.java | 38 ++- .../nms/v1_18/NMSAlgorithmsImpl.java | 8 +- .../nms/v1_18/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_18/NMSUtils.java | 25 ++ .../nms/v1_18/NMSWorldImpl.java | 114 ++++---- .../v1_18/dragon/IslandEndDragonFight.java | 20 +- .../v1_18/dragon/IslandEntityEnderDragon.java | 7 +- .../nms/v1_18/world/WorldEditSessionImpl.java | 38 ++- .../nms/v1_19/NMSAlgorithmsImpl.java | 8 +- .../nms/v1_19/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_19/NMSUtils.java | 24 ++ .../nms/v1_19/NMSWorldImpl.java | 114 ++++---- .../v1_19/dragon/IslandEndDragonFight.java | 20 +- .../v1_19/dragon/IslandEntityEnderDragon.java | 7 +- .../nms/v1_19/world/WorldEditSessionImpl.java | 37 ++- .../nms/v1_20_3/NMSAlgorithmsImpl.java | 8 +- .../nms/v1_20_3/NMSChunksImpl.java | 2 +- .../nms/v1_20_3/NMSUtils.java | 24 ++ .../nms/v1_20_3/NMSWorldImpl.java | 113 ++++---- .../v1_20_3/dragon/IslandEndDragonFight.java | 20 +- .../dragon/IslandEntityEnderDragon.java | 7 +- .../v1_20_3/world/WorldEditSessionImpl.java | 37 ++- .../nms/v1_20_4/NMSAlgorithmsImpl.java | 9 +- .../nms/v1_20_4/NMSChunksImpl.java | 2 +- .../nms/v1_20_4/NMSUtils.java | 24 ++ .../nms/v1_20_4/NMSWorldImpl.java | 113 ++++---- .../v1_20_4/dragon/IslandEndDragonFight.java | 20 +- .../dragon/IslandEntityEnderDragon.java | 7 +- .../v1_20_4/world/WorldEditSessionImpl.java | 37 ++- .../nms/v1_21/NMSAlgorithmsImpl.java | 9 +- .../nms/v1_21/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_21/NMSUtils.java | 24 ++ .../nms/v1_21/NMSWorldImpl.java | 114 ++++---- .../v1_21/dragon/IslandEndDragonFight.java | 20 +- .../v1_21/dragon/IslandEntityEnderDragon.java | 7 +- .../nms/v1_21/world/WorldEditSessionImpl.java | 38 ++- .../nms/v1_21_3/NMSAlgorithmsImpl.java | 8 +- .../nms/v1_21_3/NMSChunksImpl.java | 2 +- .../nms/v1_21_3/NMSUtils.java | 24 ++ .../nms/v1_21_3/NMSWorldImpl.java | 113 ++++---- .../v1_21_3/dragon/IslandEndDragonFight.java | 20 +- .../dragon/IslandEntityEnderDragon.java | 7 +- .../v1_21_3/world/WorldEditSessionImpl.java | 37 ++- .../nms/v1_21_4/NMSAlgorithmsImpl.java | 8 +- .../nms/v1_21_4/NMSChunksImpl.java | 2 +- .../nms/v1_21_4/NMSUtils.java | 24 ++ .../nms/v1_21_4/NMSWorldImpl.java | 114 ++++---- .../v1_21_4/dragon/IslandEndDragonFight.java | 20 +- .../dragon/IslandEntityEnderDragon.java | 7 +- .../v1_21_4/world/WorldEditSessionImpl.java | 37 ++- .../nms/v1_8_R3/NMSAlgorithmsImpl.java | 7 +- .../nms/v1_8_R3/NMSCachedBlock.java | 23 +- .../nms/v1_8_R3/NMSChunksImpl.java | 4 +- .../nms/v1_8_R3/NMSUtils.java | 24 ++ .../nms/v1_8_R3/NMSWorldImpl.java | 153 +++++----- .../v1_8_R3/world/WorldEditSessionImpl.java | 39 ++- .../SuperiorSkyblockPlugin.java | 51 ++-- .../commands/admin/CmdAdminDelWarp.java | 2 +- .../admin/CmdAdminSetBlockAmount.java | 23 +- .../commands/admin/CmdAdminSetSpawn.java | 18 +- .../commands/admin/CmdAdminTeleport.java | 9 +- .../commands/arguments/CommandArguments.java | 9 +- .../commands/player/CmdDelWarp.java | 2 +- .../commands/player/CmdExpel.java | 27 +- .../commands/player/CmdFly.java | 7 +- .../commands/player/CmdSetTeleport.java | 28 +- .../commands/player/CmdSetWarp.java | 27 +- .../commands/player/CmdToggle.java | 7 +- .../superiorskyblock/core/ChunkPosition.java | 88 ++++-- .../superiorskyblock/core/GameSoundImpl.java | 9 +- .../superiorskyblock/core/IslandArea.java | 51 +++- .../superiorskyblock/core/IslandPosition.java | 37 ++- .../superiorskyblock/core/LocationKey.java | 66 ++++- .../core/MutableChunkPosition.java | 20 ++ .../superiorskyblock/core/ObjectsPool.java | 47 ++++ .../superiorskyblock/core/ObjectsPools.java | 59 ++++ .../superiorskyblock/core/SBlockPosition.java | 4 + .../core/collections/Chunk2ObjectMap.java | 41 ++- .../bridge/IslandsDatabaseBridge.java | 8 +- .../serialization/IslandsSerializer.java | 33 ++- .../superiorskyblock/core/key/Keys.java | 11 +- .../button/impl/WarpManageLocationButton.java | 30 +- .../button/impl/WarpPagedObjectButton.java | 16 +- .../core/stackedblocks/StackedBlock.java | 2 +- .../StackedBlocksManagerImpl.java | 37 ++- .../island/GridManagerImpl.java | 17 +- .../superiorskyblock/island/IslandUtils.java | 10 +- .../superiorskyblock/island/SIsland.java | 204 ++++++++------ .../superiorskyblock/island/SpawnIsland.java | 52 ++-- .../DefaultIslandCalculationAlgorithm.java | 6 +- .../DefaultIslandCreationAlgorithm.java | 30 +- .../island/chunk/DirtyChunksContainer.java | 13 +- .../container/DefaultIslandsContainer.java | 13 +- .../island/preview/SIslandPreview.java | 16 +- .../island/signs/IslandSigns.java | 38 +-- .../island/warp/SIslandWarp.java | 14 + .../island/warp/SignWarp.java | 39 +-- .../listener/BlockChangesListener.java | 120 +++++--- .../listener/ChunksListener.java | 27 +- .../listener/FeaturesListener.java | 18 +- .../listener/IslandFlagsListener.java | 98 ++++--- .../listener/IslandOutsideListener.java | 21 +- .../listener/IslandWorldEventsListener.java | 12 +- .../listener/PlayersListener.java | 45 ++- .../listener/PortalsListener.java | 6 +- .../listener/ProtectionListener.java | 131 ++++++--- .../listener/SignsListener.java | 8 +- .../listener/StackedBlocksListener.java | 37 +-- .../listener/WorldDestructionListener.java | 58 ++-- .../mission/MissionsManagerImpl.java | 9 +- .../listeners/GeneratorsListener.java | 83 +++--- .../upgrades/type/UpgradeTypeBlockLimits.java | 36 ++- .../upgrades/type/UpgradeTypeCropGrowth.java | 11 +- .../type/UpgradeTypeEntityLimits.java | 70 +++-- .../type/UpgradeTypeIslandEffects.java | 7 +- .../upgrades/type/UpgradeTypeMobDrops.java | 12 +- .../superiorskyblock/nms/ICachedBlock.java | 3 +- .../nms/world/WorldEditSession.java | 3 +- .../player/SSuperiorPlayer.java | 37 ++- .../player/SuperiorNPCPlayer.java | 7 +- .../placeholders/PlaceholdersServiceImpl.java | 24 +- .../region/RegionManagerServiceImpl.java | 265 ++++++++++-------- .../StackedBlocksInteractionServiceImpl.java | 84 +++--- .../service/world/WorldRecordServiceImpl.java | 22 +- .../world/EntityTeleports.java | 33 +-- .../world/chunk/ChunksProvider.java | 11 +- .../world/schematic/SchematicBuilder.java | 8 +- .../schematic/SchematicsManagerImpl.java | 43 +-- .../schematic/impl/SuperiorSchematic.java | 2 +- 173 files changed, 3587 insertions(+), 1738 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/MutableChunkPosition.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPool.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java index d247b87f8c..2487daebab 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java @@ -21,6 +21,11 @@ public Location getLocation() { return this.handle.getLocation(); } + @Override + public Location getLocation(Location location) { + return this.handle.getLocation(location); + } + @Override public String getSchematic() { return this.handle.getSchematic(); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPreview.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPreview.java index 33579d94c6..c0d5d16338 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPreview.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPreview.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.api.island; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Location; @@ -18,6 +19,14 @@ public interface IslandPreview { */ Location getLocation(); + /** + * Get the location of the island preview. + * + * @param location Location object to re-use. + */ + @Nullable + Location getLocation(@Nullable Location location); + /** * Get the requested schematic. */ diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java index f0e758b21a..10d74d221e 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java @@ -34,6 +34,11 @@ public Location getLocation() { return this.handle.getLocation(); } + @Override + public Location getLocation(Location location) { + return this.handle.getLocation(location); + } + @Override public void setLocation(Location location) { this.handle.setLocation(location); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/IslandWarp.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/IslandWarp.java index 1e52907671..e51432b2ae 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/IslandWarp.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/IslandWarp.java @@ -31,6 +31,14 @@ public interface IslandWarp { */ Location getLocation(); + /** + * Get the location of the warp. + * + * @param location Location object to re-use. + */ + @Nullable + Location getLocation(@Nullable Location location); + /** * Set the location of the warp. * diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java index 8ae1661b8a..e3ffa1bb27 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java @@ -159,6 +159,11 @@ public Location getLocation() { return this.handle.getLocation(); } + @Override + public Location getLocation(Location location) { + return this.handle.getLocation(location); + } + @Override public void teleport(Location location) { this.handle.teleport(location); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java index ed31efb4f7..75e446c458 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java @@ -190,6 +190,15 @@ public interface SuperiorPlayer extends IMissionsHolder, IPersistentDataHolder, @Nullable Location getLocation(); + /** + * Get the location of the player. + * When the player is offline, {@param location} will be returned. + * + * @param location Location object to re-use. + */ + @Nullable + Location getLocation(@Nullable Location location); + /** * Teleport the player to a location. * diff --git a/Hooks/AdvancedSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_AdvancedSpawners.java b/Hooks/AdvancedSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_AdvancedSpawners.java index e7e454d7a8..3de241667f 100644 --- a/Hooks/AdvancedSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_AdvancedSpawners.java +++ b/Hooks/AdvancedSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_AdvancedSpawners.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; @@ -51,23 +52,25 @@ private class StackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerStack(AdvancedSpawnerPlaceEvent e) { - Location location = e.getSpawner().getLocation(); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle())); + } - Island island = plugin.getGrid().getIslandAt(location); - - if (island != null) - island.handleBlockPlace( - Keys.ofSpawner(e.getEntityType()), - e.getCountPlaced()); + if (island != null) { + island.handleBlockPlace(Keys.ofSpawner(e.getEntityType()), e.getCountPlaced()); + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(AdvancedSpawnersBreakEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle())); + } + if (island != null) - island.handleBlockBreak( - Keys.ofSpawner(e.getEntityType()), - e.getCountBroken()); + island.handleBlockBreak(Keys.ofSpawner(e.getEntityType()), e.getCountBroken()); } } diff --git a/Hooks/CandcSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_CandcSilkSpawners.java b/Hooks/CandcSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_CandcSilkSpawners.java index 8fbf8514b9..1885d6e1e0 100644 --- a/Hooks/CandcSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_CandcSilkSpawners.java +++ b/Hooks/CandcSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_CandcSilkSpawners.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; @@ -47,14 +48,22 @@ private class StackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerPlace(SpawnerPlaceEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle())); + } + if (island != null) island.handleBlockPlace(Keys.ofSpawner(e.getSpawnedEntity()), 1); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerBreakEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle())); + } + if (island != null) island.handleBlockBreak(Keys.ofSpawner(e.getSpawnedEntity()), 1); } diff --git a/Hooks/CoreProtect/src/main/java/com/bgsoftware/superiorskyblock/external/CoreProtectHook.java b/Hooks/CoreProtect/src/main/java/com/bgsoftware/superiorskyblock/external/CoreProtectHook.java index c6428bfe36..2cd2ca2812 100644 --- a/Hooks/CoreProtect/src/main/java/com/bgsoftware/superiorskyblock/external/CoreProtectHook.java +++ b/Hooks/CoreProtect/src/main/java/com/bgsoftware/superiorskyblock/external/CoreProtectHook.java @@ -2,10 +2,12 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.listener.IStackedBlocksListener; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import net.coreprotect.CoreProtect; import net.coreprotect.CoreProtectAPI; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.block.Block; import org.bukkit.plugin.Plugin; @@ -31,27 +33,32 @@ private static void recordBlockAction(OfflinePlayer offlinePlayer, Block block, CoreProtectAPI coreProtectAPI = ((CoreProtect) coreProtect).getAPI(); - if (coreProtectAPI.APIVersion() == 5) { - switch (action) { - case BLOCK_BREAK: - coreProtectAPI.logRemoval(offlinePlayer.getName(), block.getLocation(), block.getType(), block.getData()); - break; - case BLOCK_PLACE: - coreProtectAPI.logPlacement(offlinePlayer.getName(), block.getLocation(), block.getType(), block.getData()); - break; - } - } else if (coreProtectAPI.APIVersion() <= 9) { - switch (action) { - case BLOCK_BREAK: - coreProtectAPI.logRemoval(offlinePlayer.getName(), block.getLocation(), block.getType(), - (org.bukkit.block.data.BlockData) plugin.getNMSWorld().getBlockData(block)); - break; - case BLOCK_PLACE: - coreProtectAPI.logPlacement(offlinePlayer.getName(), block.getLocation(), block.getType(), - (org.bukkit.block.data.BlockData) plugin.getNMSWorld().getBlockData(block)); - break; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = block.getLocation(wrapper.getHandle()); + + if (coreProtectAPI.APIVersion() == 5) { + switch (action) { + case BLOCK_BREAK: + coreProtectAPI.logRemoval(offlinePlayer.getName(), location, block.getType(), block.getData()); + break; + case BLOCK_PLACE: + coreProtectAPI.logPlacement(offlinePlayer.getName(), location, block.getType(), block.getData()); + break; + } + } else if (coreProtectAPI.APIVersion() <= 9) { + switch (action) { + case BLOCK_BREAK: + coreProtectAPI.logRemoval(offlinePlayer.getName(), location, block.getType(), + (org.bukkit.block.data.BlockData) plugin.getNMSWorld().getBlockData(block)); + break; + case BLOCK_PLACE: + coreProtectAPI.logPlacement(offlinePlayer.getName(), location, block.getType(), + (org.bukkit.block.data.BlockData) plugin.getNMSWorld().getBlockData(block)); + break; + } } } + } } diff --git a/Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java b/Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java index afae13a35e..06ebb0ed51 100644 --- a/Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java +++ b/Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java @@ -3,11 +3,13 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; +import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; @@ -58,8 +60,12 @@ public void onBlockPlace(BlockPlaceEvent e) { BlockState oldState = e.getBlockReplacedState(); BukkitExecutor.sync(() -> { - worldRecordService.get().recordBlockPlace(Keys.of(e.getBlock()), e.getBlock().getLocation(), 1, - oldState, WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + worldRecordService.get().recordBlockPlace(Keys.of(e.getBlock()), + e.getBlock().getLocation(wrapper.getHandle()), 1, + oldState, WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS); + } + }, 1L); } diff --git a/Hooks/MergedSpawner/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_MergedSpawner.java b/Hooks/MergedSpawner/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_MergedSpawner.java index 5952cdd5bc..057880246d 100644 --- a/Hooks/MergedSpawner/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_MergedSpawner.java +++ b/Hooks/MergedSpawner/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_MergedSpawner.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; @@ -55,7 +56,11 @@ private class StackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerStack(MergedSpawnerPlaceEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getBlock().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); + } + int increaseAmount = e.getNewCount() - e.getOldCount(); if (island != null) island.handleBlockPlace(e.getBlock(), increaseAmount); @@ -63,7 +68,11 @@ public void onSpawnerStack(MergedSpawnerPlaceEvent e) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(MergedSpawnerBreakEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getBlock().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); + } + int decreaseAmount = e.getOldCount() - e.getNewCount(); if (island != null) island.handleBlockBreak(Keys.ofSpawner(e.getSpawnerType()), decreaseAmount); diff --git a/Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java b/Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java index 230d60c625..c555fecad0 100644 --- a/Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java +++ b/Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import io.th0rgal.oraxen.api.OraxenBlocks; @@ -93,8 +94,13 @@ private static class GeneratorListener implements Listener { public void onOraxenBlockBreak(BlockBreakEvent e) { Key blockKey = Keys.of(e.getBlock()); if (blockKey.getGlobalKey().equals(ORAXEN_PREFIX)) { - worldRecordService.get().recordBlockBreak(blockKey, e.getBlock().getLocation(), 1, - WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + worldRecordService.get().recordBlockBreak(blockKey, + e.getBlock().getLocation(wrapper.getHandle()), 1, + WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS); + } + + } } diff --git a/Hooks/PvpingSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_PvpingSpawners.java b/Hooks/PvpingSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_PvpingSpawners.java index 55c84426b4..850b361952 100644 --- a/Hooks/PvpingSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_PvpingSpawners.java +++ b/Hooks/PvpingSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_PvpingSpawners.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; @@ -51,16 +52,23 @@ private class StackerListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerStack(SpawnerStackEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); - if (island != null) - island.handleBlockPlace(e.getSpawner().getLocation().getBlock(), e.getSpawnerAmount()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location spawnerLocation = e.getSpawner().getLocation(wrapper.getHandle()); + island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(spawnerLocation)); + if (island != null) + island.handleBlockPlace(spawnerLocation.getBlock(), e.getSpawnerAmount()); + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerUnstackEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); - if (island != null) - island.handleBlockBreak(e.getSpawner().getLocation().getBlock(), e.getSpawnerAmount()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location spawnerLocation = e.getSpawner().getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(spawnerLocation); + if (island != null) + island.handleBlockBreak(spawnerLocation.getBlock(), e.getSpawnerAmount()); + } } } diff --git a/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/entities/EntitiesProvider_RoseStacker.java b/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/entities/EntitiesProvider_RoseStacker.java index fdecf6772c..565e1ea8c2 100644 --- a/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/entities/EntitiesProvider_RoseStacker.java +++ b/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/entities/EntitiesProvider_RoseStacker.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.EntitiesProvider; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits; @@ -48,9 +49,10 @@ public void onEntityDeath(EntityDeathEvent e) { if (stackedEntity == null || stackedEntity.getStackSize() <= 1) return; - Location location = e.getEntity().getLocation(); - - Island island = plugin.getGrid().getIslandAt(location); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java b/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java index 0f8e115f1d..c55fd83a57 100644 --- a/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java +++ b/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.google.common.base.Preconditions; @@ -58,16 +59,22 @@ public Collection> getBlocks(World world, int chunkX, int chu if (!Bukkit.isPrimaryThread()) return null; - ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ); - Map blockKeys = new HashMap<>(); - RoseStackerAPI.getInstance().getStackedBlocks().entrySet().stream() - .filter(entry -> chunkPosition.isInsideChunk(entry.getKey().getLocation())) - .forEach(entry -> { - Key blockKey = Key.of(entry.getKey()); - blockKeys.put(blockKey, blockKeys.getOrDefault(blockKey, 0) + entry.getValue().getStackSize()); - }); - return blockKeys.entrySet().stream().map(entry -> new Pair<>(entry.getKey(), entry.getValue())).collect(Collectors.toSet()); + + try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ); + ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + RoseStackerAPI.getInstance().getStackedBlocks().entrySet().stream() + .filter(entry -> + chunkPosition.isInsideChunk(entry.getKey().getLocation(wrapper.getHandle()))) + .forEach(entry -> { + Key blockKey = Key.of(entry.getKey()); + blockKeys.put(blockKey, blockKeys.getOrDefault(blockKey, 0) + entry.getValue().getStackSize()); + }); + } + + return blockKeys.entrySet().stream() + .map(entry -> new Pair<>(entry.getKey(), entry.getValue())) + .collect(Collectors.toSet()); } private class StackerListener implements Listener { diff --git a/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java b/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java index 392f3133d0..b554138035 100644 --- a/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java +++ b/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.external.slimefun.ProtectionModule_Dev999; @@ -120,7 +121,9 @@ private static class AndroidMineListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onAndroidMiner(AndroidMineEvent e) { - Log.debug(Debug.BLOCK_BREAK, e.getBlock().getLocation(), e.getBlock().getType()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Log.debug(Debug.BLOCK_BREAK, e.getBlock().getLocation(wrapper.getHandle()), e.getBlock().getType()); + } InteractionResult interactionResult = stackedBlocksInteractionService.get() .handleStackedBlockBreak(e.getBlock(), null); diff --git a/Hooks/TimbruSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/TimbruSilkSpawnersHook.java b/Hooks/TimbruSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/TimbruSilkSpawnersHook.java index cc06a93bc9..e8096aa840 100644 --- a/Hooks/TimbruSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/TimbruSilkSpawnersHook.java +++ b/Hooks/TimbruSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/TimbruSilkSpawnersHook.java @@ -3,9 +3,11 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.EnumHelper; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.Keys; import de.dustplanet.silkspawners.events.SilkSpawnersSpawnerChangeEvent; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.entity.EntityType; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -39,7 +41,10 @@ public void onSpawnerChange(SilkSpawnersSpawnerChangeEvent e) { if (oldEntity == null || newEntity == null || oldEntity == newEntity) return; - Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/Hooks/UltimateStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker.java b/Hooks/UltimateStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker.java index 081bdc9d8a..bf855f720a 100644 --- a/Hooks/UltimateStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker.java +++ b/Hooks/UltimateStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -51,7 +52,10 @@ private class StackerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onSpawnerStack(SpawnerPlaceEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getBlock().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); + } if (island == null) return; @@ -69,7 +73,10 @@ public void onSpawnerStack(SpawnerPlaceEvent e) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerBreakEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getBlock().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); + } if (island != null) island.handleBlockBreak(e.getBlock(), e.getAmount()); } diff --git a/Hooks/UltimateStacker3/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker3.java b/Hooks/UltimateStacker3/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker3.java index c2b06cee9b..3224be49ff 100644 --- a/Hooks/UltimateStacker3/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker3.java +++ b/Hooks/UltimateStacker3/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker3.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -49,7 +50,10 @@ private class StackerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onSpawnerStack(SpawnerPlaceEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getBlock().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); + } if (island == null) return; @@ -67,7 +71,10 @@ public void onSpawnerStack(SpawnerPlaceEvent e) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpawnerUnstack(SpawnerBreakEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getBlock().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); + } if (island != null) island.handleBlockBreak(e.getBlock(), e.getAmount()); } diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java index b64dbd3224..623bb6d97b 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java @@ -18,7 +18,7 @@ private WildStackerSnapshotsContainer() { } public static void takeSnapshot(Chunk chunk) { - ChunkPosition chunkPosition = ChunkPosition.of(chunk); + ChunkPosition chunkPosition = ChunkPosition.of(chunk, false); if (cachedSnapshots.containsKey(chunkPosition)) return; diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java index 66d2e4448d..cddd595d64 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java @@ -57,7 +57,10 @@ public SpawnersProvider_WildStacker(SuperiorSkyblockPlugin plugin) { @Override public Pair getSpawner(Location location) { - StackedSnapshot cachedSnapshot = WildStackerSnapshotsContainer.getSnapshot(ChunkPosition.of(location)); + StackedSnapshot cachedSnapshot; + try (ChunkPosition chunkPosition = ChunkPosition.of(location)) { + cachedSnapshot = WildStackerSnapshotsContainer.getSnapshot(chunkPosition); + } Map.Entry entry = cachedSnapshot.getStackedSpawner(location); return new Pair<>(entry.getKey(), entry.getValue() + ""); } @@ -69,7 +72,9 @@ public void takeSnapshot(Chunk chunk) { @Override public void releaseSnapshot(World world, int chunkX, int chunkZ) { - WildStackerSnapshotsContainer.releaseSnapshot(ChunkPosition.of(world, chunkX, chunkZ)); + try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) { + WildStackerSnapshotsContainer.releaseSnapshot(chunkPosition); + } } @SuppressWarnings("unused") diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java index c1030d62af..c6c7198f61 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java @@ -73,7 +73,11 @@ public boolean isCustomKey(Key key) { @Override public Collection> getBlocks(World world, int chunkX, int chunkZ) { - StackedSnapshot stackedSnapshot = WildStackerSnapshotsContainer.getSnapshot(ChunkPosition.of(world, chunkX, chunkZ)); + StackedSnapshot stackedSnapshot; + + try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) { + stackedSnapshot = WildStackerSnapshotsContainer.getSnapshot(chunkPosition); + } try { return stackedSnapshot.getAllBarrelsItems().values().stream() @@ -94,7 +98,9 @@ public void takeSnapshot(Chunk chunk) { @Override public void releaseSnapshot(World world, int chunkX, int chunkZ) { - WildStackerSnapshotsContainer.releaseSnapshot(ChunkPosition.of(world, chunkX, chunkZ)); + try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) { + WildStackerSnapshotsContainer.releaseSnapshot(chunkPosition); + } } @SuppressWarnings("unused") diff --git a/NMS/Spigot-1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/algorithms/NMSCachedBlock.java b/NMS/Spigot-1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/algorithms/NMSCachedBlock.java index 73bd2e1bea..8289571d53 100644 --- a/NMS/Spigot-1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/algorithms/NMSCachedBlock.java +++ b/NMS/Spigot-1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/algorithms/NMSCachedBlock.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import org.bukkit.Location; import org.bukkit.World; @@ -8,10 +9,20 @@ public class NMSCachedBlock implements ICachedBlock { - private final BlockData blockData; + private static final ObjectsPool POOL = new ObjectsPool<>(NMSCachedBlock::new); - public NMSCachedBlock(Block block) { + private BlockData blockData; + + public static NMSCachedBlock obtain(Block block) { + return POOL.obtain().initialize(block); + } + + private NMSCachedBlock() { + } + + private NMSCachedBlock initialize(Block block) { this.blockData = block.getBlockData(); + return this; } @Override @@ -21,4 +32,10 @@ public void setBlock(Location location) { world.getBlockAt(location).setBlockData(blockData); } + @Override + public void release() { + this.blockData = null; + POOL.release(this); + } + } diff --git a/NMS/Spigot/src/main/java/com/bgsoftware/superiorskyblock/nms/algorithms/NMSCachedBlock.java b/NMS/Spigot/src/main/java/com/bgsoftware/superiorskyblock/nms/algorithms/NMSCachedBlock.java index 3faba3e90c..887c88f761 100644 --- a/NMS/Spigot/src/main/java/com/bgsoftware/superiorskyblock/nms/algorithms/NMSCachedBlock.java +++ b/NMS/Spigot/src/main/java/com/bgsoftware/superiorskyblock/nms/algorithms/NMSCachedBlock.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.algorithms; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import org.bukkit.Location; import org.bukkit.World; @@ -8,10 +9,20 @@ public class NMSCachedBlock implements ICachedBlock { - private final BlockData blockData; + private static final ObjectsPool POOL = new ObjectsPool<>(NMSCachedBlock::new); - public NMSCachedBlock(Block block) { + private BlockData blockData; + + public static NMSCachedBlock obtain(Block block) { + return POOL.obtain().initialize(block); + } + + private NMSCachedBlock() { + } + + private NMSCachedBlock initialize(Block block) { this.blockData = block.getBlockData(); + return this; } @Override @@ -21,4 +32,10 @@ public void setBlock(Location location) { world.getBlockAt(location).setBlockData(blockData); } + @Override + public void release() { + this.blockData = null; + POOL.release(this); + } + } diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java index 5bc46acda9..65fcc03e29 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.algorithms.GlowEnchantment; @@ -57,7 +58,11 @@ public String parseSignLine(String original) { @Override public int getCombinedId(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); - IBlockData blockData = world.getType(new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ())); + IBlockData blockData; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockData = world.getType(wrapper.getHandle()); + } return Block.getCombinedId(blockData); } diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSCachedBlock.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSCachedBlock.java index 46bc53bec3..e3c4c0904e 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSCachedBlock.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSCachedBlock.java @@ -1,19 +1,30 @@ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; -@SuppressWarnings("deprecation") public class NMSCachedBlock implements ICachedBlock { - private final Material blockType; - private final byte blockData; + private static final ObjectsPool POOL = new ObjectsPool<>(NMSCachedBlock::new); - public NMSCachedBlock(Block block) { + private Material blockType; + private byte blockData; + + public static NMSCachedBlock obtain(Block block) { + return POOL.obtain().initialize(block); + } + + private NMSCachedBlock() { + + } + + private NMSCachedBlock initialize(Block block) { this.blockType = block.getType(); this.blockData = block.getData(); + return this; } @Override @@ -23,4 +34,10 @@ public void setBlock(Location location) { block.setData(blockData); } + @Override + public void release() { + this.blockType = null; + POOL.release(this); + } + } diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java index 95e029a184..b9a6e9454e 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java @@ -161,7 +161,7 @@ public CompletableFuture> calculateChunks(List blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); List spawnersLocations = new LinkedList<>(); diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java index 99e028d5e9..0b680d88f6 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java @@ -1,9 +1,12 @@ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.tag.CompoundTag; @@ -11,7 +14,6 @@ import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.Chunk; -import net.minecraft.server.v1_12_R1.ChunkCoordIntPair; import net.minecraft.server.v1_12_R1.ChunkProviderServer; import net.minecraft.server.v1_12_R1.ChunkSection; import net.minecraft.server.v1_12_R1.EntityHuman; @@ -24,6 +26,7 @@ import net.minecraft.server.v1_12_R1.TileEntity; import net.minecraft.server.v1_12_R1.World; import net.minecraft.server.v1_12_R1.WorldServer; +import org.bukkit.Location; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import java.util.Collection; @@ -50,10 +53,30 @@ public class NMSUtils { private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPosition.MutableBlockPosition(0, 0, 0)); + private NMSUtils() { } + @Nullable + public static T getTileEntityAt(Location location, Class type) { + org.bukkit.World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + TileEntity tileEntity = worldServer.getTileEntity(blockPosition); + return !type.isInstance(tileEntity) ? null : type.cast(tileEntity); + } + } + public static void runActionOnEntityChunks(Collection chunksCoords, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java index 0ea878db4c..77a098b0a5 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -83,25 +84,17 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { - org.bukkit.World world = location.getWorld(); - - if (world == null) + TileEntityMobSpawner mobSpawner = NMSUtils.getTileEntityAt(location, TileEntityMobSpawner.class); + if (mobSpawner == null) return; - WorldServer worldServer = ((CraftWorld) world).getHandle(); - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - TileEntity mobSpawner = worldServer.getTileEntity(blockPosition); - - if (!(mobSpawner instanceof TileEntityMobSpawner)) + MobSpawnerAbstract mobSpawnerAbstract = mobSpawner.getSpawner(); + if (mobSpawnerAbstract instanceof MobSpawnerAbstractNotifier) return; - MobSpawnerAbstract mobSpawnerAbstract = ((TileEntityMobSpawner) mobSpawner).getSpawner(); - - if (!(mobSpawnerAbstract instanceof MobSpawnerAbstractNotifier)) { - MobSpawnerAbstractNotifier mobSpawnerAbstractNotifier = new MobSpawnerAbstractNotifier(mobSpawnerAbstract, delayChangeCallback); - MOB_SPAWNER_ABSTRACT.set(mobSpawner, mobSpawnerAbstractNotifier); - mobSpawnerAbstractNotifier.updateDelay(); - } + MobSpawnerAbstractNotifier mobSpawnerAbstractNotifier = new MobSpawnerAbstractNotifier(mobSpawnerAbstract, delayChangeCallback); + MOB_SPAWNER_ABSTRACT.set(mobSpawner, mobSpawnerAbstractNotifier); + mobSpawnerAbstractNotifier.updateDelay(); } @Override @@ -168,16 +161,20 @@ public Object getBlockData(org.bukkit.block.Block block) { @Override public void setBlock(Location location, int combinedId) { WorldServer world = ((CraftWorld) location.getWorld()).getHandle(); - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null); - NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4, - new PacketPlayOutBlockChange(world, blockPosition)); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + + NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null); + NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4, + new PacketPlayOutBlockChange(world, blockPosition)); + } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return new NMSCachedBlock(block); + return NMSCachedBlock.obtain(block); } @Override @@ -188,20 +185,20 @@ public CompoundTag readBlockStates(Location location) { @Override public byte[] getLightLevels(Location location) { - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - net.minecraft.server.v1_12_R1.World world = ((CraftWorld) location.getWorld()).getHandle(); - return new byte[]{ - (byte) world.getBrightness(EnumSkyBlock.SKY, blockPosition), - (byte) world.getBrightness(EnumSkyBlock.BLOCK, blockPosition), - }; + WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return new byte[]{ + (byte) worldServer.getBrightness(EnumSkyBlock.SKY, blockPosition), + (byte) worldServer.getBrightness(EnumSkyBlock.BLOCK, blockPosition) + }; + } } @Override public CompoundTag readTileEntity(Location location) { - net.minecraft.server.v1_12_R1.World world = ((CraftWorld) location.getWorld()).getHandle(); - BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ()); - TileEntity tileEntity = world.getTileEntity(blockPosition); - + TileEntity tileEntity = NMSUtils.getTileEntityAt(location, TileEntity.class); if (tileEntity == null) return null; @@ -230,9 +227,8 @@ public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { @Override public int getDefaultAmount(org.bukkit.block.Block block) { - Location blockLocation = block.getLocation(); - IBlockData blockData = ((CraftWorld) block.getWorld()).getHandle().getType(new BlockPosition( - blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ())); + WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle(); + IBlockData blockData = worldServer.getType(new BlockPosition(block.getX(), block.getY(), block.getZ())); return getDefaultAmount(blockData); } @@ -257,28 +253,26 @@ private int getDefaultAmount(IBlockData blockData) { @Override public void placeSign(Island island, Location location) { - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); - TileEntity tileEntity = worldServer.getTileEntity(blockPosition); - if (tileEntity instanceof TileEntitySign) { - TileEntitySign tileEntitySign = (TileEntitySign) tileEntity; - String[] lines = new String[4]; - System.arraycopy(CraftSign.revertComponents(tileEntitySign.lines), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - IChatBaseComponent[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } + TileEntitySign tileEntitySign = NMSUtils.getTileEntityAt(location, TileEntitySign.class); + if (tileEntitySign == null) + return; + + String[] lines = new String[4]; + System.arraycopy(CraftSign.revertComponents(tileEntitySign.lines), 0, lines, 0, lines.length); + String[] strippedLines = new String[4]; + for (int i = 0; i < 4; i++) + strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4); + IChatBaseComponent[] newLines; + + IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); + if (result.isCancelEvent()) { + newLines = CraftSign.sanitizeLines(strippedLines); + } else { + newLines = CraftSign.sanitizeLines(lines); } + + System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4); } @Override @@ -288,33 +282,49 @@ public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { @Override public void playGeneratorSound(Location location) { - net.minecraft.server.v1_12_R1.World world = ((CraftWorld) location.getWorld()).getHandle(); + WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - double x = location.getX(); - double y = location.getY(); - double z = location.getZ(); + double x = location.getX(); + double y = location.getY(); + double z = location.getZ(); - BlockPosition blockPosition = new BlockPosition(x, y, z); - world.a(null, blockPosition, SoundEffects.dE, SoundCategory.BLOCKS, 0.5F, - 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F); + blockPosition.c(x, y, z); - for (int i = 0; i < 8; i++) - world.addParticle(EnumParticle.SMOKE_LARGE, x + Math.random(), y + 1.2D, z + Math.random(), 0.0D, 0.0D, 0.0D); + worldServer.a(null, blockPosition, SoundEffects.dE, SoundCategory.BLOCKS, 0.5F, + 2.6F + (worldServer.random.nextFloat() - worldServer.random.nextFloat()) * 0.8F); + + for (int i = 0; i < 8; i++) { + worldServer.addParticle(EnumParticle.SMOKE_LARGE, + x + Math.random(), y + 1.2D, z + Math.random(), + 0.0D, 0.0D, 0.0D); + } + } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { - net.minecraft.server.v1_12_R1.World world = ((CraftWorld) block.getWorld()).getHandle(); - BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); - world.a(null, 2001, blockPosition, net.minecraft.server.v1_12_R1.Block.getCombinedId(world.getType(blockPosition))); + WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues(block.getX(), block.getY(), block.getZ()); + worldServer.a(null, 2001, blockPosition, Block.getCombinedId(worldServer.getType(blockPosition))); + } } @Override public void playPlaceSound(Location location) { - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - net.minecraft.server.v1_12_R1.World world = ((CraftWorld) location.getWorld()).getHandle(); - SoundEffectType soundeffecttype = world.getType(blockPosition).getBlock().getStepSound(); - world.a(null, blockPosition, soundeffecttype.e(), SoundCategory.BLOCKS, (soundeffecttype.a() + 1.0F) / 2.0F, soundeffecttype.b() * 0.8F); + WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundEffectType soundEffectType = worldServer.getType(blockPosition).getBlock().getStepSound(); + + worldServer.a(null, blockPosition, soundEffectType.e(), SoundCategory.BLOCKS, + (soundEffectType.a() + 1.0F) / 2.0F, soundEffectType.b() * 0.8F); + } } @Override @@ -334,6 +344,6 @@ public IslandsGenerator createGenerator(Dimension dimension) { @Override public WorldEditSession createEditSession(World world) { - return new WorldEditSessionImpl(((CraftWorld) world).getHandle()); + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } } diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java index 016e2e938f..31fb5cb178 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.EnderDragonBattle; import net.minecraft.server.v1_12_R1.EntityEnderDragon; @@ -49,8 +50,10 @@ public void a(NBTTagCompound nbtTagCompound) { EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) enderDragonBattle; - Location entityLocation = getBukkitEntity().getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java index e285a4088b..c4d5ceb788 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -38,11 +39,14 @@ import org.bukkit.generator.ChunkGenerator; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedList; import java.util.List; public class WorldEditSessionImpl implements WorldEditSession { + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + private static final ReflectMethod TILE_ENTITY_LOAD = new ReflectMethod<>(TileEntity.class, "a", NBTTagCompound.class); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @@ -51,12 +55,20 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final List lights = new LinkedList<>(); - private final WorldServer worldServer; - private final Dimension dimension; + private WorldServer worldServer; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(WorldServer worldServer) { + return POOL.obtain().initialize(worldServer); + } - public WorldEditSessionImpl(WorldServer worldServer) { + private WorldEditSessionImpl() { + } + + public WorldEditSessionImpl initialize(WorldServer worldServer) { this.worldServer = worldServer; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld()); + return this; } @Override @@ -96,13 +108,17 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + List chunkPositions = new LinkedList<>(); World bukkitWorld = worldServer.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); - ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32)); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkCoord.x, chunkCoord.z)); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @@ -172,6 +188,19 @@ public void finish(Island island) { } }, 5L); } + + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lights.clear(); + this.worldServer = null; + this.dimension = null; + POOL.release(this); } private boolean isValidPosition(BlockPosition blockPosition) { diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java index 573d4d91d8..c9c890c93c 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -90,7 +91,11 @@ public String parseSignLine(String original) { @Override public int getCombinedId(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); - IBlockData blockData = world.getType(new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ())); + IBlockData blockData; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockData = world.getType(wrapper.getHandle()); + } return Block.getCombinedId(blockData); } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java index adc2432df2..48b1ac1766 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java @@ -239,7 +239,8 @@ public CompletableFuture> calculateChunks(List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPosition.MutableBlockPosition(0, 0, 0)); + private NMSUtils() { } + @Nullable + public static T getTileEntityAt(Location location, Class type) { + org.bukkit.World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + TileEntity tileEntity = worldServer.getTileEntity(blockPosition); + return !type.isInstance(tileEntity) ? null : type.cast(tileEntity); + } + } + public static void runActionOnChunks(Collection chunksCoords, boolean saveChunks, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, saveChunks, chunkCallback); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java index 4ca7a6d2f7..dadc6dce43 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -97,23 +98,17 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { - org.bukkit.World world = location.getWorld(); - - if (world == null) + TileEntityMobSpawner mobSpawner = NMSUtils.getTileEntityAt(location, TileEntityMobSpawner.class); + if (mobSpawner == null || mobSpawner instanceof TileEntityMobSpawnerNotifier) return; - WorldServer worldServer = ((CraftWorld) world).getHandle(); - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - TileEntity mobSpawner = worldServer.getTileEntity(blockPosition); - - if (!(mobSpawner instanceof TileEntityMobSpawner) || mobSpawner instanceof TileEntityMobSpawnerNotifier) - return; + World world = mobSpawner.getWorld(); - TileEntityMobSpawnerNotifier tileEntityMobSpawnerNotifier = new TileEntityMobSpawnerNotifier( - (TileEntityMobSpawner) mobSpawner, delayChangeCallback); + TileEntityMobSpawnerNotifier tileEntityMobSpawnerNotifier = + new TileEntityMobSpawnerNotifier(mobSpawner, delayChangeCallback); - worldServer.removeTileEntity(blockPosition); - worldServer.setTileEntity(blockPosition, tileEntityMobSpawnerNotifier); + world.removeTileEntity(mobSpawner.getPosition()); + world.setTileEntity(mobSpawner.getPosition(), tileEntityMobSpawnerNotifier); } @Override @@ -180,22 +175,32 @@ public Object getBlockData(org.bukkit.block.Block block) { @Override public void setBlock(Location location, int combinedId) { WorldServer world = ((CraftWorld) location.getWorld()).getHandle(); - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null, null); - NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4, - new PacketPlayOutBlockChange(world, blockPosition)); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + + NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null, null); + NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4, + new PacketPlayOutBlockChange(world, blockPosition)); + } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return new NMSCachedBlock(block); + return NMSCachedBlock.obtain(block); } @Override public CompoundTag readBlockStates(Location location) { - net.minecraft.server.v1_16_R3.World world = ((CraftWorld) location.getWorld()).getHandle(); - BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ()); - IBlockData blockData = world.getType(blockPosition); + World world = ((CraftWorld) location.getWorld()).getHandle(); + + IBlockData blockData; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockData = world.getType(blockPosition); + } + CompoundTag compoundTag = null; for (Map.Entry, Comparable> entry : blockData.getStateMap().entrySet()) { @@ -223,20 +228,21 @@ public CompoundTag readBlockStates(Location location) { @Override public byte[] getLightLevels(Location location) { - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); LightEngine lightEngine = ((CraftWorld) location.getWorld()).getHandle().e(); - return new byte[]{ - location.getWorld().getEnvironment() != org.bukkit.World.Environment.NORMAL ? 0 : (byte) lightEngine.a(EnumSkyBlock.SKY).b(blockPosition), - (byte) lightEngine.a(EnumSkyBlock.BLOCK).b(blockPosition) - }; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return new byte[]{ + location.getWorld().getEnvironment() != org.bukkit.World.Environment.NORMAL ? 0 : + (byte) lightEngine.a(EnumSkyBlock.SKY).b(blockPosition), + (byte) lightEngine.a(EnumSkyBlock.BLOCK).b(blockPosition) + }; + } } @Override public CompoundTag readTileEntity(Location location) { - net.minecraft.server.v1_16_R3.World world = ((CraftWorld) location.getWorld()).getHandle(); - BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ()); - TileEntity tileEntity = world.getTileEntity(blockPosition); - + TileEntity tileEntity = NMSUtils.getTileEntityAt(location, TileEntity.class); if (tileEntity == null) return null; @@ -290,28 +296,26 @@ private int getDefaultAmount(IBlockData blockData) { @Override public void placeSign(Island island, Location location) { - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); - TileEntity tileEntity = worldServer.getTileEntity(blockPosition); - if (tileEntity instanceof TileEntitySign) { - TileEntitySign tileEntitySign = (TileEntitySign) tileEntity; - String[] lines = new String[4]; - System.arraycopy(CraftSign.revertComponents(tileEntitySign.lines), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - IChatBaseComponent[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } + TileEntitySign tileEntitySign = NMSUtils.getTileEntityAt(location, TileEntitySign.class); + if (tileEntitySign == null) + return; + + String[] lines = new String[4]; + System.arraycopy(CraftSign.revertComponents(tileEntitySign.lines), 0, lines, 0, lines.length); + String[] strippedLines = new String[4]; + for (int i = 0; i < 4; i++) + strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4); + IChatBaseComponent[] newLines; + + IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); + if (result.isCancelEvent()) { + newLines = CraftSign.sanitizeLines(strippedLines); + } else { + newLines = CraftSign.sanitizeLines(lines); } + + System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4); } @Override @@ -325,29 +329,40 @@ public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { @Override public void playGeneratorSound(Location location) { - net.minecraft.server.v1_16_R3.World world = ((CraftWorld) location.getWorld()).getHandle(); - BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ()); - world.triggerEffect(1501, blockPosition, 0); + World world = ((CraftWorld) location.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues(location.getX(), location.getY(), location.getZ()); + world.triggerEffect(1501, blockPosition, 0); + } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { - net.minecraft.server.v1_16_R3.World world = ((CraftWorld) block.getWorld()).getHandle(); - BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); - world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition))); + World world = ((CraftWorld) block.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues(block.getX(), block.getY(), block.getZ()); + world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition))); + } } @Override public void playPlaceSound(Location location) { - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - net.minecraft.server.v1_16_R3.World world = ((CraftWorld) location.getWorld()).getHandle(); - SoundEffectType soundEffectType = world.getType(blockPosition).getStepSound(); + World world = ((CraftWorld) location.getWorld()).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundEffectType soundEffectType = world.getType(blockPosition).getStepSound(); - float volume = SOUND_VOLUME.isValid() ? SOUND_VOLUME.invoke(soundEffectType) : soundEffectType.getVolume(); - float pitch = SOUND_PITCH.isValid() ? SOUND_PITCH.invoke(soundEffectType) : soundEffectType.getPitch(); + float volume = SOUND_VOLUME.isValid() ? SOUND_VOLUME.invoke(soundEffectType) : soundEffectType.getVolume(); + float pitch = SOUND_PITCH.isValid() ? SOUND_PITCH.invoke(soundEffectType) : soundEffectType.getPitch(); - world.playSound(null, blockPosition, soundEffectType.getPlaceSound(), - SoundCategory.BLOCKS, (volume + 1.0F) / 2.0F, pitch * 0.8F); + world.playSound(null, blockPosition, soundEffectType.getPlaceSound(), + SoundCategory.BLOCKS, (volume + 1.0F) / 2.0F, pitch * 0.8F); + + } } @Override @@ -373,7 +388,7 @@ public IslandsGenerator createGenerator(Dimension dimension) { @Override public WorldEditSession createEditSession(org.bukkit.World world) { - return new WorldEditSessionImpl(((CraftWorld) world).getHandle()); + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java index 788dbc31fb..a74de54409 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java @@ -4,6 +4,8 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_16_R3.NMSUtils; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.BlockPredicate; import net.minecraft.server.v1_16_R3.Blocks; @@ -127,16 +129,20 @@ public ShapeDetector.ShapeDetectorCollection getExitPortalShape() { int highestBlock = this.world.getHighestBlockYAt(HeightMap.Type.MOTION_BLOCKING, this.islandBlockPosition).getY(); - for (int y = highestBlock; y >= 0; --y) { - BlockPosition currentPosition = new BlockPosition(this.islandBlockPosition.getX(), y, this.islandBlockPosition.getZ()); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition currentPosition = wrapper.getHandle(); + currentPosition.setValues(this.islandBlockPosition.getX(), 0, this.islandBlockPosition.getZ()); + for (int y = highestBlock; y >= 0; --y) { + currentPosition.setY(y); - ShapeDetector.ShapeDetectorCollection shapeDetectorCollection = EXIT_PORTAL_PATTERN.a(this.world, currentPosition); + ShapeDetector.ShapeDetectorCollection shapeDetectorCollection = EXIT_PORTAL_PATTERN.a(this.world, currentPosition); - if (shapeDetectorCollection != null) { - if (this.exitPortalLocation == null) - this.exitPortalLocation = shapeDetectorCollection.a(3, 3, 3).getPosition(); + if (shapeDetectorCollection != null) { + if (this.exitPortalLocation == null) + this.exitPortalLocation = shapeDetectorCollection.a(3, 3, 3).getPosition(); - return shapeDetectorCollection; + return shapeDetectorCollection; + } } } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java index 01190c8583..0465a99b06 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.EntityEnderDragon; import net.minecraft.server.v1_16_R3.EntityTypes; @@ -44,8 +45,10 @@ public void loadData(NBTTagCompound nbtTagCompound) { EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) ((WorldServer) world).getDragonBattle(); - Location entityLocation = getBukkitEntity().getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java index 803efe0ce5..d5f95a9fca 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -60,6 +61,8 @@ public class WorldEditSessionImpl implements WorldEditSession { + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + private static final ReflectField BIOME_BASE_ARRAY = new ReflectField<>( BiomeStorage.class, BiomeBase[].class, "h"); @@ -77,12 +80,20 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private final WorldServer worldServer; - private final Dimension dimension; + private WorldServer worldServer; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(WorldServer worldServer) { + return POOL.obtain().initialize(worldServer); + } - public WorldEditSessionImpl(WorldServer worldServer) { + private WorldEditSessionImpl() { + } + + public WorldEditSessionImpl initialize(WorldServer worldServer) { this.worldServer = worldServer; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld()); + return this; } @Override @@ -151,13 +162,17 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + List chunkPositions = new LinkedList<>(); World bukkitWorld = worldServer.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); - ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair(chunkKey); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkCoord.x, chunkCoord.z)); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @@ -230,6 +245,19 @@ public void finish(Island island) { }); this.lightenChunks.clear(); } + + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lightenChunks.clear(); + this.worldServer = null; + this.dimension = null; + POOL.release(this); } private boolean isValidPosition(BlockPosition blockPosition) { diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java index 8bc22251ef..8a9cfa2280 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -94,8 +95,11 @@ public int getCombinedId(Location location) { return 0; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(wrapper.getHandle()); + } return Block.getId(blockState); } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java index 2a739ec661..f3e60f1371 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java @@ -246,7 +246,7 @@ public CompletableFuture> calculateChunks(List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); + private NMSUtils() { } + @Nullable + public static T getBlockEntityAt(Location location, Class type) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); + } + } + public static void runActionOnEntityChunks(Collection chunksCoords, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index 9648a6d636..be62cc0aab 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -60,13 +61,15 @@ import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { + private static final byte[] EMPTY_LIGHTS = new byte[0]; + private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, Object.class, "chunkPacketBlockController") @@ -95,25 +98,19 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { - org.bukkit.World world = location.getWorld(); - - if (world == null) + SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); + if (spawnerBlockEntity == null) return; - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity)) - return; + ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel); Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new ArrayList<>(); + List tickersToAdd = new LinkedList<>(); while (blockEntityTickersIterator.hasNext()) { TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(blockPos) && + if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { blockEntityTickersIterator.remove(); tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); @@ -189,16 +186,20 @@ public void setBlock(Location location, int combinedId) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); + NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return new NMSCachedBlock(block); + return NMSCachedBlock.obtain(block); } @Override @@ -209,8 +210,13 @@ public CompoundTag readBlockStates(Location location) { return null; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getX(), location.getY(), location.getZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(blockPos); + } if (blockState.getValues().isEmpty()) return null; @@ -237,30 +243,25 @@ public byte[] getLightLevels(Location location) { org.bukkit.World bukkitWorld = location.getWorld(); if (bukkitWorld == null) - return new byte[0]; + return EMPTY_LIGHTS; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - return new byte[]{ - location.getWorld().getEnvironment() != org.bukkit.World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return new byte[]{ + location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : + (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), + (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) + }; + } } @Override public CompoundTag readTileEntity(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return null; @@ -307,16 +308,8 @@ private int getDefaultAmount(BlockState blockState) { @Override public void placeSign(Island island, Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SignBlockEntity signBlockEntity)) + SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); + if (signBlockEntity == null) return; String[] lines = new String[4]; @@ -353,15 +346,22 @@ public void playGeneratorSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + serverLevel.levelEvent(1501, blockPos, 0); + } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - BlockPos blockPos = new BlockPos(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(block.getX(), block.getY(), block.getZ()); + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + } } @Override @@ -372,11 +372,14 @@ public void playPlaceSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, + (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } } @Override @@ -398,7 +401,7 @@ public IslandsGenerator createGenerator(Dimension dimension) { @Override public WorldEditSession createEditSession(World world) { - return new WorldEditSessionImpl(((CraftWorld) world).getHandle()); + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEndDragonFight.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEndDragonFight.java index d524b38f80..ce31dc29af 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEndDragonFight.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEndDragonFight.java @@ -4,7 +4,9 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; @@ -131,16 +133,20 @@ public BlockPattern.BlockPatternMatch findExitPortal() { int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { - BlockPos currentPosition = new BlockPos(this.islandBlockPos.getX(), y, this.islandBlockPos.getZ()); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); + currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); + for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { + currentPosition.setY(y); - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - return blockPatternMatch; + return blockPatternMatch; + } } } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java index 7fc575a92e..84275be852 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; @@ -46,8 +47,10 @@ public void readAdditionalSaveData(CompoundTag compoundTag) { if (!(this.serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; - Location entityLocation = getBukkitEntity().getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java index ae5287f995..b9c6eada93 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; @@ -63,6 +64,8 @@ public class WorldEditSessionImpl implements WorldEditSession { + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + private static final ReflectField BIOME_BASE_ARRAY = new ReflectField<>( ChunkBiomeContainer.class, Biome[].class, "f"); @@ -80,12 +83,20 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private final ServerLevel serverLevel; - private final Dimension dimension; + private ServerLevel serverLevel; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { + return POOL.obtain().initialize(serverLevel); + } - public WorldEditSessionImpl(ServerLevel serverLevel) { + private WorldEditSessionImpl() { + } + + public WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + return this; } @Override @@ -154,13 +165,17 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + List chunkPositions = new LinkedList<>(); World bukkitWorld = serverLevel.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); - ChunkPos chunkPos = new ChunkPos(chunkKey); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkPos.x, chunkPos.z)); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @@ -244,6 +259,19 @@ public void finish(Island island) { }); this.lightenChunks.clear(); } + + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lightenChunks.clear(); + this.serverLevel = null; + this.dimension = null; + POOL.release(this); } private boolean isValidPosition(BlockPos blockPos) { diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java index 96fa4fbf18..8721bf7172 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -95,8 +96,11 @@ public int getCombinedId(Location location) { return 0; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(wrapper.getHandle()); + } return Block.getId(blockState); } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java index a59f820338..fc5b0b52ce 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java @@ -305,7 +305,7 @@ public CompletableFuture> calculateChunks(List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); + private NMSUtils() { } + @Nullable + public static T getBlockEntityAt(Location location, Class type) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); + } + } + public static void runActionOnEntityChunks(Collection chunksCoords, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index b66ed7c5c9..ac9b7b87a4 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -61,13 +62,15 @@ import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { + private static final byte[] EMPTY_LIGHTS = new byte[0]; + private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, Object.class, "chunkPacketBlockController") @@ -96,25 +99,19 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { - org.bukkit.World world = location.getWorld(); - - if (world == null) + SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); + if (spawnerBlockEntity == null) return; - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity)) - return; + ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel); Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new ArrayList<>(); + List tickersToAdd = new LinkedList<>(); while (blockEntityTickersIterator.hasNext()) { TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(blockPos) && + if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { blockEntityTickersIterator.remove(); tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); @@ -190,16 +187,20 @@ public void setBlock(Location location, int combinedId) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); + NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return new NMSCachedBlock(block); + return NMSCachedBlock.obtain(block); } @Override @@ -210,11 +211,13 @@ public CompoundTag readBlockStates(Location location) { return null; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getX(), location.getY(), location.getZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); - if (blockState.getValues().isEmpty()) - return null; + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(blockPos); + } CompoundTag compoundTag = new CompoundTag(); @@ -238,30 +241,25 @@ public byte[] getLightLevels(Location location) { org.bukkit.World bukkitWorld = location.getWorld(); if (bukkitWorld == null) - return new byte[0]; + return EMPTY_LIGHTS; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - return new byte[]{ - location.getWorld().getEnvironment() != org.bukkit.World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return new byte[]{ + location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : + (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), + (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) + }; + } } @Override public CompoundTag readTileEntity(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return null; @@ -308,16 +306,8 @@ private int getDefaultAmount(BlockState blockState) { @Override public void placeSign(Island island, Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SignBlockEntity signBlockEntity)) + SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); + if (signBlockEntity == null) return; String[] lines = new String[4]; @@ -355,15 +345,22 @@ public void playGeneratorSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + serverLevel.levelEvent(1501, blockPos, 0); + } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - BlockPos blockPos = new BlockPos(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(block.getX(), block.getY(), block.getZ()); + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + } } @Override @@ -374,11 +371,14 @@ public void playPlaceSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, + (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } } @Override @@ -400,7 +400,7 @@ public IslandsGenerator createGenerator(Dimension dimension) { @Override public WorldEditSession createEditSession(World world) { - return new WorldEditSessionImpl(((CraftWorld) world).getHandle()); + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEndDragonFight.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEndDragonFight.java index f08433a366..e4fcbd1911 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEndDragonFight.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEndDragonFight.java @@ -4,7 +4,9 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; @@ -128,16 +130,20 @@ public BlockPattern.BlockPatternMatch findExitPortal() { int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { - BlockPos currentPosition = new BlockPos(this.islandBlockPos.getX(), y, this.islandBlockPos.getZ()); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); + currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); + for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { + currentPosition.setY(y); - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - return blockPatternMatch; + return blockPatternMatch; + } } } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java index 1557392d02..6c0730b063 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; @@ -48,8 +49,10 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { if (!(this.serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; - Location entityLocation = getBukkitEntity().getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java index c3b4a6d26c..9bb9b80806 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; @@ -62,6 +63,8 @@ public class WorldEditSessionImpl implements WorldEditSession { + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final boolean isStarLightInterface = ((Supplier) () -> { try { @@ -76,12 +79,20 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private final ServerLevel serverLevel; - private final Dimension dimension; + private ServerLevel serverLevel; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { + return POOL.obtain().initialize(serverLevel); + } - public WorldEditSessionImpl(ServerLevel serverLevel) { + private WorldEditSessionImpl() { + } + + public WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + return this; } @Override @@ -150,13 +161,17 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + List chunkPositions = new LinkedList<>(); World bukkitWorld = serverLevel.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); - ChunkPos chunkPos = new ChunkPos(chunkKey); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkPos.x, chunkPos.z)); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @@ -232,6 +247,19 @@ public void finish(Island island) { }); this.lightenChunks.clear(); } + + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lightenChunks.clear(); + this.serverLevel = null; + this.dimension = null; + POOL.release(this); } private boolean isValidPosition(BlockPos blockPos) { diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java index 64a0715f7c..fc2feacb91 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -95,8 +96,11 @@ public int getCombinedId(Location location) { return 0; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(wrapper.getHandle()); + } return Block.getId(blockState); } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java index 0a9cf60931..7152b2185e 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java @@ -311,7 +311,7 @@ public CompletableFuture> calculateChunks(List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); + private NMSUtils() { } + @Nullable + public static T getBlockEntityAt(Location location, Class type) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); + } + } + public static void runActionOnEntityChunks(Collection chunksCoords, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index 430f4cb8e6..91e1f3f8ae 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -61,13 +62,15 @@ import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { + private static final byte[] EMPTY_LIGHTS = new byte[0]; + private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, Object.class, "chunkPacketBlockController") @@ -96,25 +99,19 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { - org.bukkit.World world = location.getWorld(); - - if (world == null) + SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); + if (spawnerBlockEntity == null) return; - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity)) - return; + ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel); Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new ArrayList<>(); + List tickersToAdd = new LinkedList<>(); while (blockEntityTickersIterator.hasNext()) { TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(blockPos) && + if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { blockEntityTickersIterator.remove(); tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); @@ -190,16 +187,20 @@ public void setBlock(Location location, int combinedId) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); + NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return new NMSCachedBlock(block); + return NMSCachedBlock.obtain(block); } @Override @@ -210,11 +211,13 @@ public CompoundTag readBlockStates(Location location) { return null; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); - if (blockState.getValues().isEmpty()) - return null; + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(blockPos); + } CompoundTag compoundTag = new CompoundTag(); @@ -238,30 +241,25 @@ public byte[] getLightLevels(Location location) { org.bukkit.World bukkitWorld = location.getWorld(); if (bukkitWorld == null) - return new byte[0]; + return EMPTY_LIGHTS; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - return new byte[]{ - location.getWorld().getEnvironment() != org.bukkit.World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return new byte[]{ + location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : + (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), + (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) + }; + } } @Override public CompoundTag readTileEntity(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return null; @@ -308,16 +306,8 @@ private int getDefaultAmount(BlockState blockState) { @Override public void placeSign(Island island, Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SignBlockEntity signBlockEntity)) + SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); + if (signBlockEntity == null) return; String[] lines = new String[4]; @@ -355,15 +345,22 @@ public void playGeneratorSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + serverLevel.levelEvent(1501, blockPos, 0); + } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - BlockPos blockPos = new BlockPos(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(block.getX(), block.getY(), block.getZ()); + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + } } @Override @@ -374,11 +371,14 @@ public void playPlaceSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, + (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } } @Override @@ -400,7 +400,7 @@ public IslandsGenerator createGenerator(Dimension dimension) { @Override public WorldEditSession createEditSession(World world) { - return new WorldEditSessionImpl(((CraftWorld) world).getHandle()); + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEndDragonFight.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEndDragonFight.java index 714321ede1..8a5b904513 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEndDragonFight.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEndDragonFight.java @@ -4,7 +4,9 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; @@ -128,16 +130,20 @@ public BlockPattern.BlockPatternMatch findExitPortal() { int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { - BlockPos currentPosition = new BlockPos(this.islandBlockPos.getX(), y, this.islandBlockPos.getZ()); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); + currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); + for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { + currentPosition.setY(y); - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - return blockPatternMatch; + return blockPatternMatch; + } } } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java index 33ee09ad07..91458b9c6a 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; @@ -48,8 +49,10 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { if (!(this.serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; - Location entityLocation = getBukkitEntity().getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java index edab62a575..0999116f2b 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; @@ -65,6 +66,8 @@ public class WorldEditSessionImpl implements WorldEditSession { + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final boolean isStarLightInterface = ((Supplier) () -> { try { @@ -79,12 +82,20 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private final ServerLevel serverLevel; - private final Dimension dimension; + private ServerLevel serverLevel; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { + return POOL.obtain().initialize(serverLevel); + } + + private WorldEditSessionImpl() { + } - public WorldEditSessionImpl(ServerLevel serverLevel) { + public WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + return this; } @Override @@ -153,13 +164,17 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + List chunkPositions = new LinkedList<>(); World bukkitWorld = serverLevel.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); - ChunkPos chunkPos = new ChunkPos(chunkKey); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkPos.x, chunkPos.z)); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @@ -237,6 +252,18 @@ public void finish(Island island) { this.lightenChunks.clear(); } + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lightenChunks.clear(); + this.serverLevel = null; + this.dimension = null; + POOL.release(this); } private boolean isValidPosition(BlockPos blockPos) { diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java index dd74cc7190..b47e1c7e92 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -103,8 +104,11 @@ public int getCombinedId(Location location) { return 0; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(wrapper.getHandle()); + } return Block.getId(blockState); } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java index ba7709c4dd..7246593bc8 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java @@ -319,7 +319,7 @@ public CompletableFuture> calculateChunks(List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); + private NMSUtils() { } + @Nullable + public static T getBlockEntityAt(Location location, Class type) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); + } + } + public static void runActionOnEntityChunks(Collection chunksCoords, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index a48338c7e7..16e2daba02 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -60,13 +61,15 @@ import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { + private static final byte[] EMPTY_LIGHTS = new byte[0]; + private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); @@ -94,17 +97,11 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { - org.bukkit.World world = location.getWorld(); - - if (world == null) + SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); + if (spawnerBlockEntity == null) return; - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity)) - return; + ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); List blockEntityTickers; @@ -115,11 +112,11 @@ public void listenSpawner(Location location, IntFunction delayChangeCal } Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new ArrayList<>(); + List tickersToAdd = new LinkedList<>(); while (blockEntityTickersIterator.hasNext()) { TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(blockPos) && + if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { blockEntityTickersIterator.remove(); tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); @@ -195,16 +192,20 @@ public void setBlock(Location location, int combinedId) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); + NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return new NMSCachedBlock(block); + return NMSCachedBlock.obtain(block); } @Override @@ -215,8 +216,13 @@ public CompoundTag readBlockStates(Location location) { return null; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(blockPos); + } if (blockState.getValues().isEmpty()) return null; @@ -243,30 +249,25 @@ public byte[] getLightLevels(Location location) { org.bukkit.World bukkitWorld = location.getWorld(); if (bukkitWorld == null) - return new byte[0]; + return EMPTY_LIGHTS; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - return new byte[]{ - location.getWorld().getEnvironment() != org.bukkit.World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return new byte[]{ + location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : + (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), + (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) + }; + } } @Override public CompoundTag readTileEntity(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return null; @@ -313,16 +314,8 @@ private int getDefaultAmount(BlockState blockState) { @Override public void placeSign(Island island, Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SignBlockEntity signBlockEntity)) + SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); + if (signBlockEntity == null) return; String[] lines = new String[4]; @@ -361,15 +354,22 @@ public void playGeneratorSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + serverLevel.levelEvent(1501, blockPos, 0); + } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - BlockPos blockPos = new BlockPos(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(block.getX(), block.getY(), block.getZ()); + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + } } @Override @@ -380,11 +380,14 @@ public void playPlaceSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, + (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } } @Override @@ -404,7 +407,7 @@ public IslandsGenerator createGenerator(Dimension dimension) { @Override public WorldEditSession createEditSession(World world) { - return new WorldEditSessionImpl(((CraftWorld) world).getHandle()); + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEndDragonFight.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEndDragonFight.java index 9c5871e715..bc4084bba9 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEndDragonFight.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEndDragonFight.java @@ -4,7 +4,9 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -133,16 +135,20 @@ public BlockPattern.BlockPatternMatch findExitPortal() { int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { - BlockPos currentPosition = new BlockPos(this.islandBlockPos.getX(), y, this.islandBlockPos.getZ()); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); + currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); + for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { + currentPosition.setY(y); - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - return blockPatternMatch; + return blockPatternMatch; + } } } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java index 4aefc80f53..73b1e0a12e 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; @@ -48,8 +49,10 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; - Location entityLocation = getBukkitEntity().getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java index bd07603518..2e3e1d4fb1 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; @@ -69,6 +70,8 @@ public class WorldEditSessionImpl implements WorldEditSession { + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final boolean isStarLightInterface = ((Supplier) () -> { try { @@ -83,12 +86,20 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private final ServerLevel serverLevel; - private final Dimension dimension; + private ServerLevel serverLevel; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { + return POOL.obtain().initialize(serverLevel); + } + + private WorldEditSessionImpl() { + } - public WorldEditSessionImpl(ServerLevel serverLevel) { + public WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + return this; } @Override @@ -157,13 +168,17 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + List chunkPositions = new LinkedList<>(); World bukkitWorld = serverLevel.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); - ChunkPos chunkPos = new ChunkPos(chunkKey); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkPos.x, chunkPos.z)); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @@ -257,6 +272,18 @@ public void finish(Island island) { this.lightenChunks.clear(); } + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lightenChunks.clear(); + this.serverLevel = null; + this.dimension = null; + POOL.release(this); } private boolean isValidPosition(BlockPos blockPos) { diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java index 1af7474753..27984c75b6 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -18,7 +19,6 @@ import io.papermc.paper.chat.ChatRenderer; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.TextReplacementConfig; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; @@ -101,8 +101,11 @@ public int getCombinedId(Location location) { return 0; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(wrapper.getHandle()); + } return Block.getId(blockState); } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java index db0017b3f7..948ad6d3cb 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java @@ -308,7 +308,7 @@ public CompletableFuture> calculateChunks(List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); + private NMSUtils() { } + @Nullable + public static T getBlockEntityAt(Location location, Class type) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); + } + } + public static void runActionOnEntityChunks(Collection chunksCoords, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index be0ec2dba5..760c14f9b5 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -61,13 +62,15 @@ import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { + private static final byte[] EMPTY_LIGHTS = new byte[0]; + private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); @@ -95,17 +98,11 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { - World world = location.getWorld(); - - if (world == null) + SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); + if (spawnerBlockEntity == null) return; - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity)) - return; + ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); List blockEntityTickers; @@ -116,11 +113,11 @@ public void listenSpawner(Location location, IntFunction delayChangeCal } Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new ArrayList<>(); + List tickersToAdd = new LinkedList<>(); while (blockEntityTickersIterator.hasNext()) { TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(blockPos) && + if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { blockEntityTickersIterator.remove(); tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); @@ -196,16 +193,20 @@ public void setBlock(Location location, int combinedId) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); + NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return new NMSCachedBlock(block); + return NMSCachedBlock.obtain(block); } @Override @@ -216,8 +217,13 @@ public CompoundTag readBlockStates(Location location) { return null; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(blockPos); + } if (blockState.getValues().isEmpty()) return null; @@ -244,30 +250,25 @@ public byte[] getLightLevels(Location location) { World bukkitWorld = location.getWorld(); if (bukkitWorld == null) - return new byte[0]; + return EMPTY_LIGHTS; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - return new byte[]{ - location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return new byte[]{ + location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : + (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), + (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) + }; + } } @Override public CompoundTag readTileEntity(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return null; @@ -314,16 +315,8 @@ private int getDefaultAmount(BlockState blockState) { @Override public void placeSign(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SignBlockEntity signBlockEntity)) + SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); + if (signBlockEntity == null) return; String[] lines = new String[4]; @@ -362,15 +355,22 @@ public void playGeneratorSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + serverLevel.levelEvent(1501, blockPos, 0); + } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - BlockPos blockPos = new BlockPos(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(block.getX(), block.getY(), block.getZ()); + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + } } @Override @@ -381,11 +381,14 @@ public void playPlaceSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, + (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } } @Override @@ -405,7 +408,7 @@ public IslandsGenerator createGenerator(Dimension dimension) { @Override public WorldEditSession createEditSession(World world) { - return new WorldEditSessionImpl(((CraftWorld) world).getHandle()); + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEndDragonFight.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEndDragonFight.java index 33c2ff8e13..e2d96c2ae3 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEndDragonFight.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEndDragonFight.java @@ -4,7 +4,9 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -133,16 +135,20 @@ public BlockPattern.BlockPatternMatch findExitPortal() { int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { - BlockPos currentPosition = new BlockPos(this.islandBlockPos.getX(), y, this.islandBlockPos.getZ()); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); + currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); + for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { + currentPosition.setY(y); - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - return blockPatternMatch; + return blockPatternMatch; + } } } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java index 86b3914046..81d872c157 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; @@ -48,8 +49,10 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; - Location entityLocation = getBukkitEntity().getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java index e2c347b729..bbb652f9e8 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; @@ -69,6 +70,8 @@ public class WorldEditSessionImpl implements WorldEditSession { + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final boolean isStarLightInterface = ((Supplier) () -> { try { @@ -83,12 +86,20 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private final ServerLevel serverLevel; - private final Dimension dimension; + private ServerLevel serverLevel; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { + return POOL.obtain().initialize(serverLevel); + } + + private WorldEditSessionImpl() { + } - public WorldEditSessionImpl(ServerLevel serverLevel) { + public WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + return this; } @Override @@ -157,13 +168,17 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + List chunkPositions = new LinkedList<>(); World bukkitWorld = serverLevel.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); - ChunkPos chunkPos = new ChunkPos(chunkKey); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkPos.x, chunkPos.z)); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @@ -257,6 +272,18 @@ public void finish(Island island) { this.lightenChunks.clear(); } + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lightenChunks.clear(); + this.serverLevel = null; + this.dimension = null; + POOL.release(this); } private boolean isValidPosition(BlockPos blockPos) { diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java index bc727dd09d..7ef4efd8ea 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -18,7 +19,6 @@ import com.bgsoftware.superiorskyblock.nms.v1_21.world.KeyBlocksCache; import io.papermc.paper.chat.ChatRenderer; import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TextReplacementConfig; import net.minecraft.SharedConstants; import net.minecraft.core.BlockPos; @@ -104,8 +104,11 @@ public int getCombinedId(Location location) { return 0; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(wrapper.getHandle()); + } return Block.getId(blockState); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java index ad42939afb..8aa75c753e 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java @@ -295,7 +295,7 @@ public CompletableFuture> calculateChunks(List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); + private NMSUtils() { } + @Nullable + public static T getBlockEntityAt(Location location, Class type) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); + } + } + public static void runActionOnEntityChunks(Collection chunksCoords, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index b533589705..49e411c051 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -61,13 +62,15 @@ import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { + private static final byte[] EMPTY_LIGHTS = new byte[0]; + private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); @@ -95,17 +98,11 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { - World world = location.getWorld(); - - if (world == null) + SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); + if (spawnerBlockEntity == null) return; - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity)) - return; + ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); List blockEntityTickers; @@ -116,11 +113,11 @@ public void listenSpawner(Location location, IntFunction delayChangeCal } Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new ArrayList<>(); + List tickersToAdd = new LinkedList<>(); while (blockEntityTickersIterator.hasNext()) { TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(blockPos) && + if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { blockEntityTickersIterator.remove(); tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); @@ -196,16 +193,20 @@ public void setBlock(Location location, int combinedId) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); + NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return new NMSCachedBlock(block); + return NMSCachedBlock.obtain(block); } @Override @@ -216,11 +217,13 @@ public CompoundTag readBlockStates(Location location) { return null; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); - if (blockState.getValues().isEmpty()) - return null; + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(blockPos); + } CompoundTag compoundTag = new CompoundTag(); @@ -244,30 +247,25 @@ public byte[] getLightLevels(Location location) { World bukkitWorld = location.getWorld(); if (bukkitWorld == null) - return new byte[0]; + return EMPTY_LIGHTS; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - return new byte[]{ - location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return new byte[]{ + location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : + (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), + (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) + }; + } } @Override public CompoundTag readTileEntity(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return null; @@ -314,16 +312,8 @@ private int getDefaultAmount(BlockState blockState) { @Override public void placeSign(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SignBlockEntity signBlockEntity)) + SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); + if (signBlockEntity == null) return; String[] lines = new String[4]; @@ -362,15 +352,22 @@ public void playGeneratorSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + serverLevel.levelEvent(1501, blockPos, 0); + } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - BlockPos blockPos = new BlockPos(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(block.getX(), block.getY(), block.getZ()); + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + } } @Override @@ -381,11 +378,14 @@ public void playPlaceSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, + (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } } @Override @@ -405,7 +405,7 @@ public IslandsGenerator createGenerator(Dimension dimension) { @Override public WorldEditSession createEditSession(World world) { - return new WorldEditSessionImpl(((CraftWorld) world).getHandle()); + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEndDragonFight.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEndDragonFight.java index 53e92e8317..9a7f3f22d3 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEndDragonFight.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEndDragonFight.java @@ -4,7 +4,9 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -133,16 +135,20 @@ public BlockPattern.BlockPatternMatch findExitPortal() { int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { - BlockPos currentPosition = new BlockPos(this.islandBlockPos.getX(), y, this.islandBlockPos.getZ()); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); + currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); + for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { + currentPosition.setY(y); - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - return blockPatternMatch; + return blockPatternMatch; + } } } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java index 42d91986ae..7744728076 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; @@ -48,8 +49,10 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; - Location entityLocation = getBukkitEntity().getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java index dacec76757..666db728d1 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; @@ -46,6 +47,7 @@ import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; @@ -67,6 +69,8 @@ public class WorldEditSessionImpl implements WorldEditSession { + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final boolean isStarLightInterface = ((Supplier) () -> { try { @@ -81,12 +85,20 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private final ServerLevel serverLevel; - private final Dimension dimension; + private ServerLevel serverLevel; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { + return POOL.obtain().initialize(serverLevel); + } + + private WorldEditSessionImpl() { + } - public WorldEditSessionImpl(ServerLevel serverLevel) { + public WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + return this; } @Override @@ -155,13 +167,17 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + List chunkPositions = new LinkedList<>(); World bukkitWorld = serverLevel.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); - ChunkPos chunkPos = new ChunkPos(chunkKey); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkPos.x, chunkPos.z)); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @@ -255,6 +271,18 @@ public void finish(Island island) { this.lightenChunks.clear(); } + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lightenChunks.clear(); + this.serverLevel = null; + this.dimension = null; + POOL.release(this); } private boolean isValidPosition(BlockPos blockPos) { diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java index 44d526e0a5..5ae230043b 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -103,8 +104,11 @@ public int getCombinedId(Location location) { return 0; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(wrapper.getHandle()); + } return Block.getId(blockState); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java index 3f14d9c784..c954235eeb 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java @@ -296,7 +296,7 @@ public CompletableFuture> calculateChunks(List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); + private NMSUtils() { } + @Nullable + public static T getBlockEntityAt(Location location, Class type) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); + } + } + public static void runActionOnEntityChunks(Collection chunksCoords, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index da968a284c..949ee86d84 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -61,13 +62,15 @@ import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { + private static final byte[] EMPTY_LIGHTS = new byte[0]; + private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); @@ -95,17 +98,11 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { - World world = location.getWorld(); - - if (world == null) + SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); + if (spawnerBlockEntity == null) return; - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity)) - return; + ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); List blockEntityTickers; @@ -116,11 +113,11 @@ public void listenSpawner(Location location, IntFunction delayChangeCal } Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new ArrayList<>(); + List tickersToAdd = new LinkedList<>(); while (blockEntityTickersIterator.hasNext()) { TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(blockPos) && + if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { blockEntityTickersIterator.remove(); tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); @@ -196,16 +193,20 @@ public void setBlock(Location location, int combinedId) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); + NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return new NMSCachedBlock(block); + return NMSCachedBlock.obtain(block); } @Override @@ -216,8 +217,13 @@ public CompoundTag readBlockStates(Location location) { return null; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(blockPos); + } if (blockState.getValues().isEmpty()) return null; @@ -244,30 +250,25 @@ public byte[] getLightLevels(Location location) { World bukkitWorld = location.getWorld(); if (bukkitWorld == null) - return new byte[0]; + return EMPTY_LIGHTS; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - return new byte[]{ - location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return new byte[]{ + location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : + (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), + (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) + }; + } } @Override public CompoundTag readTileEntity(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); if (blockEntity == null) return null; @@ -314,16 +315,8 @@ private int getDefaultAmount(BlockState blockState) { @Override public void placeSign(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SignBlockEntity signBlockEntity)) + SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); + if (signBlockEntity == null) return; String[] lines = new String[4]; @@ -362,15 +355,22 @@ public void playGeneratorSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + serverLevel.levelEvent(1501, blockPos, 0); + } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - BlockPos blockPos = new BlockPos(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(block.getX(), block.getY(), block.getZ()); + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + } } @Override @@ -381,11 +381,14 @@ public void playPlaceSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, + (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } } @Override @@ -405,7 +408,7 @@ public IslandsGenerator createGenerator(Dimension dimension) { @Override public WorldEditSession createEditSession(World world) { - return new WorldEditSessionImpl(((CraftWorld) world).getHandle()); + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEndDragonFight.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEndDragonFight.java index dfecdceb41..e5e1cc7778 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEndDragonFight.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEndDragonFight.java @@ -4,7 +4,9 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -133,16 +135,20 @@ public BlockPattern.BlockPatternMatch findExitPortal() { int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - for (int y = highestBlock; y >= this.serverLevel.getMinY(); --y) { - BlockPos currentPosition = new BlockPos(this.islandBlockPos.getX(), y, this.islandBlockPos.getZ()); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); + currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); + for (int y = highestBlock; y >= this.serverLevel.getMinY(); --y) { + currentPosition.setY(y); - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - return blockPatternMatch; + return blockPatternMatch; + } } } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java index 8b20e3a804..de18b783f5 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; @@ -48,8 +49,10 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; - Location entityLocation = getBukkitEntity().getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java index 8f89b67cf1..4a06838b4d 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; @@ -67,6 +68,8 @@ public class WorldEditSessionImpl implements WorldEditSession { + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final boolean isStarLightInterface = ((Supplier) () -> { try { @@ -81,12 +84,20 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private final ServerLevel serverLevel; - private final Dimension dimension; + private ServerLevel serverLevel; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { + return POOL.obtain().initialize(serverLevel); + } + + private WorldEditSessionImpl() { + } - public WorldEditSessionImpl(ServerLevel serverLevel) { + public WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + return this; } @Override @@ -155,13 +166,17 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + List chunkPositions = new LinkedList<>(); World bukkitWorld = serverLevel.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); - ChunkPos chunkPos = new ChunkPos(chunkKey); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkPos.x, chunkPos.z)); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @@ -255,6 +270,18 @@ public void finish(Island island) { this.lightenChunks.clear(); } + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lightenChunks.clear(); + this.serverLevel = null; + this.dimension = null; + POOL.release(this); } private boolean isValidPosition(BlockPos blockPos) { diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index 249d590bca..ec4cba9c93 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -103,8 +104,11 @@ public int getCombinedId(Location location) { return 0; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(wrapper.getHandle()); + } return Block.getId(blockState); } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java index 1eac0cb3f5..a2fa388f80 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -296,7 +296,7 @@ public CompletableFuture> calculateChunks(List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); + private NMSUtils() { } + @Nullable + public static T getBlockEntityAt(Location location, Class type) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); + } + } + public static void runActionOnEntityChunks(Collection chunksCoords, ChunkCallback chunkCallback) { runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index 5eee65ef73..618985699f 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -61,13 +62,15 @@ import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { + private static final byte[] EMPTY_LIGHTS = new byte[0]; + private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); @@ -95,17 +98,11 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { - World world = location.getWorld(); - - if (world == null) + SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); + if (spawnerBlockEntity == null) return; - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SpawnerBlockEntity spawnerBlockEntity)) - return; + ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); List blockEntityTickers; @@ -116,11 +113,11 @@ public void listenSpawner(Location location, IntFunction delayChangeCal } Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new ArrayList<>(); + List tickersToAdd = new LinkedList<>(); while (blockEntityTickersIterator.hasNext()) { TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(blockPos) && + if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { blockEntityTickersIterator.remove(); tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); @@ -196,16 +193,20 @@ public void setBlock(Location location, int combinedId) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); + NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return new NMSCachedBlock(block); + return NMSCachedBlock.obtain(block); } @Override @@ -216,8 +217,13 @@ public CompoundTag readBlockStates(Location location) { return null; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockState blockState = serverLevel.getBlockState(blockPos); + + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(blockPos); + } if (blockState.getValues().isEmpty()) return null; @@ -244,31 +250,31 @@ public byte[] getLightLevels(Location location) { World bukkitWorld = location.getWorld(); if (bukkitWorld == null) - return new byte[0]; + return EMPTY_LIGHTS; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - return new byte[]{ - location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + return new byte[]{ + location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : + (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), + (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) + }; + } } @Override public CompoundTag readTileEntity(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); + if (blockEntity == null) return null; - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + World bukkitWorld = location.getWorld(); - if (blockEntity == null) + if (bukkitWorld == null) return null; net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); @@ -314,16 +320,8 @@ private int getDefaultAmount(BlockState blockState) { @Override public void placeSign(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - - if (!(blockEntity instanceof SignBlockEntity signBlockEntity)) + SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); + if (signBlockEntity == null) return; String[] lines = new String[4]; @@ -362,15 +360,22 @@ public void playGeneratorSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + serverLevel.levelEvent(1501, blockPos, 0); + } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - BlockPos blockPos = new BlockPos(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(block.getX(), block.getY(), block.getZ()); + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + } } @Override @@ -381,11 +386,14 @@ public void playPlaceSound(Location location) { return; ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, + (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } } @Override @@ -405,7 +413,7 @@ public IslandsGenerator createGenerator(Dimension dimension) { @Override public WorldEditSession createEditSession(World world) { - return new WorldEditSessionImpl(((CraftWorld) world).getHandle()); + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEndDragonFight.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEndDragonFight.java index 90145d5df6..da25050468 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEndDragonFight.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEndDragonFight.java @@ -4,7 +4,9 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -133,16 +135,20 @@ public BlockPattern.BlockPatternMatch findExitPortal() { int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - for (int y = highestBlock; y >= this.serverLevel.getMinY(); --y) { - BlockPos currentPosition = new BlockPos(this.islandBlockPos.getX(), y, this.islandBlockPos.getZ()); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); + currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); + for (int y = highestBlock; y >= this.serverLevel.getMinY(); --y) { + currentPosition.setY(y); - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - return blockPatternMatch; + return blockPatternMatch; + } } } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java index e5e6bcec7b..f605697413 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; @@ -48,8 +49,10 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; - Location entityLocation = getBukkitEntity().getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java index 9e28acd363..fa89b64c06 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; @@ -67,6 +68,8 @@ public class WorldEditSessionImpl implements WorldEditSession { + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final boolean isStarLightInterface = ((Supplier) () -> { try { @@ -81,12 +84,20 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private final ServerLevel serverLevel; - private final Dimension dimension; + private ServerLevel serverLevel; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { + return POOL.obtain().initialize(serverLevel); + } + + private WorldEditSessionImpl() { + } - public WorldEditSessionImpl(ServerLevel serverLevel) { + public WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + return this; } @Override @@ -155,13 +166,17 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + List chunkPositions = new LinkedList<>(); World bukkitWorld = serverLevel.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); - ChunkPos chunkPos = new ChunkPos(chunkKey); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkPos.x, chunkPos.z)); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @@ -255,6 +270,18 @@ public void finish(Island island) { this.lightenChunks.clear(); } + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lightenChunks.clear(); + this.serverLevel = null; + this.dimension = null; + POOL.release(this); } private boolean isValidPosition(BlockPos blockPos) { diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java index 55c4a99125..10a90bd311 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.algorithms.GlowEnchantment; @@ -57,7 +58,11 @@ public String parseSignLine(String original) { @Override public int getCombinedId(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); - IBlockData blockData = world.getType(new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ())); + IBlockData blockData; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockData = world.getType(wrapper.getHandle()); + } return Block.getCombinedId(blockData); } diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSCachedBlock.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSCachedBlock.java index 0c5ca86907..43b3272b8e 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSCachedBlock.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSCachedBlock.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_8_R3; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import org.bukkit.Location; import org.bukkit.Material; @@ -8,12 +9,22 @@ @SuppressWarnings("deprecation") public class NMSCachedBlock implements ICachedBlock { - private final Material blockType; - private final byte blockData; + private static final ObjectsPool POOL = new ObjectsPool<>(NMSCachedBlock::new); - public NMSCachedBlock(Block block) { + private Material blockType; + private byte blockData; + + public static NMSCachedBlock obtain(Block block) { + return POOL.obtain().initialize(block); + } + + private NMSCachedBlock() { + } + + private NMSCachedBlock initialize(Block block) { this.blockType = block.getType(); this.blockData = block.getData(); + return this; } @Override @@ -23,4 +34,10 @@ public void setBlock(Location location) { block.setData(blockData); } + @Override + public void release() { + this.blockType = null; + POOL.release(this); + } + } diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java index 1ba50afa1a..a4c86044e8 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java @@ -132,7 +132,7 @@ public CompletableFuture> calculateChunks(List blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); List spawnersLocations = new LinkedList<>(); @@ -295,7 +295,7 @@ private static void removeTileEntities(Chunk chunk) { } catch (Throwable ignored) { } - if(hasWorldHField) { + if (hasWorldHField) { chunk.tileEntities.forEach(((blockPosition, tileEntity) -> { chunk.world.tileEntityList.remove(tileEntity); chunk.world.h.remove(tileEntity); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java index c01ea03dbd..5817846438 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java @@ -1,8 +1,11 @@ package com.bgsoftware.superiorskyblock.nms.v1_8_R3; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.google.common.collect.Maps; @@ -22,6 +25,7 @@ import net.minecraft.server.v1_8_R3.TileEntity; import net.minecraft.server.v1_8_R3.World; import net.minecraft.server.v1_8_R3.WorldServer; +import org.bukkit.Location; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import java.util.Collection; @@ -39,10 +43,30 @@ public class NMSUtils { private static final Map chunkLoadersMap = Maps.newHashMap(); + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPosition.MutableBlockPosition(0, 0, 0)); + private NMSUtils() { } + @Nullable + public static T getTileEntityAt(Location location, Class type) { + org.bukkit.World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + WorldServer worldServer = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + TileEntity tileEntity = worldServer.getTileEntity(blockPosition); + return !type.isInstance(tileEntity) ? null : type.cast(tileEntity); + } + } + public static void runActionOnChunks(Collection chunksCoords, boolean saveChunks, ChunkCallback chunkCallback) { List unloadedChunks = new LinkedList<>(); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java index 67e5fb1fd8..87897701ff 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -83,25 +84,17 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { - org.bukkit.World world = location.getWorld(); - - if (world == null) + TileEntityMobSpawner mobSpawner = NMSUtils.getTileEntityAt(location, TileEntityMobSpawner.class); + if (mobSpawner == null) return; - WorldServer worldServer = ((CraftWorld) world).getHandle(); - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - TileEntity mobSpawner = worldServer.getTileEntity(blockPosition); - - if (!(mobSpawner instanceof TileEntityMobSpawner)) + MobSpawnerAbstract mobSpawnerAbstract = mobSpawner.getSpawner(); + if (mobSpawnerAbstract instanceof MobSpawnerAbstractNotifier) return; - MobSpawnerAbstract mobSpawnerAbstract = ((TileEntityMobSpawner) mobSpawner).getSpawner(); - - if (!(mobSpawnerAbstract instanceof MobSpawnerAbstractNotifier)) { - MobSpawnerAbstractNotifier mobSpawnerAbstractNotifier = new MobSpawnerAbstractNotifier(mobSpawnerAbstract, delayChangeCallback); - MOB_SPAWNER_ABSTRACT.set(mobSpawner, mobSpawnerAbstractNotifier); - mobSpawnerAbstractNotifier.updateDelay(); - } + MobSpawnerAbstractNotifier mobSpawnerAbstractNotifier = new MobSpawnerAbstractNotifier(mobSpawnerAbstract, delayChangeCallback); + MOB_SPAWNER_ABSTRACT.set(mobSpawner, mobSpawnerAbstractNotifier); + mobSpawnerAbstractNotifier.updateDelay(); } @Override @@ -174,15 +167,19 @@ public Object getBlockData(org.bukkit.block.Block block) { @Override public void setBlock(Location location, int combinedId) { WorldServer world = ((CraftWorld) location.getWorld()).getHandle(); - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null); - NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4, - new PacketPlayOutBlockChange(world, blockPosition)); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + + NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null); + NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4, + new PacketPlayOutBlockChange(world, blockPosition)); + } } @Override public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return new NMSCachedBlock(block); + return NMSCachedBlock.obtain(block); } @Override @@ -193,20 +190,23 @@ public CompoundTag readBlockStates(Location location) { @Override public byte[] getLightLevels(Location location) { - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - Chunk chunk = ((CraftWorld) location.getWorld()).getHandle().getChunkAtWorldCoords(blockPosition); - return new byte[]{ - (byte) chunk.getBrightness(EnumSkyBlock.SKY, blockPosition), - (byte) chunk.getBrightness(EnumSkyBlock.BLOCK, blockPosition), - }; + WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + + Chunk chunk = worldServer.getChunkAtWorldCoords(blockPosition); + + return new byte[]{ + (byte) chunk.getBrightness(EnumSkyBlock.SKY, blockPosition), + (byte) chunk.getBrightness(EnumSkyBlock.BLOCK, blockPosition) + }; + } } @Override public CompoundTag readTileEntity(Location location) { - net.minecraft.server.v1_8_R3.World world = ((CraftWorld) location.getWorld()).getHandle(); - BlockPosition blockPosition = new BlockPosition(location.getX(), location.getY(), location.getZ()); - TileEntity tileEntity = world.getTileEntity(blockPosition); - + TileEntity tileEntity = NMSUtils.getTileEntityAt(location, TileEntity.class); if (tileEntity == null) return null; @@ -234,9 +234,8 @@ public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { @Override public int getDefaultAmount(org.bukkit.block.Block block) { - Location blockLocation = block.getLocation(); - IBlockData blockData = ((CraftWorld) block.getWorld()).getHandle().getType(new BlockPosition( - blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ())); + WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle(); + IBlockData blockData = worldServer.getType(new BlockPosition(block.getX(), block.getY(), block.getZ())); return getDefaultAmount(blockData); } @@ -261,28 +260,26 @@ private int getDefaultAmount(IBlockData blockData) { @Override public void placeSign(Island island, Location location) { - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); - TileEntity tileEntity = worldServer.getTileEntity(blockPosition); - if (tileEntity instanceof TileEntitySign) { - TileEntitySign tileEntitySign = (TileEntitySign) tileEntity; - String[] lines = new String[4]; - System.arraycopy(CraftSign.revertComponents(tileEntitySign.lines), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - IChatBaseComponent[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } + TileEntitySign tileEntitySign = NMSUtils.getTileEntityAt(location, TileEntitySign.class); + if (tileEntitySign == null) + return; + + String[] lines = new String[4]; + System.arraycopy(CraftSign.revertComponents(tileEntitySign.lines), 0, lines, 0, lines.length); + String[] strippedLines = new String[4]; + for (int i = 0; i < 4; i++) + strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4); + IChatBaseComponent[] newLines; + + IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); + if (result.isCancelEvent()) { + newLines = CraftSign.sanitizeLines(strippedLines); + } else { + newLines = CraftSign.sanitizeLines(lines); } + + System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4); } @Override @@ -292,33 +289,49 @@ public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { @Override public void playGeneratorSound(Location location) { - net.minecraft.server.v1_8_R3.World world = ((CraftWorld) location.getWorld()).getHandle(); + WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + + double x = location.getX(); + double y = location.getY(); + double z = location.getZ(); - double x = location.getX(); - double y = location.getY(); - double z = location.getZ(); + blockPosition.c(x, y, z); - world.makeSound(x + 0.5D, y + 0.5D, z + 0.5D, "random.fizz", 0.5F, - 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F); + worldServer.makeSound(x + 0.5D, y + 0.5D, z + 0.5D, "random.fizz", 0.5F, + 2.6F + (worldServer.random.nextFloat() - worldServer.random.nextFloat()) * 0.8F); - for (int i = 0; i < 8; i++) - world.addParticle(EnumParticle.SMOKE_LARGE, x + Math.random(), y + 1.2D, z + Math.random(), 0.0D, 0.0D, 0.0D); + for (int i = 0; i < 8; i++) { + worldServer.addParticle(EnumParticle.SMOKE_LARGE, + x + Math.random(), y + 1.2D, z + Math.random(), + 0.0D, 0.0D, 0.0D); + } + } } @Override public void playBreakAnimation(org.bukkit.block.Block block) { - net.minecraft.server.v1_8_R3.World world = ((CraftWorld) block.getWorld()).getHandle(); - BlockPosition blockPosition = new BlockPosition(block.getX(), block.getY(), block.getZ()); - world.a(null, 2001, blockPosition, net.minecraft.server.v1_8_R3.Block.getCombinedId(world.getType(blockPosition))); + WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.c(block.getX(), block.getY(), block.getZ()); + worldServer.a(null, 2001, blockPosition, Block.getCombinedId(worldServer.getType(blockPosition))); + } } @Override public void playPlaceSound(Location location) { - BlockPosition blockPosition = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - net.minecraft.server.v1_8_R3.World world = ((CraftWorld) location.getWorld()).getHandle(); - net.minecraft.server.v1_8_R3.Block.StepSound stepSound = world.getType(blockPosition).getBlock().stepSound; - world.makeSound(blockPosition.getX() + 0.5F, blockPosition.getY() + 0.5F, blockPosition.getZ() + 0.5F, - stepSound.getPlaceSound(), (stepSound.getVolume1() + 1.0F) / 2.0F, stepSound.getVolume2() * 0.8F); + WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + + Block.StepSound stepSound = worldServer.getType(blockPosition).getBlock().stepSound; + worldServer.makeSound(blockPosition.getX() + 0.5F, blockPosition.getY() + 0.5F, blockPosition.getZ() + 0.5F, + stepSound.getPlaceSound(), (stepSound.getVolume1() + 1.0F) / 2.0F, stepSound.getVolume2() * 0.8F); + } } @Override @@ -338,7 +351,7 @@ public IslandsGenerator createGenerator(Dimension dimension) { @Override public WorldEditSession createEditSession(World world) { - return new WorldEditSessionImpl(((CraftWorld) world).getHandle()); + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } } diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java index 1e68392122..0d1183985f 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -37,23 +38,34 @@ import org.bukkit.generator.ChunkGenerator; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedList; import java.util.List; public class WorldEditSessionImpl implements WorldEditSession { + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final List lights = new LinkedList<>(); - private final WorldServer worldServer; - private final Dimension dimension; + private WorldServer worldServer; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(WorldServer worldServer) { + return POOL.obtain().initialize(worldServer); + } - public WorldEditSessionImpl(WorldServer worldServer) { + private WorldEditSessionImpl() { + } + + public WorldEditSessionImpl initialize(WorldServer worldServer) { this.worldServer = worldServer; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld()); + return this; } @Override @@ -94,13 +106,17 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + List chunkPositions = new LinkedList<>(); World bukkitWorld = worldServer.getWorld(); LongIterator iterator = chunks.keyIterator(); while (iterator.hasNext()) { long chunkKey = iterator.next(); - ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32)); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkCoord.x, chunkCoord.z)); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); } return chunkPositions; } @@ -172,6 +188,19 @@ public void finish(Island island) { } }, 5L); } + + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lights.clear(); + this.worldServer = null; + this.dimension = null; + POOL.release(this); } private boolean isValidPosition(BlockPosition blockPosition) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index df72227687..d8c67b7ab7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -17,6 +17,7 @@ import com.bgsoftware.superiorskyblock.commands.admin.AdminCommandsMap; import com.bgsoftware.superiorskyblock.commands.player.PlayerCommandsMap; import com.bgsoftware.superiorskyblock.config.SettingsManagerImpl; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PluginLoadingStage; import com.bgsoftware.superiorskyblock.core.PluginReloadReason; import com.bgsoftware.superiorskyblock.core.database.DataManager; @@ -81,6 +82,7 @@ import com.bgsoftware.superiorskyblock.world.schematic.container.DefaultSchematicsContainer; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import org.bukkit.plugin.java.JavaPlugin; @@ -289,26 +291,29 @@ public void onEnable() { } BukkitExecutor.sync(() -> { - for (Player player : Bukkit.getOnlinePlayers()) { - SuperiorPlayer superiorPlayer = playersHandler.getSuperiorPlayer(player); - superiorPlayer.updateLastTimeStatus(); - Island island = gridHandler.getIslandAt(superiorPlayer.getLocation()); - Island playerIsland = superiorPlayer.getIsland(); - - if (superiorPlayer.hasIslandFlyEnabled()) { - if (island != null && island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) { - player.setAllowFlight(true); - player.setFlying(true); - } else { - superiorPlayer.toggleIslandFly(); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + for (Player player : Bukkit.getOnlinePlayers()) { + SuperiorPlayer superiorPlayer = playersHandler.getSuperiorPlayer(player); + superiorPlayer.updateLastTimeStatus(); + + Island island = gridHandler.getIslandAt(player.getLocation(wrapper.getHandle())); + Island playerIsland = superiorPlayer.getIsland(); + + if (superiorPlayer.hasIslandFlyEnabled()) { + if (island != null && island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) { + player.setAllowFlight(true); + player.setFlying(true); + } else { + superiorPlayer.toggleIslandFly(); + } } - } - if (playerIsland != null) - playerIsland.setCurrentlyActive(true); + if (playerIsland != null) + playerIsland.setCurrentlyActive(true); - if (island != null) - island.setPlayerInside(superiorPlayer, true); + if (island != null) + island.setPlayerInside(superiorPlayer, true); + } } }, 1L); @@ -484,11 +489,13 @@ public void reloadPlugin(PluginReloadReason reloadReason) throws ManagerLoadExce modulesHandler.runModuleLifecycle(ModuleLoadTime.AFTER_MODULE_DATA_LOAD, reloadReason == PluginReloadReason.COMMAND); BukkitExecutor.sync(() -> { - for (Player player : Bukkit.getOnlinePlayers()) { - SuperiorPlayer superiorPlayer = playersHandler.getSuperiorPlayer(player); - Island island = gridHandler.getIslandAt(player.getLocation()); - superiorPlayer.updateWorldBorder(island); - if (island != null) island.applyEffects(superiorPlayer); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + for (Player player : Bukkit.getOnlinePlayers()) { + SuperiorPlayer superiorPlayer = playersHandler.getSuperiorPlayer(player); + Island island = gridHandler.getIslandAt(player.getLocation(wrapper.getHandle())); + superiorPlayer.updateWorldBorder(island); + if (island != null) island.applyEffects(superiorPlayer); + } } }); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java index 991cfa4f80..3db97acf73 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java @@ -76,7 +76,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab island.deleteWarp(islandWarp.getName()); Message.DELETE_WARP.send(sender, islandWarp.getName()); - ChunksProvider.loadChunk(ChunkPosition.of(islandWarp.getLocation()), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { + ChunksProvider.loadChunk(ChunkPosition.of(islandWarp), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { SignWarp.trySignWarpBreak(islandWarp, sender); }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockAmount.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockAmount.java index ab64b128c0..61260fe1e9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockAmount.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockAmount.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Location; import org.bukkit.World; @@ -87,17 +88,25 @@ public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sen if (args.length == 3) { list = CommandTabCompletes.getWorlds(args[2]); } else if (sender instanceof Player) { - Location location = ((Player) sender).getLocation(); + String blockX; + String blockY; + String blockZ; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = ((Player) sender).getLocation(wrapper.getHandle()); + blockX = String.valueOf(location.getBlockX()); + blockY = String.valueOf(location.getBlockY()); + blockZ = String.valueOf(location.getBlockZ()); + } if (args.length == 4) { - if ((location.getBlockX() + "").contains(args[3])) - list.add(location.getBlockX() + ""); + if (blockX.contains(args[3])) + list.add(blockX); } else if (args.length == 5) { - if ((location.getBlockY() + "").contains(args[4])) - list.add(location.getBlockY() + ""); + if (blockY.contains(args[4])) + list.add(blockY); } else if (args.length == 6) { - if ((location.getBlockZ() + "").contains(args[5])) - list.add(location.getBlockZ() + ""); + if (blockZ.contains(args[5])) + list.add(blockZ); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSpawn.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSpawn.java index 95820c0091..de1163790d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSpawn.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSpawn.java @@ -1,9 +1,10 @@ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import org.bukkit.Location; import org.bukkit.command.CommandSender; @@ -52,18 +53,21 @@ public boolean canBeExecutedByConsole() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { Player player = (Player) sender; - Location playerLocation = player.getLocation(); - Location spawnLocation = new Location(player.getWorld(), playerLocation.getBlockX(), playerLocation.getBlockY(), - playerLocation.getBlockZ(), playerLocation.getYaw(), playerLocation.getPitch()); - - String newSpawnLocation = Serializers.LOCATION_SPACED_SERIALIZER.serialize(spawnLocation); + String newSpawnLocation; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = player.getLocation(wrapper.getHandle()); + location.setX(location.getBlockX()); + location.setY(location.getBlockY()); + location.setZ(location.getBlockZ()); + newSpawnLocation = Serializers.LOCATION_SPACED_SERIALIZER.serialize(location); + } try { plugin.getSettings().updateValue("spawn.location", newSpawnLocation); plugin.getGrid().updateSpawn(); } catch (Exception error) { - Log.entering("ENTER", spawnLocation); + Log.entering("ENTER", newSpawnLocation); Log.error(error, "An unexpected error occurred while setting spawn:"); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java index eb9dc7fff3..380a351c7a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java @@ -10,10 +10,13 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; +import org.bukkit.Location; import org.bukkit.PortalType; import org.bukkit.World; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import java.util.Arrays; import java.util.Collections; @@ -93,8 +96,10 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (dimension != plugin.getSettings().getWorlds().getDefaultWorldDimension()) { if (!island.wasSchematicGenerated(dimension)) { PortalType portalType = dimension.getEnvironment() == World.Environment.NETHER ? PortalType.NETHER : PortalType.ENDER; - portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, superiorPlayer.getLocation(), - portalType, false); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, + ((Player) sender).getLocation(wrapper.getHandle()), portalType, false); + } return; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java index 37b43e8d3f..bf2510a49b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; @@ -116,8 +117,12 @@ public static IslandArgument getIslandWhereStanding(SuperiorSkyblockPlugin plugi } SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - Island locationIsland = plugin.getGrid().getIslandAt(superiorPlayer.getLocation()); - Island island = locationIsland == null || locationIsland.isSpawn() ? superiorPlayer.getIsland() : locationIsland; + + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Island locationIsland = plugin.getGrid().getIslandAt(((Player) sender).getLocation(wrapper.getHandle())); + island = locationIsland == null || locationIsland.isSpawn() ? superiorPlayer.getIsland() : locationIsland; + } if (island == null) Message.INVALID_ISLAND.send(sender); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java index c48e985a6a..b7c3023d32 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java @@ -80,7 +80,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer island.deleteWarp(islandWarp.getName()); Message.DELETE_WARP.send(superiorPlayer, islandWarp.getName()); - ChunksProvider.loadChunk(ChunkPosition.of(islandWarp.getLocation()), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { + ChunksProvider.loadChunk(ChunkPosition.of(islandWarp), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { SignWarp.trySignWarpBreak(islandWarp, player); }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdExpel.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdExpel.java index e62703790a..76d9b58ab1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdExpel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdExpel.java @@ -7,9 +7,11 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -78,7 +80,10 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer return; } - Island targetIsland = plugin.getGrid().getIslandAt(target.getLocation()); + Island targetIsland; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + targetIsland = plugin.getGrid().getIslandAt(target.getLocation(wrapper.getHandle())); + } if (targetIsland == null) { Message.PLAYER_NOT_INSIDE_ISLAND.send(sender); @@ -99,18 +104,26 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer } targetPlayer.teleport(plugin.getGrid().getSpawnIsland()); - target.getLocation().setDirection(plugin.getGrid().getSpawnIsland() - .getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getDirection()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + target.getLocation(wrapper.getHandle()).setDirection(plugin.getGrid().getSpawnIsland() + .getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getDirection()); + } Message.EXPELLED_PLAYER.send(sender, targetPlayer.getName()); Message.GOT_EXPELLED.send(targetPlayer, sender.getName()); } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { - return args.length != 2 ? Collections.emptyList() : island != null ? - CommandTabCompletes.getIslandVisitors(island, args[1], plugin.getSettings().isTabCompleteHideVanished()) : - CommandTabCompletes.getOnlinePlayers(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), - onlinePlayer -> plugin.getGrid().getIslandAt(onlinePlayer.getLocation()) != null); + if (args.length != 2) + return Collections.emptyList(); + + if (island != null) + return CommandTabCompletes.getIslandVisitors(island, args[1], plugin.getSettings().isTabCompleteHideVanished()); + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return CommandTabCompletes.getOnlinePlayers(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), + onlinePlayer -> plugin.getGrid().getIslandAt(onlinePlayer.getLocation(wrapper.getHandle())) != null); + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java index 98c6ef085f..ae94b6fc94 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java @@ -3,9 +3,11 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -56,8 +58,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ if (!plugin.getEventsBus().callPlayerToggleFlyEvent(superiorPlayer)) return; - Island island = plugin.getGrid().getIslandAt(superiorPlayer.getLocation()); Player player = (Player) sender; + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); + } if (superiorPlayer.hasIslandFlyEnabled()) { player.setAllowFlight(false); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java index 86d583e7b7..63a9d9ba09 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java @@ -5,10 +5,11 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; -import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.Location; import java.util.Arrays; @@ -63,20 +64,23 @@ public Message getPermissionLackMessage() { @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { - Location newLocation = superiorPlayer.getLocation(); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location newLocation = superiorPlayer.getLocation(wrapper.getHandle()); - if (!island.isInsideRange(newLocation)) { - Message.TELEPORT_LOCATION_OUTSIDE_ISLAND.send(superiorPlayer); - return; - } + if (!island.isInsideRange(newLocation)) { + Message.TELEPORT_LOCATION_OUTSIDE_ISLAND.send(superiorPlayer); + return; + } + + EventResult eventResult = plugin.getEventsBus().callIslandSetHomeEvent(island, newLocation, + IslandSetHomeEvent.Reason.SET_HOME_COMMAND, superiorPlayer); - EventResult eventResult = plugin.getEventsBus().callIslandSetHomeEvent(island, newLocation, - IslandSetHomeEvent.Reason.SET_HOME_COMMAND, superiorPlayer); + if (eventResult.isCancelled()) + return; - if (eventResult.isCancelled()) - return; + island.setIslandHome(eventResult.getResult()); + } - island.setIslandHome(eventResult.getResult()); Message.CHANGED_TELEPORT_LOCATION.send(superiorPlayer); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java index 9d826e7cda..54ff9f5d02 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java @@ -5,11 +5,12 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.google.common.base.Preconditions; import org.bukkit.Location; @@ -95,9 +96,11 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer return; } - if (!island.isInsideRange(superiorPlayer.getLocation())) { - Message.SET_WARP_OUTSIDE.send(superiorPlayer); - return; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (!island.isInsideRange(superiorPlayer.getLocation(wrapper.getHandle()))) { + Message.SET_WARP_OUTSIDE.send(superiorPlayer); + return; + } } String categoryName = null; @@ -122,16 +125,18 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer WarpCategory warpCategory = categoryName == null ? null : island.createWarpCategory(categoryName); - Location warpLocation = superiorPlayer.getLocation(); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location warpLocation = superiorPlayer.getLocation(wrapper.getHandle()); - Preconditions.checkState(warpLocation != null, "Null location for a warp."); + Preconditions.checkState(warpLocation != null, "Null location for a warp."); - if (!plugin.getEventsBus().callIslandCreateWarpEvent(superiorPlayer, island, warpName, warpLocation, warpCategory)) - return; + if (!plugin.getEventsBus().callIslandCreateWarpEvent(superiorPlayer, island, warpName, warpLocation, warpCategory)) + return; - island.createWarp(warpName, warpLocation, warpCategory); + island.createWarp(warpName, warpLocation, warpCategory); - Message.SET_WARP.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(warpLocation)); + Message.SET_WARP.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(warpLocation)); + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java index f91ce5c224..66b45e30ee 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java @@ -4,8 +4,11 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; +import org.bukkit.Location; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; @@ -67,7 +70,9 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ } superiorPlayer.toggleWorldBorder(); - superiorPlayer.updateWorldBorder(plugin.getGrid().getIslandAt(superiorPlayer.getLocation())); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + superiorPlayer.updateWorldBorder(plugin.getGrid().getIslandAt(((Player) sender).getLocation(wrapper.getHandle()))); + } } else if (args[1].equalsIgnoreCase("blocks")) { if (!superiorPlayer.hasPermission("superior.island.toggle.blocks")) { Message.NO_COMMAND_PERMISSION.send(sender); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java index bb0625816a..e66e64d808 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java @@ -1,37 +1,29 @@ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.block.Block; import java.lang.ref.WeakReference; import java.util.Objects; import java.util.Optional; -public class ChunkPosition { +public class ChunkPosition implements ObjectsPool.Releasable, AutoCloseable { - private final WorldInfo worldInfo; - private final int x; - private final int z; + private static final ObjectsPool POOL = new ObjectsPool<>(ChunkPosition::new); - private long pairedXZ = -1; - @Nullable - private WeakReference cachedBukkitWorld = new WeakReference<>(null); + protected WorldInfo worldInfo; + protected int x; + protected int z; - private ChunkPosition(WorldInfo worldInfo, int x, int z) { - this.worldInfo = worldInfo; - this.x = x; - this.z = z; - } - - public static ChunkPosition of(Block block) { - World world = block.getWorld(); - return of(WorldInfo.of(world), block.getX() >> 4, block.getZ() >> 4).withBukkitWorld(world); - } + protected long pairedXZ = -1; + @Nullable + protected WeakReference cachedBukkitWorld = new WeakReference<>(null); + private final boolean isPool; public static ChunkPosition of(Location location) { World world = location.getWorld(); @@ -39,16 +31,50 @@ public static ChunkPosition of(Location location) { } public static ChunkPosition of(Chunk chunk) { + return of(chunk, true); + } + + public static ChunkPosition of(Chunk chunk, boolean fromPool) { World world = chunk.getWorld(); - return of(WorldInfo.of(world), chunk.getX(), chunk.getZ()).withBukkitWorld(world); + return of(WorldInfo.of(world), chunk.getX(), chunk.getZ(), fromPool).withBukkitWorld(world); } public static ChunkPosition of(World world, int x, int z) { - return of(WorldInfo.of(world), x, z).withBukkitWorld(world); + return of(world, x, z, true); + } + + public static ChunkPosition of(World world, int x, int z, boolean fromPool) { + return of(WorldInfo.of(world), x, z, fromPool).withBukkitWorld(world); } public static ChunkPosition of(WorldInfo worldInfo, int x, int z) { - return new ChunkPosition(worldInfo, x, z); + return of(worldInfo, x, z, true); + } + + public static ChunkPosition of(WorldInfo worldInfo, int x, int z, boolean fromPool) { + ChunkPosition chunkPosition = fromPool ? POOL.obtain() : new ChunkPosition(false); + return chunkPosition.initialize(worldInfo, x, z); + } + + public static ChunkPosition of(IslandWarp islandWarp) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return of(islandWarp.getLocation(wrapper.getHandle())); + } + } + + protected ChunkPosition() { + this(true); + } + + protected ChunkPosition(boolean isPool) { + this.isPool = isPool; + } + + private ChunkPosition initialize(WorldInfo worldInfo, int x, int z) { + this.worldInfo = worldInfo; + this.x = x; + this.z = z; + return this; } public World getWorld() { @@ -95,6 +121,26 @@ public int distanceSquared(ChunkPosition other) { return (deltaX * deltaX) + (deltaZ * deltaZ); } + @Override + public void release() { + if (!isPool) + return; + + this.worldInfo = null; + this.pairedXZ = -1; + this.cachedBukkitWorld.clear(); + POOL.release(this); + } + + public ChunkPosition copy() { + return new ChunkPosition().initialize(this.worldInfo, this.x, this.z); + } + + @Override + public void close() { + release(); + } + @Override public int hashCode() { return Objects.hash(worldInfo.getName(), x, z); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/GameSoundImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/GameSoundImpl.java index b4ab69befb..f73f898ac2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/GameSoundImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/GameSoundImpl.java @@ -2,6 +2,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.world.GameSound; +import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; @@ -40,8 +41,12 @@ public static void playSound(HumanEntity humanEntity, @Nullable GameSound gameSo } public static void playSound(Player player, @Nullable GameSound gameSound) { - if (!isEmpty(gameSound)) - player.playSound(player.getLocation(), gameSound.getSound(), gameSound.getVolume(), gameSound.getPitch()); + if (!isEmpty(gameSound)) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + player.playSound(player.getLocation(wrapper.getHandle()), gameSound.getSound(), + gameSound.getVolume(), gameSound.getPitch()); + } + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java index 4e7ec3685e..5a51ab2b42 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java @@ -2,22 +2,42 @@ import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; -public class IslandArea { +public class IslandArea implements ObjectsPool.Releasable, AutoCloseable { + + private static final ObjectsPool POOL = new ObjectsPool<>(IslandArea::new); private double minX; private double minZ; private double maxX; private double maxZ; - public IslandArea(BlockPosition center, double size) { - this(center.getX() - size, center.getZ() - size, center.getX() + size, center.getZ() + size); + public static IslandArea of(BlockPosition center, double size) { + return of(center, size, true); + } + + public static IslandArea of(BlockPosition center, double size, boolean fromPool) { + return of(center.getX() - size, center.getZ() - size, center.getX() + size, center.getZ() + size, fromPool); + } + + public static IslandArea of(double minX, double minZ, double maxX, double maxZ) { + return of(minX, minZ, maxX, maxZ, true); + } + + public static IslandArea of(double minX, double minZ, double maxX, double maxZ, boolean fromPool) { + IslandArea islandArea = fromPool ? POOL.obtain() : new IslandArea(); + return islandArea.initialize(minX, minZ, maxX, maxZ); } - public IslandArea(double minX, double minZ, double maxX, double maxZ) { + private IslandArea() { + + } + + private IslandArea initialize(double minX, double minZ, double maxX, double maxZ) { this.minX = minX; this.minZ = minZ; this.maxX = maxX; this.maxZ = maxZ; + return this; } public void expand(double size) { @@ -31,10 +51,10 @@ public void expand(double size) { public void rshift(int shift) { if (shift != 0) { - this.minX = (int)this.minX >> shift; - this.minZ = (int)this.minZ >> shift; - this.maxX = (int)this.maxX >> shift; - this.maxZ = (int)this.maxZ >> shift; + this.minX = (int) this.minX >> shift; + this.minZ = (int) this.minZ >> shift; + this.maxX = (int) this.maxX >> shift; + this.maxZ = (int) this.maxZ >> shift; } } @@ -43,7 +63,20 @@ public boolean intercepts(double x, double z) { } public IslandArea copy() { - return new IslandArea(this.minX, this.minZ, this.maxX, this.maxZ); + return of(this.minX, this.minZ, this.maxX, this.maxZ); } + @Override + public void release() { + this.minX = 0; + this.minZ = 0; + this.maxX = 0; + this.maxZ = 0; + POOL.release(this); + } + + @Override + public void close() { + release(); + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java index 9cb0c954c7..1ef1dfd56b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java @@ -6,19 +6,25 @@ import java.util.Objects; -public class IslandPosition { +public class IslandPosition implements ObjectsPool.Releasable, AutoCloseable { + + private static final ObjectsPool POOL = new ObjectsPool<>(IslandPosition::new); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @Nullable - private final String worldName; - private final int x; - private final int z; + private String worldName; + private int x; + private int z; + + private IslandPosition() { + } - private IslandPosition(@Nullable String worldName, int x, int z) { + private IslandPosition initialize(@Nullable String worldName, int x, int z) { this.worldName = worldName; this.x = x; this.z = z; + return this; } public static IslandPosition of(Location location) { @@ -26,10 +32,29 @@ public static IslandPosition of(Location location) { } public static IslandPosition of(String worldName, int locX, int locZ) { + return of(worldName, locX, locZ, true); + } + + public static IslandPosition of(String worldName, int locX, int locZ, boolean fromPool) { int radius = plugin.getSettings().getMaxIslandSize() * 3; int x = (Math.abs(locX) + (radius / 2)) / radius; int z = (Math.abs(locZ) + (radius / 2)) / radius; - return new IslandPosition(plugin.getProviders().hasCustomWorldsSupport() ? worldName : null, locX < 0 ? -x : x, locZ < 0 ? -z : z); + + IslandPosition islandPosition = fromPool ? POOL.obtain() : new IslandPosition(); + + return islandPosition.initialize(plugin.getProviders().hasCustomWorldsSupport() ? worldName : null, + locX < 0 ? -x : x, locZ < 0 ? -z : z); + } + + @Override + public void release() { + this.worldName = null; + POOL.release(this); + } + + @Override + public void close() { + this.release(); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/LocationKey.java b/src/main/java/com/bgsoftware/superiorskyblock/core/LocationKey.java index 4104062072..aa29b07852 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/LocationKey.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/LocationKey.java @@ -1,29 +1,75 @@ package com.bgsoftware.superiorskyblock.core; +import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import org.bukkit.Location; import java.util.Objects; -public class LocationKey { +public class LocationKey implements ObjectsPool.Releasable, AutoCloseable { - private final String worldName; - private final double x; - private final double y; - private final double z; + private static final ObjectsPool POOL = new ObjectsPool<>(LocationKey::new); - public LocationKey(Location location) { - this(LazyWorldLocation.getWorldName(location), location.getX(), location.getY(), location.getZ()); + private String worldName; + private double x; + private double y; + private double z; + + public static LocationKey of(Location location) { + return of(location, true); + } + + public static LocationKey of(Location location, boolean fromPool) { + return of(LazyWorldLocation.getWorldName(location), location.getX(), location.getY(), location.getZ(), fromPool); + } + + public static LocationKey of(LazyWorldLocation location) { + return of(location, true); + } + + public static LocationKey of(LazyWorldLocation location, boolean fromPool) { + return of(location.getWorldName(), location.getX(), location.getY(), location.getZ(), fromPool); + } + + public static LocationKey of(String worldName, double x, double y, double z) { + return of(worldName, x, y, z, true); + } + + public static LocationKey of(String worldName, double x, double y, double z, boolean fromPool) { + LocationKey locationKey = fromPool ? POOL.obtain() : new LocationKey(); + return locationKey.initialize(worldName, x, y, z); } - public LocationKey(LazyWorldLocation location) { - this(location.getWorldName(), location.getX(), location.getY(), location.getZ()); + public static LocationKey of(IslandWarp islandWarp) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return of(islandWarp.getLocation(wrapper.getHandle())); + } } - public LocationKey(String worldName, double x, double y, double z) { + private LocationKey() { + + } + + private LocationKey initialize(String worldName, double x, double y, double z) { this.worldName = worldName; this.x = x; this.y = y; this.z = z; + return this; + } + + public LocationKey copy() { + return of(worldName, x, y, z, false); + } + + @Override + public void release() { + this.worldName = null; + POOL.release(this); + } + + @Override + public void close() { + release(); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/MutableChunkPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/MutableChunkPosition.java new file mode 100644 index 0000000000..b0c6c92b7e --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/MutableChunkPosition.java @@ -0,0 +1,20 @@ +package com.bgsoftware.superiorskyblock.core; + +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; + +public class MutableChunkPosition extends ChunkPosition { + + public MutableChunkPosition() { + super(false); + } + + public MutableChunkPosition reset(WorldInfo worldInfo, int x, int z) { + this.worldInfo = worldInfo; + this.x = x; + this.z = z; + this.pairedXZ = -1; + this.cachedBukkitWorld.clear(); + return this; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPool.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPool.java new file mode 100644 index 0000000000..fe97f71236 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPool.java @@ -0,0 +1,47 @@ +package com.bgsoftware.superiorskyblock.core; + +import java.util.LinkedList; +import java.util.Queue; + +public class ObjectsPool { + + private final Queue backend = new LinkedList<>(); + private final Creator creator; + + public ObjectsPool(Creator creator) { + this(creator, 0); + } + + public ObjectsPool(Creator creator, int initialCapacity) { + this.creator = creator; + for (int i = 0; i < initialCapacity; ++i) + this.backend.offer(creator.create()); + } + + public T obtain() { + T obj; + synchronized (this) { + obj = this.backend.poll(); + } + return obj == null ? this.creator.create() : obj; + } + + public void release(T obj) { + synchronized (this) { + this.backend.offer(obj); + } + } + + public interface Creator { + + T create(); + + } + + public interface Releasable { + + void release(); + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java new file mode 100644 index 0000000000..d4708083de --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java @@ -0,0 +1,59 @@ +package com.bgsoftware.superiorskyblock.core; + +import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; +import org.bukkit.Location; + +import javax.annotation.Nullable; +import java.util.function.Consumer; + +public class ObjectsPools { + + public static final ObjectsPool> LOCATION = createNewPool(() -> new Location(null, 0D, 0D, 0D)); + + private ObjectsPools() { + + } + + public static ObjectsPool> createNewPool(ObjectsPool.Creator creator) { + MutableObject>> wrapperReference = new MutableObject<>(null); + + ObjectsPool> pool = new ObjectsPool<>( + () -> new Wrapper<>(creator.create(), + obj -> onWrapperRelease(obj, wrapperReference.getValue()))); + + wrapperReference.setValue(pool); + + return pool; + } + + private static void onWrapperRelease(T obj, @Nullable ObjectsPool pool) { + if (pool != null) + pool.release(obj); + } + + public static class Wrapper implements ObjectsPool.Releasable, AutoCloseable { + + private final T handle; + private final Consumer> releaseMethod; + + Wrapper(T handle, Consumer> releaseMethod) { + this.handle = handle; + this.releaseMethod = releaseMethod; + } + + public T getHandle() { + return handle; + } + + @Override + public void release() { + this.releaseMethod.accept(this); + } + + @Override + public void close() { + release(); + } + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/SBlockPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/SBlockPosition.java index d363667041..1e446c81fd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/SBlockPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/SBlockPosition.java @@ -25,6 +25,10 @@ public SBlockPosition(Location location) { this(LazyWorldLocation.getWorldName(location), location.getBlockX(), location.getBlockY(), location.getBlockZ()); } + public SBlockPosition(Block block) { + this(block.getWorld().getName(), block.getX(), block.getY(), block.getZ()); + } + public SBlockPosition(String worldName, int x, int y, int z) { this.worldName = worldName; this.x = x; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/Chunk2ObjectMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/Chunk2ObjectMap.java index bed6c08180..a401ff015b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/Chunk2ObjectMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/Chunk2ObjectMap.java @@ -3,6 +3,7 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.MutableChunkPosition; import com.bgsoftware.superiorskyblock.core.WorldInfoImpl; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; @@ -190,12 +191,19 @@ public void clear() { private class KeySetItr extends Itr { + private final MutableChunkPosition mutableChunkPosition = new MutableChunkPosition(); + private WorldInfoImpl cachedWorldInfo = null; + @Override protected ChunkPosition getNext() { - return ChunkPosition.of(new WorldInfoImpl(this.currWorld, null), - getChunkXFromPair(this.currChunk), getChunkZFromPair(this.currChunk)); + return this.mutableChunkPosition.reset(this.cachedWorldInfo, getChunkXFromPair(this.currChunk), + getChunkZFromPair(this.currChunk)); } + @Override + protected void onWorldChange() { + this.cachedWorldInfo = new WorldInfoImpl(this.currWorld, null); + } } } @@ -278,22 +286,36 @@ public void clear() { private class EntrySetItr extends Itr> { + private final MutableChunkPosition mutableChunkPosition = new MutableChunkPosition(); + private final EntryImpl mutableEntry = new EntryImpl(); + private WorldInfoImpl cachedWorldInfo = null; + @Override protected Entry getNext() { - return new EntryImpl(ChunkPosition.of( - new WorldInfoImpl(this.currWorld, null), - getChunkXFromPair(this.currChunk), getChunkZFromPair(this.currChunk)), this.currValue); + return mutableEntry.reset( + this.mutableChunkPosition.reset(this.cachedWorldInfo, + getChunkXFromPair(this.currChunk), getChunkZFromPair(this.currChunk)), + this.currValue); + } + + @Override + protected void onWorldChange() { + this.cachedWorldInfo = new WorldInfoImpl(this.currWorld, null); } private class EntryImpl implements Entry { - private final ChunkPosition chunkPosition; + private ChunkPosition chunkPosition; private V cachedValue; + EntryImpl() { + + } - EntryImpl(ChunkPosition chunkPosition, V value) { + EntryImpl reset(ChunkPosition chunkPosition, V value) { this.chunkPosition = chunkPosition; this.cachedValue = value; + return this; } @Override @@ -351,6 +373,7 @@ public final T next() { Entry> nextWorld = this.worldsIterator.next(); this.currWorldIterator = nextWorld.getValue().entryIterator(); this.currWorld = nextWorld.getKey(); + onWorldChange(); } Long2ObjectMapView.Entry nextChunk = this.currWorldIterator.next(); @@ -360,6 +383,10 @@ public final T next() { return getNext(); } + protected void onWorldChange() { + + } + protected abstract T getNext(); @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index fdc1259f1b..3128ddb248 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -43,6 +43,8 @@ @SuppressWarnings("unchecked") public class IslandsDatabaseBridge { + private static final Location LOCATION = new Location(null, 0, 100, 0); + private static final Map>> SAVE_METHODS_TO_BE_EXECUTED = new ConcurrentHashMap<>(); private IslandsDatabaseBridge() { @@ -348,7 +350,7 @@ public static void saveWarp(Island island, IslandWarp islandWarp) { new Pair<>("island", island.getUniqueId().toString()), new Pair<>("name", islandWarp.getName()), new Pair<>("category", category == null ? "" : category.getName()), - new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation())), + new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(LOCATION))), new Pair<>("private", islandWarp.hasPrivateFlag()), new Pair<>("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(icon)) )); @@ -364,7 +366,7 @@ public static void updateWarpName(Island island, IslandWarp islandWarp, String o public static void updateWarpLocation(Island island, IslandWarp islandWarp) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_warps", createFilter("island", island, new Pair<>("name", islandWarp.getName())), - new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation())) + new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(LOCATION))) )); } @@ -471,7 +473,7 @@ public static void saveGeneratedSchematics(Island island) { public static void saveDirtyChunks(DirtyChunksContainer dirtyChunksContainer) { runOperationIfRunning(dirtyChunksContainer.getIsland().getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", createFilter("uuid", dirtyChunksContainer.getIsland()), - new Pair<>("dirty_chunks", IslandsSerializer.serializeDirtyChunkPositions(dirtyChunksContainer.getDirtyChunks())) + new Pair<>("dirty_chunks", IslandsSerializer.serializeDirtyChunkPositions(dirtyChunksContainer)) )); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsSerializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsSerializer.java index 0fd2752fc2..0b94bb9ffd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsSerializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsSerializer.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.DirtyChunk; +import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; @@ -62,19 +63,29 @@ public static String serializeDirtyChunks(List dirtyChunks) { public static String serializeDirtyChunkPositions(List dirtyChunks) { JsonObject dirtyChunksObject = new JsonObject(); - dirtyChunks.forEach(dirtyChunk -> { - JsonArray dirtyChunksArray; - - if (dirtyChunksObject.has(dirtyChunk.getWorldName())) { - dirtyChunksArray = dirtyChunksObject.getAsJsonArray(dirtyChunk.getWorldName()); - } else { - dirtyChunksArray = new JsonArray(); - dirtyChunksObject.add(dirtyChunk.getWorldName(), dirtyChunksArray); - } + dirtyChunks.forEach(dirtyChunk -> + serializeDirtyChunkPosition(dirtyChunksObject, dirtyChunk)); + return gson.toJson(dirtyChunksObject); + } - dirtyChunksArray.add(new JsonPrimitive(dirtyChunk.getX() + "," + dirtyChunk.getZ())); - }); + public static String serializeDirtyChunkPositions(DirtyChunksContainer container) { + JsonObject dirtyChunksObject = new JsonObject(); + container.getDirtyChunks(dirtyChunk -> + serializeDirtyChunkPosition(dirtyChunksObject, dirtyChunk)); return gson.toJson(dirtyChunksObject); } + private static void serializeDirtyChunkPosition(JsonObject dirtyChunksObject, ChunkPosition dirtyChunk) { + JsonArray dirtyChunksArray; + + if (dirtyChunksObject.has(dirtyChunk.getWorldName())) { + dirtyChunksArray = dirtyChunksObject.getAsJsonArray(dirtyChunk.getWorldName()); + } else { + dirtyChunksArray = new JsonArray(); + dirtyChunksObject.add(dirtyChunk.getWorldName(), dirtyChunksArray); + } + + dirtyChunksArray.add(new JsonPrimitive(dirtyChunk.getX() + "," + dirtyChunk.getZ())); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/Keys.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/Keys.java index 6119c1f50d..fc96b088a6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/Keys.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/Keys.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.key.types.CustomKey; @@ -72,7 +73,9 @@ public static Key of(Block block) { baseKey = MaterialKey.of(blockType, data, MaterialKeySource.BLOCK); } - return plugin.getBlockValues().convertKey(baseKey, block.getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return plugin.getBlockValues().convertKey(baseKey, block.getLocation(wrapper.getHandle())); + } } public static Key of(BlockState blockState) { @@ -84,7 +87,9 @@ public static Key of(BlockState blockState) { baseKey = MaterialKey.of(blockState.getType(), data, MaterialKeySource.BLOCK); } - return plugin.getBlockValues().convertKey(baseKey, blockState.getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return plugin.getBlockValues().convertKey(baseKey, blockState.getLocation(wrapper.getHandle())); + } } public static Key of(Key baseKey, Location location) { @@ -103,7 +108,7 @@ public static Key of(ItemStack itemStack) { } public static Key of(Material type, short data) { - if(ServerVersion.isLessThan(ServerVersion.v1_21) || type == Materials.SPAWNER.toBukkitType()) { + if (ServerVersion.isLessThan(ServerVersion.v1_21) || type == Materials.SPAWNER.toBukkitType()) { return of(new ItemStack(type, 1, data)); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java index f882dc738f..47e142759d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.EventResult; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; @@ -29,15 +30,18 @@ public void onButtonClick(InventoryClickEvent clickEvent) { Player player = (Player) clickEvent.getWhoClicked(); IslandWarp islandWarp = menuView.getIslandWarp(); - Location playerLocation = player.getLocation(); + EventResult eventResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location playerLocation = player.getLocation(wrapper.getHandle()); - if (!islandWarp.getIsland().isInsideRange(playerLocation)) { - Message.SET_WARP_OUTSIDE.send(player); - return; - } + if (!islandWarp.getIsland().isInsideRange(playerLocation)) { + Message.SET_WARP_OUTSIDE.send(player); + return; + } - EventResult eventResult = plugin.getEventsBus().callIslandChangeWarpLocationEvent( - plugin.getPlayers().getSuperiorPlayer(player), islandWarp.getIsland(), islandWarp, playerLocation); + eventResult = plugin.getEventsBus().callIslandChangeWarpLocationEvent( + plugin.getPlayers().getSuperiorPlayer(player), islandWarp.getIsland(), islandWarp, playerLocation); + } if (eventResult.isCancelled()) return; @@ -45,12 +49,14 @@ public void onButtonClick(InventoryClickEvent clickEvent) { Message.WARP_LOCATION_UPDATE.send(player); - Location warpLocation = islandWarp.getLocation(); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location warpLocation = islandWarp.getLocation(wrapper.getHandle()); - if (!warpLocation.equals(eventResult.getResult())) { - ChunksProvider.loadChunk(ChunkPosition.of(warpLocation), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { - SignWarp.trySignWarpBreak(islandWarp, player); - }); + if (!warpLocation.equals(eventResult.getResult())) { + ChunksProvider.loadChunk(ChunkPosition.of(warpLocation), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { + SignWarp.trySignWarpBreak(islandWarp, player); + }); + } } islandWarp.setLocation(eventResult.getResult()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java index e2198520be..1274f5706f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; @@ -13,6 +14,7 @@ import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import org.bukkit.Location; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; @@ -45,12 +47,14 @@ public ItemStack modifyViewItem(ItemStack buttonItem) { if (menuView.hasManagePerms() && !Menus.MENU_WARPS.getEditLore().isEmpty()) itemBuilder.appendLore(Menus.MENU_WARPS.getEditLore()); - return itemBuilder.replaceAll("{0}", pagedObject.getName()) - .replaceAll("{1}", Formatters.LOCATION_FORMATTER.format(pagedObject.getLocation())) - .replaceAll("{2}", pagedObject.hasPrivateFlag() ? - ensureNotNull(Message.ISLAND_WARP_PRIVATE.getMessage(superiorPlayer.getUserLocale())) : - ensureNotNull(Message.ISLAND_WARP_PUBLIC.getMessage(superiorPlayer.getUserLocale()))) - .build(superiorPlayer); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return itemBuilder.replaceAll("{0}", pagedObject.getName()) + .replaceAll("{1}", Formatters.LOCATION_FORMATTER.format(pagedObject.getLocation(wrapper.getHandle()))) + .replaceAll("{2}", pagedObject.hasPrivateFlag() ? + ensureNotNull(Message.ISLAND_WARP_PRIVATE.getMessage(superiorPlayer.getUserLocale())) : + ensureNotNull(Message.ISLAND_WARP_PUBLIC.getMessage(superiorPlayer.getUserLocale()))) + .build(superiorPlayer); + } } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java index c546681092..4015758676 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java @@ -84,7 +84,7 @@ public void updateName() { } if (hologram == null) - hologram = hologramsService.get().createHologram(getLocation().add(0.5, 1, 0.5)); + hologram = hologramsService.get().createHologram(location.add(0.5, 1, 0.5)); hologram.setHologramName(plugin.getSettings().getStackedBlocks().getCustomName() .replace("{0}", String.valueOf(amount)) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java index aeeb2f50f0..4f6cfe81e3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.Manager; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; import com.bgsoftware.superiorskyblock.core.database.bridge.StackedBlocksDatabaseBridge; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; @@ -69,7 +70,9 @@ public void loadData() { @Override public int getStackedBlockAmount(Block block) { Preconditions.checkNotNull(block, "block parameter cannot be null."); - return getStackedBlockAmount(block.getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return getStackedBlockAmount(block.getLocation(wrapper.getHandle())); + } } @Override @@ -93,7 +96,9 @@ public Key getStackedBlockKey(Location location) { @Override public boolean setStackedBlock(Block block, int amount) { Preconditions.checkNotNull(block, "block parameter cannot be null."); - return setStackedBlock(block.getLocation(), Keys.of(block), amount); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return setStackedBlock(block.getLocation(wrapper.getHandle()), Keys.of(block), amount); + } } @Override @@ -153,7 +158,9 @@ public Map removeStackedBlocks(Chunk chunk) { @Override public Map removeStackedBlocks(World world, int chunkX, int chunkZ) { Preconditions.checkNotNull(world, "world parameter cannot be null."); - return removeStackedBlocks(ChunkPosition.of(WorldInfo.of(world), chunkX, chunkZ)); + try (ChunkPosition chunkPosition = ChunkPosition.of(WorldInfo.of(world), chunkX, chunkZ)) { + return removeStackedBlocks(chunkPosition); + } } public Map removeStackedBlocks(ChunkPosition chunkPosition) { @@ -184,12 +191,12 @@ public Map getStackedBlocks(Chunk chunk) { @Override public Map getStackedBlocks(World world, int chunkX, int chunkZ) { Preconditions.checkNotNull(world, "world parameter cannot be null."); - ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ); - Map chunkStackedBlocks = new LinkedHashMap<>(); - this.stackedBlocksContainer.forEach(chunkPosition, stackedBlock -> - chunkStackedBlocks.put(stackedBlock.getLocation(), stackedBlock.getAmount())); + try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) { + this.stackedBlocksContainer.forEach(chunkPosition, stackedBlock -> + chunkStackedBlocks.put(stackedBlock.getLocation(), stackedBlock.getAmount())); + } return Collections.unmodifiableMap(chunkStackedBlocks); } @@ -219,11 +226,13 @@ public void updateStackedBlockHologram(Location location) { @Override public void updateStackedBlockHolograms(Chunk chunk) { Preconditions.checkNotNull(chunk, "chunk parameter cannot be null."); - this.stackedBlocksContainer.forEach(ChunkPosition.of(chunk), stackedBlock -> { - stackedBlock.updateName(); - if (stackedBlock.getAmount() <= 1) - removeStackedBlock(stackedBlock.getLocation()); - }); + try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { + this.stackedBlocksContainer.forEach(chunkPosition, stackedBlock -> { + stackedBlock.updateName(); + if (stackedBlock.getAmount() <= 1) + removeStackedBlock(stackedBlock.getLocation()); + }); + } } @Override @@ -241,7 +250,9 @@ public void removeStackedBlockHologram(Location location) { @Override public void removeStackedBlockHolograms(Chunk chunk) { Preconditions.checkNotNull(chunk, "chunk parameter cannot be null."); - this.stackedBlocksContainer.forEach(ChunkPosition.of(chunk), StackedBlock::removeHologram); + try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { + this.stackedBlocksContainer.forEach(chunkPosition, StackedBlock::removeHologram); + } } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index 8597a403cb..a4d47243d4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.Manager; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; @@ -564,8 +565,10 @@ public Island getIslandAt(Chunk chunk) { if (!plugin.getGrid().isIslandsWorld(chunk.getWorld())) return null; - ChunkPosition chunkPosition = ChunkPosition.of(chunk); - Location cornerLocation = WorldBlocks.getChunkBlock(chunkPosition, 0, 100, 0); + Location cornerLocation; + try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { + cornerLocation = WorldBlocks.getChunkBlock(chunkPosition, 0, 100, 0); + } Island island; @@ -600,8 +603,10 @@ public List getIslandsAt(Chunk chunk) { Set islands = new LinkedHashSet<>(); - ChunkPosition chunkPosition = ChunkPosition.of(chunk); - Location cornerLocation = WorldBlocks.getChunkBlock(chunkPosition, 0, 100, 0); + Location cornerLocation; + try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { + cornerLocation = WorldBlocks.getChunkBlock(chunkPosition, 0, 100, 0); + } Island island; @@ -809,7 +814,9 @@ public List getIslands(SortingType sortingType) { @Deprecated public int getBlockAmount(Block block) { Preconditions.checkNotNull(block, "block parameter cannot be null."); - return getBlockAmount(block.getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return getBlockAmount(block.getLocation(wrapper.getHandle())); + } } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java index 31beae280b..4e55a3d597 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.EnumHelper; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; @@ -22,6 +23,7 @@ import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import org.bukkit.Chunk; +import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.event.inventory.InventoryType; @@ -85,7 +87,7 @@ public static List getChunkCoords(Island island, WorldInfo worldI for (int x = min.getX() >> 4; x <= max.getX() >> 4; x++) { for (int z = min.getZ() >> 4; z <= max.getZ() >> 4; z++) { if (!noEmptyChunks || island.isChunkDirty(worldInfo.getName(), x, z)) { - chunkCoords.add(ChunkPosition.of(worldInfo, x, z)); + chunkCoords.add(ChunkPosition.of(worldInfo, x, z, false)); } } } @@ -274,8 +276,10 @@ public static boolean handleBorderColorUpdate(SuperiorPlayer superiorPlayer, Bor return false; superiorPlayer.setBorderColor(borderColor); - plugin.getNMSWorld().setWorldBorder(superiorPlayer, - plugin.getGrid().getIslandAt(superiorPlayer.getLocation())); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + plugin.getNMSWorld().setWorldBorder(superiorPlayer, + plugin.getGrid().getIslandAt(superiorPlayer.getLocation(wrapper.getHandle()))); + } Message.BORDER_PLAYER_COLOR_UPDATED.send(superiorPlayer, Formatters.BORDER_COLOR_FORMATTER.format(borderColor, superiorPlayer.getUserLocale())); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 96b0cbd891..8de564ce63 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -42,6 +42,7 @@ import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.LegacyMasks; import com.bgsoftware.superiorskyblock.core.LocationKey; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; @@ -317,8 +318,11 @@ public SIsland(IslandBuilderImpl builder) { builder.dirtyChunks.forEach(dirtyChunk -> { try { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dirtyChunk.getWorldName()); - if (worldInfo != null) - this.dirtyChunksContainer.markDirty(ChunkPosition.of(worldInfo, dirtyChunk.getX(), dirtyChunk.getZ()), false); + if (worldInfo != null) { + try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, dirtyChunk.getX(), dirtyChunk.getZ())) { + this.dirtyChunksContainer.markDirty(chunkPosition, false); + } + } } catch (IllegalStateException ignored) { } }); @@ -626,10 +630,12 @@ public void banMember(SuperiorPlayer superiorPlayer, @Nullable SuperiorPlayer wh plugin.getMenus().refreshIslandBannedPlayers(this); - Location location = superiorPlayer.getLocation(); - - if (location != null && isInside(location)) - superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); + superiorPlayer.runIfOnline(player -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (isInside(player.getLocation(wrapper.getHandle()))) + superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); + } + }); IslandsDatabaseBridge.addBannedPlayer(this, superiorPlayer, whom == null ? CONSOLE_UUID : whom.getUniqueId(), @@ -681,15 +687,17 @@ public void removeCoop(SuperiorPlayer superiorPlayer) { if (!uncoopPlayer) return; - Location location = superiorPlayer.getLocation(); - - if (isLocked() && location != null && isInside(location)) { - MenuView openedView = superiorPlayer.getOpenedView(); - if (openedView != null) - openedView.closeView(); + superiorPlayer.runIfOnline(player -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (isLocked() && isInside(player.getLocation(wrapper.getHandle()))) { + MenuView openedView = superiorPlayer.getOpenedView(); + if (openedView != null) + openedView.closeView(); - superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); - } + superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); + } + } + }); plugin.getMenus().refreshCoops(this); } @@ -1351,10 +1359,10 @@ public boolean isInside(Location location, double extraRadius) { int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); - IslandArea islandArea = new IslandArea(this.center, islandDistance); - islandArea.expand(extraRadius); - - return islandArea.intercepts(location.getBlockX(), location.getBlockZ()); + try (IslandArea islandArea = IslandArea.of(this.center, islandDistance)) { + islandArea.expand(extraRadius); + return islandArea.intercepts(location.getBlockX(), location.getBlockZ()); + } } @Override @@ -1366,19 +1374,21 @@ public boolean isInside(World world, int chunkX, int chunkZ) { int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); - IslandArea islandArea = new IslandArea(this.center, islandDistance); - islandArea.rshift(4); - return islandArea.intercepts(chunkX, chunkZ); + try (IslandArea islandArea = IslandArea.of(this.center, islandDistance)) { + islandArea.rshift(4); + return islandArea.intercepts(chunkX, chunkZ); + } } private boolean isChunkInside(int chunkX, int chunkZ) { int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); - IslandArea islandArea = new IslandArea(this.center, islandDistance); - islandArea.rshift(4); - return islandArea.intercepts(chunkX, chunkZ); + try (IslandArea islandArea = IslandArea.of(this.center, islandDistance)) { + islandArea.rshift(4); + return islandArea.intercepts(chunkX, chunkZ); + } } @Override @@ -1399,10 +1409,10 @@ public boolean isInsideRange(Location location, double extraRadius) { if (!isIslandWorld(location.getWorld())) return false; - IslandArea islandArea = new IslandArea(center, getIslandSize()); - islandArea.expand(extraRadius); - - return islandArea.intercepts(location.getBlockX(), location.getBlockZ()); + try (IslandArea islandArea = IslandArea.of(this.center, getIslandSize())) { + islandArea.expand(extraRadius); + return islandArea.intercepts(location.getBlockX(), location.getBlockZ()); + } } @Override @@ -1412,10 +1422,10 @@ public boolean isInsideRange(Chunk chunk) { if (!isIslandWorld(chunk.getWorld())) return false; - IslandArea islandArea = new IslandArea(center, getIslandSize()); - islandArea.rshift(4); - - return islandArea.intercepts(chunk.getX(), chunk.getZ()); + try (IslandArea islandArea = IslandArea.of(this.center, getIslandSize())) { + islandArea.rshift(4); + return islandArea.intercepts(chunk.getX(), chunk.getZ()); + } } private boolean isIslandWorld(@Nullable World world) { @@ -1583,13 +1593,17 @@ public void setPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandP privilegeNode.setPermission(islandPrivilege, value); - if (superiorPlayer.isOnline() && isInside(superiorPlayer.getLocation())) { - if (islandPrivilege == IslandPrivileges.FLY) { - updateIslandFly(superiorPlayer); - } else if (islandPrivilege == IslandPrivileges.VILLAGER_TRADING) { - IslandUtils.updateTradingMenus(this, superiorPlayer); + superiorPlayer.runIfOnline(player -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (isInside(player.getLocation(wrapper.getHandle()))) { + if (islandPrivilege == IslandPrivileges.FLY) { + updateIslandFly(superiorPlayer); + } else if (islandPrivilege == IslandPrivileges.VILLAGER_TRADING) { + IslandUtils.updateTradingMenus(this, superiorPlayer); + } + } } - } + }); IslandsDatabaseBridge.savePlayerPermission(this, superiorPlayer, islandPrivilege, value); @@ -1945,19 +1959,19 @@ public Biome getBiome() { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, defaultWorldDimension); Location centerBlock = getCenter(defaultWorldDimension); - ChunkPosition centerChunkPosition = ChunkPosition.of(worldInfo, - centerBlock.getBlockX() >> 4, centerBlock.getBlockZ() >> 4); - - return ChunksProvider.loadChunk(centerChunkPosition, ChunkLoadReason.BIOME_REQUEST, null) - .thenApply(chunk -> centerBlock.getBlock().getBiome()) - .whenComplete((biome, error) -> { - if (error != null) - error.printStackTrace(); - else { - this.biome = biome; - biomeGetterTask.set((CompletableFuture) null); - } - }); + try (ChunkPosition centerChunkPosition = ChunkPosition.of(worldInfo, + centerBlock.getBlockX() >> 4, centerBlock.getBlockZ() >> 4)) { + return ChunksProvider.loadChunk(centerChunkPosition, ChunkLoadReason.BIOME_REQUEST, null) + .thenApply(chunk -> centerBlock.getBlock().getBiome()) + .whenComplete((biome, error) -> { + if (error != null) + error.printStackTrace(); + else { + this.biome = biome; + biomeGetterTask.set((CompletableFuture) null); + } + }); + } }); return IslandUtils.getDefaultWorldBiome(plugin.getSettings().getWorlds().getDefaultWorldDimension()); @@ -2670,21 +2684,27 @@ public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, worldName); Preconditions.checkArgument(worldInfo != null && isChunkInside(chunkX, chunkZ), "Chunk must be within the island boundaries."); - return this.dirtyChunksContainer.isMarkedDirty(ChunkPosition.of(worldInfo, chunkX, chunkZ)); + try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) { + return this.dirtyChunksContainer.isMarkedDirty(chunkPosition); + } } @Override public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(world, "world parameter cannot be null."); Preconditions.checkArgument(isInside(world, chunkX, chunkZ), "Chunk must be within the island boundaries."); - this.dirtyChunksContainer.markDirty(ChunkPosition.of(WorldInfo.of(world), chunkX, chunkZ), save); + try (ChunkPosition chunkPosition = ChunkPosition.of(WorldInfo.of(world), chunkX, chunkZ)) { + this.dirtyChunksContainer.markDirty(chunkPosition, save); + } } @Override public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(world, "world parameter cannot be null."); Preconditions.checkArgument(isInside(world, chunkX, chunkZ), "Chunk must be within the island boundaries."); - this.dirtyChunksContainer.markEmpty(ChunkPosition.of(WorldInfo.of(world), chunkX, chunkZ), save); + try (ChunkPosition chunkPosition = ChunkPosition.of(WorldInfo.of(world), chunkX, chunkZ)) { + this.dirtyChunksContainer.markEmpty(chunkPosition, save); + } } @Override @@ -3502,7 +3522,9 @@ public void renameWarp(IslandWarp islandWarp, String newName) { @Override public IslandWarp getWarp(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); - return warpsByLocation.get(new LocationKey(location)); + try (LocationKey locationKey = LocationKey.of(location)) { + return warpsByLocation.get(locationKey); + } } @Override @@ -3538,7 +3560,11 @@ public void warpPlayer(SuperiorPlayer superiorPlayer, String warp) { public void deleteWarp(@Nullable SuperiorPlayer superiorPlayer, Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); - IslandWarp islandWarp = warpsByLocation.remove(new LocationKey(location)); + IslandWarp islandWarp; + try (LocationKey locationKey = LocationKey.of(location)) { + islandWarp = warpsByLocation.remove(location); + } + if (islandWarp != null) { deleteWarp(islandWarp.getName()); if (superiorPlayer != null) @@ -3556,7 +3582,9 @@ public void deleteWarp(String name) { WarpCategory warpCategory = islandWarp == null ? null : islandWarp.getCategory(); if (islandWarp != null) { - warpsByLocation.remove(new LocationKey(islandWarp.getLocation())); + try (LocationKey locationKey = LocationKey.of(islandWarp)) { + warpsByLocation.remove(locationKey); + } warpCategory.getWarps().remove(islandWarp); IslandsDatabaseBridge.removeWarp(this, islandWarp); @@ -4387,7 +4415,7 @@ public IslandWarp loadIslandWarp(String name, LazyWorldLocation location, @Nulla warpsByName.put(warpName, islandWarp); - warpsByLocation.put(new LocationKey(location), islandWarp); + warpsByLocation.put(LocationKey.of(location, false), islandWarp); return islandWarp; } @@ -4505,41 +4533,43 @@ private void warpPlayerWithoutWarmup(SuperiorPlayer superiorPlayer, IslandWarp i return; } - Location location = islandWarp.getLocation(); - if (location.getWorld() == null) { - if (shouldRetryOnNullWorld && location instanceof LazyWorldLocation && - plugin.getProviders().getWorldsProvider() instanceof LazyWorldsProvider) { - LazyWorldsProvider worldsProvider = (LazyWorldsProvider) plugin.getProviders().getWorldsProvider(); - WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(this, ((LazyWorldLocation) location).getWorldName()); - worldsProvider.prepareWorld(this, worldInfo.getDimension(), - () -> warpPlayerWithoutWarmup(superiorPlayer, islandWarp, false)); - return; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = islandWarp.getLocation(wrapper.getHandle()); + if (location.getWorld() == null) { + if (shouldRetryOnNullWorld && location instanceof LazyWorldLocation && + plugin.getProviders().getWorldsProvider() instanceof LazyWorldsProvider) { + LazyWorldsProvider worldsProvider = (LazyWorldsProvider) plugin.getProviders().getWorldsProvider(); + WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(this, ((LazyWorldLocation) location).getWorldName()); + worldsProvider.prepareWorld(this, worldInfo.getDimension(), + () -> warpPlayerWithoutWarmup(superiorPlayer, islandWarp, false)); + return; + } } - } - superiorPlayer.setTeleportTask(null); + superiorPlayer.setTeleportTask(null); - if (!isInsideRange(location)) { - Message.UNSAFE_WARP.send(superiorPlayer); - if (plugin.getSettings().getDeleteUnsafeWarps()) - deleteWarp(islandWarp.getName()); - return; - } + if (!isInsideRange(location)) { + Message.UNSAFE_WARP.send(superiorPlayer); + if (plugin.getSettings().getDeleteUnsafeWarps()) + deleteWarp(islandWarp.getName()); + return; + } - if (!WorldBlocks.isSafeBlock(location.getBlock())) { - Message.UNSAFE_WARP.send(superiorPlayer); - return; - } + if (!WorldBlocks.isSafeBlock(location.getBlock())) { + Message.UNSAFE_WARP.send(superiorPlayer); + return; + } - superiorPlayer.teleport(location, success -> { - if (success) { - Message.TELEPORTED_TO_WARP.send(superiorPlayer); - if (superiorPlayer.isShownAsOnline()) { - IslandUtils.sendMessage(this, Message.TELEPORTED_TO_WARP_ANNOUNCEMENT, - Collections.singletonList(superiorPlayer.getUniqueId()), superiorPlayer.getName(), islandWarp.getName()); + superiorPlayer.teleport(location, success -> { + if (success) { + Message.TELEPORTED_TO_WARP.send(superiorPlayer); + if (superiorPlayer.isShownAsOnline()) { + IslandUtils.sendMessage(this, Message.TELEPORTED_TO_WARP_ANNOUNCEMENT, + Collections.singletonList(superiorPlayer.getUniqueId()), superiorPlayer.getName(), islandWarp.getName()); + } } - } - }); + }); + } } /* diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 20cb805611..6adc8d3890 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -154,7 +154,7 @@ public SpawnIsland() throws ManagerLoadException { this.islandSize = plugin.getSettings().getSpawn().getSize(); this.center = new SBlockPosition(worldName, smartCenter.getBlockX(), smartCenter.getBlockY(), smartCenter.getBlockZ()); - this.islandArea = new IslandArea(this.center, this.islandSize); + this.islandArea = IslandArea.of(this.center, this.islandSize, false); this.spawnWorldInfo = new WorldInfoImpl(this.spawnWorld.getName(), Dimensions.fromEnvironment(this.spawnWorld.getEnvironment())); this.homeYaw = smartCenter.getYaw(); @@ -505,7 +505,11 @@ public List getAllChunks(Dimension unused, @IslandChunkFlags int flags) { for (int x = minChunk.getX(); x <= maxChunk.getX(); x++) { for (int z = minChunk.getZ(); z <= maxChunk.getZ(); z++) { - if (!noEmptyChunks || this.dirtyChunksContainer.isMarkedDirty(ChunkPosition.of(this.spawnWorldInfo, x, z))) + boolean addChunk; + try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, x, z)) { + addChunk = !noEmptyChunks || this.dirtyChunksContainer.isMarkedDirty(chunkPosition); + } + if (addChunk) chunks.add(minChunk.getWorld().getChunkAt(x, z)); } } @@ -574,10 +578,13 @@ public List getLoadedChunks(Dimension unused, @IslandChunkFlags int flags for (int chunkX = min.getBlockX() >> 4; chunkX <= max.getBlockX() >> 4; chunkX++) { for (int chunkZ = min.getBlockZ() >> 4; chunkZ <= max.getBlockZ() >> 4; chunkZ++) { - if (this.spawnWorld.isChunkLoaded(chunkX, chunkZ) && (!noEmptyChunks || this.dirtyChunksContainer.isMarkedDirty( - ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)))) { - chunks.add(this.spawnWorld.getChunkAt(chunkX, chunkZ)); + boolean addChunk; + try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { + addChunk = this.spawnWorld.isChunkLoaded(chunkX, chunkZ) && + (!noEmptyChunks || this.dirtyChunksContainer.isMarkedDirty(chunkPosition)); } + if (addChunk) + chunks.add(this.spawnWorld.getChunkAt(chunkX, chunkZ)); } } @@ -774,13 +781,13 @@ public boolean isInside(Location location, double extraRadius) { if (!location.getWorld().equals(this.spawnWorld)) return false; - IslandArea islandArea = this.islandArea; - if (extraRadius != 0) { - islandArea = islandArea.copy(); - islandArea.expand(extraRadius); - } + try (IslandArea islandArea = this.islandArea.copy()) { + if (extraRadius != 0) { + islandArea.expand(extraRadius); + } - return islandArea.intercepts(location.getBlockX(), location.getBlockZ()); + return islandArea.intercepts(location.getBlockX(), location.getBlockZ()); + } } @Override @@ -789,9 +796,10 @@ public boolean isInside(World world, int chunkX, int chunkZ) { } public boolean isChunkInside(int chunkX, int chunkZ) { - IslandArea islandArea = this.islandArea.copy(); - islandArea.rshift(4); - return islandArea.intercepts(chunkX, chunkZ); + try (IslandArea islandArea = this.islandArea.copy()) { + islandArea.rshift(4); + return islandArea.intercepts(chunkX, chunkZ); + } } @Override @@ -1382,7 +1390,9 @@ public Map handleBlocksBreakWithResult(Map public boolean isChunkDirty(World world, int chunkX, int chunkZ) { Preconditions.checkNotNull(world, "world parameter cannot be null."); Preconditions.checkArgument(isInside(world, chunkX, chunkZ), "Chunk must be within the island boundaries."); - return this.dirtyChunksContainer.isMarkedDirty(ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)); + try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { + return this.dirtyChunksContainer.isMarkedDirty(chunkPosition); + } } @Override @@ -1390,21 +1400,27 @@ public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) { Preconditions.checkNotNull(worldName, "worldName parameter cannot be null."); Preconditions.checkArgument(this.spawnWorldInfo.getName().equals(worldName) && isChunkInside(chunkX, chunkZ), "Chunk must be within the island boundaries."); - return this.dirtyChunksContainer.isMarkedDirty(ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)); + try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { + return this.dirtyChunksContainer.isMarkedDirty(chunkPosition); + } } @Override public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(world, "world parameter cannot be null."); Preconditions.checkArgument(isInside(world, chunkX, chunkZ), "Chunk must be within the island boundaries."); - this.dirtyChunksContainer.markDirty(ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ), save); + try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { + this.dirtyChunksContainer.markDirty(chunkPosition, save); + } } @Override public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(world, "world parameter cannot be null."); Preconditions.checkArgument(isInside(world, chunkX, chunkZ), "Chunk must be within the island boundaries."); - this.dirtyChunksContainer.markEmpty(ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ), save); + try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { + this.dirtyChunksContainer.markEmpty(chunkPosition, save); + } } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java index edf659dbea..19cc038b5a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java @@ -76,8 +76,10 @@ public CompletableFuture calculateIsland(Island island) ChunkLoadReason.BLOCKS_RECALCULATE, plugin.getProviders()::takeSnapshots).forEach(completableFuture -> { CompletableFuture> calculateCompletable = new CompletableFuture<>(); completableFuture.whenComplete((chunk, ex) -> { - plugin.getNMSChunks().calculateChunks(Collections.singletonList(ChunkPosition.of(chunk)), CACHED_CALCULATED_CHUNKS) - .whenComplete((pair, ex2) -> calculateCompletable.complete(pair)); + try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { + plugin.getNMSChunks().calculateChunks(Collections.singletonList(chunkPosition), CACHED_CALCULATED_CHUNKS) + .whenComplete((pair, ex2) -> calculateCompletable.complete(pair)); + } }); chunksToLoad.add(calculateCompletable); }); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java index 20a02ac7c1..f3dd0528e5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.world.algorithm.IslandCreationAlgorithm; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.events.EventResult; import com.bgsoftware.superiorskyblock.core.logging.Debug; @@ -99,19 +100,22 @@ public CompletableFuture createIsland(Island.Builder build CompletableFuture completableFuture = new CompletableFuture<>(); - schematic.pasteSchematic(island, islandLocation.getBlock().getRelative(BlockFace.DOWN).getLocation(), () -> { - plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation, - builder.owner.getUniqueId(), builder.uuid); - completableFuture.complete(new IslandCreationResult(IslandCreationResult.Status.SUCCESS, island, islandLocation, event.getResult())); - island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); - Profiler.end(profiler); - }, error -> { - island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); - plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation, - builder.owner.getUniqueId(), builder.uuid); - completableFuture.completeExceptionally(error); - Profiler.end(profiler); - }); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = islandLocation.getBlock().getRelative(BlockFace.DOWN).getLocation(wrapper.getHandle()); + schematic.pasteSchematic(island, location, () -> { + plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation, + builder.owner.getUniqueId(), builder.uuid); + completableFuture.complete(new IslandCreationResult(IslandCreationResult.Status.SUCCESS, island, islandLocation, event.getResult())); + island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); + Profiler.end(profiler); + }, error -> { + island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); + plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation, + builder.owner.getUniqueId(), builder.uuid); + completableFuture.completeExceptionally(error); + Profiler.end(profiler); + }); + } return completableFuture; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/chunk/DirtyChunksContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/chunk/DirtyChunksContainer.java index b478e3603a..1f6f296737 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/chunk/DirtyChunksContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/chunk/DirtyChunksContainer.java @@ -6,15 +6,15 @@ import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.MutableChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; -import org.bukkit.World; import java.util.BitSet; import java.util.Collections; -import java.util.EnumMap; import java.util.LinkedList; import java.util.List; +import java.util.function.Consumer; public class DirtyChunksContainer { @@ -97,11 +97,11 @@ public void markDirty(ChunkPosition chunkPosition, boolean save) { } } - public List getDirtyChunks() { + public void getDirtyChunks(Consumer consumer) { if (this.dirtyChunks.isEmpty()) - return Collections.emptyList(); + return; - List dirtyChunkPositions = new LinkedList<>(); + MutableChunkPosition mutableChunkPosition = new MutableChunkPosition(); for (Dimension dimension : Dimension.values()) { BitSet dirtyChunks = this.dirtyChunks.get(dimension); @@ -111,13 +111,12 @@ public List getDirtyChunks() { for (int j = dirtyChunks.nextSetBit(0); j >= 0; j = dirtyChunks.nextSetBit(j + 1)) { int deltaX = j / this.chunksInXAxis; int deltaZ = j % this.chunksInXAxis; - dirtyChunkPositions.add(ChunkPosition.of(worldInfo, deltaX + this.minChunkX, deltaZ + this.minChunkZ)); + consumer.accept(mutableChunkPosition.reset(worldInfo, deltaX + this.minChunkX, deltaZ + this.minChunkZ)); } } } } - return dirtyChunkPositions; } private int getChunkIndex(ChunkPosition chunkPosition) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index 03f1ac1248..e3bbb42274 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -55,7 +55,7 @@ public void addIsland(Island island) { Preconditions.checkNotNull(defaultWorld, "Default world information cannot be null!"); - this.islandsByPositions.put(IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ()), island); + this.islandsByPositions.put(IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ(), false), island); if (plugin.getProviders().hasCustomWorldsSupport()) { // We don't know the logic of the custom worlds support, therefore we add a position @@ -83,7 +83,9 @@ public void removeIsland(Island island) { Preconditions.checkNotNull(defaultWorld, "Default world information cannot be null!"); - this.islandsByPositions.remove(IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ()), island); + try (IslandPosition islandPosition = IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ())) { + this.islandsByPositions.remove(islandPosition, island); + } if (plugin.getProviders().hasCustomWorldsSupport()) { for (Dimension dimension : Dimension.values()) { @@ -132,7 +134,10 @@ public int getIslandsAmount() { @Nullable @Override public Island getIslandAt(Location location) { - Island island = this.islandsByPositions.get(IslandPosition.of(location)); + Island island; + try (IslandPosition islandPosition = IslandPosition.of(location)) { + island = this.islandsByPositions.get(islandPosition); + } return island == null || !island.isInside(location) ? null : island; } @@ -240,7 +245,7 @@ private void runWithCustomWorld(WorldInfo defaultWorld, BlockPosition center, Is Dimension dimension, Consumer consumer) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); if (worldInfo != null && !worldInfo.equals(defaultWorld)) - consumer.accept(IslandPosition.of(worldInfo.getName(), center.getX(), center.getZ())); + consumer.accept(IslandPosition.of(worldInfo.getName(), center.getX(), center.getZ(), false)); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java b/src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java index fab569636b..618b188f32 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java @@ -48,7 +48,21 @@ public SuperiorPlayer getPlayer() { @Override public Location getLocation() { - return previewLocation; + return previewLocation.clone(); + } + + @Override + public Location getLocation(Location location) { + if (location != null) { + location.setWorld(this.previewLocation.getWorld()); + location.setX(this.previewLocation.getX()); + location.setY(this.previewLocation.getY()); + location.setZ(this.previewLocation.getZ()); + location.setYaw(this.previewLocation.getYaw()); + location.setPitch(this.previewLocation.getPitch()); + } + + return location; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java b/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java index 19e685c42f..d03ed3f481 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.EventResult; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -31,9 +32,11 @@ public static Result handleSignPlace(SuperiorPlayer superiorPlayer, Location war if (island == null) return new Result(Reason.NOT_IN_ISLAND, false); - Location playerLocation = superiorPlayer.getLocation(); - if (playerLocation != null) - warpLocation.setYaw(playerLocation.getYaw()); + superiorPlayer.runIfOnline(player -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + warpLocation.setYaw(player.getLocation(wrapper.getHandle()).getYaw()); + } + }); if (isWarpSign(warpLines[0])) { Reason reason = handleWarpSignPlace(superiorPlayer, island, warpLocation, warpLines, sendMessage); @@ -46,24 +49,27 @@ public static Result handleSignPlace(SuperiorPlayer superiorPlayer, Location war } public static Result handleSignBreak(SuperiorPlayer superiorPlayer, Sign sign) { - Island island = plugin.getGrid().getIslandAt(sign.getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location signLocation = sign.getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(signLocation); - if (island == null) - return new Result(Reason.NOT_IN_ISLAND, false); + if (island == null) + return new Result(Reason.NOT_IN_ISLAND, false); - IslandWarp islandWarp = island.getWarp(sign.getLocation()); + IslandWarp islandWarp = island.getWarp(signLocation); - if (islandWarp != null) { - if (!plugin.getEventsBus().callIslandDeleteWarpEvent(superiorPlayer, island, islandWarp)) - return new Result(Reason.EVENT_CANCELLED, true); - - island.deleteWarp(superiorPlayer, sign.getLocation()); - } else { - if (sign.getLine(0).equalsIgnoreCase(plugin.getSettings().getVisitorsSign().getActive())) { - if (!plugin.getEventsBus().callIslandRemoveVisitorHomeEvent(superiorPlayer, island)) + if (islandWarp != null) { + if (!plugin.getEventsBus().callIslandDeleteWarpEvent(superiorPlayer, island, islandWarp)) return new Result(Reason.EVENT_CANCELLED, true); - island.setVisitorsLocation(null); + island.deleteWarp(superiorPlayer, signLocation); + } else { + if (sign.getLine(0).equalsIgnoreCase(plugin.getSettings().getVisitorsSign().getActive())) { + if (!plugin.getEventsBus().callIslandRemoveVisitorHomeEvent(superiorPlayer, island)) + return new Result(Reason.EVENT_CANCELLED, true); + + island.setVisitorsLocation(null); + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java index 03645978ce..3c6380215e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java @@ -59,6 +59,20 @@ public Location getLocation() { return location.clone(); } + @Override + public Location getLocation(Location location) { + if (location != null) { + location.setWorld(this.location.getWorld()); + location.setX(this.location.getX()); + location.setY(this.location.getY()); + location.setZ(this.location.getZ()); + location.setYaw(this.location.getYaw()); + location.setPitch(this.location.getPitch()); + } + + return location; + } + @Override public void setLocation(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java index 074a4fa36d..1567d7ac2f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java @@ -2,7 +2,9 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; @@ -22,29 +24,32 @@ private SignWarp() { } public static void trySignWarpBreak(IslandWarp islandWarp, CommandSender commandSender) { - Block signBlock = islandWarp.getLocation().getBlock(); - BlockState blockState = signBlock.getState(); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location warpLocation = islandWarp.getLocation(wrapper.getHandle()); + Block signBlock = warpLocation.getBlock(); + BlockState blockState = signBlock.getState(); - // We check for a sign block at the warp's location. - if (!(blockState instanceof Sign)) - return; + // We check for a sign block at the warp's location. + if (!(blockState instanceof Sign)) + return; - Sign sign = (Sign) blockState; + Sign sign = (Sign) blockState; - List configSignWarp = new ArrayList<>(plugin.getSettings().getSignWarp()); - configSignWarp.replaceAll(line -> line.replace("{0}", islandWarp.getName())); - String[] signLines = sign.getLines(); + List configSignWarp = new ArrayList<>(plugin.getSettings().getSignWarp()); + configSignWarp.replaceAll(line -> line.replace("{0}", islandWarp.getName())); + String[] signLines = sign.getLines(); - for (int i = 0; i < signLines.length && i < configSignWarp.size(); ++i) { - if (!signLines[i].equals(configSignWarp.get(i))) - return; - } + for (int i = 0; i < signLines.length && i < configSignWarp.size(); ++i) { + if (!signLines[i].equals(configSignWarp.get(i))) + return; + } - // Detected warp sign - signBlock.setType(Material.AIR); - signBlock.getWorld().dropItemNaturally(signBlock.getLocation(), new ItemStack(Material.SIGN)); + // Detected warp sign + signBlock.setType(Material.AIR); + signBlock.getWorld().dropItemNaturally(warpLocation, new ItemStack(Material.SIGN)); - Message.DELETE_WARP_SIGN_BROKE.send(commandSender); + Message.DELETE_WARP_SIGN_BROKE.send(commandSender); + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index fabce0ed67..7188006829 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; @@ -100,17 +101,23 @@ public BlockChangesListener(SuperiorSkyblockPlugin plugin) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) private void onBlockPlace(BlockPlaceEvent e) { boolean shouldAvoidReplacedState = e.getBlockReplacedState().equals(e.getBlock().getState()); - this.worldRecordService.get().recordBlockPlace(Keys.of(e.getBlock()), - e.getBlock().getLocation(), plugin.getNMSWorld().getDefaultAmount(e.getBlock()), - shouldAvoidReplacedState ? null : e.getBlockReplacedState(), - REGULAR_RECORD_FLAGS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockPlace(Keys.of(e.getBlock()), + e.getBlock().getLocation(wrapper.getHandle()), + plugin.getNMSWorld().getDefaultAmount(e.getBlock()), + shouldAvoidReplacedState ? null : e.getBlockReplacedState(), + REGULAR_RECORD_FLAGS); + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) private void onBucketEmpty(PlayerBucketEmptyEvent e) { Key blockKey = Keys.ofMaterialAndData(e.getBucket().name().replace("_BUCKET", "")); - this.worldRecordService.get().recordBlockPlace(blockKey, e.getBlockClicked().getLocation(), 1, - null, REGULAR_RECORD_FLAGS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockPlace(blockKey, + e.getBlockClicked().getLocation(wrapper.getHandle()), 1, + null, REGULAR_RECORD_FLAGS); + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -133,15 +140,20 @@ private void onStructureGrow(StructureGrowEvent e) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockGrow(BlockGrowEvent e) { - this.worldRecordService.get().recordBlockPlace(Keys.of(e.getNewState()), e.getBlock().getLocation(), - 1, null, REGULAR_RECORD_FLAGS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockPlace(Keys.of(e.getNewState()), + e.getBlock().getLocation(wrapper.getHandle()), + 1, null, REGULAR_RECORD_FLAGS); + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) private void onBlockFrom(BlockFormEvent e) { - Location location = e.getNewState().getLocation(); - // Do not save block counts - this.worldRecordService.get().recordBlockBreak(Keys.of(e.getBlock()), location, 1, WorldRecordFlags.DIRTY_CHUNKS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = e.getNewState().getLocation(wrapper.getHandle()); + // Do not save block counts + this.worldRecordService.get().recordBlockBreak(Keys.of(e.getBlock()), location, 1, WorldRecordFlags.DIRTY_CHUNKS); + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -152,8 +164,11 @@ private void onPlayerInteract(PlayerInteractEvent e) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockSpread(BlockSpreadEvent e) { - this.worldRecordService.get().recordBlockPlace(Keys.of(e.getNewState()), e.getBlock().getLocation(), - 1, e.getBlock().getState(), REGULAR_RECORD_FLAGS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockPlace(Keys.of(e.getNewState()), + e.getBlock().getLocation(wrapper.getHandle()), + 1, e.getBlock().getState(), REGULAR_RECORD_FLAGS); + } } private void onMinecartPlace(PlayerInteractEvent e) { @@ -174,9 +189,13 @@ private void onMinecartPlace(PlayerInteractEvent e) { return; Key minecartBlockKey = getMinecartBlockKey(handItemType); - if (minecartBlockKey != null) - this.worldRecordService.get().recordBlockPlace(minecartBlockKey, e.getClickedBlock().getLocation(), - 1, null, REGULAR_RECORD_FLAGS); + if (minecartBlockKey != null) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockPlace(minecartBlockKey, + e.getClickedBlock().getLocation(wrapper.getHandle()), + 1, null, REGULAR_RECORD_FLAGS); + } + } } private void onSpawnerChange(PlayerInteractEvent e) { @@ -205,8 +224,10 @@ private void onSpawnerChange(PlayerInteractEvent e) { Key newSpawnerKey = Keys.of(block); if (!oldSpawnerKey.equals(newSpawnerKey)) { - this.worldRecordService.get().recordBlockPlace(newSpawnerKey, block.getLocation(), - 1, oldBlockState, REGULAR_RECORD_FLAGS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockPlace(newSpawnerKey, block.getLocation(wrapper.getHandle()), + 1, oldBlockState, REGULAR_RECORD_FLAGS); + } } }, 1L); } @@ -239,9 +260,12 @@ private void onMinecartPlaceByDispenser(BlockDispenseEvent e) { return; Key minecartBlockKey = getMinecartBlockKey(dispenseItemType); - if (minecartBlockKey != null) - this.worldRecordService.get().recordBlockPlace(minecartBlockKey, targetBlock.getLocation(), - 1, null, REGULAR_RECORD_FLAGS); + if (minecartBlockKey != null) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockPlace(minecartBlockKey, targetBlock.getLocation(wrapper.getHandle()), + 1, null, REGULAR_RECORD_FLAGS); + } + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -255,8 +279,10 @@ private void onEntityChangeBlock(EntityChangeBlockEvent e) { blockKey = Keys.of(e.getTo(), (byte) 0); } - this.worldRecordService.get().recordBlockPlace(blockKey, e.getBlock().getLocation(), 1, - e.getBlock().getState(), WorldRecordFlags.SAVE_BLOCK_COUNT); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockPlace(blockKey, e.getBlock().getLocation(wrapper.getHandle()), 1, + e.getBlock().getState(), WorldRecordFlags.SAVE_BLOCK_COUNT); + } } /* BLOCK BREAKS */ @@ -270,8 +296,10 @@ private void onBlockBreak(BlockBreakEvent e) { private void onEntityBlockDeath(EntityDeathEvent e) { if (e.getEntity() instanceof FallingBlock) { Key blockKey = plugin.getNMSAlgorithms().getFallingBlockType((FallingBlock) e.getEntity()); - this.worldRecordService.get().recordBlockBreak(blockKey, e.getEntity().getLocation(), - 1, REGULAR_RECORD_FLAGS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockBreak(blockKey, e.getEntity().getLocation(wrapper.getHandle()), + 1, REGULAR_RECORD_FLAGS); + } } } @@ -280,20 +308,25 @@ private void onBucketFill(PlayerBucketFillEvent e) { boolean isWaterLogged = plugin.getNMSWorld().isWaterLogged(e.getBlockClicked()); if (isWaterLogged || e.getBlockClicked().isLiquid()) { Key blockKey = isWaterLogged ? ConstantKeys.WATER : Keys.of(e.getBlockClicked()); - this.worldRecordService.get().recordBlockBreak(blockKey, e.getBlockClicked().getLocation(), - 1, REGULAR_RECORD_FLAGS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockBreak(blockKey, + e.getBlockClicked().getLocation(wrapper.getHandle()), + 1, REGULAR_RECORD_FLAGS); + } } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) private void onDragonEggDrop(ItemSpawnEvent e) { if (e.getEntity().getItemStack().getType() == Material.DRAGON_EGG) { - for (Entity nearby : e.getEntity().getNearbyEntities(2, 2, 2)) { - if (nearby instanceof FallingBlock) { - Key blockKey = plugin.getNMSAlgorithms().getFallingBlockType((FallingBlock) nearby); - this.worldRecordService.get().recordBlockBreak(blockKey, nearby.getLocation(), - 1, WorldRecordFlags.SAVE_BLOCK_COUNT); - return; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + for (Entity nearby : e.getEntity().getNearbyEntities(2, 2, 2)) { + if (nearby instanceof FallingBlock) { + Key blockKey = plugin.getNMSAlgorithms().getFallingBlockType((FallingBlock) nearby); + this.worldRecordService.get().recordBlockBreak(blockKey, nearby.getLocation(wrapper.getHandle()), + 1, WorldRecordFlags.SAVE_BLOCK_COUNT); + return; + } } } } @@ -351,8 +384,10 @@ private void onEntityExplode(EntityExplodeEvent e) { private void onMinecartBreak(VehicleDestroyEvent e) { if (e.getVehicle() instanceof Minecart) { Key blockKey = plugin.getNMSAlgorithms().getMinecartBlock((Minecart) e.getVehicle()); - this.worldRecordService.get().recordBlockBreak(blockKey, e.getVehicle().getLocation(), - 1, REGULAR_RECORD_FLAGS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockBreak(blockKey, e.getVehicle().getLocation(wrapper.getHandle()), + 1, REGULAR_RECORD_FLAGS); + } e.getVehicle().setMetadata("SSB-VehicleDestory", new FixedMetadataValue(plugin, true)); } } @@ -415,14 +450,17 @@ private class SpongeAbsorbListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSpongeAbsorb(org.bukkit.event.block.SpongeAbsorbEvent e) { - Location location = e.getBlock().getLocation(); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = e.getBlock().getLocation(wrapper.getHandle()); - if (alreadySpongeAbosrbCalled.contains(location)) - return; + if (alreadySpongeAbosrbCalled.contains(location)) + return; - worldRecordService.get().recordBlockPlace(ConstantKeys.WET_SPONGE, location, 1, - e.getBlock().getState(), WorldRecordFlags.SAVE_BLOCK_COUNT); - alreadySpongeAbosrbCalled.add(location); + worldRecordService.get().recordBlockPlace(ConstantKeys.WET_SPONGE, location, 1, + e.getBlock().getState(), WorldRecordFlags.SAVE_BLOCK_COUNT); + + alreadySpongeAbosrbCalled.add(location.clone()); + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java index 0471449ebc..263315b215 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; @@ -101,15 +102,15 @@ private void handleChunkLoad(Chunk chunk, boolean isNewChunk) { List chunkIslands = plugin.getGrid().getIslandsAt(chunk); chunkIslands.forEach(island -> { - if (!island.isSpawn()) - handleIslandChunkLoad(island, chunk, isNewChunk); + if (!island.isSpawn()) { + try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { + handleIslandChunkLoad(island, chunk, chunkPosition, isNewChunk); + } + } }); } - private void handleIslandChunkLoad(Island island, Chunk chunk, boolean isNewChunk) { - ChunkPosition chunkPosition = ChunkPosition.of(chunk); - - + private void handleIslandChunkLoad(Island island, Chunk chunk, ChunkPosition chunkPosition, boolean isNewChunk) { World world = chunk.getWorld(); Dimension dimension = plugin.getGrid().getIslandsWorldDimension(world); @@ -120,7 +121,7 @@ private void handleIslandChunkLoad(Island island, Chunk chunk, boolean isNewChun List playersToUpdate = new SequentialListBuilder() .filter(player -> player.getWorld().equals(world)) .build(island.getAllPlayersInside(), SuperiorPlayer::asPlayer); - plugin.getNMSChunks().setBiome(Collections.singletonList(ChunkPosition.of(chunk)), island.getBiome(), playersToUpdate); + plugin.getNMSChunks().setBiome(Collections.singletonList(chunkPosition), island.getBiome(), playersToUpdate); } } @@ -165,11 +166,13 @@ private void handleIslandChunkLoad(Island island, Chunk chunk, boolean isNewChun if (!island.getEntitiesTracker().canRecalculateEntityCounts()) recalculateEntities.set(false); - for (Entity entity : chunk.getEntities()) { - // We want to delete old holograms of stacked blocks + count entities for the chunk - if (entity instanceof ArmorStand && isOldHologram((ArmorStand) entity) && - plugin.getStackedBlocks().getStackedBlockAmount(entity.getLocation().subtract(0, 1, 0)) > 1) { - entity.remove(); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + for (Entity entity : chunk.getEntities()) { + // We want to delete old holograms of stacked blocks + count entities for the chunk + if (entity instanceof ArmorStand && isOldHologram((ArmorStand) entity) && + plugin.getStackedBlocks().getStackedBlockAmount(entity.getLocation(wrapper.getHandle()).subtract(0, 1, 0)) > 1) { + entity.remove(); + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java index 55d27a5241..5cb47eeb50 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java @@ -14,6 +14,7 @@ import com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; @@ -22,6 +23,7 @@ import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; @@ -125,7 +127,10 @@ private void onObsidianClick(PlayerInteractEvent e) { if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) return; - Island island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation(wrapper.getHandle())); + } if (island == null) return; @@ -138,8 +143,10 @@ private void onObsidianClick(PlayerInteractEvent e) { PlayerHand usedItem = BukkitItems.getHand(e); BukkitItems.setHandItem(e.getPlayer(), usedItem, inHandItem.getAmount() == 0 ? null : inHandItem); - BukkitItems.addItem(new ItemStack(Material.LAVA_BUCKET), e.getPlayer().getInventory(), - e.getPlayer().getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + BukkitItems.addItem(new ItemStack(Material.LAVA_BUCKET), e.getPlayer().getInventory(), + e.getPlayer().getLocation(wrapper.getHandle())); + } island.handleBlockBreak(ConstantKeys.OBSIDIAN, 1); @@ -158,7 +165,10 @@ public void onPlayerCommand(PlayerCommandPreprocessEvent e) { if (superiorPlayer.hasBypassModeEnabled()) return; - Island island = plugin.getGrid().getIslandAt(e.getPlayer().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getPlayer().getLocation(wrapper.getHandle())); + } if (island == null || island.isSpawn() || !island.isVisitor(superiorPlayer, true)) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java index b17b544634..8b125d46a7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; @@ -116,24 +117,28 @@ public boolean preventEntitySpawn(Location location, CreatureSpawnEvent.SpawnRea @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) private void onHangingBreakByEntity(HangingBreakByEntityEvent e) { - if (e.getCause() == HangingBreakEvent.RemoveCause.EXPLOSION) { - if (e.getRemover() instanceof Player) { - // Explosion was set by TNT. - if (preventAction(e.getEntity().getLocation(), IslandFlags.TNT_EXPLOSION)) { - e.setCancelled(true); - return; - } - } else if (e.getRemover() instanceof Ghast) { - // Explosion was set by TNT. - if (preventAction(e.getEntity().getLocation(), IslandFlags.GHAST_FIREBALL)) { - e.setCancelled(true); - return; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = e.getEntity().getLocation(wrapper.getHandle()); + + if (e.getCause() != HangingBreakEvent.RemoveCause.EXPLOSION) { + if (e.getRemover() instanceof Player) { + // Explosion was set by TNT. + if (preventAction(entityLocation, IslandFlags.TNT_EXPLOSION)) { + e.setCancelled(true); + return; + } + } else if (e.getRemover() instanceof Ghast) { + // Explosion was set by TNT. + if (preventAction(entityLocation, IslandFlags.GHAST_FIREBALL)) { + e.setCancelled(true); + return; + } } } - } - if (preventEntityExplosion(e.getRemover(), e.getEntity().getLocation())) { - e.setCancelled(true); + if (preventEntityExplosion(e.getRemover(), entityLocation)) { + e.setCancelled(true); + } } } @@ -145,8 +150,10 @@ private void onEntityExplode(EntityExplodeEvent e) { @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) private void onEntityChangeBlock(EntityChangeBlockEvent e) { - if (preventEntityExplosion(e.getEntity(), e.getBlock().getLocation())) - e.setCancelled(true); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventEntityExplosion(e.getEntity(), e.getBlock().getLocation(wrapper.getHandle()))) + e.setCancelled(true); + } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -193,14 +200,18 @@ public boolean preventEntityExplosion(Entity source, Location explodeLocation) { private void onBlockFlow(BlockFromToEvent e) { IslandFlag islandFlag = plugin.getNMSWorld().isWaterLogged(e.getBlock()) ? IslandFlags.WATER_FLOW : IslandFlags.LAVA_FLOW; - if (preventAction(e.getToBlock().getLocation(), islandFlag)) - e.setCancelled(true); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventAction(e.getToBlock().getLocation(wrapper.getHandle()), islandFlag)) + e.setCancelled(true); + } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) private void onCropsGrowth(BlockGrowEvent e) { - if (preventAction(e.getBlock().getLocation(), IslandFlags.CROPS_GROWTH)) - e.setCancelled(true); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventAction(e.getBlock().getLocation(wrapper.getHandle()), IslandFlags.CROPS_GROWTH)) + e.setCancelled(true); + } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) @@ -211,29 +222,46 @@ private void onTreeGrowth(StructureGrowEvent e) { @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) private void onFireSpread(BlockBurnEvent e) { - if (preventAction(e.getBlock().getLocation(), IslandFlags.FIRE_SPREAD)) - e.setCancelled(true); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventAction(e.getBlock().getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD)) + e.setCancelled(true); + } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) private void onBlockIgnite(BlockIgniteEvent e) { - if (e.getCause() == BlockIgniteEvent.IgniteCause.SPREAD && preventAction(e.getBlock().getLocation(), IslandFlags.FIRE_SPREAD)) - e.setCancelled(true); + if (e.getCause() != BlockIgniteEvent.IgniteCause.SPREAD) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventAction(e.getBlock().getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD)) + e.setCancelled(true); + } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) private void onEndermanGrief(EntityChangeBlockEvent e) { - if (e.getEntity() instanceof Enderman && preventAction(e.getBlock().getLocation(), IslandFlags.ENDERMAN_GRIEF)) - e.setCancelled(true); + if (!(e.getEntity() instanceof Enderman)) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventAction(e.getBlock().getLocation(wrapper.getHandle()), IslandFlags.ENDERMAN_GRIEF)) + e.setCancelled(true); + } } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) private void onEggLay(ItemSpawnEvent e) { - if (e.getEntity().getItemStack().getType() == Material.EGG && preventAction(e.getEntity().getLocation(), IslandFlags.EGG_LAY)) { - for (Entity entity : e.getEntity().getNearbyEntities(1, 1, 1)) { - if (entity instanceof Chicken) { - e.setCancelled(true); - return; + if (e.getEntity().getItemStack().getType() != Material.EGG) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventAction(e.getEntity().getLocation(wrapper.getHandle()), IslandFlags.EGG_LAY)) { + for (Entity entity : e.getEntity().getNearbyEntities(1, 1, 1)) { + if (entity instanceof Chicken) { + e.setCancelled(true); + return; + } } } } @@ -245,8 +273,10 @@ private void onPoisonAttack(ProjectileHitEvent e) { return; BukkitEntities.getPlayerSource(e.getEntity()).ifPresent(shooterPlayer -> { - if (!preventAction(e.getEntity().getLocation(), IslandFlags.PVP)) - return; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (!preventAction(e.getEntity().getLocation(wrapper.getHandle()), IslandFlags.PVP)) + return; + } List nearbyEntities = e.getEntity().getNearbyEntities(2, 2, 2); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java index c87e41b412..36b06a4373 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.Location; import org.bukkit.World; @@ -36,11 +37,13 @@ private void onMinecartRightClick(PlayerInteractAtEntityEvent e) { if (superiorPlayer.hasBypassModeEnabled()) return; - Location entityLocation = e.getRightClicked().getLocation(); - Island entityIsland = plugin.getGrid().getIslandAt(entityLocation); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = e.getRightClicked().getLocation(wrapper.getHandle()); + Island entityIsland = plugin.getGrid().getIslandAt(entityLocation); - if (entityIsland != null && entityIsland.isInsideRange(entityLocation, 1D)) - return; + if (entityIsland != null && entityIsland.isInsideRange(entityLocation, 1D)) + return; + } e.setCancelled(true); } @@ -56,11 +59,13 @@ private void onMinecartRightClick(VehicleEnterEvent e) { if (e.getEntered() instanceof Player && plugin.getPlayers().getSuperiorPlayer(e.getEntered()).hasBypassModeEnabled()) return; - Location vehicleLocation = e.getVehicle().getLocation(); - Island entityIsland = plugin.getGrid().getIslandAt(vehicleLocation); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location vehicleLocation = e.getVehicle().getLocation(wrapper.getHandle()); + Island entityIsland = plugin.getGrid().getIslandAt(vehicleLocation); - if (entityIsland != null && entityIsland.isInsideRange(vehicleLocation, 1D)) - return; + if (entityIsland != null && entityIsland.isInsideRange(vehicleLocation, 1D)) + return; + } e.setCancelled(true); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java index 9264a6bdb4..3db1c9e84e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java @@ -5,6 +5,8 @@ import com.bgsoftware.superiorskyblock.api.service.hologram.HologramsService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -30,7 +32,10 @@ private void onBlockRedstone(BlockRedstoneEvent e) { if (!plugin.getSettings().isDisableRedstoneOffline() && !plugin.getSettings().getAFKIntegrations().isDisableRedstone()) return; - Island island = plugin.getGrid().getIslandAt(e.getBlock().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); + } if (island == null || island.isSpawn()) return; @@ -48,7 +53,10 @@ private void onEntitySpawn(CreatureSpawnEvent e) { hologramsService.get().isHologram(e.getEntity())) return; - Island island = plugin.getGrid().getIslandAt(e.getEntity().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle())); + } if (island == null || island.isSpawn() || !island.getAllPlayersInside().stream().allMatch(SuperiorPlayer::isAFK)) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java index 12dd6a6a91..b1b63d7ba7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.EventResult; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; @@ -130,11 +131,15 @@ private void onPlayerJoin(PlayerJoinEvent e) { if (superiorPlayer.isShownAsOnline()) IslandNotifications.notifyPlayerJoin(superiorPlayer); - Location playerLocation = e.getPlayer().getLocation(); - Island island = plugin.getGrid().getIslandAt(playerLocation); + MoveResult moveResult; + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location playerLocation = e.getPlayer().getLocation(wrapper.getHandle()); + island = plugin.getGrid().getIslandAt(playerLocation); + moveResult = this.regionManagerService.get().handlePlayerJoin(superiorPlayer, playerLocation); + } - MoveResult moveResult = this.regionManagerService.get().handlePlayerJoin(superiorPlayer, playerLocation); boolean teleportToSpawn = moveResult != MoveResult.SUCCESS; BukkitExecutor.sync(() -> { @@ -146,7 +151,10 @@ private void onPlayerJoin(PlayerJoinEvent e) { plugin.getNMSPlayers().setSkinTexture(superiorPlayer); if (!superiorPlayer.hasBypassModeEnabled()) { - Island delayedIsland = plugin.getGrid().getIslandAt(e.getPlayer().getLocation()); + Island delayedIsland; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + delayedIsland = plugin.getGrid().getIslandAt(e.getPlayer().getLocation(wrapper.getHandle())); + } // Checking if the player is in the islands world, not inside an island. if ((delayedIsland == island && teleportToSpawn) || (plugin.getGrid().isIslandsWorld(superiorPlayer.getWorld()) && delayedIsland == null)) { @@ -203,7 +211,9 @@ private void onPlayerQuit(PlayerQuitEvent e) { } } - this.regionManagerService.get().handlePlayerQuit(superiorPlayer, e.getPlayer().getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.regionManagerService.get().handlePlayerQuit(superiorPlayer, e.getPlayer().getLocation(wrapper.getHandle())); + } // Remove all player chat-listeners PlayerChat.remove(e.getPlayer()); @@ -264,7 +274,10 @@ private void onPlayerTeleport(PlayerTeleportEvent e) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) private void onPlayerChangeWorld(PlayerChangedWorldEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getPlayer().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getPlayer().getLocation(wrapper.getHandle())); + } SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); if (island != null && superiorPlayer.hasIslandFlyEnabled() && !e.getPlayer().getAllowFlight() && @@ -287,7 +300,10 @@ private void onPlayerDamage(EntityDamageEvent e) { if (targetPlayer instanceof SuperiorNPCPlayer) return; - Island island = plugin.getGrid().getIslandAt(e.getEntity().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle())); + } SuperiorPlayer damagerPlayer = !(e instanceof EntityDamageByEntityEvent) ? null : BukkitEntities.getPlayerSource(((EntityDamageByEntityEvent) e).getDamager()) @@ -407,12 +423,15 @@ private void onSchematicSelection(PlayerInteractEvent e) { e.setCancelled(true); - if (e.getAction() == Action.RIGHT_CLICK_BLOCK || e.getAction() == Action.RIGHT_CLICK_AIR) { - Message.SCHEMATIC_RIGHT_SELECT.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(e.getClickedBlock().getLocation())); - superiorPlayer.setSchematicPos1(e.getClickedBlock()); - } else { - Message.SCHEMATIC_LEFT_SELECT.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(e.getClickedBlock().getLocation())); - superiorPlayer.setSchematicPos2(e.getClickedBlock()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = e.getClickedBlock().getLocation(wrapper.getHandle()); + if (e.getAction() == Action.RIGHT_CLICK_BLOCK || e.getAction() == Action.RIGHT_CLICK_AIR) { + Message.SCHEMATIC_RIGHT_SELECT.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(location)); + superiorPlayer.setSchematicPos1(e.getClickedBlock()); + } else { + Message.SCHEMATIC_LEFT_SELECT.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(location)); + superiorPlayer.setSchematicPos2(e.getClickedBlock()); + } } if (superiorPlayer.getSchematicPos1() != null && superiorPlayer.getSchematicPos2() != null) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java index ef2f8d6014..96532af9c6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer; @@ -77,7 +78,10 @@ public void onEntityPortalEnter(EntityPortalEnterEvent e) { // - Using an end portal in the end // - The target world is disabled - Island island = plugin.getGrid().getIslandAt(e.getEntity().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 3556e91d07..d37cfdfb54 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; @@ -229,8 +230,12 @@ public void onBrushUse(PlayerInteractEvent e) { return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction( - superiorPlayer, e.getClickedBlock().getLocation(), IslandPrivileges.BRUSH); + + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + interactionResult = this.protectionManager.get().handleCustomInteraction( + superiorPlayer, e.getClickedBlock().getLocation(wrapper.getHandle()), IslandPrivileges.BRUSH); + } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(true); } @@ -241,8 +246,12 @@ public void onChorusFruitConsume(PlayerItemConsumeEvent e) { return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handlePlayerConsumeChorusFruit( - superiorPlayer, e.getPlayer().getLocation()); + + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + interactionResult = this.protectionManager.get().handlePlayerConsumeChorusFruit( + superiorPlayer, e.getPlayer().getLocation(wrapper.getHandle())); + } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(true); } @@ -266,8 +275,11 @@ private void onMinecartPlace(PlayerInteractEvent e) { if ((Materials.isMinecart(handItemType) && Materials.isRail(clickedBlockType)) || Materials.isBoat(handItemType)) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, - e.getClickedBlock().getLocation(), IslandPrivileges.MINECART_PLACE); + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, + e.getClickedBlock().getLocation(wrapper.getHandle()), IslandPrivileges.MINECART_PLACE); + } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(true); } @@ -279,8 +291,11 @@ public void onWindChargeUse(ProjectileLaunchEvent e) { return; BukkitEntities.getPlayerSource(e.getEntity()).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(shooerPlayer -> { - InteractionResult interactionResult = this.protectionManager.get().handlePlayerUseWindCharge( - shooerPlayer, shooerPlayer.getLocation()); + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + interactionResult = this.protectionManager.get().handlePlayerUseWindCharge(shooerPlayer, + shooerPlayer.getLocation(wrapper.getHandle())); + } if (ProtectionHelper.shouldPreventInteraction(interactionResult, shooerPlayer, true)) e.setCancelled(true); }); @@ -360,10 +375,14 @@ public void onVillagerTrade(InventoryClickEvent e) { if (openInventory == null || openInventory.getType() != InventoryType.MERCHANT) return; - Location location = e.getWhoClicked().getLocation(); SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getWhoClicked()); - InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, - location, IslandPrivileges.VILLAGER_TRADING); + + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = e.getWhoClicked().getLocation(wrapper.getHandle()); + interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, + location, IslandPrivileges.VILLAGER_TRADING); + } if (ProtectionHelper.shouldPreventInteraction(interactionResult, null, false)) { e.setCancelled(true); e.getWhoClicked().closeInventory(); @@ -405,9 +424,13 @@ public void onVehicleEnter(VehicleEnterEvent e) { return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getEntered()); - Location vehicleLocation = e.getVehicle().getLocation(); - InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, - vehicleLocation, IslandPrivileges.MINECART_ENTER); + + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location vehicleLocation = e.getVehicle().getLocation(wrapper.getHandle()); + interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, + vehicleLocation, IslandPrivileges.MINECART_ENTER); + } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(true); } @@ -420,9 +443,12 @@ public void onVehicleOpen(InventoryOpenEvent e) { return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - Location minecartLocation = ((Minecart) inventoryHolder).getLocation(); - InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, - minecartLocation, IslandPrivileges.MINECART_OPEN); + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location minecartLocation = ((Minecart) inventoryHolder).getLocation(wrapper.getHandle()); + interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, + minecartLocation, IslandPrivileges.MINECART_OPEN); + } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(true); } @@ -461,8 +487,10 @@ public void onPearlTeleport(PlayerTeleportEvent e) { e.setCancelled(true); if (e.getPlayer().getGameMode() != GameMode.CREATIVE) { - BukkitItems.addItem(new ItemStack(Material.ENDER_PEARL), e.getPlayer().getInventory(), - e.getPlayer().getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + BukkitItems.addItem(new ItemStack(Material.ENDER_PEARL), e.getPlayer().getInventory(), + e.getPlayer().getLocation(wrapper.getHandle())); + } } } @@ -473,8 +501,13 @@ public void onPlayerFish(ProjectileLaunchEvent e) { BukkitEntities.getPlayerSource(e.getEntity()).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(fisherPlayer -> { IslandPrivilege islandPrivilege = e.getEntity() instanceof FishHook ? IslandPrivileges.FISH : IslandPrivileges.PICKUP_DROPS; - Location entityLocation = e.getEntity().getLocation(); - InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction(fisherPlayer, entityLocation, islandPrivilege); + + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = e.getEntity().getLocation(wrapper.getHandle()); + interactionResult = this.protectionManager.get().handleCustomInteraction(fisherPlayer, + entityLocation, islandPrivilege); + } if (ProtectionHelper.shouldPreventInteraction(interactionResult, fisherPlayer, true)) e.setCancelled(true); }); @@ -486,40 +519,47 @@ public void onProjectileHit(ProjectileHitEvent e) { Location location; IslandPrivilege islandPrivilege; Block hitBlock; + InteractionResult interactionResult; - if (e.getEntity() instanceof FishHook) { - if (!PROJECTILE_HIT_TARGET_ENTITY.isValid()) - return; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (e.getEntity() instanceof FishHook) { + if (!PROJECTILE_HIT_TARGET_ENTITY.isValid()) + return; - Entity hitEntity = PROJECTILE_HIT_TARGET_ENTITY.invoke(e); + Entity hitEntity = PROJECTILE_HIT_TARGET_ENTITY.invoke(e); - if (hitEntity == null) - return; + if (hitEntity == null) + return; - location = hitEntity.getLocation(); - islandPrivilege = BukkitEntities.getCategory(e.getEntityType()).getDamagePrivilege(); - hitBlock = null; - } else { - if (!PROJECTILE_HIT_EVENT_TARGET_BLOCK.isValid()) - return; + location = hitEntity.getLocation(wrapper.getHandle()); + islandPrivilege = BukkitEntities.getCategory(e.getEntityType()).getDamagePrivilege(); + hitBlock = null; + } else { + if (!PROJECTILE_HIT_EVENT_TARGET_BLOCK.isValid()) + return; - hitBlock = PROJECTILE_HIT_EVENT_TARGET_BLOCK.invoke(e); + hitBlock = PROJECTILE_HIT_EVENT_TARGET_BLOCK.invoke(e); - if (hitBlock == null || hitBlock.getType() != CHORUS_FLOWER) - return; + if (hitBlock == null || hitBlock.getType() != CHORUS_FLOWER) + return; - location = hitBlock.getLocation(); - islandPrivilege = IslandPrivileges.BREAK; - } + location = hitBlock.getLocation(wrapper.getHandle()); + islandPrivilege = IslandPrivileges.BREAK; + } - InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction(shooterPlayer, - location, islandPrivilege); + interactionResult = this.protectionManager.get().handleCustomInteraction(shooterPlayer, location, islandPrivilege); + } if (ProtectionHelper.shouldPreventInteraction(interactionResult, shooterPlayer, true)) { e.getEntity().remove(); if (hitBlock != null) { ICachedBlock cachedBlock = plugin.getNMSWorld().cacheBlock(hitBlock); hitBlock.setType(Material.AIR); - BukkitExecutor.sync(() -> cachedBlock.setBlock(hitBlock.getLocation()), 1L); + BukkitExecutor.sync(() -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + cachedBlock.setBlock(hitBlock.getLocation(wrapper.getHandle())); + } + cachedBlock.release(); + }, 1L); } } }); @@ -539,8 +579,11 @@ private void onWindChargeExplodeEvent(EntityExplodeEvent e) { IslandPrivilege islandPrivilege = blockType == CHORUS_FLOWER || blockType == POINTED_DRIPSTONE ? IslandPrivileges.BREAK : IslandPrivileges.INTERACT; - InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction(shooterPlayer, - block.getLocation(), islandPrivilege); + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + interactionResult = this.protectionManager.get().handleCustomInteraction(shooterPlayer, + block.getLocation(wrapper.getHandle()), islandPrivilege); + } if (ProtectionHelper.shouldPreventInteraction(interactionResult, shooterPlayer, true)) blocksIterator.remove(); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java index 623634267b..37cdc329a6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java @@ -2,9 +2,11 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; +import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; @@ -32,7 +34,11 @@ private void onSignPlace(SignChangeEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); String[] signLines = e.getLines().clone(); - IslandSigns.Result result = IslandSigns.handleSignPlace(superiorPlayer, e.getBlock().getLocation(), signLines, true); + IslandSigns.Result result; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + result = IslandSigns.handleSignPlace(superiorPlayer, + e.getBlock().getLocation(wrapper.getHandle()), signLines, true); + } switch (result.getReason()) { case NOT_IN_ISLAND: return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java index df5b5b75c2..aa2ee1d6c5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.key.Keys; @@ -179,17 +180,19 @@ public void onExplode(EntityExplodeEvent e) { blockItem = block.getState().getData().toItemStack(amount); - Location location = block.getLocation(); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = block.getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(location); - if (island != null) - island.handleBlockBreak(block, amount); + Island island = plugin.getGrid().getIslandAt(location); + if (island != null) + island.handleBlockBreak(block, amount); - plugin.getStackedBlocks().removeStackedBlock(location); - block.setType(Material.AIR); + plugin.getStackedBlocks().removeStackedBlock(location); + block.setType(Material.AIR); - // Dropping the item - block.getWorld().dropItemNaturally(location, blockItem); + // Dropping the item + block.getWorld().dropItemNaturally(location, blockItem); + } } } @@ -226,18 +229,20 @@ public void onGolemCreate(CreatureSpawnEvent e) { if (entityTemplateOffsets == null) return; - Location entityLocation = e.getEntity().getLocation(); - - if (plugin.getStackedBlocks().getStackedBlockAmount(entityLocation) > 1) { - e.setCancelled(true); - return; - } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = e.getEntity().getLocation(wrapper.getHandle()); - for (BlockOffset blockOffset : entityTemplateOffsets) { - if (plugin.getStackedBlocks().getStackedBlockAmount(blockOffset.applyToLocation(entityLocation)) > 1) { + if (plugin.getStackedBlocks().getStackedBlockAmount(entityLocation) > 1) { e.setCancelled(true); return; } + + for (BlockOffset blockOffset : entityTemplateOffsets) { + if (plugin.getStackedBlocks().getStackedBlockAmount(blockOffset.applyToLocation(entityLocation)) > 1) { + e.setCancelled(true); + return; + } + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java index 3865c2833d..3aafa2de02 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java @@ -1,8 +1,11 @@ package com.bgsoftware.superiorskyblock.listener; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import org.bukkit.Location; +import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -12,8 +15,8 @@ import org.bukkit.event.block.BlockSpreadEvent; import org.bukkit.event.world.StructureGrowEvent; -import java.util.LinkedList; import java.util.List; +import java.util.function.Function; public class WorldDestructionListener implements Listener { @@ -27,38 +30,48 @@ public WorldDestructionListener(SuperiorSkyblockPlugin plugin) { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onStructureGrow(StructureGrowEvent e) { Island island = plugin.getGrid().getIslandAt(e.getLocation()); - if (island != null && plugin.getGrid().isIslandsWorld(e.getLocation().getWorld())) - e.getBlocks().removeIf(blockState -> !island.isInsideRange(blockState.getLocation())); + if (island != null && plugin.getGrid().isIslandsWorld(e.getLocation().getWorld())) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + e.getBlocks().removeIf(blockState -> + !island.isInsideRange(blockState.getLocation(wrapper.getHandle()))); + } + } } //Checking for chorus flower spread outside island. @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) private void onBlockSpread(BlockSpreadEvent e) { - if (preventDestruction(e.getSource().getLocation()) || preventDestruction(e.getBlock().getLocation())) - e.setCancelled(true); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventDestruction(e.getSource().getLocation(wrapper.getHandle())) || + preventDestruction(e.getBlock().getLocation(wrapper.getHandle()))) + e.setCancelled(true); + } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onPistonExtend(BlockPistonExtendEvent e) { - List blockLocations = new LinkedList<>(); - e.getBlocks().forEach(block -> blockLocations.add(block.getRelative(e.getDirection()).getLocation())); - if (preventMultiDestruction(e.getBlock().getLocation(), blockLocations)) - e.setCancelled(true); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventMultiDestruction(e.getBlock().getLocation(wrapper.getHandle()), e.getBlocks(), null)) + e.setCancelled(true); + } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onPistonRetract(BlockPistonRetractEvent e) { - List blockLocations = new LinkedList<>(); - e.getBlocks().forEach(block -> blockLocations.add(block.getRelative(e.getDirection()).getLocation())); - if (preventMultiDestruction(e.getBlock().getLocation(), blockLocations)) - e.setCancelled(true); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventMultiDestruction(e.getBlock().getLocation(wrapper.getHandle()), e.getBlocks(), + block -> block.getRelative(e.getDirection()))) + e.setCancelled(true); + } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBlockFlow(BlockFromToEvent e) { - Location blockLocation = e.getBlock().getRelative(e.getFace()).getLocation(); - if (preventDestruction(blockLocation)) - e.setCancelled(true); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = e.getBlock().getRelative(e.getFace()).getLocation(wrapper.getHandle()); + if (preventDestruction(blockLocation)) + e.setCancelled(true); + } } /* INTERNAL */ @@ -68,15 +81,20 @@ private boolean preventDestruction(Location location) { return island == null ? plugin.getGrid().isIslandsWorld(location.getWorld()) : !island.isInsideRange(location); } - private boolean preventMultiDestruction(Location islandLocation, List blockLocations) { + private boolean preventMultiDestruction(Location islandLocation, List blockList, + @Nullable Function blockTransform) { Island island = plugin.getGrid().getIslandAt(islandLocation); if (island == null) return plugin.getGrid().isIslandsWorld(islandLocation.getWorld()); - for (Location blockLocation : blockLocations) { - if (!island.isInsideRange(blockLocation)) - return true; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + for (Block block : blockList) { + if (blockTransform != null) + block = blockTransform.apply(block); + if (!island.isInsideRange(block.getLocation(wrapper.getHandle()))) + return true; + } } return false; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java index 13ce27f161..ffc3b284d2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.core.Either; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Manager; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.EventResult; import com.bgsoftware.superiorskyblock.core.events.EventsBus; import com.bgsoftware.superiorskyblock.core.io.FileClassLoader; @@ -28,6 +29,7 @@ import com.bgsoftware.superiorskyblock.world.BukkitItems; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -328,8 +330,11 @@ public void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, .replaceAll("{2}", getIslandPlaceholder(missionsHolder)) .build(); toGive.setAmount(itemStack.getAmount()); - BukkitExecutor.ensureMain(() -> superiorPlayer.runIfOnline(player -> - BukkitItems.addItem(toGive, player.getInventory(), player.getLocation()))); + BukkitExecutor.ensureMain(() -> superiorPlayer.runIfOnline(player -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + BukkitItems.addItem(toGive, player.getInventory(), player.getLocation(wrapper.getHandle())); + } + })); } BukkitExecutor.ensureMain(() -> { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java index 5326099821..78d18de3d1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.EnumHelper; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.module.generators.GeneratorsModule; import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.GeneratorType; @@ -39,32 +40,34 @@ public void onBlockFormEvent(BlockFormEvent e) { if (!module.isEnabled()) return; - Location blockLocation = e.getBlock().getLocation(); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = e.getBlock().getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(blockLocation); + Island island = plugin.getGrid().getIslandAt(blockLocation); - if (island == null) - return; + if (island == null) + return; - GeneratorType generatorType = e.getNewState().getType() == BASALT_MATERIAL ? - GeneratorType.BASALT : GeneratorType.NORMAL; + GeneratorType generatorType = e.getNewState().getType() == BASALT_MATERIAL ? + GeneratorType.BASALT : GeneratorType.NORMAL; - if (e.getBlock().getType() != LAVA_MATERIAL || generatorType != GeneratorType.BASALT) - return; + if (e.getBlock().getType() != LAVA_MATERIAL || generatorType != GeneratorType.BASALT) + return; - Dimension dimension; - if (module.isMatchGeneratorWorld()) { - dimension = Dimensions.NETHER; - } else { - World blockWorld = blockLocation.getWorld(); - dimension = Optional.ofNullable(plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(blockWorld)) - .orElseGet(() -> Dimensions.fromEnvironment(blockWorld.getEnvironment())); - } + Dimension dimension; + if (module.isMatchGeneratorWorld()) { + dimension = Dimensions.NETHER; + } else { + World blockWorld = blockLocation.getWorld(); + dimension = Optional.ofNullable(plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(blockWorld)) + .orElseGet(() -> Dimensions.fromEnvironment(blockWorld.getEnvironment())); + } - Key generatedBlock = island.generateBlock(blockLocation, dimension, true); + Key generatedBlock = island.generateBlock(blockLocation, dimension, true); - if (generatedBlock != null && !generatedBlock.equals(generatorType.getDefaultBlock())) - e.setCancelled(true); + if (generatedBlock != null && !generatedBlock.equals(generatorType.getDefaultBlock())) + e.setCancelled(true); + } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) @@ -79,33 +82,35 @@ public void onBlockFromToEvent(BlockFromToEvent e) { if (block.getType().isSolid()) return; - Location blockLocation = block.getLocation(); - World blockWorld = blockLocation.getWorld(); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = block.getLocation(wrapper.getHandle()); + World blockWorld = blockLocation.getWorld(); - Island island = plugin.getGrid().getIslandAt(blockLocation); + Island island = plugin.getGrid().getIslandAt(blockLocation); - if (island == null) - return; + if (island == null) + return; - if (e.getBlock().getType() != LAVA_MATERIAL) - return; + if (e.getBlock().getType() != LAVA_MATERIAL) + return; - GeneratorType generatorType = GeneratorType.detectGenerator(block); - if (generatorType == GeneratorType.NONE) - return; + GeneratorType generatorType = GeneratorType.detectGenerator(block); + if (generatorType == GeneratorType.NONE) + return; - Dimension dimension; - if (module.isMatchGeneratorWorld()) { - dimension = generatorType == GeneratorType.BASALT ? Dimensions.NETHER : Dimensions.NORMAL; - } else { - dimension = Optional.ofNullable(plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(blockWorld)) - .orElseGet(() -> Dimensions.fromEnvironment(blockWorld.getEnvironment())); - } + Dimension dimension; + if (module.isMatchGeneratorWorld()) { + dimension = generatorType == GeneratorType.BASALT ? Dimensions.NETHER : Dimensions.NORMAL; + } else { + dimension = Optional.ofNullable(plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(blockWorld)) + .orElseGet(() -> Dimensions.fromEnvironment(blockWorld.getEnvironment())); + } - Key generatedBlock = island.generateBlock(blockLocation, dimension, true); + Key generatedBlock = island.generateBlock(blockLocation, dimension, true); - if (generatedBlock != null && !generatedBlock.equals(generatorType.getDefaultBlock())) - e.setCancelled(true); + if (generatedBlock != null && !generatedBlock.equals(generatorType.getDefaultBlock())) + e.setCancelled(true); + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java index 407780d74c..870fdac826 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java @@ -6,13 +6,14 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Location; import org.bukkit.Material; @@ -56,8 +57,10 @@ private class BlockLimitsListener implements Listener { @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onBlockPlace(BlockPlaceEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getBlockPlaced().getLocation()); - + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlockPlaced().getLocation(wrapper.getHandle())); + } if (island == null) return; @@ -89,10 +92,12 @@ public void onCartPlace(PlayerInteractEvent e) { MutableObject minecraftKey = new MutableObject<>(null); - if (preventMinecartPlace(handItemType, e.getClickedBlock().getLocation(), minecraftKey)) { - e.setCancelled(true); - Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format( - minecraftKey.getValue().getGlobalKey())); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventMinecartPlace(handItemType, e.getClickedBlock().getLocation(wrapper.getHandle()), minecraftKey)) { + e.setCancelled(true); + Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format( + minecraftKey.getValue().getGlobalKey())); + } } } @@ -123,8 +128,10 @@ private void onMinecartPlaceByDispenser(BlockDispenseEvent e) { if (!Materials.isRail(targetBlock.getType())) return; - if (preventMinecartPlace(dispenseItemType, targetBlock.getLocation(), null)) - e.setCancelled(true); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventMinecartPlace(dispenseItemType, targetBlock.getLocation(wrapper.getHandle()), null)) + e.setCancelled(true); + } } @@ -169,8 +176,10 @@ private boolean preventMinecartPlace(Material minecartType, Location location, @ @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onBucketEmpty(PlayerBucketEmptyEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getBlockClicked().getLocation()); - + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlockClicked().getLocation(wrapper.getHandle())); + } if (island == null) return; @@ -184,7 +193,10 @@ public void onBucketEmpty(PlayerBucketEmptyEvent e) { @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onBlockGrow(BlockGrowEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getBlock().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java index 194278de83..f6660649db 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java @@ -3,8 +3,10 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddCropGrowth; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetCropGrowth; +import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -40,9 +42,12 @@ private class CropGrowthListener implements Listener { // Should potentially fix crop growth tile entities "disappearing" @EventHandler(priority = EventPriority.LOWEST) public void onBlockGrow(BlockGrowEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getBlock().getLocation()); - if (island != null && island.isInsideRange(e.getBlock().getLocation())) - plugin.getNMSChunks().startTickingChunk(island, e.getBlock().getChunk(), false); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = e.getBlock().getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(blockLocation); + if (island != null && island.isInsideRange(blockLocation)) + plugin.getNMSChunks().startTickingChunk(island, e.getBlock().getChunk(), false); + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java index ad83ca3959..2563ae6d37 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.LocationKey; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalMap; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; @@ -33,6 +34,7 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.vehicle.VehicleCreateEvent; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; import java.lang.ref.WeakReference; import java.util.Collections; @@ -105,8 +107,12 @@ public void onEntitySpawn(CreatureSpawnEvent e) { if (spawningPlayer != null && spawningPlayer.isOnline()) { Message.REACHED_ENTITY_LIMIT.send(spawningPlayer, Formatters.CAPITALIZED_FORMATTER.format(entityType.toString())); List itemsToGiveBack = spawningPlayerData.itemStacks; - for (ItemStack itemStack : itemsToGiveBack) { - BukkitItems.addItem(itemStack, spawningPlayer.getInventory(), spawningPlayer.getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = spawningPlayer.getLocation(wrapper.getHandle()); + PlayerInventory inventory = spawningPlayer.getInventory(); + for (ItemStack itemStack : itemsToGiveBack) { + BukkitItems.addItem(itemStack, inventory, location); + } } } } @@ -120,7 +126,10 @@ public void onHangingPlace(HangingPlaceEvent e) { if (BukkitEntities.canBypassEntityLimit(entity) || !BukkitEntities.canHaveLimit(entityType)) return; - Island island = plugin.getGrid().getIslandAt(entity.getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle())); + } if (island == null) return; @@ -154,18 +163,18 @@ public void onVehicleSpawn(PlayerInteractEvent e) { if (!isMinecart && !isBoat) return; - Location blockLocation = e.getClickedBlock().getLocation(); - Island island = plugin.getGrid().getIslandAt(blockLocation); + LocationKey futureEntitySpawnLocation; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = e.getClickedBlock().getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(blockLocation); - if (island == null) - return; + if (island == null) + return; - LocationKey futureEntitySpawnLocation = isMinecart ? new LocationKey(blockLocation) : new LocationKey( - blockLocation.getWorld().getName(), - blockLocation.getX(), - blockLocation.getY() + 1, - blockLocation.getZ() - ); + futureEntitySpawnLocation = isMinecart ? LocationKey.of(blockLocation, false) : + LocationKey.of(blockLocation.getWorld().getName(), blockLocation.getX(), + blockLocation.getY() + 1, blockLocation.getZ(), false); + } vehiclesOwners.put(futureEntitySpawnLocation, new SpawningPlayerData(e.getPlayer())); } @@ -178,19 +187,23 @@ public void onVehicleSpawn(VehicleCreateEvent e) { if (BukkitEntities.canBypassEntityLimit(entity) || !BukkitEntities.canHaveLimit(entityType)) return; - Location entityLocation = entity.getLocation(); + Island island; + LocationKey entityBlockLocation; - Island island = plugin.getGrid().getIslandAt(entityLocation); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = entity.getLocation(wrapper.getHandle()); + island = plugin.getGrid().getIslandAt(entityLocation); - if (island == null) - return; + if (island == null) + return; - LocationKey entityBlockLocation = new LocationKey( - entityLocation.getWorld().getName(), - entityLocation.getBlockX(), - entityLocation.getBlockY(), - entityLocation.getBlockZ() - ); + entityBlockLocation = LocationKey.of( + entityLocation.getWorld().getName(), + entityLocation.getBlockX(), + entityLocation.getBlockY(), + entityLocation.getBlockZ() + ); + } SpawningPlayerData vehicleOwnerData = vehiclesOwners.remove(entityBlockLocation); Player vehicleOwner = vehicleOwnerData == null ? null : vehicleOwnerData.player.get(); @@ -219,8 +232,10 @@ public void onSpawnEggUse(PlayerInteractEvent e) { if (spawnEggEntityType == EntityType.UNKNOWN || !BukkitEntities.canHaveLimit(spawnEggEntityType)) return; - Island island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation()); - + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation(wrapper.getHandle())); + } if (island == null) return; @@ -259,7 +274,10 @@ public void onEntityBreed(EntityBreedEvent e) { if (!(e.getBreeder() instanceof Player) || !BukkitEntities.canHaveLimit(childEntityType)) return; - Island island = plugin.getGrid().getIslandAt(child.getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(child.getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeIslandEffects.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeIslandEffects.java index b2e4f6e4d5..5181b6dcb7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeIslandEffects.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeIslandEffects.java @@ -3,9 +3,11 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddEffect; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetEffect; +import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -46,7 +48,10 @@ public void onPlayerEffect(EntityPotionEffectEvent e) { e.getCause() == EntityPotionEffectEvent.Cause.PLUGIN || e.getCause() == EntityPotionEffectEvent.Cause.BEACON) return; - Island island = plugin.getGrid().getIslandAt(e.getEntity().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java index bb164d5752..c9aeaf640d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java @@ -3,10 +3,12 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddMobDrops; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetMobDrops; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; @@ -65,7 +67,10 @@ public void onLastDamageEntity(EntityDamageEvent e) { if (livingEntity.getHealth() - e.getFinalDamage() > 0) return; - Island island = plugin.getGrid().getIslandAt(livingEntity.getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(livingEntity.getLocation(wrapper.getHandle())); + } if (island == null) return; @@ -77,7 +82,10 @@ public void onEntityDeath(EntityDeathEvent e) { if (!canDupeDropsForEntity(e.getEntity())) return; - Island island = plugin.getGrid().getIslandAt(e.getEntity().getLocation()); + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle())); + } if (island == null) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/ICachedBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/ICachedBlock.java index dc54bf2454..8bd3099fe7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/ICachedBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/ICachedBlock.java @@ -1,8 +1,9 @@ package com.bgsoftware.superiorskyblock.nms; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import org.bukkit.Location; -public interface ICachedBlock { +public interface ICachedBlock extends ObjectsPool.Releasable { void setBlock(Location location); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java index 8d63738c9f..ee35617cca 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java @@ -3,13 +3,14 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import org.bukkit.Chunk; import org.bukkit.Location; import java.util.List; -public interface WorldEditSession { +public interface WorldEditSession extends ObjectsPool.Releasable { void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag blockEntityData); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index 2008a037bb..4977407b91 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Counter; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; @@ -129,7 +130,10 @@ private static HitActionResult checkPvPAllow(SuperiorPlayer player, boolean targ if (player.hasPlayerStatus(PlayerStatus.PVP_IMMUNED)) return target ? HitActionResult.TARGET_PVP_WARMUP : HitActionResult.PVP_WARMUP; - Island standingIsland = plugin.getGrid().getIslandAt(player.getLocation()); + Island standingIsland; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + standingIsland = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); + } if (standingIsland != null && (plugin.getSettings().getSpawn().isProtected() || !standingIsland.isSpawn())) { // Checks for pvp status @@ -378,8 +382,8 @@ public HitActionResult canHit(SuperiorPlayer otherPlayer) { @Override public World getWorld() { - Location location = getLocation(); - return location == null ? null : location.getWorld(); + Player player = asPlayer(); + return player == null ? null : player.getWorld(); } @Override @@ -388,6 +392,17 @@ public Location getLocation() { return player == null ? null : player.getLocation(); } + @Override + public Location getLocation(@Nullable Location location) { + if (location != null) { + Player player = asPlayer(); + if (player != null) + player.getLocation(location); + } + + return location; + } + @Override public void teleport(Location location) { teleport(location, null); @@ -455,7 +470,9 @@ public void teleport(Island island, World.Environment environment, @Nullable Con public boolean isInsideIsland() { Player player = asPlayer(); Island island = getIsland(); - return player != null && island != null && island.isInside(player.getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return player != null && island != null && island.isInside(player.getLocation(wrapper.getHandle())); + } } /* @@ -769,8 +786,10 @@ public BlockPosition getSchematicPos1() { @Override public void setSchematicPos1(@Nullable Block block) { - Log.debug(Debug.SET_SCHEMATIC_POSITION, getName(), block == null ? "null" : block.getLocation()); - this.schematicPos1 = block == null ? null : new SBlockPosition(block.getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Log.debug(Debug.SET_SCHEMATIC_POSITION, getName(), block == null ? "null" : block.getLocation(wrapper.getHandle())); + } + this.schematicPos1 = block == null ? null : new SBlockPosition(block); } @Override @@ -780,8 +799,10 @@ public SBlockPosition getSchematicPos2() { @Override public void setSchematicPos2(@Nullable Block block) { - Log.debug(Debug.SET_SCHEMATIC_POSITION, getName(), block == null ? "null" : block.getLocation()); - this.schematicPos2 = block == null ? null : new SBlockPosition(block.getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Log.debug(Debug.SET_SCHEMATIC_POSITION, getName(), block == null ? "null" : block.getLocation(wrapper.getHandle())); + } + this.schematicPos2 = block == null ? null : new SBlockPosition(block); } /* diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java index 4d4be14362..9aa0d09c87 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java @@ -153,7 +153,7 @@ public HitActionResult canHit(SuperiorPlayer other) { @Override public World getWorld() { - return npc.getLocation().getWorld(); + return npc.getWorld(); } @Override @@ -161,6 +161,11 @@ public Location getLocation() { return npc.getLocation(); } + @Override + public Location getLocation(Location location) { + return this.npc.getLocation(location); + } + @Override public void teleport(Location location) { // Do nothing. diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index 19a41e657a..42ae51b181 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlayerPlaceholderParser; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; @@ -21,6 +22,7 @@ import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.service.IService; import com.google.common.collect.ImmutableMap; +import org.bukkit.Location; import org.bukkit.OfflinePlayer; import java.time.Duration; @@ -256,8 +258,14 @@ public String handlePluginPlaceholder(@Nullable OfflinePlayer offlinePlayer, Str IslandPlaceholderParser customIslandParser = CUSTOM_ISLAND_PARSERS.get( isLocationPlaceholder ? placeholder.substring(9) : placeholder); if (customIslandParser != null) { - Island island = isLocationPlaceholder ? plugin.getGrid().getIslandAt(superiorPlayer.getLocation()) : - superiorPlayer.getIsland(); + Island island; + if (isLocationPlaceholder) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(superiorPlayer.getLocation(wrapper.getHandle())); + } + } else { + island = superiorPlayer.getIsland(); + } placeholderResult = Optional.ofNullable(customIslandParser.apply(island, superiorPlayer)); } } @@ -269,8 +277,16 @@ public String handlePluginPlaceholder(@Nullable OfflinePlayer offlinePlayer, Str placeholderResult = parsePlaceholdersForPlayer(superiorPlayer, subPlaceholder); } else if ((matcher = ISLAND_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String subPlaceholder = matcher.group(1).toLowerCase(Locale.ENGLISH); - Island island = superiorPlayer == null ? null : subPlaceholder.startsWith("location_") ? - plugin.getGrid().getIslandAt(superiorPlayer.getLocation()) : superiorPlayer.getIsland(); + Island island; + if (superiorPlayer == null) { + island = null; + } else if (subPlaceholder.startsWith("location_")) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(superiorPlayer.getLocation(wrapper.getHandle())); + } + } else { + island = superiorPlayer.getIsland(); + } placeholderResult = parsePlaceholdersForIsland(island, superiorPlayer, placeholder.replace("location_", ""), subPlaceholder.replace("location_", "")); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 11e83ebc29..eb725eb28c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -17,6 +17,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; @@ -115,10 +116,12 @@ public InteractionResult handleBlockPlace(SuperiorPlayer superiorPlayer, Block b Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); - Location blockLocation = block.getLocation(); - Island island = plugin.getGrid().getIslandAt(blockLocation); - - return handleInteractionInternal(superiorPlayer, blockLocation, island, IslandPrivileges.BUILD, 0, true, true); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = block.getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(blockLocation); + return handleInteractionInternal(superiorPlayer, blockLocation, island, IslandPrivileges.BUILD, + 0, true, true); + } } @Override @@ -126,22 +129,24 @@ public InteractionResult handleBlockBreak(SuperiorPlayer superiorPlayer, Block b Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); - Location blockLocation = block.getLocation(); - Island island = plugin.getGrid().getIslandAt(blockLocation); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = block.getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(blockLocation); - Material blockType = block.getType(); - IslandPrivilege islandPrivilege = blockType == Materials.SPAWNER.toBukkitType() ? IslandPrivileges.SPAWNER_BREAK : IslandPrivileges.BREAK; + Material blockType = block.getType(); + IslandPrivilege islandPrivilege = blockType == Materials.SPAWNER.toBukkitType() ? IslandPrivileges.SPAWNER_BREAK : IslandPrivileges.BREAK; - InteractionResult interactionResult = handleInteractionInternal(superiorPlayer, blockLocation, island, islandPrivilege, 0, true, true); + InteractionResult interactionResult = handleInteractionInternal(superiorPlayer, blockLocation, island, islandPrivilege, 0, true, true); - if (interactionResult != InteractionResult.SUCCESS) - return interactionResult; + if (interactionResult != InteractionResult.SUCCESS) + return interactionResult; - if (island == null) - return InteractionResult.SUCCESS; + if (island == null) + return InteractionResult.SUCCESS; - if (plugin.getSettings().getValuableBlocks().contains(Keys.of(block))) - return handleInteractionInternal(superiorPlayer, blockLocation, island, IslandPrivileges.VALUABLE_BREAK, 0, false, false); + if (plugin.getSettings().getValuableBlocks().contains(Keys.of(block))) + return handleInteractionInternal(superiorPlayer, blockLocation, island, IslandPrivileges.VALUABLE_BREAK, 0, false, false); + } return InteractionResult.SUCCESS; } @@ -151,53 +156,56 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); - Location blockLocation = block.getLocation(); - Key blockKey = Keys.of(block); - - boolean isInteractableItem = BukkitItems.isInteractableItem(usedItem); - - int stackedBlockAmount = plugin.getStackedBlocks().getStackedBlockAmount(blockLocation); - - if (!isInteractableItem && stackedBlockAmount <= 1 && !INTERACTABLES_CACHE.contains(blockKey)) - return InteractionResult.SUCCESS; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = block.getLocation(wrapper.getHandle()); + Key blockKey = Keys.of(block); + + boolean isInteractableItem = BukkitItems.isInteractableItem(usedItem); + + int stackedBlockAmount = plugin.getStackedBlocks().getStackedBlockAmount(blockLocation); + + if (!isInteractableItem && stackedBlockAmount <= 1 && !INTERACTABLES_CACHE.contains(blockKey)) + return InteractionResult.SUCCESS; + + Island island = plugin.getGrid().getIslandAt(blockLocation); + + BlockState blockState = block.getState(); + EntityType spawnType = usedItem == null ? EntityType.UNKNOWN : BukkitItems.getEntityType(usedItem); + Material blockType = block.getType(); + + IslandPrivilege islandPrivilege; + + if (spawnType != EntityType.UNKNOWN) { + islandPrivilege = BukkitEntities.getCategory(spawnType).getSpawnPrivilege(); + } else if (usedItem != null && Materials.isMinecart(usedItem.getType()) ? Materials.isRail(blockType) : Materials.isBoat(blockType)) { + islandPrivilege = IslandPrivileges.MINECART_PLACE; + } else if (Materials.isChest(blockType)) { + islandPrivilege = IslandPrivileges.CHEST_ACCESS; + } else if (blockState instanceof InventoryHolder) { + islandPrivilege = IslandPrivileges.USE; + } else if (blockState instanceof Sign) { + islandPrivilege = IslandPrivileges.SIGN_INTERACT; + } else if (blockType == Materials.SPAWNER.toBukkitType()) { + islandPrivilege = IslandPrivileges.SPAWNER_BREAK; + } else if (blockType == FARMLAND) { + islandPrivilege = action == Action.PHYSICAL ? IslandPrivileges.FARM_TRAMPING : IslandPrivileges.BUILD; + } else if (blockType == TURTLE_EGG) { + islandPrivilege = action == Action.PHYSICAL ? IslandPrivileges.TURTLE_EGG_TRAMPING : IslandPrivileges.BUILD; + } else if (blockType == SWEET_BERRY_BUSH && action == Action.RIGHT_CLICK_BLOCK) { + islandPrivilege = Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem) ? IslandPrivileges.FERTILIZE : IslandPrivileges.FARM_TRAMPING; + } else if (stackedBlockAmount > 1) { + islandPrivilege = IslandPrivileges.BREAK; + } else if (blockType == Material.PUMPKIN) { + islandPrivilege = IslandPrivileges.BREAK; + } else if (blockType == LECTERN) { + islandPrivilege = IslandPrivileges.PICKUP_LECTERN_BOOK; + } else { + islandPrivilege = IslandPrivileges.INTERACT; + } - Island island = plugin.getGrid().getIslandAt(blockLocation); - - BlockState blockState = block.getState(); - EntityType spawnType = usedItem == null ? EntityType.UNKNOWN : BukkitItems.getEntityType(usedItem); - Material blockType = block.getType(); - - IslandPrivilege islandPrivilege; - - if (spawnType != EntityType.UNKNOWN) { - islandPrivilege = BukkitEntities.getCategory(spawnType).getSpawnPrivilege(); - } else if (usedItem != null && Materials.isMinecart(usedItem.getType()) ? Materials.isRail(blockType) : Materials.isBoat(blockType)) { - islandPrivilege = IslandPrivileges.MINECART_PLACE; - } else if (Materials.isChest(blockType)) { - islandPrivilege = IslandPrivileges.CHEST_ACCESS; - } else if (blockState instanceof InventoryHolder) { - islandPrivilege = IslandPrivileges.USE; - } else if (blockState instanceof Sign) { - islandPrivilege = IslandPrivileges.SIGN_INTERACT; - } else if (blockType == Materials.SPAWNER.toBukkitType()) { - islandPrivilege = IslandPrivileges.SPAWNER_BREAK; - } else if (blockType == FARMLAND) { - islandPrivilege = action == Action.PHYSICAL ? IslandPrivileges.FARM_TRAMPING : IslandPrivileges.BUILD; - } else if (blockType == TURTLE_EGG) { - islandPrivilege = action == Action.PHYSICAL ? IslandPrivileges.TURTLE_EGG_TRAMPING : IslandPrivileges.BUILD; - } else if (blockType == SWEET_BERRY_BUSH && action == Action.RIGHT_CLICK_BLOCK) { - islandPrivilege = Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem) ? IslandPrivileges.FERTILIZE : IslandPrivileges.FARM_TRAMPING; - } else if (stackedBlockAmount > 1) { - islandPrivilege = IslandPrivileges.BREAK; - } else if (blockType == Material.PUMPKIN) { - islandPrivilege = IslandPrivileges.BREAK; - } else if (blockType == LECTERN) { - islandPrivilege = IslandPrivileges.PICKUP_LECTERN_BOOK; - } else { - islandPrivilege = IslandPrivileges.INTERACT; - } - - return handleInteractionInternal(superiorPlayer, blockLocation, island, islandPrivilege, 0, true, true); + return handleInteractionInternal(superiorPlayer, blockLocation, island, islandPrivilege, + 0, true, true); + } } @Override @@ -205,10 +213,13 @@ public InteractionResult handleBlockFertilize(SuperiorPlayer superiorPlayer, Blo Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); - Location blockLocation = block.getLocation(); - Island island = plugin.getGrid().getIslandAt(blockLocation); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = block.getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(blockLocation); - return handleInteractionInternal(superiorPlayer, blockLocation, island, IslandPrivileges.FERTILIZE, 0, true, true); + return handleInteractionInternal(superiorPlayer, blockLocation, island, IslandPrivileges.FERTILIZE, + 0, true, true); + } } @Override @@ -216,40 +227,43 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(entity, "entity cannot be null"); - Location entityLocation = entity.getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); - + InteractionResult interactionResult; boolean closeInventory = false; - IslandPrivilege islandPrivilege; - - if (entity instanceof ArmorStand) { - islandPrivilege = IslandPrivileges.INTERACT; - } else if (usedItem != null && entity instanceof Animals && plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) entity)) { - islandPrivilege = IslandPrivileges.ANIMAL_BREED; - } else if (usedItem != null && usedItem.getType() == Material.NAME_TAG) { - islandPrivilege = IslandPrivileges.NAME_ENTITY; - } else if (entity instanceof Villager) { - islandPrivilege = IslandPrivileges.VILLAGER_TRADING; - closeInventory = true; - } else if (entity instanceof Horse || (ServerVersion.isAtLeast(ServerVersion.v1_11) && (entity instanceof Mule || entity instanceof Donkey))) { - islandPrivilege = IslandPrivileges.HORSE_INTERACT; - closeInventory = true; - } else if (usedItem != null && entity instanceof Creeper && usedItem.getType() == Material.FLINT_AND_STEEL) { - islandPrivilege = IslandPrivileges.IGNITE_CREEPER; - } else if (usedItem != null && ServerVersion.isAtLeast(ServerVersion.v1_17) && usedItem.getType() == Material.WATER_BUCKET && entity.getType() == AXOLOTL_TYPE) { - islandPrivilege = IslandPrivileges.PICKUP_AXOLOTL; - } else if (entity instanceof ItemFrame) { - islandPrivilege = IslandPrivileges.ITEM_FRAME; - } else if (entity instanceof Painting) { - islandPrivilege = IslandPrivileges.PAINTING; - } else if (entity instanceof Fish && !ServerVersion.isLegacy()) { - islandPrivilege = IslandPrivileges.PICKUP_FISH; - } else { - return InteractionResult.SUCCESS; - } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = entity.getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(entityLocation); + + IslandPrivilege islandPrivilege; + + if (entity instanceof ArmorStand) { + islandPrivilege = IslandPrivileges.INTERACT; + } else if (usedItem != null && entity instanceof Animals && plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) entity)) { + islandPrivilege = IslandPrivileges.ANIMAL_BREED; + } else if (usedItem != null && usedItem.getType() == Material.NAME_TAG) { + islandPrivilege = IslandPrivileges.NAME_ENTITY; + } else if (entity instanceof Villager) { + islandPrivilege = IslandPrivileges.VILLAGER_TRADING; + closeInventory = true; + } else if (entity instanceof Horse || (ServerVersion.isAtLeast(ServerVersion.v1_11) && (entity instanceof Mule || entity instanceof Donkey))) { + islandPrivilege = IslandPrivileges.HORSE_INTERACT; + closeInventory = true; + } else if (usedItem != null && entity instanceof Creeper && usedItem.getType() == Material.FLINT_AND_STEEL) { + islandPrivilege = IslandPrivileges.IGNITE_CREEPER; + } else if (usedItem != null && ServerVersion.isAtLeast(ServerVersion.v1_17) && usedItem.getType() == Material.WATER_BUCKET && entity.getType() == AXOLOTL_TYPE) { + islandPrivilege = IslandPrivileges.PICKUP_AXOLOTL; + } else if (entity instanceof ItemFrame) { + islandPrivilege = IslandPrivileges.ITEM_FRAME; + } else if (entity instanceof Painting) { + islandPrivilege = IslandPrivileges.PAINTING; + } else if (entity instanceof Fish && !ServerVersion.isLegacy()) { + islandPrivilege = IslandPrivileges.PICKUP_FISH; + } else { + return InteractionResult.SUCCESS; + } - InteractionResult interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, island, islandPrivilege, 0, true, true); + interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, island, islandPrivilege, 0, true, true); + } if (closeInventory && interactionResult != InteractionResult.SUCCESS) { BukkitExecutor.sync(() -> { @@ -275,11 +289,16 @@ public InteractionResult handleEntityDamage(Entity damager, Entity entity) { if (!damagerSource.isPresent()) return InteractionResult.SUCCESS; - Location entityLocation = entity.getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); - IslandPrivilege islandPrivilege = BukkitEntities.getCategory(entity.getType()).getDamagePrivilege(); + InteractionResult interactionResult; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = entity.getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(entityLocation); + IslandPrivilege islandPrivilege = BukkitEntities.getCategory(entity.getType()).getDamagePrivilege(); - InteractionResult interactionResult = handleInteractionInternal(damagerSource.get(), entityLocation, island, islandPrivilege, 0, true, false); + interactionResult = handleInteractionInternal(damagerSource.get(), entityLocation, island, islandPrivilege, + 0, true, false); + } if (interactionResult != InteractionResult.SUCCESS && damager instanceof Arrow && entity.getFireTicks() > 0) entity.setFireTicks(0); @@ -292,10 +311,13 @@ public InteractionResult handleEntityShear(SuperiorPlayer superiorPlayer, Entity Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(entity, "entity cannot be null"); - Location entityLocation = entity.getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = entity.getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(entityLocation); - return handleInteractionInternal(superiorPlayer, entityLocation, island, IslandPrivileges.ANIMAL_SHEAR, 0, true, false); + return handleInteractionInternal(superiorPlayer, entityLocation, island, IslandPrivileges.ANIMAL_SHEAR, + 0, true, false); + } } @Override @@ -303,10 +325,13 @@ public InteractionResult handleEntityLeash(SuperiorPlayer superiorPlayer, Entity Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(entity, "entity cannot be null"); - Location entityLocation = entity.getLocation(); - Island island = plugin.getGrid().getIslandAt(entityLocation); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = entity.getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(entityLocation); - return handleInteractionInternal(superiorPlayer, entityLocation, island, IslandPrivileges.LEASH, 0, true, false); + return handleInteractionInternal(superiorPlayer, entityLocation, island, IslandPrivileges.LEASH, + 0, true, false); + } } @Override @@ -317,10 +342,13 @@ public InteractionResult handlePlayerPickupItem(SuperiorPlayer superiorPlayer, I if (plugin.getNMSPlayers().wasThrownByPlayer(item, superiorPlayer)) return InteractionResult.SUCCESS; - Location itemLocation = item.getLocation(); - Island island = plugin.getGrid().getIslandAt(itemLocation); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location itemLocation = item.getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(itemLocation); - return handleInteractionInternal(superiorPlayer, itemLocation, island, IslandPrivileges.PICKUP_DROPS, MAX_PICKUP_DISTANCE, true, false); + return handleInteractionInternal(superiorPlayer, itemLocation, island, IslandPrivileges.PICKUP_DROPS, + MAX_PICKUP_DISTANCE, true, false); + } } @Override @@ -328,10 +356,13 @@ public InteractionResult handlePlayerDropItem(SuperiorPlayer superiorPlayer, Ite Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(item, "item cannot be null"); - Location itemLocation = item.getLocation(); - Island island = plugin.getGrid().getIslandAt(itemLocation); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location itemLocation = item.getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(itemLocation); - return handleInteractionInternal(superiorPlayer, itemLocation, island, IslandPrivileges.DROP_ITEMS, 0, true, false); + return handleInteractionInternal(superiorPlayer, itemLocation, island, IslandPrivileges.DROP_ITEMS, + 0, true, false); + } } @Override @@ -429,9 +460,15 @@ public MoveResult handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, //Checking for out of distance from preview location. IslandPreview islandPreview = plugin.getGrid().getIslandPreview(superiorPlayer); - if (islandPreview != null && (!islandPreview.getLocation().getWorld().equals(to.getWorld()) || islandPreview.getLocation().distanceSquared(to) > 10000)) { - islandPreview.handleEscape(); - return MoveResult.ISLAND_PREVIEW_MOVED_TOO_FAR; + if (islandPreview != null) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location islandPreviewLocation = islandPreview.getLocation(wrapper.getHandle()); + if (!islandPreviewLocation.getWorld().equals(to.getWorld()) || + islandPreviewLocation.distanceSquared(to) > 10000) { + islandPreview.handleEscape(); + return MoveResult.ISLAND_PREVIEW_MOVED_TOO_FAR; + } + } } MoveResult moveResult; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java index 2902943a30..4eeb21efb5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java @@ -14,6 +14,7 @@ import com.bgsoftware.superiorskyblock.core.Either; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.key.BaseKey; @@ -107,54 +108,56 @@ public InteractionResult checkStackedBlockInteraction(SuperiorPlayer superiorPla public InteractionResult handleStackedBlockBreak(Block block, @Nullable SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(block, "block cannot be null"); - Location blockLocation = block.getLocation(); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = block.getLocation(wrapper.getHandle()); - int blockAmount = plugin.getStackedBlocks().getStackedBlockAmount(blockLocation); - if (blockAmount <= 1) - return InteractionResult.NOT_STACKED_BLOCK; + int blockAmount = plugin.getStackedBlocks().getStackedBlockAmount(blockLocation); + if (blockAmount <= 1) + return InteractionResult.NOT_STACKED_BLOCK; - Island island = plugin.getGrid().getIslandAt(blockLocation); - if (superiorPlayer != null && island != null) { - com.bgsoftware.superiorskyblock.api.service.region.InteractionResult interactionResult = - this.regionManagerService.get().handleBlockBreak(superiorPlayer, block); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - return InteractionResult.STACKED_BLOCK_PROTECTED; - } + Island island = plugin.getGrid().getIslandAt(blockLocation); + if (superiorPlayer != null && island != null) { + com.bgsoftware.superiorskyblock.api.service.region.InteractionResult interactionResult = + this.regionManagerService.get().handleBlockBreak(superiorPlayer, block); + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) + return InteractionResult.STACKED_BLOCK_PROTECTED; + } - Player onlinePlayer = superiorPlayer == null ? null : superiorPlayer.asPlayer(); + Player onlinePlayer = superiorPlayer == null ? null : superiorPlayer.asPlayer(); - int amountToBreak = Math.min(blockAmount, onlinePlayer != null && onlinePlayer.isSneaking() ? 64 : 1); + int amountToBreak = Math.min(blockAmount, onlinePlayer != null && onlinePlayer.isSneaking() ? 64 : 1); - int leftAmount = blockAmount - amountToBreak; + int leftAmount = blockAmount - amountToBreak; - if (!plugin.getEventsBus().callBlockUnstackEvent(block, onlinePlayer, blockAmount, leftAmount)) - return InteractionResult.EVENT_CANCELLED; + if (!plugin.getEventsBus().callBlockUnstackEvent(block, onlinePlayer, blockAmount, leftAmount)) + return InteractionResult.EVENT_CANCELLED; - if (!plugin.getStackedBlocks().setStackedBlock(block, leftAmount)) - return InteractionResult.GLITCHED_STACKED_BLOCK; + if (!plugin.getStackedBlocks().setStackedBlock(block, leftAmount)) + return InteractionResult.GLITCHED_STACKED_BLOCK; - plugin.getNMSWorld().playBreakAnimation(block); + plugin.getNMSWorld().playBreakAnimation(block); - if (superiorPlayer != null) { - OfflinePlayer offlinePlayer = onlinePlayer == null ? superiorPlayer.asOfflinePlayer() : onlinePlayer; - plugin.getProviders().notifyStackedBlocksListeners(offlinePlayer, block, IStackedBlocksListener.Action.BLOCK_BREAK); - } + if (superiorPlayer != null) { + OfflinePlayer offlinePlayer = onlinePlayer == null ? superiorPlayer.asOfflinePlayer() : onlinePlayer; + plugin.getProviders().notifyStackedBlocksListeners(offlinePlayer, block, IStackedBlocksListener.Action.BLOCK_BREAK); + } - if (island != null) - island.handleBlockBreak(block, amountToBreak); + if (island != null) + island.handleBlockBreak(block, amountToBreak); - ItemStack blockItem = ServerVersion.isLegacy() ? - block.getState().getData().toItemStack(amountToBreak) : - new ItemStack(block.getType(), amountToBreak); + ItemStack blockItem = ServerVersion.isLegacy() ? + block.getState().getData().toItemStack(amountToBreak) : + new ItemStack(block.getType(), amountToBreak); - if (leftAmount <= 0) - block.setType(Material.AIR); + if (leftAmount <= 0) + block.setType(Material.AIR); - // Dropping the item - if (onlinePlayer != null && plugin.getSettings().getStackedBlocks().isAutoCollect()) { - BukkitItems.addItem(blockItem, onlinePlayer.getInventory(), blockLocation); - } else { - block.getWorld().dropItemNaturally(blockLocation.add(0, 0.5, 0), blockItem); + // Dropping the item + if (onlinePlayer != null && plugin.getSettings().getStackedBlocks().isAutoCollect()) { + BukkitItems.addItem(blockItem, onlinePlayer.getInventory(), blockLocation); + } else { + block.getWorld().dropItemNaturally(blockLocation.add(0, 0.5, 0), blockItem); + } } return InteractionResult.SUCCESS; @@ -197,9 +200,16 @@ private InteractionResult checkBlockStackInternal(SuperiorPlayer superiorPlayer, private InteractionResult handleBlockStackInternal(SuperiorPlayer superiorPlayer, Block stackedBlock, int amountToDeposit, Either removalData) { - Player onlinePlayer = superiorPlayer.asPlayer(); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return handleBlockStackInternal(superiorPlayer, stackedBlock, stackedBlock.getLocation(wrapper.getHandle()), + amountToDeposit, removalData); + } + } - Location stackedBlockLocation = stackedBlock.getLocation(); + private InteractionResult handleBlockStackInternal(SuperiorPlayer superiorPlayer, Block stackedBlock, + Location stackedBlockLocation, int amountToDeposit, + Either removalData) { + Player onlinePlayer = superiorPlayer.asPlayer(); int blockAmount = plugin.getStackedBlocks().getStackedBlockAmount(stackedBlockLocation); Key blockKey = plugin.getStackedBlocks().getStackedBlockKey(stackedBlockLocation); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java index 0c4e693b27..139dd40c99 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; @@ -54,7 +55,9 @@ public Class getAPIClass() { public RecordResult recordBlockPlace(Block block, int blockCount, @Nullable BlockState oldBlockState, @WorldRecordFlags int flags) { Preconditions.checkNotNull(block, "block cannot be null"); - return recordBlockPlace(Keys.of(block), block.getLocation(), blockCount, oldBlockState, flags); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return recordBlockPlace(Keys.of(block), block.getLocation(wrapper.getHandle()), blockCount, oldBlockState, flags); + } } @Override @@ -148,7 +151,9 @@ public RecordResult recordBlockBreak(Block block, @WorldRecordFlags int flags) { @Override public RecordResult recordBlockBreak(Block block, int blockCount, @WorldRecordFlags int flags) { Preconditions.checkNotNull(block, "block cannot be null"); - return recordBlockBreak(Keys.of(block), block.getLocation(), blockCount, flags); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return recordBlockBreak(Keys.of(block), block.getLocation(wrapper.getHandle()), blockCount, flags); + } } @Override @@ -250,7 +255,9 @@ public RecordResult recordEntitySpawn(Entity entity) { if (BukkitEntities.canBypassEntityLimit(entity)) return RecordResult.ENTITY_CANNOT_BE_TRACKED; - return recordEntitySpawnInternal(entity.getType(), entity.getLocation()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return recordEntitySpawnInternal(entity.getType(), entity.getLocation(wrapper.getHandle())); + } } @Override @@ -287,7 +294,10 @@ public RecordResult recordEntityDespawn(Entity entity) { if (BukkitEntities.canBypassEntityLimit(entity)) return RecordResult.ENTITY_CANNOT_BE_TRACKED; - RecordResult recordResult = recordEntityDespawnInternal(entity.getType(), entity.getLocation()); + RecordResult recordResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + recordResult = recordEntityDespawnInternal(entity.getType(), entity.getLocation(wrapper.getHandle())); + } if (recordResult != RecordResult.SUCCESS) return recordResult; @@ -297,7 +307,9 @@ public RecordResult recordEntityDespawn(Entity entity) { } else { // Vehicle was not registered by VehicleDestroyEvent; We want to register its block break Key blockKey = plugin.getNMSAlgorithms().getMinecartBlock((Minecart) entity); - recordBlockBreak(blockKey, entity.getLocation(), 1, REGULAR_RECORD_FLAGS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + recordBlockBreak(blockKey, entity.getLocation(wrapper.getHandle()), 1, REGULAR_RECORD_FLAGS); + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java index 04afcf03dd..3808506780 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.EventResult; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -23,10 +24,10 @@ import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; -import java.util.ArrayList; import java.util.Comparator; -import java.util.List; +import java.util.LinkedList; import java.util.Objects; +import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; @@ -133,13 +134,14 @@ public static CompletableFuture findIslandSafeLocation(Island island, private static void findNewSafeSpotOnIsland(Island island, World islandsWorld, Location homeLocation, float rotationYaw, float rotationPitch, CompletableFuture result) { - ChunkPosition homeChunk = ChunkPosition.of(homeLocation); - - List islandChunks = new ArrayList<>(IslandUtils.getChunkCoords(island, + LinkedList islandChunks = new LinkedList<>(IslandUtils.getChunkCoords(island, WorldInfo.of(islandsWorld), IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS)); - islandChunks.sort(Comparator.comparingInt(o -> o.distanceSquared(homeChunk))); - findSafeSpotInChunk(island, islandChunks, 0, islandsWorld, homeLocation, safeSpot -> { + try (ChunkPosition homeChunk = ChunkPosition.of(homeLocation)) { + islandChunks.sort(Comparator.comparingInt(o -> o.distanceSquared(homeChunk))); + } + + findSafeSpotInChunk(island, islandChunks, islandsWorld, homeLocation, safeSpot -> { if (safeSpot != null) { result.complete(adjustLocationToHome(island, safeSpot.getBlock(), rotationYaw, rotationPitch)); } else { @@ -148,20 +150,19 @@ private static void findNewSafeSpotOnIsland(Island island, World islandsWorld, L }); } - private static void findSafeSpotInChunk(Island island, List islandChunks, int index, - World islandsWorld, Location homeLocation, Consumer onResult) { - if (index >= islandChunks.size()) { + private static void findSafeSpotInChunk(Island island, Queue islandChunks, World islandsWorld, + Location homeLocation, Consumer onResult) { + ChunkPosition chunkPosition = islandChunks.poll(); + if (chunkPosition == null) { onResult.accept(null); return; } - ChunkPosition chunkPosition = islandChunks.get(index); - ChunksProvider.loadChunk(chunkPosition, ChunkLoadReason.FIND_SAFE_SPOT, null).whenComplete((chunk, err) -> { ChunkSnapshot chunkSnapshot = chunk.getChunkSnapshot(); if (WorldBlocks.isChunkEmpty(island, chunkSnapshot)) { - findSafeSpotInChunk(island, islandChunks, index + 1, islandsWorld, homeLocation, onResult); + findSafeSpotInChunk(island, islandChunks, islandsWorld, homeLocation, onResult); return; } @@ -207,7 +208,7 @@ private static void findSafeSpotInChunk(Island island, List islan if (location != null) { onResult.accept(location); } else { - findSafeSpotInChunk(island, islandChunks, index + 1, islandsWorld, homeLocation, onResult); + findSafeSpotInChunk(island, islandChunks, islandsWorld, homeLocation, onResult); } }); @@ -222,8 +223,8 @@ private static void teleportEntity(Entity entity, Location location, @Nullable C private static Location adjustLocationToHome(Island island, Block block, float yaw, float pitch) { Location newHomeLocation; - { - Location location = block.getLocation().add(0.5, 0, 0.5); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = block.getLocation(wrapper.getHandle()).add(0.5, 0, 0.5); location.setYaw(yaw); location.setPitch(pitch); EventResult eventResult = plugin.getEventsBus().callIslandSetHomeEvent(island, location, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunksProvider.java b/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunksProvider.java index 3d64b4015d..02162cd56b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunksProvider.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunksProvider.java @@ -40,10 +40,12 @@ public static CompletableFuture loadChunk(ChunkPosition chunkPosition, Ch Log.debug(Debug.LOAD_CHUNK, chunkPosition, chunkLoadReason); Chunk loadedChunk = ChunkPosition.getLoadedChunk(chunkPosition).orElse(null); + if (loadedChunk != null) { processPendingChunkLoadRequest(loadedChunk, chunkPosition); if (onLoadConsumer != null) onLoadConsumer.accept(loadedChunk); + chunkPosition.release(); return CompletableFuture.completedFuture(loadedChunk); } @@ -52,6 +54,7 @@ public static CompletableFuture loadChunk(ChunkPosition chunkPosition, Ch if (pendingRequest != null) { if (onLoadConsumer != null) pendingRequest.callbacks.add(onLoadConsumer); + chunkPosition.release(); return pendingRequest.completableFuture; } else { CompletableFuture completableFuture = new CompletableFuture<>(); @@ -60,8 +63,12 @@ public static CompletableFuture loadChunk(ChunkPosition chunkPosition, Ch if (onLoadConsumer != null) chunkConsumers.add(onLoadConsumer); - pendingRequests.put(chunkPosition, new PendingChunkLoadRequest(completableFuture, chunkConsumers)); - chunksExecutor.addWorker(new ChunkLoadWorker(chunkPosition, chunkLoadReason)); + // Copy pool resource + ChunkPosition clonedChunkPos = chunkPosition.copy(); + chunkPosition.release(); + + pendingRequests.put(clonedChunkPos, new PendingChunkLoadRequest(completableFuture, chunkConsumers)); + chunksExecutor.addWorker(new ChunkLoadWorker(clonedChunkPos, chunkLoadReason)); if (!chunksExecutor.isRunning()) start(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java index f670d97a3b..0ebeb35ac9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.schematic.SchematicEntityFilter; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; @@ -63,9 +64,12 @@ public SchematicBuilder withTileEntity(CompoundTag tileEntity) { public SchematicBuilder applyEntity(Entity entity, Location min) { if (!(entity instanceof Player)) { - Location offset = entity.getLocation().subtract(min); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location offset = entity.getLocation(wrapper.getHandle()).subtract(min); + compoundValue.put("offset", new StringTag(Serializers.LOCATION_SERIALIZER.serialize(offset))); + } + compoundValue.put("entityType", new StringTag(entity.getType().name())); - compoundValue.put("offset", new StringTag(Serializers.LOCATION_SERIALIZER.serialize(offset))); compoundValue.put("NBT", SchematicEntityFilter.filterNBTTag(plugin.getNMSTags().getNBTTag(entity))); } return this; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index bde7c19344..38a7811df0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -7,8 +7,10 @@ import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParseException; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Manager; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; @@ -130,22 +132,26 @@ public List getSchematicParsers() { @Override public void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); - Preconditions.checkNotNull(superiorPlayer.getLocation(), "superiorPlayer must be online."); + Preconditions.checkArgument(superiorPlayer.isOnline(), "superiorPlayer must be online."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); - Location pos1 = superiorPlayer.getSchematicPos1().parse(); - Location pos2 = superiorPlayer.getSchematicPos2().parse(); - Location min = new Location(pos1.getWorld(), - Math.min(pos1.getX(), pos2.getX()), - Math.min(pos1.getY(), pos2.getY()), - Math.min(pos1.getZ(), pos2.getZ()) - ); - Location offset = superiorPlayer.getLocation().clone().subtract(min.clone().add(0, 1, 0)); + BlockPosition pos1 = superiorPlayer.getSchematicPos1(); + BlockPosition pos2 = superiorPlayer.getSchematicPos2(); + + Location offset; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location min = new Location(pos1.getWorld(), + Math.min(pos1.getX(), pos2.getX()), + Math.min(pos1.getY(), pos2.getY()), + Math.min(pos1.getZ(), pos2.getZ()) + ); + + offset = superiorPlayer.getLocation(wrapper.getHandle()).subtract(min.add(0, 1, 0)); + } - saveSchematic(superiorPlayer.getSchematicPos1().parse(), superiorPlayer.getSchematicPos2().parse(), - offset.getBlockX(), offset.getBlockY(), offset.getBlockZ(), offset.getYaw(), offset.getPitch(), schematicName, () -> - Message.SCHEMATIC_SAVED.send(superiorPlayer)); + saveSchematic(pos1.parse(), pos2.parse(), offset.getBlockX(), offset.getBlockY(), offset.getBlockZ(), + offset.getYaw(), offset.getPitch(), schematicName, () -> Message.SCHEMATIC_SAVED.send(superiorPlayer)); superiorPlayer.setSchematicPos1(null); superiorPlayer.setSchematicPos2(null); @@ -208,9 +214,12 @@ public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY for (int y = 0; y <= ySize; y++) { Block block = world.getBlockAt(x + min.getBlockX(), y + min.getBlockY(), z + min.getBlockZ()); Material blockType = block.getType(); - Location blockLocation = block.getLocation(); + if (blockType == Material.AIR) + continue; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = block.getLocation(wrapper.getHandle()); - if (blockType != Material.AIR) { CompoundTag tileEntity = plugin.getNMSWorld().readTileEntity(blockLocation); if (tileEntity != null && block.getState() instanceof InventoryHolder) tileEntity.setString("inventoryType", ((InventoryHolder) block.getState()).getInventory().getType().name()); @@ -337,8 +346,10 @@ private List getEntities(Location min, Location max) { for (int z = minChunk.getZ(); z <= maxChunk.getZ(); z++) { Chunk currentChunk = min.getWorld().getChunkAt(x, z); for (Entity entity : currentChunk.getEntities()) { - if (!(entity instanceof Player) && betweenLocations(entity.getLocation(), min, max)) - livingEntities.add(entity); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (!(entity instanceof Player) && betweenLocations(entity.getLocation(wrapper.getHandle()), min, max)) + livingEntities.add(entity); + } } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java index b5d3c2b819..bef96b739d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java @@ -294,7 +294,7 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long plugin.getEventsBus().callIslandSchematicPasteEvent(island, name, location); Profiler.end(profiler); - + synchronized (this) { try { prepareCallback(affectedChunks, min); From a5946ba38e027b0cdd2cac8ff05a1a0985797a65 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 14 Dec 2024 19:16:30 +0200 Subject: [PATCH 014/600] Fixed some errors and unintended world loading --- .../superiorskyblock/core/LazyWorldLocation.java | 7 +++++++ .../core/database/bridge/IslandsDatabaseBridge.java | 10 +++++++++- .../superiorskyblock/island/GridManagerImpl.java | 2 +- .../superiorskyblock/island/SpawnIsland.java | 3 ++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java b/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java index f7490a6296..5298ac43a4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java @@ -1,5 +1,7 @@ package com.bgsoftware.superiorskyblock.core; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; @@ -19,6 +21,11 @@ public static LazyWorldLocation of(Location location) { location.getYaw(), location.getPitch()); } + public static LazyWorldLocation of(WorldInfo worldInfo, BlockPosition blockPosition) { + return new LazyWorldLocation(worldInfo.getName(), blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), + 0f, 0f); + } + public LazyWorldLocation(String worldName, double x, double y, double z, float yaw, float pitch) { super(Bukkit.getWorld(worldName), x, y, z, yaw, pitch); this.worldName = worldName; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index 3128ddb248..443918e233 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.core.database.bridge; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.data.DatabaseFilter; @@ -17,8 +18,11 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.LegacyMasks; import com.bgsoftware.superiorskyblock.core.database.serialization.IslandsSerializer; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; @@ -43,6 +47,8 @@ @SuppressWarnings("unchecked") public class IslandsDatabaseBridge { + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final Location LOCATION = new Location(null, 0, 100, 0); private static final Map>> SAVE_METHODS_TO_BE_EXECUTED = new ConcurrentHashMap<>(); @@ -612,10 +618,12 @@ public static void clearIslandSettings(Island island) { public static void insertIsland(Island island, List dirtyChunks) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + BlockPosition centerPosition = island.getCenterPosition(); + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, Dimensions.NORMAL); databaseBridge.insertObject("islands", new Pair<>("uuid", island.getUniqueId().toString()), new Pair<>("owner", island.getOwner().getUniqueId().toString()), - new Pair<>("center", Serializers.LOCATION_SERIALIZER.serialize(island.getCenter(Dimensions.NORMAL))), + new Pair<>("center", Serializers.LOCATION_SERIALIZER.serialize(LazyWorldLocation.of(worldInfo, centerPosition))), new Pair<>("creation_time", island.getCreationTime()), new Pair<>("island_type", island.getSchematicName()), new Pair<>("discord", island.getDiscord()), diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index a4d47243d4..269dfebf97 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -349,7 +349,7 @@ private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Bi if (spawnOffset != null) homeLocation = spawnOffset.applyToLocation(homeLocation); - island.setIslandHome(homeLocation); + island.setIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension(), homeLocation); BukkitExecutor.sync(() -> builder.owner.runIfOnline(player -> { if (updateGamemode) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 6adc8d3890..3dfa4dd8d2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -778,7 +778,8 @@ public boolean isInside(Location location, int extraRadius) { @Override public boolean isInside(Location location, double extraRadius) { - if (!location.getWorld().equals(this.spawnWorld)) + World bukkitWorld = location.getWorld(); + if (bukkitWorld == null || !bukkitWorld.equals(this.spawnWorld)) return false; try (IslandArea islandArea = this.islandArea.copy()) { From 0becc7210877a237ffd2e1595989671341595315 Mon Sep 17 00:00:00 2001 From: JorisvD01 <99077822+JorisvD01@users.noreply.github.com> Date: Sat, 21 Dec 2024 11:58:46 +0100 Subject: [PATCH 015/600] Add missing blocks to interactables.yml (#2301) * Add missing Bamboo & Cherry variants, and enderpearl & lectern to interactables.yml * Removed ENDER_PEARL as it isn't an interactable block * 1.21: Added all copper door + trapdoor variants, and crafter * added decorated pot --- src/main/resources/interactables.yml | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index eb0a71038a..65d25d40aa 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -19,8 +19,14 @@ interactables: - 'ACACIA_WALL_HANGING_SIGN' - 'ACACIA_WALL_SIGN' - 'ANVIL' + - 'BAMBOO_BUTTON' + - 'BAMBOO_DOOR' + - 'BAMBOO_FENCE' + - 'BAMBOO_FENCE_GATE' - 'BAMBOO_HANGING_SIGN' + - 'BAMBOO_PRESSURE_PLATE' - 'BAMBOO_SIGN' + - 'BAMBOO_TRAPDOOR' - 'BAMBOO_WALL_HANGING_SIGN' - 'BAMBOO_WALL_SIGN' - 'BARREL' @@ -51,8 +57,14 @@ interactables: - 'CAULDRON' - 'CAVE_VINES_PLANT' - 'CHAIN_COMMAND_BLOCK' + - 'CHERRY_BUTTON' + - 'CHERRY_DOOR' + - 'CHERRY_FENCE' + - 'CHERRY_FENCE_GATE' - 'CHERRY_HANGING_SIGN' + - 'CHERRY_PRESSURE_PLATE' - 'CHERRY_SIGN' + - 'CHERRY_TRAPDOOR' - 'CHERRY_WALL_HANGING_SIGN' - 'CHERRY_WALL_SIGN' - 'CHEST' @@ -62,6 +74,9 @@ interactables: - 'COMMAND_CHAIN' - 'COMMAND_REPEATING' - 'COMPARATOR' + - 'COPPER_DOOR' + - 'COPPER_TRAPDOOR' + - 'CRAFTER' - 'CRAFTING_TABLE' - 'CRIMSON_BUTTON' - 'CRIMSON_DOOR' @@ -87,6 +102,7 @@ interactables: - 'DARK_OAK_WALL_SIGN' - 'DAYLIGHT_DETECTOR' - 'DAYLIGHT_DETECTOR_INVERTED' + - 'DECORATED_POT' - 'DIODE_BLOCK_OFF' - 'DIODE_BLOCK_ON' - 'DISPENSER' @@ -96,6 +112,8 @@ interactables: - 'ENCHANTMENT_TABLE' - 'ENDER_CHEST' - 'ENDER_PORTAL_FRAME' + - 'EXPOSED_COPPER_DOOR' + - 'EXPOSED_COPPER_TRAPDOOR' - 'FARMLAND' - 'FENCE' - 'FENCE_GATE' @@ -126,6 +144,7 @@ interactables: - 'JUNGLE_TRAPDOOR' - 'JUNGLE_WALL_HANGING_SIGN' - 'JUNGLE_WALL_SIGN' + - 'LECTERN' - 'LEVER' - 'LIGHT_BLUE_BED' - 'LIGHT_BLUE_SHULKER_BOX' @@ -158,6 +177,8 @@ interactables: - 'OAK_WALL_SIGN' - 'ORANGE_BED' - 'ORANGE_SHULKER_BOX' + - 'OXIDIZED_COPPER_DOOR' + - 'OXIDIZED_COPPER_TRAPDOOR' - 'PINK_BED' - 'PINK_SHULKER_BOX' - 'POLISHED_BLACKSTONE_BUTTON' @@ -244,6 +265,16 @@ interactables: - 'WARPED_TRAPDOOR' - 'WARPED_WALL_HANGING_SIGN' - 'WARPED_WALL_SIGN' + - 'WAXED_COPPER_DOOR' + - 'WAXED_COPPER_TRAPDOOR' + - 'WAXED_EXPOSED_COPPER_DOOR' + - 'WAXED_EXPOSED_COPPER_TRAPDOOR' + - 'WAXED_OXIDIZED_COPPER_DOOR' + - 'WAXED_OXIDIZED_COPPER_TRAPDOOR' + - 'WAXED_WEATHERED_COPPER_DOOR' + - 'WAXED_WEATHERED_COPPER_TRAPDOOR' + - 'WEATHERED_COPPER_DOOR' + - 'WEATHERED_COPPER_TRAPDOOR' - 'WHITE_BED' - 'WHITE_SHULKER_BOX' - 'WOODEN_DOOR' From 9209e833e357b8deb72a691253109ba2195ddb41 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 21 Dec 2024 14:22:26 +0200 Subject: [PATCH 016/600] Updated nms-loader --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 69f10aecd2..27b0068e61 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b9' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b10' implementation 'com.zaxxer:HikariCP:4.0.3' implementation 'org.slf4j:slf4j-api:2.0.5' From 78f84d14cd529f240d98644dc112b74c47ca759b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 21 Dec 2024 14:53:17 +0200 Subject: [PATCH 017/600] Fix random errors when creating new islands --- .../DefaultIslandCreationAlgorithm.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java index f3dd0528e5..b90bffbcbc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java @@ -100,22 +100,22 @@ public CompletableFuture createIsland(Island.Builder build CompletableFuture completableFuture = new CompletableFuture<>(); - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = islandLocation.getBlock().getRelative(BlockFace.DOWN).getLocation(wrapper.getHandle()); - schematic.pasteSchematic(island, location, () -> { - plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation, - builder.owner.getUniqueId(), builder.uuid); - completableFuture.complete(new IslandCreationResult(IslandCreationResult.Status.SUCCESS, island, islandLocation, event.getResult())); - island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); - Profiler.end(profiler); - }, error -> { - island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); - plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation, - builder.owner.getUniqueId(), builder.uuid); - completableFuture.completeExceptionally(error); - Profiler.end(profiler); - }); - } + // Clone location as pasteSchematic uses the same location in later scheduled tasks + Location location = islandLocation.getBlock().getRelative(BlockFace.DOWN).getLocation(); + + schematic.pasteSchematic(island, location, () -> { + plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation, + builder.owner.getUniqueId(), builder.uuid); + completableFuture.complete(new IslandCreationResult(IslandCreationResult.Status.SUCCESS, island, islandLocation, event.getResult())); + island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); + Profiler.end(profiler); + }, error -> { + island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); + plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation, + builder.owner.getUniqueId(), builder.uuid); + completableFuture.completeExceptionally(error); + Profiler.end(profiler); + }); return completableFuture; } From 1e41e7d13aa2e4f6c431205f82d783a4bdf81852 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 27 Dec 2024 16:25:29 +0200 Subject: [PATCH 018/600] Fixed compiling errors with Paper's hard-fork --- NMS/Paper-1_20_3/build.gradle | 4 ++-- NMS/v1_17/build.gradle | 6 +++--- NMS/v1_18/build.gradle | 4 ++-- NMS/v1_19/build.gradle | 4 ++-- NMS/v1_20_3/build.gradle | 4 ++-- NMS/v1_20_4/build.gradle | 4 ++-- NMS/v1_21/build.gradle | 4 ++-- NMS/v1_21_3/build.gradle | 4 ++-- NMS/v1_21_4/build.gradle | 4 ++-- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 11 files changed, 21 insertions(+), 21 deletions(-) diff --git a/NMS/Paper-1_20_3/build.gradle b/NMS/Paper-1_20_3/build.gradle index b621b602ad..56aabad643 100644 --- a/NMS/Paper-1_20_3/build.gradle +++ b/NMS/Paper-1_20_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.7.1" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" } group 'NMS:Paper-1_20_3' @@ -11,7 +11,7 @@ java { } dependencies { - paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.20.4-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":API") compileOnly rootProject diff --git a/NMS/v1_17/build.gradle b/NMS/v1_17/build.gradle index dce7024262..8239e92160 100644 --- a/NMS/v1_17/build.gradle +++ b/NMS/v1_17/build.gradle @@ -1,17 +1,17 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.7.1" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" } java { toolchain { - languageVersion.set(JavaLanguageVersion.of(16)) + languageVersion.set(JavaLanguageVersion.of(17)) } } group 'NMS:v1_17' dependencies { - paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.17.1-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.17.1-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot") compileOnly project(":NMS:Paper") compileOnly project(":API") diff --git a/NMS/v1_18/build.gradle b/NMS/v1_18/build.gradle index 399d094043..70e30d95a5 100644 --- a/NMS/v1_18/build.gradle +++ b/NMS/v1_18/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.7.1" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" } java { @@ -11,7 +11,7 @@ java { group 'NMS:v1_18' dependencies { - paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.18.2-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.18.2-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot") compileOnly project(":NMS:Paper") compileOnly project(":API") diff --git a/NMS/v1_19/build.gradle b/NMS/v1_19/build.gradle index 94be173421..e1dcbb6651 100644 --- a/NMS/v1_19/build.gradle +++ b/NMS/v1_19/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.7.1" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" } java { @@ -11,7 +11,7 @@ java { group 'NMS:v1_19' dependencies { - paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.19.4-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.19.4-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot") compileOnly project(":NMS:Paper") compileOnly project(":API") diff --git a/NMS/v1_20_3/build.gradle b/NMS/v1_20_3/build.gradle index c039bbcb8d..92346110a8 100644 --- a/NMS/v1_20_3/build.gradle +++ b/NMS/v1_20_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.7.1" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" } java { @@ -11,7 +11,7 @@ java { group 'NMS:v1_20_3' dependencies { - paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.20.4-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") diff --git a/NMS/v1_20_4/build.gradle b/NMS/v1_20_4/build.gradle index 43d6461847..eb9e16b745 100644 --- a/NMS/v1_20_4/build.gradle +++ b/NMS/v1_20_4/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.7.1" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" } java { @@ -11,7 +11,7 @@ java { group 'NMS:v1_20_4' dependencies { - paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.20.6-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.20.6-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") diff --git a/NMS/v1_21/build.gradle b/NMS/v1_21/build.gradle index e76273dd2d..dd1d58f09b 100644 --- a/NMS/v1_21/build.gradle +++ b/NMS/v1_21/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.7.1" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" } java { @@ -11,7 +11,7 @@ java { group 'NMS:v1_21' dependencies { - paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.21.1-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.21.1-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") diff --git a/NMS/v1_21_3/build.gradle b/NMS/v1_21_3/build.gradle index 40980c291f..4ece9c65b7 100644 --- a/NMS/v1_21_3/build.gradle +++ b/NMS/v1_21_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.7.1" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" } java { @@ -11,7 +11,7 @@ java { group 'NMS:v1_21_3' dependencies { - paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.21.3-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.21.3-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") diff --git a/NMS/v1_21_4/build.gradle b/NMS/v1_21_4/build.gradle index 5dcad64f7b..05b844dfa6 100644 --- a/NMS/v1_21_4/build.gradle +++ b/NMS/v1_21_4/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "1.7.1" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" } java { @@ -11,7 +11,7 @@ java { group 'NMS:v1_21_4' dependencies { - paperweightDevelopmentBundle("io.papermc.paper:dev-bundle:1.21.4-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.21.4-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") diff --git a/build.gradle b/build.gradle index 27b0068e61..003a348d11 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'io.github.goooler.shadow' version '8.1.7' + id 'io.github.goooler.shadow' version '8.1.8' id 'maven-publish' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 48c0a02ca4..d6e308a637 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From c68bf0fe5024a51df3e0b84a34d2890109eb08c3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 28 Dec 2024 10:19:54 +0200 Subject: [PATCH 019/600] Fixed detection of whether the BlocksMissions was already completed (#2303) --- .../resources/modules/missions/BlocksMissions | Bin 34731 -> 34768 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/modules/missions/BlocksMissions b/src/main/resources/modules/missions/BlocksMissions index 1c2eedca77f37df7014106d8b0eed759fe5db1cc..b8eb8d2e57b3816f5a5fe3f3a3db6cfdf0ccff56 100644 GIT binary patch delta 14214 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 From c919543e3948c84c46553246941c1a263e3fa186 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 28 Dec 2024 10:46:24 +0200 Subject: [PATCH 020/600] Fix conflicts with command aliases and disabled commands (#2304) --- .../commands/CommandsMap.java | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java index ae303c0507..b28b09b576 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java @@ -37,7 +37,7 @@ public static void registerCallbacks(CallbacksBus bus) { } private final Map subCommands = new LinkedHashMap<>(); - private final Map aliasesToCommand = new HashMap<>(); + private final Map> aliasesToCommand = new HashMap<>(); protected final SuperiorSkyblockPlugin plugin; @@ -49,17 +49,17 @@ protected CommandsMap(SuperiorSkyblockPlugin plugin) { public void registerCommand(SuperiorCommand superiorCommand, boolean sort) { List aliases = new LinkedList<>(superiorCommand.getAliases()); - String label = aliases.get(0).toLowerCase(Locale.ENGLISH); + String label = aliases.remove(0).toLowerCase(Locale.ENGLISH); aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(label, Collections.emptyList())); - if (subCommands.containsKey(label)) { - subCommands.remove(label); - aliasesToCommand.values().removeIf(sC -> sC.getAliases().get(0).equals(aliases.get(0))); + if (subCommands.remove(label) != null) { + aliasesToCommand.values().forEach(commandsList -> + commandsList.removeIf(sC -> sC.getAliases().get(0).equalsIgnoreCase(label))); } subCommands.put(label, superiorCommand); for (String alias : aliases) { - aliasesToCommand.put(alias.toLowerCase(Locale.ENGLISH), superiorCommand); + aliasesToCommand.computeIfAbsent(alias.toLowerCase(Locale.ENGLISH), a -> new LinkedList<>()).add(superiorCommand); } if (sort) { @@ -74,18 +74,28 @@ public void unregisterCommand(SuperiorCommand superiorCommand) { Preconditions.checkNotNull(superiorCommand, "superiorCommand parameter cannot be null."); List aliases = new LinkedList<>(superiorCommand.getAliases()); - String label = aliases.get(0).toLowerCase(Locale.ENGLISH); + String label = aliases.remove(0).toLowerCase(Locale.ENGLISH); aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(label, Collections.emptyList())); subCommands.remove(label); - aliasesToCommand.values().removeIf(sC -> sC.getAliases().get(0).equals(aliases.get(0))); + aliasesToCommand.values().forEach(commandsList -> + commandsList.removeIf(sC -> sC.getAliases().get(0).equals(aliases.get(0)))); } @Nullable public SuperiorCommand getCommand(String label) { label = label.toLowerCase(Locale.ENGLISH); - SuperiorCommand superiorCommand = subCommands.getOrDefault(label, aliasesToCommand.get(label)); - return superiorCommand != null && !isCommandEnabled(superiorCommand) ? null : superiorCommand; + SuperiorCommand superiorCommand = subCommands.get(label); + if (superiorCommand == null || !isCommandEnabled(superiorCommand)) { + List commandAliases = aliasesToCommand.getOrDefault(label, Collections.emptyList()); + for (SuperiorCommand commandAlias : commandAliases) { + if (isCommandEnabled(commandAlias)) { + superiorCommand = commandAlias; + break; + } + } + } + return superiorCommand; } public List getSubCommands(boolean includeDisabled) { From 9124c47a1c95cffa7f5d6f5c37c5f60615d4b560 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 28 Dec 2024 10:52:34 +0200 Subject: [PATCH 021/600] Fix ratings not removed when players join islands that were rated (#2305) --- .../superiorskyblock/commands/admin/CmdAdminAdd.java | 1 - .../superiorskyblock/commands/player/CmdAccept.java | 1 - .../bgsoftware/superiorskyblock/island/SIsland.java | 10 +++++----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java index 5cec71f909..5e57451730 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java @@ -78,7 +78,6 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab IslandUtils.sendMessage(island, Message.JOIN_ANNOUNCEMENT, Collections.emptyList(), targetPlayer.getName()); - island.revokeInvite(targetPlayer); island.addMember(targetPlayer, SPlayerRole.defaultRole()); if (superiorPlayer == null) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java index da845187a6..b4c860529c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java @@ -91,7 +91,6 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ IslandUtils.sendMessage(island, Message.JOIN_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); - island.revokeInvite(superiorPlayer); island.addMember(superiorPlayer, SPlayerRole.defaultRole()); if (targetPlayer == null) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 8de564ce63..fa140b88cc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -526,14 +526,14 @@ public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) { boolean addedNewMember = members.writeAndGet(members -> members.add(superiorPlayer)); - // This player is already an member of the island + // This player is already a member of the island if (!addedNewMember) return; - // Removing player from being a coop. - if (isCoop(superiorPlayer)) { - removeCoop(superiorPlayer); - } + // Remove player from being coop, invited and its ratings + removeCoop(superiorPlayer); + revokeInvite(superiorPlayer); + removeRating(superiorPlayer); superiorPlayer.setIsland(this); From 73009deec065e1a6f91f0fae2942e5e01e5ea47e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 28 Dec 2024 10:56:46 +0200 Subject: [PATCH 022/600] Adds the ability to use `amount` in menu items (#2306) --- .../bgsoftware/superiorskyblock/core/io/MenuParserImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java index 1371462ad9..927daaff1b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java @@ -321,6 +321,9 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec if (section.contains("lore")) itemBuilder.withLore(section.getStringList("lore")); + if (section.isInt("amount")) + itemBuilder.withAmount(section.getInt("amount")); + if (section.contains("enchants")) { for (String _enchantment : section.getConfigurationSection("enchants").getKeys(false)) { Enchantment enchantment; From ff5e486b33a2a11c1b774d202dd0b75a2cd3998b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 28 Dec 2024 11:44:54 +0200 Subject: [PATCH 023/600] Fixed issues with placing large schematics with a lot of empty blocks (#2307) --- .../superiorskyblock/core/BigBitSet.java | 26 ++++++++++++++----- .../schematic/impl/SuperiorSchematic.java | 10 +++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/BigBitSet.java b/src/main/java/com/bgsoftware/superiorskyblock/core/BigBitSet.java index fb2cbc5ab6..8ec8c8b5c9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/BigBitSet.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/BigBitSet.java @@ -37,19 +37,31 @@ public int nextSetBit(int fromIndex) { int backendIdx = fromIndex / DEFAULT_CAPACITY; int bitSetIdx = fromIndex % DEFAULT_CAPACITY; - int next = -1; + return nextSetBitInternal(backendIdx, bitSetIdx); + } + + private int nextSetBitInternal(int backendIdx, int bitSetIdx) { + if (backendIdx < 0 || backendIdx >= this.backend.length) + return -1; BitSet bitSet = this.backend[backendIdx]; if (bitSet != null) { - next = bitSet.nextSetBit(bitSetIdx); - if (next == -1 && ++backendIdx < this.backend.length) { - bitSet = this.backend[backendIdx]; - if (bitSet != null) - next = bitSet.nextSetBit(0); + int next = bitSet.nextSetBit(bitSetIdx); + if (next != -1) { + return backendIdx * DEFAULT_CAPACITY + next; } } - return next == -1 ? -1 : backendIdx * DEFAULT_CAPACITY + next; + return nextSetBitInternal(backendIdx + 1, 0); + } + + public int cardinality() { + int cardinality = 0; + for (BitSet bitSet : backend) { + if (bitSet != null) + cardinality += bitSet.cardinality(); + } + return cardinality; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java index bef96b739d..e9867981f3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.core.VarintArray; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; import com.bgsoftware.superiorskyblock.core.profiler.ProfileType; import com.bgsoftware.superiorskyblock.core.profiler.Profiler; import com.bgsoftware.superiorskyblock.core.schematic.SchematicBlock; @@ -246,8 +247,17 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long List> chunkFutures = new ArrayList<>(affectedChunks.size()); AtomicBoolean failed = new AtomicBoolean(false); + MutableBoolean printedWarning = new MutableBoolean(false); affectedChunks.forEach(chunkPosition -> { + if (!island.isInside(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ())) { + if (!printedWarning.get()) { + Log.warn("Part of the schematic ", name, " is placed outside of the island, skipping this part..."); + printedWarning.set(true); + } + return; + } + chunkFutures.add(ChunksProvider.loadChunk(chunkPosition, ChunkLoadReason.SCHEMATIC_PLACE, chunk -> { if (failed.get()) return; From e7c7202e4c4ad0157d6a568a31482526a31ac804 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 28 Dec 2024 12:23:57 +0200 Subject: [PATCH 024/600] Fixed out-of-bounds errors when unregistering commands --- .../superiorskyblock/commands/CommandsMap.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java index b28b09b576..01c1b7cd63 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java @@ -52,10 +52,7 @@ public void registerCommand(SuperiorCommand superiorCommand, boolean sort) { String label = aliases.remove(0).toLowerCase(Locale.ENGLISH); aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(label, Collections.emptyList())); - if (subCommands.remove(label) != null) { - aliasesToCommand.values().forEach(commandsList -> - commandsList.removeIf(sC -> sC.getAliases().get(0).equalsIgnoreCase(label))); - } + removeCommand(label); subCommands.put(label, superiorCommand); for (String alias : aliases) { @@ -77,9 +74,7 @@ public void unregisterCommand(SuperiorCommand superiorCommand) { String label = aliases.remove(0).toLowerCase(Locale.ENGLISH); aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(label, Collections.emptyList())); - subCommands.remove(label); - aliasesToCommand.values().forEach(commandsList -> - commandsList.removeIf(sC -> sC.getAliases().get(0).equals(aliases.get(0)))); + removeCommand(label); } @Nullable @@ -111,4 +106,11 @@ private boolean isCommandEnabled(SuperiorCommand superiorCommand) { return superiorCommand instanceof IAdminIslandCommand || !DISABLED_COMMANDS_CACHE.contains(superiorCommand); } + private void removeCommand(String label) { + if (subCommands.remove(label) != null) { + aliasesToCommand.values().forEach(commandsList -> + commandsList.removeIf(sC -> sC.getAliases().get(0).equalsIgnoreCase(label))); + } + } + } From a37e6ea03ade73eb7bedac6599ba2c902c82b400 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 28 Dec 2024 12:36:40 +0200 Subject: [PATCH 025/600] Optimized saving of schematics --- .../schematic/SchematicsManagerImpl.java | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index 38a7811df0..f8e3f1d175 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -202,17 +202,33 @@ public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY Math.max(pos1.getZ(), pos2.getZ()) ); - int xSize = max.getBlockX() - min.getBlockX(); - int ySize = max.getBlockY() - min.getBlockY(); - int zSize = max.getBlockZ() - min.getBlockZ(); + int minBlockX = min.getBlockX(); + int minBlockY = min.getBlockY(); + int minBlockZ = min.getBlockZ(); + + int xSize = max.getBlockX() - minBlockX; + int ySize = max.getBlockY() - minBlockY; + int zSize = max.getBlockZ() - minBlockZ; List> blocks = new ArrayList<>(); List> entities = new ArrayList<>(); for (int x = 0; x <= xSize; x++) { - for (int z = 0; z <= zSize; z++) { + int blockX = minBlockX + x; + for (int z = 0; z <= zSize; /* z increments inside loop */) { + int blockZ = minBlockZ + z; + // Check if we at start of new chunk + if ((blockX & 0xF) == 0 && (blockZ & 0xF) == 0) { + Chunk chunk = world.getChunkAt(blockX >> 4, blockZ >> 4); + if (plugin.getNMSChunks().isChunkEmpty(chunk)) { + // Skip empty chunk + z += 16; + continue; + } + } + for (int y = 0; y <= ySize; y++) { - Block block = world.getBlockAt(x + min.getBlockX(), y + min.getBlockY(), z + min.getBlockZ()); + Block block = world.getBlockAt(blockX, minBlockY + y, blockZ); Material blockType = block.getType(); if (blockType == Material.AIR) continue; @@ -235,6 +251,8 @@ public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY ); } } + + ++z; } } From 98e71ee9dd0d67be67bf735345af9973d3975018 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 28 Dec 2024 13:16:06 +0200 Subject: [PATCH 026/600] Fixed detection of disabled commands broken after recent changes (#2304) --- .../superiorskyblock/commands/CommandsMap.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java index 01c1b7cd63..0c5b75bc27 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java @@ -81,16 +81,17 @@ public void unregisterCommand(SuperiorCommand superiorCommand) { public SuperiorCommand getCommand(String label) { label = label.toLowerCase(Locale.ENGLISH); SuperiorCommand superiorCommand = subCommands.get(label); - if (superiorCommand == null || !isCommandEnabled(superiorCommand)) { - List commandAliases = aliasesToCommand.getOrDefault(label, Collections.emptyList()); - for (SuperiorCommand commandAlias : commandAliases) { - if (isCommandEnabled(commandAlias)) { - superiorCommand = commandAlias; - break; - } + if (superiorCommand != null && isCommandEnabled(superiorCommand)) + return superiorCommand; + + List commandAliases = aliasesToCommand.getOrDefault(label, Collections.emptyList()); + for (SuperiorCommand commandAlias : commandAliases) { + if (isCommandEnabled(commandAlias)) { + return commandAlias; } } - return superiorCommand; + + return null; } public List getSubCommands(boolean includeDisabled) { From 2504fd5f019a19e08cd60864d76ce26ec29ac6c3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 28 Dec 2024 14:49:43 +0200 Subject: [PATCH 027/600] Fixed detection of broken sign warps (#2311) --- .../superiorskyblock/island/SIsland.java | 2 +- .../listener/SignsListener.java | 22 ++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index fa140b88cc..a14d15f541 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -3562,7 +3562,7 @@ public void deleteWarp(@Nullable SuperiorPlayer superiorPlayer, Location locatio IslandWarp islandWarp; try (LocationKey locationKey = LocationKey.of(location)) { - islandWarp = warpsByLocation.remove(location); + islandWarp = warpsByLocation.remove(locationKey); } if (islandWarp != null) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java index 37cdc329a6..44812ca075 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java @@ -21,6 +21,10 @@ public class SignsListener implements Listener { + private static final BlockFace[] NEARBY_BLOCKS = new BlockFace[]{ + BlockFace.UP, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.EAST + }; + private final SuperiorSkyblockPlugin plugin; public SignsListener(SuperiorSkyblockPlugin plugin) { @@ -77,27 +81,29 @@ public void onSignBreak(BlockBreakEvent e) { if (result.isCancelEvent()) e.setCancelled(true); } else { - for (BlockFace blockFace : BlockFace.values()) { + for (BlockFace blockFace : NEARBY_BLOCKS) { Block faceBlock = e.getBlock().getRelative(blockFace); BlockState blockState = faceBlock.getState(); if (blockState instanceof Sign) { - boolean isSign; + boolean isSignGonnaBreak; if (ServerVersion.isLegacy()) { org.bukkit.material.Sign sign = (org.bukkit.material.Sign) blockState.getData(); - isSign = sign.getAttachedFace().getOppositeFace() == blockFace; + isSignGonnaBreak = sign.getAttachedFace().getOppositeFace() == blockFace; } else { Object blockData = plugin.getNMSWorld().getBlockData(faceBlock); - if (blockData instanceof org.bukkit.block.data.Rotatable) { - isSign = ((org.bukkit.block.data.Rotatable) blockData).getRotation().getOppositeFace() == blockFace; - } else if (blockData instanceof org.bukkit.block.data.Directional) { - isSign = ((org.bukkit.block.data.Directional) blockData).getFacing().getOppositeFace() == blockFace; + if (blockData instanceof org.bukkit.block.data.type.WallSign) { + // Wall signs will only be broken if they are attached to the block + isSignGonnaBreak = ((org.bukkit.block.data.type.WallSign) blockData).getFacing() == blockFace; + } else if (blockData instanceof org.bukkit.block.data.type.Sign) { + // Standing signs will only be broken if they are placed on top of the block + isSignGonnaBreak = blockFace == BlockFace.UP; } else { throw new RuntimeException("Found sign that cannot be handled: " + blockData); } } - if (isSign) { + if (isSignGonnaBreak) { IslandSigns.Result result = IslandSigns.handleSignBreak(superiorPlayer, (Sign) blockState); if (result.isCancelEvent()) { e.setCancelled(true); From 8eaccffed73c21a58aeed18b77d27b0d23a579ee Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 2 Jan 2025 21:39:43 +0200 Subject: [PATCH 028/600] [CI SKIP] Do not build against Java 16 & update userdev --- Hooks/Oraxen/build.gradle | 2 +- NMS/Paper-1_20_3/build.gradle | 2 +- NMS/v1_17/build.gradle | 2 +- NMS/v1_18/build.gradle | 2 +- NMS/v1_19/build.gradle | 2 +- NMS/v1_20_3/build.gradle | 2 +- NMS/v1_20_4/build.gradle | 2 +- NMS/v1_21/build.gradle | 2 +- NMS/v1_21_3/build.gradle | 2 +- NMS/v1_21_4/build.gradle | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Hooks/Oraxen/build.gradle b/Hooks/Oraxen/build.gradle index f9fbf6db3d..5fa0a07828 100644 --- a/Hooks/Oraxen/build.gradle +++ b/Hooks/Oraxen/build.gradle @@ -2,7 +2,7 @@ group 'Hooks:Oraxen' java { toolchain { - languageVersion.set(JavaLanguageVersion.of(16)) + languageVersion.set(JavaLanguageVersion.of(17)) } } diff --git a/NMS/Paper-1_20_3/build.gradle b/NMS/Paper-1_20_3/build.gradle index 56aabad643..6dc5afd0de 100644 --- a/NMS/Paper-1_20_3/build.gradle +++ b/NMS/Paper-1_20_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" } group 'NMS:Paper-1_20_3' diff --git a/NMS/v1_17/build.gradle b/NMS/v1_17/build.gradle index 8239e92160..627e339389 100644 --- a/NMS/v1_17/build.gradle +++ b/NMS/v1_17/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" } java { diff --git a/NMS/v1_18/build.gradle b/NMS/v1_18/build.gradle index 70e30d95a5..94104dbd12 100644 --- a/NMS/v1_18/build.gradle +++ b/NMS/v1_18/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" } java { diff --git a/NMS/v1_19/build.gradle b/NMS/v1_19/build.gradle index e1dcbb6651..5642e98ee6 100644 --- a/NMS/v1_19/build.gradle +++ b/NMS/v1_19/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" } java { diff --git a/NMS/v1_20_3/build.gradle b/NMS/v1_20_3/build.gradle index 92346110a8..40ff4eaede 100644 --- a/NMS/v1_20_3/build.gradle +++ b/NMS/v1_20_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" } java { diff --git a/NMS/v1_20_4/build.gradle b/NMS/v1_20_4/build.gradle index eb9e16b745..4fd3c1b8f5 100644 --- a/NMS/v1_20_4/build.gradle +++ b/NMS/v1_20_4/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" } java { diff --git a/NMS/v1_21/build.gradle b/NMS/v1_21/build.gradle index dd1d58f09b..8a98614ad7 100644 --- a/NMS/v1_21/build.gradle +++ b/NMS/v1_21/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" } java { diff --git a/NMS/v1_21_3/build.gradle b/NMS/v1_21_3/build.gradle index 4ece9c65b7..f551333bc2 100644 --- a/NMS/v1_21_3/build.gradle +++ b/NMS/v1_21_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" } java { diff --git a/NMS/v1_21_4/build.gradle b/NMS/v1_21_4/build.gradle index 05b844dfa6..f5199ecaec 100644 --- a/NMS/v1_21_4/build.gradle +++ b/NMS/v1_21_4/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.8" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" } java { From e8b7bce1a7f6da0ead975c33ac40ee2204cfb096 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 2 Jan 2025 21:39:54 +0200 Subject: [PATCH 029/600] Fix glow enchantment in 1.21.4 --- .../v1_21_4/enchantment/GlowEnchantment.java | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java index 96e07d945c..1bd25d1d18 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java @@ -2,6 +2,7 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.common.reflection.ReflectMethod; +import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; import net.minecraft.core.MappedRegistry; import net.minecraft.core.Registry; @@ -12,9 +13,9 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.tags.TagKey; import net.minecraft.world.item.enchantment.Enchantment; -import org.bukkit.NamespacedKey; import org.bukkit.craftbukkit.enchantments.CraftEnchantment; +import javax.annotation.Nullable; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Map; @@ -42,9 +43,16 @@ public class GlowEnchantment extends CraftEnchantment { private static final String GLOW_ENCHANTMENT_NAME = "superiorskyblock_glowing_enchant"; - private static final Enchantment HANDLE = initializeHandle(); + private static final Holder HANDLE = initializeHandle(); + + @Nullable + private static Holder initializeHandle() { + Registry registry = MinecraftServer.getServer().registryAccess() + .lookup(Registries.ENCHANTMENT).orElse(null); + + if (registry == null) + return null; - private static Enchantment initializeHandle() { Enchantment handle = new Enchantment( Component.empty(), Enchantment.definition( @@ -58,21 +66,21 @@ private static Enchantment initializeHandle() { DataComponentMap.EMPTY ); - MinecraftServer.getServer().registryAccess().lookup(Registries.ENCHANTMENT).ifPresent(registry -> { + Holder holder; + + try { + REGISTRY_FROZEN.set(registry, false); try { - REGISTRY_FROZEN.set(registry, false); - try { - // This may throw IllegalStateException which we don't care about. - registry.createIntrusiveHolder(handle); - } catch (Throwable ignored) { - } - Registry.register(registry, ResourceLocation.withDefaultNamespace(GLOW_ENCHANTMENT_NAME), handle); - } finally { - freezeRegistry(registry); + // This may throw IllegalStateException which we don't care about. + registry.createIntrusiveHolder(handle); + } catch (Throwable ignored) { } - }); + holder = Registry.registerForHolder(registry, ResourceLocation.withDefaultNamespace(GLOW_ENCHANTMENT_NAME), handle); + } finally { + freezeRegistry(registry); + } - return handle; + return holder; } private static void freezeRegistry(Registry registry) { @@ -107,7 +115,7 @@ private static void freezeRegistryUnsafe(Registry registry) throws Exception } public GlowEnchantment() { - super(NamespacedKey.minecraft(GLOW_ENCHANTMENT_NAME), HANDLE); + super(HANDLE); } } From 75858f27f8a8ce732b3f5de9af3ca78d88cdceca Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 3 Jan 2025 12:46:07 +0200 Subject: [PATCH 030/600] Adds the ability to change the amount of commands listed in commands list (#2316) --- .../api/config/SettingsManager.java | 6 ++ .../commands/CommandsHelper.java | 22 +++++ .../commands/CommandsManagerImpl.java | 14 +-- .../commands/CommandsMap.java | 4 + .../commands/player/CmdAdmin.java | 85 +++++++++++++------ .../commands/player/CmdHelp.java | 75 +++++++++++----- .../config/SettingsContainer.java | 2 + .../config/SettingsManagerImpl.java | 5 ++ .../config/section/GlobalSection.java | 4 + .../core/events/CallbacksBus.java | 7 +- .../core/messages/Message.java | 4 +- src/main/resources/config.yml | 6 +- 12 files changed, 177 insertions(+), 57 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsHelper.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index f4726a2121..f5df901271 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -634,6 +634,12 @@ public interface SettingsManager { */ boolean getChatSigningSupport(); + /** + * Amount of commands to be listed in the `/is help` and `/is admin` commands. + * Config-path: commands-per-page + */ + int getCommandsPerPage(); + interface Database { /** diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsHelper.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsHelper.java new file mode 100644 index 0000000000..23c901eb2b --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsHelper.java @@ -0,0 +1,22 @@ +package com.bgsoftware.superiorskyblock.commands; + +import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; +import com.bgsoftware.superiorskyblock.core.Text; +import org.bukkit.command.CommandSender; + +public class CommandsHelper { + + private CommandsHelper() { + + } + + public static boolean shouldDisplayCommandForPlayer(SuperiorCommand superiorCommand, CommandSender executor) { + return superiorCommand.displayCommand() && hasCommandAccess(superiorCommand, executor); + } + + public static boolean hasCommandAccess(SuperiorCommand superiorCommand, CommandSender executor) { + String permission = superiorCommand.getPermission(); + return Text.isBlank(permission) || executor.hasPermission(permission); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java index c388b605ab..3abc6e861e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java @@ -264,7 +264,7 @@ public boolean execute(CommandSender sender, String label, String[] args) { return false; } - if (!command.getPermission().isEmpty() && !sender.hasPermission(command.getPermission())) { + if (!CommandsHelper.hasCommandAccess(command, sender)) { Log.debugResult(Debug.EXECUTE_COMMAND, "Return Missing Permission", command.getPermission()); Message.NO_COMMAND_PERMISSION.send(sender, locale); return false; @@ -346,20 +346,20 @@ public List tabComplete(CommandSender sender, String label, String[] arg if (args.length > 0) { SuperiorCommand command = playerCommandsMap.getCommand(args[0]); if (command != null) { - return command.getPermission() != null && !sender.hasPermission(command.getPermission()) ? - Collections.emptyList() : command.tabComplete(plugin, sender, args); + return CommandsHelper.shouldDisplayCommandForPlayer(command, sender) ? + command.tabComplete(plugin, sender, args) : Collections.emptyList(); } } List list = new LinkedList<>(); for (SuperiorCommand subCommand : getSubCommands()) { - if (subCommand.getPermission() == null || sender.hasPermission(subCommand.getPermission())) { + if (CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender)) { List aliases = new LinkedList<>(subCommand.getAliases()); aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(aliases.get(0).toLowerCase(Locale.ENGLISH), Collections.emptyList())); - for (String _aliases : aliases) { - if (_aliases.contains(args[0].toLowerCase(Locale.ENGLISH))) { - list.add(_aliases); + for (String alias : aliases) { + if (alias.contains(args[0].toLowerCase(Locale.ENGLISH))) { + list.add(alias); } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java index 0c5b75bc27..c70ae874d3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java @@ -65,6 +65,8 @@ public void registerCommand(SuperiorCommand superiorCommand, boolean sort) { subCommands.clear(); superiorCommands.forEach(s -> subCommands.put(s.getAliases().get(0), s)); } + + plugin.getCallbacksBus().notifyCallbacks(CallbacksBus.CallbackType.COMMANDS_UPDATE); } public void unregisterCommand(SuperiorCommand superiorCommand) { @@ -75,6 +77,8 @@ public void unregisterCommand(SuperiorCommand superiorCommand) { aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(label, Collections.emptyList())); removeCommand(label); + + plugin.getCallbacksBus().notifyCallbacks(CallbacksBus.CallbackType.COMMANDS_UPDATE); } @Nullable diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java index 7d95957800..04a57b2096 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java @@ -2,8 +2,12 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; +import com.bgsoftware.superiorskyblock.commands.CommandsHelper; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -18,6 +22,17 @@ public class CmdAdmin implements ISuperiorCommand { + private static final Int2ObjectMapView> commandsPerPageCache = CollectionsFactory.createInt2ObjectArrayMap(); + + public static void registerCallbacks(CallbacksBus bus) { + bus.registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CmdAdmin::onCommandsRefresh); + bus.registerCallback(CallbacksBus.CallbackType.COMMANDS_UPDATE, CmdAdmin::onCommandsRefresh); + } + + private static void onCommandsRefresh() { + commandsPerPageCache.clear(); + } + @Override public List getAliases() { return Collections.singletonList("admin"); @@ -67,7 +82,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; } - if (!command.getPermission().isEmpty() && !sender.hasPermission(command.getPermission())) { + if (!CommandsHelper.hasCommandAccess(command, sender)) { Log.debugResult(Debug.EXECUTE_COMMAND, "Return Missing Permission", command.getPermission()); Message.NO_COMMAND_PERMISSION.send(sender, locale); return; @@ -89,17 +104,19 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ if (args.length == 2) { try { page = Integer.parseInt(args[1]); - } catch (Throwable ignored) { + } catch (IllegalArgumentException ex) { + Message.INVALID_AMOUNT.send(sender, args[1]); + return; } } if (page <= 0) { - Message.INVALID_AMOUNT.send(sender, locale, page); + Message.INVALID_AMOUNT.send(sender, page); return; } List subCommands = new SequentialListBuilder() - .filter(subCommand -> subCommand.getPermission().isEmpty() || sender.hasPermission(subCommand.getPermission())) + .filter(subCommand -> CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender)) .build(plugin.getCommands().getAdminSubCommands()); if (subCommands.isEmpty()) { @@ -107,25 +124,39 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; } - int lastPage = subCommands.size() / 7; - if (subCommands.size() % 7 != 0) lastPage++; + int commandsPerPageCount = plugin.getSettings().getCommandsPerPage(); + + int lastPage; + if (commandsPerPageCount > 0) { + lastPage = subCommands.size() / commandsPerPageCount; + if (subCommands.size() % commandsPerPageCount != 0) lastPage++; + } else { + lastPage = 1; + } if (page > lastPage) { - Message.INVALID_AMOUNT.send(sender, locale, page); + Message.INVALID_AMOUNT.send(sender, page); return; } - subCommands = subCommands.subList((page - 1) * 7, Math.min(subCommands.size(), page * 7)); - Message.ADMIN_HELP_HEADER.send(sender, locale, page, lastPage); - for (SuperiorCommand _subCommand : subCommands) { - if (_subCommand.displayCommand() && (_subCommand.getPermission().isEmpty() || sender.hasPermission(_subCommand.getPermission()))) { - String description = _subCommand.getDescription(locale); - if (description == null) - new NullPointerException("The description of the command " + _subCommand.getAliases().get(0) + " is null.").printStackTrace(); - Message.ADMIN_HELP_LINE.send(sender, locale, plugin.getCommands().getLabel() + " " + _subCommand.getUsage(locale), description); + List commandsOfPage; + if (commandsPerPageCount > 0) { + commandsOfPage = commandsPerPageCache.get(page); + if (commandsOfPage == null) { + commandsOfPage = subCommands.subList((page - 1) * commandsPerPageCount, Math.min(subCommands.size(), page * commandsPerPageCount)); + commandsPerPageCache.put(page, commandsOfPage); } + } else { + commandsOfPage = subCommands; + } + + for (SuperiorCommand subCommand : commandsOfPage) { + String description = subCommand.getDescription(locale); + if (description == null) + new NullPointerException("The description of the command " + subCommand.getAliases().get(0) + " is null.").printStackTrace(); + Message.ADMIN_HELP_LINE.send(sender, locale, plugin.getCommands().getLabel() + " " + subCommand.getUsage(locale), description); } if (page != lastPage) @@ -139,28 +170,28 @@ public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sen if (args.length > 1) { SuperiorCommand command = plugin.getCommands().getAdminCommand(args[1]); if (command != null) { - return command.getPermission() != null && !sender.hasPermission(command.getPermission()) ? - Collections.emptyList() : command.tabComplete(plugin, sender, args); + return CommandsHelper.hasCommandAccess(command, sender) ? + command.tabComplete(plugin, sender, args) : Collections.emptyList(); } + } else if (args.length == 1) { + return Collections.emptyList(); } List list = new LinkedList<>(); - if (args.length != 1) { - for (SuperiorCommand subCommand : plugin.getCommands().getAdminSubCommands()) { - if (subCommand.displayCommand() && (subCommand.getPermission() == null || sender.hasPermission(subCommand.getPermission()))) { - List aliases = new LinkedList<>(subCommand.getAliases()); - aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(aliases.get(0).toLowerCase(Locale.ENGLISH), Collections.emptyList())); - for (String _aliases : aliases) { - if (_aliases.contains(args[1].toLowerCase(Locale.ENGLISH))) { - list.add(_aliases); - } + for (SuperiorCommand subCommand : plugin.getCommands().getAdminSubCommands()) { + if (CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender)) { + List aliases = new LinkedList<>(subCommand.getAliases()); + aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(aliases.get(0).toLowerCase(Locale.ENGLISH), Collections.emptyList())); + for (String alias : aliases) { + if (alias.contains(args[1].toLowerCase(Locale.ENGLISH))) { + list.add(alias); } } } } - return Collections.unmodifiableList(list); + return list.isEmpty() ? Collections.emptyList() : Collections.unmodifiableList(list); } private boolean isNumber(String str) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java index a0731d4df5..e595f7f5fd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java @@ -2,8 +2,12 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; +import com.bgsoftware.superiorskyblock.commands.CommandsHelper; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; @@ -14,6 +18,17 @@ public class CmdHelp implements ISuperiorCommand { + private static final Int2ObjectMapView> commandsPerPageCache = CollectionsFactory.createInt2ObjectArrayMap(); + + public static void registerCallbacks(CallbacksBus bus) { + bus.registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CmdHelp::onCommandsRefresh); + bus.registerCallback(CallbacksBus.CallbackType.COMMANDS_UPDATE, CmdHelp::onCommandsRefresh); + } + + private static void onCommandsRefresh() { + commandsPerPageCache.clear(); + } + @Override public List getAliases() { return Collections.singletonList("help"); @@ -68,8 +83,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ } List subCommands = new SequentialListBuilder() - .filter(subCommand -> subCommand.displayCommand() && (subCommand.getPermission().isEmpty() || - sender.hasPermission(subCommand.getPermission()))) + .filter(subCommand -> CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender)) .build(plugin.getCommands().getSubCommands()); if (subCommands.isEmpty()) { @@ -77,25 +91,41 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; } - int lastPage = subCommands.size() / 7; - if (subCommands.size() % 7 != 0) lastPage++; + int commandsPerPageCount = plugin.getSettings().getCommandsPerPage(); + + int lastPage; + if (commandsPerPageCount > 0) { + lastPage = subCommands.size() / commandsPerPageCount; + if (subCommands.size() % commandsPerPageCount != 0) lastPage++; + } else { + lastPage = 1; + } if (page > lastPage) { Message.INVALID_AMOUNT.send(sender, page); return; } - subCommands = subCommands.subList((page - 1) * 7, Math.min(subCommands.size(), page * 7)); - Message.ISLAND_HELP_HEADER.send(sender, page, lastPage); java.util.Locale locale = PlayerLocales.getLocale(sender); - for (SuperiorCommand _subCommand : subCommands) { - String description = _subCommand.getDescription(locale); + List commandsOfPage; + if (commandsPerPageCount > 0) { + commandsOfPage = commandsPerPageCache.get(page); + if (commandsOfPage == null) { + commandsOfPage = subCommands.subList((page - 1) * commandsPerPageCount, Math.min(subCommands.size(), page * commandsPerPageCount)); + commandsPerPageCache.put(page, commandsOfPage); + } + } else { + commandsOfPage = subCommands; + } + + for (SuperiorCommand subCommand : commandsOfPage) { + String description = subCommand.getDescription(locale); if (description == null) - new NullPointerException("The description of the command " + _subCommand.getAliases().get(0) + " is null.").printStackTrace(); - Message.ISLAND_HELP_LINE.send(sender, plugin.getCommands().getLabel() + " " + _subCommand.getUsage(locale), description == null ? "" : description); + new NullPointerException("The description of the command " + subCommand.getAliases().get(0) + " is null.").printStackTrace(); + Message.ISLAND_HELP_LINE.send(sender, plugin.getCommands().getLabel() + " " + subCommand.getUsage(locale), description == null ? "" : description); } if (page != lastPage) @@ -106,21 +136,28 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + if (args.length != 2) + return Collections.emptyList(); + List list = new LinkedList<>(); - if (args.length == 2) { - List subCommands = new SequentialListBuilder() - .filter(subCommand -> subCommand.displayCommand() && (subCommand.getPermission().isEmpty() || - sender.hasPermission(subCommand.getPermission()))) - .build(plugin.getCommands().getSubCommands()); + List subCommands = new SequentialListBuilder() + .filter(subCommand -> CommandsHelper.shouldDisplayCommandForPlayer(subCommand, sender)) + .build(plugin.getCommands().getSubCommands()); - int lastPage = subCommands.size() / 7; - if (subCommands.size() % 7 != 0) lastPage++; + int commandsPerPageCount = plugin.getSettings().getCommandsPerPage(); - for (int i = 1; i <= lastPage; i++) - list.add(i + ""); + int lastPage; + if (commandsPerPageCount > 0) { + lastPage = subCommands.size() / commandsPerPageCount; + if (subCommands.size() % commandsPerPageCount != 0) lastPage++; + } else { + lastPage = 1; } + for (int i = 1; i <= lastPage; i++) + list.add(i + ""); + return Collections.unmodifiableList(list); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index d683dd4e4e..319f769913 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -214,6 +214,7 @@ public class SettingsContainer { public final List playerRespawnActions; public final BigInteger blockCountsSaveThreshold; public final boolean chatSigningSupport; + public final int commandsPerPage; public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config) throws ManagerLoadException { databaseType = config.getString("database.type").toUpperCase(Locale.ENGLISH); @@ -534,6 +535,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config this.playerRespawnActions = Collections.unmodifiableList(playerRespawnActions); blockCountsSaveThreshold = BigInteger.valueOf(config.getInt("block-counts-save-threshold", 100)); chatSigningSupport = config.getBoolean("chat-signing-support", true); + commandsPerPage = config.getInt("commands-per-page", 7); } private List loadInteractables(SuperiorSkyblockPlugin plugin) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index 22e01f3ec2..e541162858 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -581,6 +581,11 @@ public boolean getChatSigningSupport() { return this.global.getChatSigningSupport(); } + @Override + public int getCommandsPerPage() { + return this.global.getCommandsPerPage(); + } + public void updateValue(String path, Object value) throws IOException { File file = new File(plugin.getDataFolder(), "config.yml"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index 1b7f1c0d43..1c990b5a62 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -364,4 +364,8 @@ public boolean getChatSigningSupport() { return getContainer().chatSigningSupport; } + public int getCommandsPerPage() { + return getContainer().commandsPerPage; + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java index c817cbe40a..e2861b8868 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java @@ -1,6 +1,8 @@ package com.bgsoftware.superiorskyblock.core.events; import com.bgsoftware.superiorskyblock.commands.CommandsMap; +import com.bgsoftware.superiorskyblock.commands.player.CmdAdmin; +import com.bgsoftware.superiorskyblock.commands.player.CmdHelp; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.SpawnIsland; @@ -22,6 +24,8 @@ public void registerDefaultCallbacks() { CommandsMap.registerCallbacks(this); SpawnIsland.registerCallbacks(this); RegionManagerServiceImpl.registerCallbacks(this); + CmdHelp.registerCallbacks(this); + CmdAdmin.registerCallbacks(this); } public void registerCallback(CallbackType callbackType, Runnable callback) { @@ -42,7 +46,8 @@ public void notifyCallbacks(CallbackType callbackType) { public enum CallbackType { - SETTINGS_UPDATE + SETTINGS_UPDATE, + COMMANDS_UPDATE } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 0469e31cab..e225c59d8c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.service.message.MessagesService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandsHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; @@ -806,8 +807,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { Message.ISLAND_PROTECTED.send(sender, locale, args); SuperiorCommand bypassCommand = plugin.getCommands().getAdminCommand("bypass"); - - if (bypassCommand != null && sender.hasPermission(bypassCommand.getPermission())) + if (CommandsHelper.hasCommandAccess(bypassCommand, sender)) Message.ISLAND_PROTECTED_OPPED.send(sender, locale, args); } }, diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 4f2115a184..78708dafb9 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -821,4 +821,8 @@ block-counts-save-threshold: 100 # with the signing of chat messages. However, this may cause issues with other # plugins that do not properly handle signed messages, and in this case it # might be better to disable it. -chat-signing-support: true \ No newline at end of file +chat-signing-support: true + +# Amount of commands to be listed in the `/is help` and `/is admin` commands. +# Setting this to 0 or below will result all commands to be shown in a single page. +commands-per-page: 7 \ No newline at end of file From d0b485141766dfbd2b9120ef94602cdcbb3afc22 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 3 Jan 2025 12:57:37 +0200 Subject: [PATCH 031/600] Fixed descriptions of custom menu commands do not have colors parsed correctly (#2314) --- .../core/menu/impl/internal/MenuCustom.java | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java index 1aa0afd1f7..2472eafd6f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java @@ -3,8 +3,11 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; +import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; +import com.bgsoftware.superiorskyblock.api.service.message.MessagesService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -13,6 +16,7 @@ import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; +import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import org.bukkit.configuration.ConfigurationSection; @@ -27,6 +31,14 @@ public class MenuCustom extends AbstractMenu { + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final LazyReference messagesService = new LazyReference() { + @Override + protected MessagesService create() { + return plugin.getServices().getService(MessagesService.class); + } + }; + private MenuCustom(MenuParseResult parseResult, String fileName, @Nullable CommandArgs commandArgs) { super(MenuIdentifiers.MENU_CUSTOM_PREFIX + fileName, parseResult); if (commandArgs != null) @@ -58,12 +70,17 @@ public static MenuCustom createInstance(File menuFile) { return null; } - List aliases = Arrays.asList(commandsSection.getString("aliases", "").split(", ")); + List aliases = commandsSection.isList("aliases") ? + commandsSection.getStringList("aliases") : + Arrays.asList(commandsSection.getString("aliases", "").split(", ")); String permission = commandsSection.getString("permission", ""); - Map descriptions = new ArrayMap<>(); - if (commandsSection.contains("description")) { - for (String locale : commandsSection.getConfigurationSection("description").getKeys(false)) - descriptions.put(PlayerLocales.getLocale(locale), commandsSection.getString("description." + locale)); + Map descriptions = new ArrayMap<>(); + if (commandsSection.isConfigurationSection("description")) { + ConfigurationSection description = commandsSection.getConfigurationSection("description"); + for (String locale : description.getKeys(false)) { + descriptions.put(PlayerLocales.getLocale(locale), + messagesService.get().parseComponent(cfg, description.getCurrentPath() + "." + locale)); + } } boolean displayCommand = commandsSection.getBoolean("display-command", false); @@ -77,10 +94,10 @@ private static class CommandArgs { private final List aliases; private final String permission; - private final Map descriptions; + private final Map descriptions; private final boolean displayCommand; - CommandArgs(List aliases, String permission, Map descriptions, boolean displayCommand) { + CommandArgs(List aliases, String permission, Map descriptions, boolean displayCommand) { this.aliases = aliases; this.permission = permission; this.descriptions = descriptions; @@ -114,7 +131,7 @@ public String getUsage(Locale locale) { @Override public String getDescription(Locale locale) { - return this.args.descriptions.getOrDefault(locale, ""); + return this.args.descriptions.getOrDefault(locale, EmptyMessageComponent.getInstance()).getMessage(); } @Override From f8eb6600aef27dbad39e94fa0b83ca62b96baaa0 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 3 Jan 2025 19:00:00 +0200 Subject: [PATCH 032/600] Fixed sounds not working correctly in menus in 1.21.4 (#2313) --- .../superiorskyblock/core/io/MenuParserImpl.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java index 927daaff1b..bae579d8d0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.PagedMenuView; import com.bgsoftware.superiorskyblock.api.world.GameSound; +import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; @@ -424,12 +425,8 @@ public List parseButtonSlots(ConfigurationSection section, String key, return !section.contains(key) ? Collections.emptyList() : menuPatternSlots.getSlots(section.getString(key)); } - private static > E getMinecraftEnum(Class type, String name) throws IllegalArgumentException { - String mappedName = MinecraftNamesMapper.getMinecraftName(name) - .map(minecraftKey -> NAMES_MAPPER.get().getMappedName(type, minecraftKey).orElse(minecraftKey)) - .orElse(name); - - return Enum.valueOf(type, mappedName.toUpperCase(Locale.ENGLISH)); + private static T getMinecraftEnum(Class type, String name) throws IllegalArgumentException { + return getMinecraftEnum(type, name, mappedName -> EnumHelper.getEnum(type, mappedName)); } private static T getMinecraftEnum(Class type, String name, Function enumCreator) throws IllegalArgumentException { From 26d477e3b061a382f17528be5534407a1d15aa62 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 3 Jan 2025 19:19:19 +0200 Subject: [PATCH 033/600] Fix for HIDE_ATTRIBUTES not working in 1.20.6+ (#2310) --- .../nms/v1_20_4/NMSAlgorithmsImpl.java | 17 +++++++++++------ .../nms/v1_21/NMSAlgorithmsImpl.java | 12 ++++++++++++ .../nms/v1_21_3/NMSAlgorithmsImpl.java | 12 ++++++++++++ .../nms/v1_21_4/NMSAlgorithmsImpl.java | 12 ++++++++++++ .../core/itemstack/ItemBuilder.java | 9 ++++++++- .../superiorskyblock/nms/NMSAlgorithms.java | 3 +++ 6 files changed, 58 insertions(+), 7 deletions(-) diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java index 27984c75b6..bf950823a2 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_4; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -16,6 +15,8 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_4.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_20_4.menu.MenuHopperBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.KeyBlocksCache; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; import io.papermc.paper.chat.ChatRenderer; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.TextReplacementConfig; @@ -32,9 +33,9 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.NamespacedKey; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.entity.CraftFallingBlock; @@ -54,15 +55,14 @@ import org.jetbrains.annotations.NotNull; import java.util.EnumMap; -import java.util.Map; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectField> REGISTRY_CACHE = - new ReflectField<>(CraftRegistry.class, Map.class, "cache"); + private static final Multimap EMPTY_ATTRIBUTES_MAP = + MultimapBuilder.hashKeys().hashSetValues().build(); private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); @@ -222,6 +222,11 @@ public void handlePaperChatRenderer(Object event) { asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); } + @Override + public void hideAttributes(ItemMeta itemMeta) { + itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); + } + private interface MenuCreator extends BiFunction { } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java index 7ef4efd8ea..6dfea17088 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java @@ -17,6 +17,8 @@ import com.bgsoftware.superiorskyblock.nms.v1_21.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21.menu.MenuHopperBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21.world.KeyBlocksCache; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; import io.papermc.paper.chat.ChatRenderer; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.TextReplacementConfig; @@ -36,6 +38,8 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftServer; @@ -67,6 +71,9 @@ public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final ReflectField> REGISTRY_CACHE = new ReflectField<>(CraftRegistry.class, Map.class, "cache"); + private static final Multimap EMPTY_ATTRIBUTES_MAP = + MultimapBuilder.hashKeys().hashSetValues().build(); + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { @@ -229,6 +236,11 @@ public void handlePaperChatRenderer(Object event) { asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); } + @Override + public void hideAttributes(ItemMeta itemMeta) { + itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); + } + private interface MenuCreator extends BiFunction { } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java index 5ae230043b..f4b5fddef9 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java @@ -17,6 +17,8 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_3.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_3.menu.MenuHopperBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.KeyBlocksCache; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; import io.papermc.paper.chat.ChatRenderer; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.TextReplacementConfig; @@ -36,6 +38,8 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftServer; @@ -67,6 +71,9 @@ public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final ReflectField> REGISTRY_CACHE = new ReflectField<>(CraftRegistry.class, Map.class, "cache"); + private static final Multimap EMPTY_ATTRIBUTES_MAP = + MultimapBuilder.hashKeys().hashSetValues().build(); + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { @@ -229,6 +236,11 @@ public void handlePaperChatRenderer(Object event) { asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); } + @Override + public void hideAttributes(ItemMeta itemMeta) { + itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); + } + private interface MenuCreator extends BiFunction { } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index ec4cba9c93..3b615162ec 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -17,6 +17,8 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuHopperBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; import io.papermc.paper.chat.ChatRenderer; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.TextReplacementConfig; @@ -36,6 +38,8 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftServer; @@ -67,6 +71,9 @@ public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final ReflectField> REGISTRY_CACHE = new ReflectField<>(CraftRegistry.class, Map.class, "cache"); + private static final Multimap EMPTY_ATTRIBUTES_MAP = + MultimapBuilder.hashKeys().hashSetValues().build(); + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { @@ -229,6 +236,11 @@ public void handlePaperChatRenderer(Object event) { asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); } + @Override + public void hideAttributes(ItemMeta itemMeta) { + itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); + } + private interface MenuCreator extends BiFunction { } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java b/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java index 198a92faaf..cabc2bab90 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java @@ -193,8 +193,15 @@ public ItemBuilder withEnchant(Enchantment enchant, int level) { } public ItemBuilder withFlags(ItemFlag... itemFlags) { - if (itemMeta != null) + if (itemMeta != null) { itemMeta.addItemFlags(itemFlags); + for (ItemFlag itemFlag : itemFlags) { + if (itemFlag == ItemFlag.HIDE_ATTRIBUTES) { + plugin.getNMSAlgorithms().hideAttributes(itemMeta); + break; + } + } + } return this; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java index 36998a6f76..c2ddb03383 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java @@ -84,4 +84,7 @@ default void handlePaperChatRenderer(Object event) { throw new UnsupportedOperationException(); } + default void hideAttributes(ItemMeta itemMeta) { + + } } From 7a92aeb010fadec0272e3eb2cd22a116a62d2840 Mon Sep 17 00:00:00 2001 From: Jayms Date: Fri, 3 Jan 2025 10:41:47 -0700 Subject: [PATCH 034/600] Add placeholder to return schematic name (#2318) Add `superior_island_schematic` to return the schematic name for the players island, stored under `island_type` in the database. --- .../service/placeholders/PlaceholdersServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index 42ae51b181..935af07ea7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -100,6 +100,7 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { island.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getBlockZ() + "") .put("world", (island, superiorPlayer) -> island.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getWorld().getName()) + .put("schematic", (island, superiorPlayer) -> island.getSchematicName()) .put("team_size", (island, superiorPlayer) -> island.getIslandMembers(true).size() + "") .put("team_size_online", (island, superiorPlayer) -> island.getIslandMembers(true).stream().filter(SuperiorPlayer::isShownAsOnline).count() + "") From fde052774258ffa744f65cf30b806e5c16adc7ca Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 10 Jan 2025 15:38:14 +0200 Subject: [PATCH 035/600] Fixed errors with Enchantment registry in latest versions --- .../nms/v1_21_4/NMSAlgorithmsImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index 3b615162ec..db5754a08f 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -188,7 +188,15 @@ public Enchantment getGlowEnchant() { public Enchantment createGlowEnchantment() { Enchantment enchantment = getGlowEnchant(); - Map registryCache = REGISTRY_CACHE.get(Registry.ENCHANTMENT); + Registry registry = Registry.ENCHANTMENT; + try { + if (registry instanceof io.papermc.paper.registry.legacy.DelayedRegistry) { + registry = ((io.papermc.paper.registry.legacy.DelayedRegistry) registry).delegate(); + } + } catch (Throwable ignored) { + } + + Map registryCache = REGISTRY_CACHE.get(registry); registryCache.put(enchantment.getKey(), enchantment); From 60b2f8ce819ed8f87166e491d8827c28fbf04408 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 10 Jan 2025 18:56:13 +0200 Subject: [PATCH 036/600] Changed missions to show requirement placeholders per requirement-group --- .../resources/modules/missions/BlocksMissions | Bin 34768 -> 40213 bytes .../modules/missions/BrewingMissions | Bin 22023 -> 28802 bytes .../modules/missions/CraftingMissions | Bin 17871 -> 24865 bytes .../modules/missions/EnchantingMissions | Bin 21817 -> 28964 bytes .../modules/missions/FarmingMissions | Bin 30053 -> 37488 bytes .../modules/missions/FishingMissions | Bin 17986 -> 24781 bytes .../resources/modules/missions/IslandMissions | Bin 20326 -> 27266 bytes .../resources/modules/missions/ItemsMissions | Bin 16147 -> 23297 bytes .../resources/modules/missions/KillsMissions | Bin 14797 -> 22023 bytes .../modules/missions/StatisticsMissions | Bin 16008 -> 23148 bytes 10 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/modules/missions/BlocksMissions b/src/main/resources/modules/missions/BlocksMissions index b8eb8d2e57b3816f5a5fe3f3a3db6cfdf0ccff56..52cdbd5285bcc2bf62acd07e9421580c9226194f 100644 GIT binary patch delta 25468 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 delta 20739 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 F{{bs*09F71 diff --git a/src/main/resources/modules/missions/EnchantingMissions b/src/main/resources/modules/missions/EnchantingMissions index 14a696a0ef9dd2c0032fa8919d17b2302e2a4cb7..39ccafe7d8d57c006a076b0040c0698a7f7d6528 100644 GIT binary patch literal 28964 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 delta 18822 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 OZ)9vZINh+jcmD_Zo50Ti delta 19167 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 diff --git a/src/main/resources/modules/missions/FishingMissions b/src/main/resources/modules/missions/FishingMissions index a20b384dca9e2066027a6cc4a21b67ae4d4e8c76..2818e7a57dff674bc266493d75bb456b40698cad 100644 GIT binary patch literal 24781 zcmb@t18{E9mM$9ek8RtwZQHhOCp)&WV<$UyvSZsjwr%I`^SbZrbGl!>dbj({sP%s!EASfsxi8N|$puYp;AFsay`tKtrrYb}yB`?kZ3Z(dd3t9)_ zs5AtCT;co`!20{3{S7<08w>;oc$0 zKPgj6ApVzC!Tu^Uaj^TB1^=@Q!oSNHTevuwyLuQooBh9v6aH6m7dJ;UXDbJ17aK2Q zTL%-Hf0@tppEiQ(|HFJcD;F0l2YZ+QqG&CQbcq-o2nZe#2uSe%M3K0ai=~ylh1|a@ zCS{^Gu{CmW8Pd?vK+!<`f{z417wLjgYb)v05#@)hs?$g|S7;t+7d5TnB=3@9v1CTN z053eXR|WJ@5WMe&)Rs`X)zBNPMLa1yc(~T+KV<@{p}~N|q|py1`F#Smd-7O5zGh~A z19@U>v*avP7bcBysW0oP+SPLEN3M66@q{@K*EIzzFXBnG%1U4@<#yR0k%t^#sUTwx z5TNKljH&~rV2LbwZZRLVU%EyRi1Vqqgq__y3EBCtFWBiHl%7*k%{bNUEhSib_BXgl z57VH!YRpZ6CuzBBVYzrQT~=xvS%&fhPW7O~g;NUbCh#vD$V!Nzv>=6&6>ZS=B6Tvt4{ug=bUf&R)sA0?w*Phd`qo=&0x<0SMUY&%znG z(^4xvu{Vtuki8b znw`{ODZzCTVL?9(-@+#WAd%VBsM)ULiy$dZUX<8kc~skh&t7jePL{W#qVuY72Gxia zPyvH;fhqu>sut3mQfR6h=d4ZuU1S|u3+mCo`Ct#{9kOhp^8pC&~pVJ$AS&o;; z;$d56;hDKtl+Y%qx#pR*mC=p0eDzzvyJwu_du_o|5L_{%J3V>izdLY5aH)Q<6uJ3r zvkX3ty@0Syy4mpohG&YvRuWyy5wC#uT-AM+*M>Akxf57 zu||B1J{ZKs|FvY-OuhqQAGP~YXx*aDN$M+R5tW*I2N0RU%pt00vUjUA^$ls~?1AW3 zW?S2}c1sAMnkecVY^WOd^y3(p6lr_$wicgsLaIDFyfe<@K`G!Zp&i)yvO%O8A0;9f z(Lce#MJZ-Nz%TRJN??kf864MDIarD=7Eg@dr89EQjvGi}Q!um5nw8@}L}S_LQKzy! z4=t$}u9i-R;e+h&_Gfe*g`B}#l0KY|GN!FLmR)+Z)t)dZ9lJ~^;D#@&%cjrFGUD2E z-nHM#DyuH0n^}G-w|B%PYkis(;CGvv+Eatbckpf}iWL2g=LrgcuTd_>D7Y>)-8OM0 ze<#>iyo2t*hf!&JXw5?nin#G@KE0)!j z<^-|gn0tdRMV(w+C?N9Y@d4tqBRwZd}sYdjkqrMmi{Kr)gouom;Po~W+0B-CTQPL{4lr5fAbrk8kZ=xiO(5u3) zqz5JFG{r81#v2+zerVuHV|!4b^S(5oxB^rl02t7tRMeb*qMIM0398xeHze!}hzpU) zRty23*_bp-!1kLqoF%|GZinZ)^Go1A9MwO7+-YMUWd#%n2p#ILH~XL9@4w@*sUXZ`K+@EmZB%g6JUZKMv!+fg*erT+EQF$v_3hG>w^YlY3+DG; z=6!)ZgB=Wk6WJ1D3tWNsKfi~u2#)EAx|o?4toS#4X4;Q$d49V*9mNOuf5P>``HHof zc)=AZ!*$i%;4EN>Big}kKYir)=s59K*|S~{*70#Lrd{NlcP<^4@~)+<_$^ez8h|5t z6J+s}?q=98Y1Z(fs+SW>jpp6uB&mn?H=3)@37zm~<|WimmTSYx6j*|V<~ak%VC+UT z*;}JShmy1YG#qQhN~``_FEHxl>4)PBSV_3DA&Q_)i?^m~FDQrk%{gPlZEm*$e+)gQ z>n{=!M-KKK$C%9g#GIzAKWE}jB^s02cxJCUoQ z?jPd#`faBQKvquMZx424OBY}$j!S2(HiAmWlqKxffn#tMsb$khLhX)0^71-NDBMq} zY!g@XkflJb(g_8AvK;7))3~V&SLzZ!;hqyi^9t5S+pYXf*)lo0+Z3kz`hbZ(V|{0# z#y!lG*oR3Do!f$AFRAHNB*P7ml>z(Z61g;h?AArpEYjAezK%5EfDh&wU2`Gg4@Gj! zG>W@8bR`7K2LBr|o_S`>@M?9D-ZO51(+ei*6}e#b>uRGfFTT6+(pRmELG@z!8}=?;hZkt@A9)=-@t- z3U+HnxJRpnM!is6?B(2i$Ve{WPou2Gz=ItXN2;Ea6>cRJLJsTNCO_+9_9L3Q<`uZ`mmRlvASa;rD@aY*8D1F+vpD_PKdP;o- zZ}68Uz2Fu3)Q?R;)>kGBb{E-xBD0kw62oDey|^sySCc>{>S+Dix0`g_LM2x^KrtDl zJ@QPKeBzXjdd@u9c;QEfrb&MH{CR_S=c`Es!NghwkTDDyr!qx2>iK@2*(F%j>9cU^ zj{KcSjwTaeL_N$&Xrh9Eyg0&OEMPwmj(TDo;}X+N&qRWpdk|0><_S^t@&k!Nv3Eps z|MMO_`|fH$J^sjtr#?<0s~WpYCObv+-6XmkzT%(-x0y67mQxMHV9+kPLeM3-Z&hNtKln5%8R>V!t}wVd)?7xCLQLcZEE z+rPp-pOt?0GvQsFGa1TGcnm-^Y-o^gRm(>lVh)jrbtpxNe&j1=+A}zmG3Lt zKn??@;{1~3VP$C{>3GGIG$C4GI6ulHw2!1BFeR$UsFi6eNj8ue-dxZ#t~O`t+Zrhq zyoZEBE)CA_qdv>N%i_Ul!CoC7%3Xb>S-cQMLEUJeURH=FHR3`JJIzboPhJXBdQ?JR zPGHvABWc-+rUCO&GOkrJkZL!kIM3`9Y28^SNyPhks3VlU~z_wA~6$OWVyWVkx}|Wr?_NY{1=8?$N&N*YI9E^TuzR!GDOpwsCm4CPB?gp~j-Dm0Z6s+oHwqMgS^})( zeVWn1KTRI#sgoR3mbK$|JuRj=?lzVFspL?`WLeR5AjeQy>?6u(-7&#YSF`d}#DDD6 zCZ|)4-NpLXRkQr*LJ#C?TR#m6*AhvEGKeYMRH^%7(F#WJ7`1>484C z>FOz40jh%)4Su2>iumcf#0jP0UJ9lwn_JUnq;G6m%ni_&q$M#~7}b)}4-pcdEcvEmzW)<7R_$Y?G>@`L)T`i1K9I3wPJ6vYtYEU?gC>ljcKG~c+z zEo%UK;v1;FaGnT8a(O7S8?+f)$eUPEp*%FYYU-AHH75Wv5j6jplAhgVg8HG}j1k_zl-*8z|siyfav%SVi+8DwSl$G$p0($UHm&(ff#Z9DW$yXs>)ZSyp zUT)55W0dz(Tc;`+Bi{`O7igXG`u7N?nO2wg0ZzqGAzy#MW^4K$5_y(nxrdKMxpIN% zp>JPSrOEOeB?9EFWuV$~eG-Uo1!{a8%0k&j}pN zjf~4gq4jEQ7;lmw#p|}EI2cacYdz`NX+0*M3whwT7A>-s>)H)70$?WrIs0d;xc9ImkJ<)F%mU@jN<-MkTI}vrAyHq_7_4%1I>dH7zeI7MSdQO4KZ-U5d26~>qWqok4 z?xxn>ARDt=AA^w++fX677Me+p7)M_1d54Q*Z_n8=nYw*wK#|QRWmk~<7)N&587#KX zcJRu}Px&jo23t5i#;GQsgRMbMBUIP+0$+m(-->$RmRIdoGQpNcFLzq}yF;w*k}{PI zo{^4wqZPNBB%<$=$zYpyd=Gf+@nR!NyHP$J&izU$Nj{dmP5N!Q=*lYX= zZaS66ZlXRLmuj13kK`iClecNze&^sQaHFt9N&w{~PWNG7S8$@nIXlTK;EjDI&xM!P zXdM4NctX6crry$qTKMK!2paML^p2<-=Bl+*HT~C4N+5Nk*V_d!}D$;wz@~_>Tq>eEoRjtZ~%U#JAUT#Y+G9cdEHG@MP)ApoJEr z$=t5PN^l473h=9d)B4i>!Ccj))bp~?uiCeiF-K<)dACXJt}VTSRuY?)<`!FBi3DZj ztEhRRERi|*XgudK$XNkWs!7&)m{JK-QDx%9aJ44}h`zuJ*d5V73>oa+sg)}!5xFhf zpYj3P@ZC<|q=6B>`aSs(y#0cf`t_$9_v}4JZZhj$T-7LxvJ-99Pxst5F=(w@y3ijool#u&1}TF%O6z2IqI}7`AVtOner^ zAVfm9TX#y|SX{Pz@3Df~;ccp0P#11#v(4+EoMJu0s+g0(eRI6}0R2o3NGYTy@QDt- zV>s47*d{CO8pP+zi-NKDq;pyny%yvsE}WZv`cax9a_5Z2dl!W;EfB)yMhwFUSDPcB z$R3W&XY(-7A2oPoDdEA39$SJORmO4fZj%16-FC2h_%UFuA8!SNtv{e)>KOxaM5%Ki zdURKtKQd3Vk*{QFu!0TzS?TM5w2UL9&GpV6r{#NqcOBXTlX9>Dix7|yjf|&8pELV8 zE6P)!bFqTY8pkqzA~Sq|ypTbh;nb%4N8ef&W#h@fy{Z0p3>HO7pG^u2#)6-=dv!E* z8!R@(9*>x^UC!WbHLK^tbB0dvu(33JE_o7e1Pd&SHLJESGGJ zc*&=Sy?jLue~VJ4HHte{tMF~UQY^LGZPqUA_`*Z*U2qYj*HvtBZ(9y2?D~&-;jxr{ zdk2^5g?YjJ_MBe{IBbrOK8DpKs8$F=18-OG=<5X{%2)4AiP7%QB^VIQ1h|i#kPAZ0 z8#c`mC`Qw@Kg3PO5_m9dBgJbxT}V?TPb7u~b!gG9>(nDsB~QmSX)_I67-~70Gp&a=H+Ymae%0pU)Ggrc+TIl! zqD8nE!Hezl&*64{)$8C*=v)l|dbTA`tq^Oy7?6Oxxs85{U|;0@5$^o0>LS3;_M;nL zckz3i<-Pt_sXL;2XQ(mC zrAQkpFn2^`6{q?4ioJ1mB+bwunlG?^pLE>KV_M@OE=t+&&~bDW83d!2NIsE_sD7qr zP>~0EhbP`#$!^lP$!eHPb4b@nOlHzJRr>Ao{zBEQaw@8B2JsaoY_wyouy?2dU z?#B-uu=ad~R>aLctJ?+hnl zfnq|L!XZ8Ti73Rm6w;(xZiSS7DfzNQalH|CZ|Rz_z2Ot=+=B1Ll= zXM3BTiVbewB;Y2gN|?gDwhy2y)2uhbdMhtJ+35&cJL2D!UGV_H8;o;HX+J(F`=g(} ztSV!}sVHY^@bIwb+zfoPUqbqMHLjRLCf-c;HY2y6G`S5I+afW%(Z2))+G;xE6w;Sr zZ|&HovC?l?d0Se?TF2(oREv%9_)@fr*^z6kru>*$Q{NtZ|zK@i3(} za5PVXOCOr(!*?xA2MQ))RNn-d>s}ovimM?#T5OL-(aizmJ0tCDl9pJ58OPu0n)xE! zuMemy(dgBG(W!YN<>%s6<3dn6s{r-iI{BuKQzM=|IPY`*CE6MAj0NwG*9fTPA^oX) zjV})ss&nn{(kCM+6Wl)A7^@#+AX8bSLV9m|UOZoome@ z`U>W=g(=!l7pwq+f3-gxa)T6#rI<5yw}k1prXrprgH*`euFKXJ(PGs+jyi}MEdxM$ zx1;*2+c_otB|g2{0$OTRe$@}s*AxE?BJ!bot@f42-ylY~y=-sdP=O+Ngq_rI_*#&3 zs4e69cKh8`o^<|z$QYJ6!syp#si`S2=tQH_f7;?_kdOA=+xRW1_JKu#n8>yxrjvwy z+!RB4&+_#1XZ^SBfW!LsY?XQX3?x?(Px|s&;9xk3c;dmqYVtgnyPu8UWxkTF>_d93c{xVp>sfMWyb z0y8ZkqJ1yyxMy_b5{kXz#)(q}G~0&p&1k52r|{2p2U<6iSF6g8Xxr(YLIvlF!POov zg#g!|UsT_T0o>;?6~njRkpI!O`_DWSrvH#P_!q z_|QWsK3FJ3Vt=%m39X?c{}7w~|+bduqTXl|hvoVZ=KXo%viC>VduxK`BF2_IH-v zXxm9Y^38dY$-P={+?0}F4vcGFr7GGCc=g<_YCaz~U(VZV;CUfxdZ6IzRUb_rX?vl2uiqscwa)i&hG}>YAce&KPAnD_^pd(7r{{`7_5opwjC}YH>)| zJjbSbX4TNAQ2EulIcMxbj#Vb(RKXROY=KhcNS9)B#XEKAPLvE80m}Nm8O&pPVAOmP zt9^^gpneGI1Z)}YgCRz{ZDI*3(2bqun(3~J+Sa(L`1a>YD2jTPHb}TDavLs#x@4eYE7n*SEhtqQr1jj%fjt7Yi0t+lpipUxJ3 z&-+MumQBR_RaWfEs%M+pI-pJi)L;>XyALU7+vz=E13zHo3wzqi5k5QyaFyR>@(uhS z_Vy3+SUc^H)&6T9qJPOxV*ed`lXG)5GPX4nc5tvYGqV4;R!>P{xBLJjYFKKeSM5hxn4av2C{xd;bETg^JFxRdfAPd#B!0;VSrK8#bcI9gr9>a*@opO3Mx z5ASav$56g-6$3h5hr%UJ|D8lfH)jUo3Sz#12av;=&9Fu7O2tl-iZbS$wsfhd(}%TeXaV{@!_~J-URgQ75E%k;U#~b|ITB#DVZyjxG@a0A=@AY; zUT2rF>S$P?Dg>Nu`lC#lB?s;+(nmI3Ry0RX3@BXQ=3aOcNy&~-#3_}Q7iqJU1TYnJ z=f!xCDC@S>)N`-X^CX*`UhJ~ixD)m@lkiU7=(|3CHyYNl6G7wL@ z>HvHyBlCAKdd2d1EcTh8dP&8Dre%JnMMow?)Fy`N&t)g|W!DBw3$sy^6N+WQZrsr~ zP!o$y?kQIPKusG&8@Pt-Db(Np^z&>|skQ4+DJ&8GQmioG|C>Kg(bmYs%+kTu)XdrC zfAg%m)pa~j#Sp)^JI72pM4*VEfnx}XugHv0fRT_vh=@9pU>gFXR>q2x0X&&n=H@|! zUx;~J68fIKMWXv5BNp3!&mNwtAKo6w7A_+2(H1lE&#oF8evfKuD<5yq3Id>RTf`6eDe_U2KIuZ_; zt$-jF22wNjUW57MlepgQ#Zcx%8pyQVY*y)z83nZ+EORCAb|wl<(H{j4~!B#_+fB%)dWi8_SrJl4hcVgUMvR!|<)R=Xm5tM?BlE0u`CIh57* zX|Y<$f0o6i3%(2#Nba3A}!$}AhF^V zrYO^ilsTuFIP(CA1)OwO++iF#Pdo{*h8Yl>lxkfidMZt9We^_g;3}elt{s0Ni0W%q zZe$<&IaP)??S!GZtmKXPS%z6#@Oc)HbgeZt7j}YLl|CKL zq!{RvW;H&&XVfS(wT>2tN%f%R(K%`5XTAk*Qi^iJ^vjMRXDVYQ!P2t}VOFkE8R~nu z?3U{<0{3v@ro&vp>3eQvKjvW_p^>J_5?cDDgX1$LxODKOs}0pZEwNZSFvTskbK1wQ zx_wKeFm1y!d{OPl#q?|VZWCS6y1&9-C)_MZeBsDiz{0PSi3OzKqD^{Rzo!nDJCLax8v5SB4D)ZJkaGNv{veW7kmkX0J zoI!VQEjK-T!CXnU6^@I8maWvX+BEB0#$j&{hu>p!3w0wPaI+|}K1(Ah8;@q0?^Kq{ zdV*eIy|4+lsCagCk{}{1=?Wcq7VXROh{?Zjsy)V&@GffEeOLA)*L9R#e}p!A)FIJw zoXDdZq0=e+xs3B#fn#H%LWjOH3ZaAbN58%3_BRfm;rX#`#+_3fUgiagtC{!De4d48 zuy=`LO4)PXG?%V@J2e(j;A9GmoE4Ypj%UuuJ?%_q0!9a z4#(|50|cvrWg+=3d*fejZn?4L)ofkW$W~Ze_eiu+G%F<)oQ6eVBE1liU5Gnl6v%x< zK$N?QfKRE`)>m2qB24u$?eCK1x5Gsd3IWl4+WW#17YeLNKV<2U22O^xa0}nD)I9_? zIm7GOh~bg6k=QLZKd8z~V8*d;P}FwpNWi);(4D77BQQ(+z-igQgrs*rLa5r`b7jETV>z-P;H0rkXDL)zvwcgd58Lw3uVN zJBu{lXC=zepGS?~m-bB4`53B#n0WR$c2IuBw>K1U_q*Lqg=l|BX*GH#;>6{4oxf*f zWEqa;2qhv11Mt2|WU|Lq!gk*(lB5zSZKdjMuYQ`p(6sY71D)5bdeR|AsM-`fEgQ?fFAc-iXw>2j@g9zy`@+frx3aw zx9un2=9r;h-_V6OYu1D>-L^3{sVhJhi~wlZ%J84W}D0TxiD_CdBB`g~4)tx3rs zLttjHMd(DCD0ddA`KWC1g8wCnYTpnU19C@J$Of^ByNt_TTjOM2L9zbQN`*kue>e~1 zUPZmCb*5|{R8n3ti-&Gg4)}gjCOL*VR+R2iW+?`ETzFb59gMt?#yI(o6Ked74SRc{ zQAF%N;jM+WPPfkra~^9ABEqS%@D7kkm)_%7bd~z))rn~8lo#ha@J8xLSnEJ-88%+|4ar`96^oc4`J&4gN zb+OY{o6@ReaG)X*&B;CT{N0mqbVk^rdcQ>HDu-1GJ+H)(s zGN?{K&<9*ke@$fc!x`D(B5B2r+$);;c}m#MopfX|t+adMv4xaP4AHi#Q}>_gGOCFg zsL{&#`Xtw2MR1nNtiHpWHRTj=nnl}knPF~Z&7rLy?R9sXm3LUFKu2$kWuF(X$7r>v z@|T_FT=hYC7X*e&it?HQ#XiK$#fX06oq&l1RaYHgUH9EduEH1D|#FCP+SwnlH3x^HOC`hJ~55faW=)14zPQVVVbABS_(o)_jXI1ft5kW=pf zadfJIkk1VhuN=k_guY?;UivaB16NOks+Hj55T6%s93m$EEw9_N_+ELo2k~Hhfxs;p zvLM&ZkO;7Qq`m-II=unR2Kz)O^+hrNPi%Ix_iF|niqCq zIWvY*Tv@YdcO8Klwwo;c{*ScbA2=v3V@Lh^H*HY(i-lVMowVU!BF}&R5O=dTas9`I zf`7+G6*&hKCPX}n_0Uj30Ya)0Uo=E%E?0&e$sej>v8YJR; zB2kbb{ec8vm^$H>!mr@m5S}J|_PzFRFMe$c_=EJ)cn%w4o{SPisQ+xA*~oX;$HFd% z&7B@mhEx$iUWTcu4j{h}EuRgb@CrnsQLn{MGX!K^hOC6Rd_}$|EmRcU zazWHCwZkxJzGKjYj2QA|`!GNo-5mX{q!Y;$;%ha9C}~mbcf&-@?kvJq-8Dy3&mZn} zK@s|h=woxO^mCp)Q-s_ykZ>N?L72naAJN2&QEbnfo72f*@tm9N8kohBUR|5=$(rgC zq|WMdm-fAFS6;gnofU{FIWUPFtd*%LyQM9XLz(NUtV4{=P57Fl9qT8<+qOv($6uK) zKB0*q%4!ON>#)=qaTT*m6Fv7T^z*(_4FdeCQb_DO6QtygDPqb>K7a?XLvZgn55`J< zfUjyo95?8-Owg&}7a*?& z^4J;M``ApW5(&A0wNL)=sdGEsrf9}%s0>Bjfl%!l52os0aAo-XPnix|IdZk;Um|nX z-)lD_|5JPWH_O`8eAhu;!Sau%1~jwwKlC`NkTHq_*)fao(tyRo zGp8nL6R~|{yydRt7S`CUvRc-BP?BmFo2;@*AnB0k~3TsP)EyY1m%|y3c(q6PYOSFW`%xYmX z-Z0#N1>Oq1(Zg5~j0S?n-z{jT(7=&+aTQM>n|BuZ{7m7~368CdA6;FA!=!^VH$CXB zy0T>3C};Ru?|Ej~@Jmv61?@PWC6C*Ulgp8ME<5Jg1Aq5p7$|wSOUi_$g{&wUwx+c# zO8TLlJ$61#dospaJU-Scxqe{HR0k5gx==g!6I7$G(sD&^^AeFVnjJ4XANaf<%BWj# z6mO|y0wc9Czmw9#O}rT|mNNJrBwiF0#-k#02rY|bw0Y?v!+hjQO|N;IpmmCE@wT+x zML4HR+V{OVy0tl?p`#|&ru1Br<{4rugp*q?UC3ksTBdMsPckIWz_^)vt1yV9T*MD8 z&Bz7J=5tOx=n*!wE%*}T&q=VBvkLJr!n-9V5^Mdm_Z&Bm>Wug=lF!kB4YP2T~FVLk06j~q|` zK#@@rJgOnywAe*W1XxbJHr7J7p*kL7lTkz%eE<_$WPlO}cA(Q336Gf{5lUteLpQd7-LWb zSrLnBn!B8)miA(UMTLrnbnZ0NR(vD!I|+cv{xFtMdwzqU7qWzzps?m>5f7XIseDoH zIm6nNjX{0vg~^vSM&gz!2(HAK73vEG`GaC?p!s8{$_N$Y#K~8C-aovozQ)Ydcm&Sm zww&tX8<(G9VGkCm`l<0l2G#5jNqyhNYR1+0Mae55n%gh4R|`vSWT$|D!*t7KhmO3O zD3)$BcWzJz^&QQZEr!A=&(1iX(i_;o4zgQyxPi6vbJRyLyzz8xLy;O{{g?}&o*tzk ze(HGJ*ms+)p$8tfl_KA@SQ1cL%lu<)LHuj2>ugXfN@l_F?1wvbN0pbsLc6rC=_5&X zjJ+kSxpt%i43aN_K!VzP#KS>kBMS2ttZ#s?8t!y0R$m47hid*SwzoO>49jixZsr$@ zJ^a{!HlaT9SF`IrQdb~G6;s&HnsUKf2nHD2yn7|`k~jqTimpH91J-NJwjgg@A|73w zL^tAy;~?99(yW&Eb{9V>#S-#T%0UEGGRF!WJNa(56Q-Xl8LShEn zu0U6d5lFU913cEQ&L6yr@f8m|+xN+>kL?!=tI9{)=N2eRhWw_WWMu1->I>ww_xguO#1xYFZ62Mxa|elzS*fB=*ORFdl{|RHPx>MZx!i`@{F; zdHre2vtp|9Mmjd-hh(A<*up$n3`QfY?tI4upUJI$S_cMDRBa2%YUfl9Vc$Ab7Ch>O zW66Jnrqw7#Vs6O9NVdW|fgPG~o;`nH-@11V46Oa|*wZW4kIedr6L4{d{K+5B29EE6 z=6OMc@Ke9`4Z@n#k45`_EmpaenLk}6^CnQWgyffWW<+^)JsFH|!b+HFgG^y#3HV$+IxbwUct{;#t_L|I!U&bkDIOQe z)^Kd$Uq#l~Z(^!!9FAUH&0Ph&5tCknP@DK|U}fyt1I4YLwdR(pwf-+?yjcSyvAF!H z0~RhXd%IM;MBs3)Ucnu|q-INzgQIe6T3DcZ)B(YE<(?=!Xt?S(fx(K(K~D-B_YO^9 z+pRw0_9cnMG}Hwq;5u!Om;>gRthJHdb)4rr0Np1htrk2K&nyQF#>nlRoZ}1>)-!L{ z{c~4gED!ua4oQ@~FTNM@9x)67af_F#c$S!tr84L_gA!0)$bKBY=<8X%RL|7s;OnE@ zjtEu$?J^kOpSw9TmlYtb7IzzYL#?p%@yRP;!u;gjfkvLo{tnmz-oTM-KRstC=vDCW zfpq9u_Fp#0UDUwtEZF`mGNr9BZmuXN{&uuy(LjwV2dFU>9sWwfIub}vb|-`FGvGr! ze9_@&4;bp6*+nkBFIr*xB>0a&`9Jq_{#)%AXEP@^D`zu1Gke#6y<_{2FkD7N42Sq{ z7!)BxWWI?;GN>ak3wXZ>hGAw+7m4^WuRI1v3zYyEh)Up^}EojID$;HLG}A`*E<-5Wh1 z${p&b6%SEyWYx^YAq5G5k=C3=9R*P(F?>LcGIaD^b^v!b@C%)7?c)3_I zlc)EHI2X_*DPS^Nsu$33v#Y^901wA3OG>SU2_=-2cTGmPQDfJOE)9jMM&^%{5;k`09_U+zq`j; zj5qcG3fwq9Yk%l7nV<>|v2&KS<|01D@~`kOui$>LAp)c`t{Q7oL3pn_eM;4sA-?Kl zzKrPVM72pAS8=9w)1^~ix8SL>s-LU;J;eHCu+@Zed2z;~`cbg6E$S* zc;nrq1_OS3UNM^$juCq>H6=Y1-kIf-u~>L?b8|Of3dgQZq7sKsD7k!ZCJbTDrY!&5 zQ*w=?*4Ah5?q2z8jSPPiM5X_+RZ9I=gEUL%lLi$+6so;1oO6ke~H&iWggmbA7bru8~sukqLhR$ zXGmcBxTd{bv)D^~ky{Qv0oth#exJgb(bqD@E^$WkF))qL~g72w`m*qH|yajb9^KjNceh5;MELR|W)Sb?g&7!BDOQJ4XJEfcN( zN9}gukYcj@+wILKdD5H^z=%ij^{snNUj>wJZe?{yZJ1Sf{Zm@tuE5B9HB5SIh1x*ioA#H$0OV%e zOT)zC;Z@5}ZYx@?s#7H8a~Etm^?z-tBvxSQ=&pAD8nQhI2A zoR-ZG?*|M=@NQru3e(l5oT_ui2pxn>*Tjpg0raz>1%gtHA5!{WyJlf~`3VF#ll)9# z8$q)Tv1hMM6e;-Mc9!;jP|T|==VL*FJ8LIq&3Ng|043p?{+%C^Dk_Kgtm;7}H_X{y zOU&aPM>G6>K(Ktr5yS{(9N&+C5JH^`vM+q6oM~Wg3UmEkup5jhhTD5tD-?@w-$Y8E zhfN6zLke^7y|l<|>8Tr7e>p=6M|cdVH~+#h<}t5A^&j|zRRwMMgCq71ruLWf+ilWn zZ9S1;$C3IM4xIH2w)ZB#pH24JuL2Jpkk*XD-RVVea;ZK;XtLYZVcD_-|6t_`!|i&! z9Z9kaZ!^hS1i|mcAK(sKo4cf#dchoYw*Kn@#<}%k{D*TM|63zd{2w3S|A*77{C{yV z_>x08o#c`+vy}4=b0KRm>SWX^UWz}635k|{QTNv5 ziHebol^BkCX1H8N1pNJ9A$E{(!!h_AE?gnk))Dxf4LG@ZQF|VI`MA%he{nbuE8Cp5 zul-5)rrZqLkA5zA7}9JDa(A}?0gW+Q<>u+lt%dj9f^E@;`~dYpEjx1GS&%j9?5p#6 zl7(Ofl>8Yt7oAGjOsWO6U@cQeW-umI>q=T1Oa}IN23^lm|R2c*t~+%moZT z*3n6ZjV08o@}L7W$DB>q-TEGF9P$NOY8=#Y9!r= z%Mg03uZg(w+4c&kfT=`~dhsQJlXjv$EH|ATgrL(X2?|QBwudlR(UZB}c1kBm&-NXX zK4rJgSE_);JDzWFzM&D!(?=DaG*ivLJ6vC+5V*Kmz3gJ9v@UXWPtyCkm+p(I`RDT& zm*Sl(8~WD5@^y)IQ?lry8%0!rFzPG3HzX$tV>Vri15u7OSh27KN^! z(vpn{1Ejf!cXd*a4$%*_bAq_$2JtK}O_PinhB$e;dKS$v*Pm~udml`yfd@F}i^bX{X5(ox2FEA%>UUe{ zUfEr&aObp&F2>v2g-?vUI^$&Q0d2}jolntStnATfF|4d< zXo)I>*s(H<4=kt5jC2{lF)y%`Of>dj2a}nR@RPQgZe|xQ@o_frui9I2HyKgS7v^0Z z5)JCEwd>1!ORZ<95kbVK4>5HkVdUR#^IeCzl#ZdK6oXNu0EJV6^^Nkkh~Q)vi=vK( z8)0nq*$gzM7NI^-4q~7yp@A78lF~h%DE`#oY*@>+0e6B*MFxB)7n@kNSQMbsNhs2? z_Z4LDLih!B!jWe2=N`%&oYj&V1!`p07VCVrGk!wT*YwF4m`y zyZ;pTK8^HCZFln*AQ70N=SQm?SLw^nGHl3{GWlf7P}^$>BD`T^zJ_s``QAXZx8q#Z z6y>J3TDyplyf{CyBwy+hbzZ9GC{3Y`0W(8jv-+oQo}600p2;W=yu^n4d4}^=-SU*1 zEd8fMS(iE9nJyY!a%Z5WxtG`zE*Uu9H+g=Uvu8|O4RVG`@#*8`)WWv5QO`Vyv>l%w zImZc|m(MONKfD=Tl6s=(aWTv^o{N|ZZ<%YASkT;3HuGi<)|Vyar^+7W+g~X2Kk7*g z*^>9MAkx4*bW-v{7u*74S?5S*|0*U{spzUuQWa1t`0AzkFd->eCla@0{$A=@Xw)-^ zA20#Cd}-G27D7f&;xknzZeUK!c(F9GT3M&fR7k z(1OG)=LyUL(g1lTfp+RMnuO-Hiad}ilfVlvvaquZC=C7Jmhb3mN|&hQKA)tBZM;bG z@OBVoB%zrA9ZEdVO+I1$V(HBaKx$!6x& z*dn|D>G%3#>XgK|J;|9=6Z2p=g)okzaq5-fiTWHNa)dT3($(|+3&pN#nA;UD;a z-E&x;<_7ToEWKXZM5+8a+1xs%*F}b8!`DI1^Xkp8aQ@M9ly{zm&uAP9nEFZgwddw+ z_>A@44n+RJ5Gug)b(&)}74SMaLO=&s|$ zaOQUBdJ8fn^{a{slqtTyy6s_1|%j47}O_v{se z&&;&*7j-Qq^ieLWEs@;6O3lK#5lCOuXlIqbNrKJdz(kqpd&3^4IrQm75{Jr2jiosL zM0hZVV*twCjSLxMm%3+8+%QHk*Fp+l8LFhKFS|b&Os5YDc}r7~tp)cpdB%+-z{g$E z>%XJV4HzkwZ_{MU<*e9#na4dc6@8h`6@egF(Q=Hq$Y4(%%(>yvW0gjy(8 zd>AX(uE{%0z~QTV_bmyt__h4=i*>C+jic~wVHyjE_{^95rOZwbdr*m@HeU#?)-Yei zPjB-thu!KN;-`tYc+$SbomszdOfmhjH8*>}+jp&|4deILtj#V|q(u7EqzY)(8_T_XE?s6Iji1SbEqT-Txs=ST>|3t5^o1X(~uBA7}7l zHFIe4O=gm!flAB=kdyeAEZY_E_9c+Yoa34X_I|p(VQj}~oOuo%0!4A&=@lcPUC`3A zQUfb0)eu`IHjaX#SsgNB;iqI-N`vZ(W!WY|3!FTfD5IhBjoXS06+NlN=A77Prv>rN zT9a;T0MALKQ9P0De-+Km*==jGR(?a~1Jl)6BN8)I5Crf;| z07@KSY;iNx z)Cxb>Pri-R>j^0W$w@N>P}P|BN!^%|Cy@o`E9Psf!}|gp96}8r>hDs>0*w5}Pa_SU zFw;aR1@YdrAdNO=9vB{PiYit$Zm<_$%1EEJX~5faqtyum=FlZ^S{i?Ht5<2=QQN(2 zIWrt7iZva!>YcbL+fa<(o-HB53awaGeA#D8)6}sE;r6@ZqkKs?h;9PO*irJe&}8_v zct?5UEkGj5M2exvWAv(sTHeUB{5Jn&yV_=_EyMMbdpXn4`l4BSYlZoG#54|*RLjFSfsXtku4YZ8iu`X>0;jH)Yf?lAskSrx6-UzP)R_!+tm`&_1 z6eq#x#=I87Azv7qG}%;%ml$h8_hN5Crq?4z+_8O>l+J_D=XI`griU#|J_{aH@NBf30WGA_jyAX%OZ4u$3 z415E!eOl`X9!YAiWykwVRI_2l6Kk}B30(2SYbghGq*Shm8r=~*lesBJ=D?a8M*sTh zobHG^VHutzD#B|EkQe9WD6C%h*BHxQ?puLe3w1kn<>Ud4CfFtraenuX7ERbbSg!qfU^lMLv@ZM23Hrip zekzNX3L^^JGB3XrC5X>k_IzD^W`UbTUE}OyR6>eeSma zmkY7uddh(V3W2)Ht*ocnmkTE9fF(iPbKG<1WMK$D`O|7wFX}Zd}pxW40$ql6X5bChPIKd?L#IE#>J0l*if!5*`?uT17+T@_*{Opo#8w&>;?yQ^U!ir9nYOuF;A8$x7#oi zh28VSJ0Op%vI6%nOMWuyv(U|1cP<~HYzajvFigE`4cpiXA`&|pE6AJ|kqpfQyS!1b z;nIo(GBubZX-v+wBfuRQP{;7Z`~JgTy^l}Q=;w?2=ygMG+J8L4vUcF56KV4RYoI5w z6m97L(Io1cd;U6!+UQBVNb#7`(&{4Rd)H3{ENDk(l1uECiXpk2id1h2ZsZECjWy?9 zjHeby$`-bNf~$uhWi%i^ez^p7Ilor6X;KF3!EDU*z}-vBQTkGY!d&78oe64`YNFns zZjYq*Y4dQ-s`O`STTn(lO6*Q|QLS@)ZJx48H;BXLlvcn~_? zqQ1E9cPcx16V+F83xjCu9$BY+C36#d0h?jeR>Q`j#{JifujtD$x=~=QUOagJoB#D_ zH~VAwUk`qK&~gF}*i!%Qc7zS~s02(x*8|emZ|wls1O4%U0`}kaIG}+2)((24pg$h; zI6?^f?>e9Q-u2r!JAdu`3q9;nX~)sSeiL}03Nd;YV5stow7|6eTDx5+pVi%Ayy zx1LzK|3vI}szOZaSWGlbYQ#gd0fK)p2u!r^-+!`_FrhIy)efPlNq-;uo8#pu7N${o zP)l~$LfQWT){o=nsQBY5%MQhl{*L&c>dY{)Fw2wsVV<^WJEggkCc(P*_*BnAV zpoqKUCvC?~Q}F{9!Ya`VBzXk)Zjv$M^S#+i_9)L#)a_#`;$=`=fvGaWUCL z9n@w2biBtzXph1l7tB0_kCXdT_+vwxm(e6!&0_VcJuNxNf?CFudce nD@T^1?vYv>} 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 diff --git a/src/main/resources/modules/missions/IslandMissions b/src/main/resources/modules/missions/IslandMissions index a28edeaa75f6f827c9d68034d09e83c699bc75bc..6081ea90debad7e2945644db71b980388b3e8fd9 100644 GIT binary patch delta 13074 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 cBJ2MhAGFml?ixb?0NLHmj{^YED*k!qK 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 F{{Y~5edGWD delta 13581 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 B?vDTf delta 12307 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 AfdBvi diff --git a/src/main/resources/modules/missions/StatisticsMissions b/src/main/resources/modules/missions/StatisticsMissions index 178f34f54cb3001014a0b282c1a904607ec5acc1..99bc39ab575d1b2334a1b66ca83b69ba1ea2bc4f 100644 GIT binary patch literal 23148 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 Date: Fri, 10 Jan 2025 18:56:42 +0200 Subject: [PATCH 037/600] Fixed default miner missions not considered both cobblestone and stone for progress (#2328) --- src/main/resources/modules/missions/categories/miner/miner_1.yml | 1 + src/main/resources/modules/missions/categories/miner/miner_2.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/resources/modules/missions/categories/miner/miner_1.yml b/src/main/resources/modules/missions/categories/miner/miner_1.yml index 3b6dc9aa64..d33a6047cd 100644 --- a/src/main/resources/modules/missions/categories/miner/miner_1.yml +++ b/src/main/resources/modules/missions/categories/miner/miner_1.yml @@ -31,6 +31,7 @@ required-blocks: '1': types: - 'STONE' + - 'COBBLESTONE' amount: 48 '2': types: diff --git a/src/main/resources/modules/missions/categories/miner/miner_2.yml b/src/main/resources/modules/missions/categories/miner/miner_2.yml index c0c85b2c85..66dff22a22 100644 --- a/src/main/resources/modules/missions/categories/miner/miner_2.yml +++ b/src/main/resources/modules/missions/categories/miner/miner_2.yml @@ -34,6 +34,7 @@ required-missions: required-blocks: '1': types: + - 'STONE' - 'COBBLESTONE' amount: 96 '2': From a63ad0de1fd0a86fdbf40604864b8c6d95759ebb Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Jan 2025 11:54:17 +0200 Subject: [PATCH 038/600] Fix creation of large schematics may cause a server crash (#2329) --- .../nms/v1_12_R1/NMSTagsImpl.java | 12 - .../nms/v1_12_R1/NMSWorldImpl.java | 47 +--- .../nms/v1_12_R1/world/ChunkReaderImpl.java | 206 +++++++++++++++ .../nms/v1_16_R3/NMSTagsImpl.java | 11 - .../nms/v1_16_R3/NMSWorldImpl.java | 87 +----- .../nms/v1_16_R3/world/ChunkReaderImpl.java | 246 +++++++++++++++++ .../nms/v1_17/NMSTagsImpl.java | 12 - .../nms/v1_17/NMSWorldImpl.java | 88 +------ .../nms/v1_17/world/ChunkReaderImpl.java | 247 ++++++++++++++++++ .../nms/v1_18/NMSTagsImpl.java | 12 - .../nms/v1_18/NMSWorldImpl.java | 85 +----- .../nms/v1_18/world/ChunkReaderImpl.java | 228 ++++++++++++++++ .../nms/v1_19/NMSTagsImpl.java | 12 - .../nms/v1_19/NMSWorldImpl.java | 85 +----- .../nms/v1_19/world/ChunkReaderImpl.java | 229 ++++++++++++++++ .../nms/v1_20_3/NMSTagsImpl.java | 12 - .../nms/v1_20_3/NMSWorldImpl.java | 88 +------ .../nms/v1_20_3/world/ChunkReaderImpl.java | 239 +++++++++++++++++ .../nms/v1_20_4/NMSTagsImpl.java | 12 - .../nms/v1_20_4/NMSWorldImpl.java | 89 +------ .../nms/v1_20_4/world/ChunkReaderImpl.java | 240 +++++++++++++++++ .../nms/v1_21/NMSTagsImpl.java | 12 - .../nms/v1_21/NMSWorldImpl.java | 85 +----- .../nms/v1_21/world/ChunkReaderImpl.java | 240 +++++++++++++++++ .../nms/v1_21_3/NMSTagsImpl.java | 12 - .../nms/v1_21_3/NMSWorldImpl.java | 88 +------ .../nms/v1_21_3/world/ChunkReaderImpl.java | 240 +++++++++++++++++ .../nms/v1_21_4/NMSTagsImpl.java | 12 - .../nms/v1_21_4/NMSWorldImpl.java | 93 +------ .../nms/v1_21_4/world/ChunkReaderImpl.java | 240 +++++++++++++++++ .../nms/v1_8_R3/NMSTagsImpl.java | 11 - .../nms/v1_8_R3/NMSWorldImpl.java | 51 +--- .../nms/v1_8_R3/world/ChunkReaderImpl.java | 215 +++++++++++++++ .../superiorskyblock/nms/NMSTags.java | 2 - .../superiorskyblock/nms/NMSWorld.java | 11 +- .../nms/world/ChunkReader.java | 35 +++ .../superiorskyblock/world/WorldReader.java | 80 ++++++ .../world/chunk/ChunkLoadReason.java | 1 + .../world/schematic/SchematicBuilder.java | 22 +- .../schematic/SchematicsManagerImpl.java | 175 +++++++------ 40 files changed, 2880 insertions(+), 1032 deletions(-) create mode 100644 NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java create mode 100644 NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java create mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java create mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java create mode 100644 NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/ChunkReaderImpl.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/nms/world/ChunkReader.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/WorldReader.java diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSTagsImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSTagsImpl.java index 33817d6826..fc977fa8cd 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSTagsImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSTagsImpl.java @@ -6,7 +6,6 @@ import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.tag.Tag; import net.minecraft.server.v1_12_R1.ChunkRegionLoader; -import net.minecraft.server.v1_12_R1.Entity; import net.minecraft.server.v1_12_R1.ItemStack; import net.minecraft.server.v1_12_R1.MinecraftKey; import net.minecraft.server.v1_12_R1.NBTBase; @@ -24,7 +23,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack; import org.bukkit.entity.EntityType; import org.bukkit.event.entity.CreatureSpawnEvent; @@ -70,16 +68,6 @@ private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag com return CraftItemStack.asCraftMirror(itemStack); } - @Override - public CompoundTag getNBTTag(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); - NBTTagCompound nbtTagCompound = new NBTTagCompound(); - entity.c(nbtTagCompound); - nbtTagCompound.set("Yaw", new NBTTagFloat(entity.yaw)); - nbtTagCompound.set("Pitch", new NBTTagFloat(entity.pitch)); - return CompoundTag.fromNBT(nbtTagCompound); - } - @Override public void spawnEntity(EntityType entityType, Location location, CompoundTag compoundTag) { CraftWorld craftWorld = (CraftWorld) location.getWorld(); diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java index 77a098b0a5..964a86538d 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java @@ -15,31 +15,30 @@ import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.spawners.MobSpawnerAbstractNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockDoubleStep; import net.minecraft.server.v1_12_R1.BlockPosition; import net.minecraft.server.v1_12_R1.EnumParticle; -import net.minecraft.server.v1_12_R1.EnumSkyBlock; import net.minecraft.server.v1_12_R1.IBlockData; import net.minecraft.server.v1_12_R1.IChatBaseComponent; import net.minecraft.server.v1_12_R1.MobSpawnerAbstract; -import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_12_R1.PacketPlayOutBlockChange; import net.minecraft.server.v1_12_R1.PacketPlayOutWorldBorder; import net.minecraft.server.v1_12_R1.SoundCategory; import net.minecraft.server.v1_12_R1.SoundEffectType; import net.minecraft.server.v1_12_R1.SoundEffects; -import net.minecraft.server.v1_12_R1.TileEntity; import net.minecraft.server.v1_12_R1.TileEntityMobSpawner; import net.minecraft.server.v1_12_R1.TileEntitySign; import net.minecraft.server.v1_12_R1.WorldBorder; import net.minecraft.server.v1_12_R1.WorldServer; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.Material; @@ -177,40 +176,6 @@ public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } - @Override - public CompoundTag readBlockStates(Location location) { - // Doesn't exist - return null; - } - - @Override - public byte[] getLightLevels(Location location) { - WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - return new byte[]{ - (byte) worldServer.getBrightness(EnumSkyBlock.SKY, blockPosition), - (byte) worldServer.getBrightness(EnumSkyBlock.BLOCK, blockPosition) - }; - } - } - - @Override - public CompoundTag readTileEntity(Location location) { - TileEntity tileEntity = NMSUtils.getTileEntityAt(location, TileEntity.class); - if (tileEntity == null) - return null; - - NBTTagCompound tileEntityCompound = tileEntity.save(new NBTTagCompound()); - - tileEntityCompound.remove("x"); - tileEntityCompound.remove("y"); - tileEntityCompound.remove("z"); - - return CompoundTag.fromNBT(tileEntityCompound); - } - @Override public boolean isWaterLogged(org.bukkit.block.Block block) { Material blockType = block.getType(); @@ -346,4 +311,10 @@ public IslandsGenerator createGenerator(Dimension dimension) { public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } + } diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..a2008976a8 --- /dev/null +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java @@ -0,0 +1,206 @@ +package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_12_R1.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.server.v1_12_R1.BlockPosition; +import net.minecraft.server.v1_12_R1.Chunk; +import net.minecraft.server.v1_12_R1.ChunkSection; +import net.minecraft.server.v1_12_R1.DataPaletteBlock; +import net.minecraft.server.v1_12_R1.Entity; +import net.minecraft.server.v1_12_R1.NBTTagCompound; +import net.minecraft.server.v1_12_R1.NBTTagFloat; +import net.minecraft.server.v1_12_R1.NibbleArray; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_12_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final short[] EMPTY_BLOCKS = new short[4096]; + private static final byte[] EMPTY_DATA = new byte[2048]; + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + private final int x; + private final int z; + + private final Map tileEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final short[][] blockids; + private final byte[][] blockdata; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(org.bukkit.Chunk bukkitChunk) { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + this.x = chunk.locX; + this.z = chunk.locZ; + + ChunkSection[] chunkSections = chunk.getSections(); + this.blockids = new short[chunkSections.length][]; + this.blockdata = new byte[chunkSections.length][]; + this.skylight = new byte[chunkSections.length][]; + this.emitlight = new byte[chunkSections.length][]; + + for (int i = 0; i < this.blockids.length; ++i) { + ChunkSection chunkSection = chunkSections[i]; + + if (chunkSection == null) { + this.blockids[i] = EMPTY_BLOCKS; + this.blockdata[i] = EMPTY_DATA; + this.skylight[i] = EMPTY_LIGHT; + this.emitlight[i] = EMPTY_LIGHT; + } else { + copyBlockIds(chunkSection.getBlocks(), i); + + if (chunkSection.getSkyLightArray() == null) { + skylight[i] = EMPTY_LIGHT; + } else { + skylight[i] = new byte[2048]; + System.arraycopy(chunkSection.getSkyLightArray().asBytes(), 0, skylight[i], 0, 2048); + } + + emitlight[i] = new byte[2048]; + System.arraycopy(chunkSection.getEmittedLightArray().asBytes(), 0, emitlight[i], 0, 2048); + } + } + + chunk.getTileEntities().forEach((blockPosition, tileEntity) -> { + NBTTagCompound tileEntityCompound = tileEntity.save(new NBTTagCompound()); + + tileEntityCompound.remove("x"); + tileEntityCompound.remove("y"); + tileEntityCompound.remove("z"); + + InventoryHolder inventoryHolder = tileEntity.getOwner(); + if (inventoryHolder != null) + tileEntityCompound.setString("inventoryType", inventoryHolder.getInventory().getType().name()); + + tileEntities.put(blockPosition, CompoundTag.fromNBT(tileEntityCompound)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return Material.getMaterial(this.getBlockId(x, y, z)); + } + + @Override + public short getData(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + return (short) (this.blockdata[y >> 4][off] >> ((x & 1) << 2) & 15); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues((this.x << 4) + x, y, (this.z << 4) + z); + return this.tileEntities.get(blockPosition); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + // Doesn't exist + return null; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[y >> 4][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[y >> 4][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private int getBlockId(int x, int y, int z) { + return this.blockids[y >> 4][(y & 15) << 8 | z << 4 | x]; + } + + private void copyBlockIds(DataPaletteBlock palette, int i) { + byte[] rawIds = new byte[4096]; + NibbleArray data = new NibbleArray(); + palette.exportData(rawIds, data); + + short[] blockids = this.blockids[i] = new short[4096]; + this.blockdata[i] = data.asBytes(); + + for (int j = 0; j < 4096; ++j) { + blockids[j] = (short) (rawIds[j] & 255); + } + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.locX; + this.y = entity.locY; + this.z = entity.locZ; + this.yaw = entity.getBukkitYaw(); + this.pitch = entity.pitch; + this.entityType = entity.getBukkitEntity().getType(); + + NBTTagCompound nbtTagCompound = new NBTTagCompound(); + entity.c(nbtTagCompound); + nbtTagCompound.set("Yaw", new NBTTagFloat(entity.yaw)); + nbtTagCompound.set("Pitch", new NBTTagFloat(entity.pitch)); + + this.entityTag = CompoundTag.fromNBT(nbtTagCompound); + } + + } + +} diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSTagsImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSTagsImpl.java index 3c995b8790..c2a34446ef 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSTagsImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSTagsImpl.java @@ -28,7 +28,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; @@ -83,16 +82,6 @@ private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag com return CraftItemStack.asCraftMirror(itemStack); } - @Override - public CompoundTag getNBTTag(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); - NBTTagCompound nbtTagCompound = new NBTTagCompound(); - entity.save(nbtTagCompound); - nbtTagCompound.set("Yaw", NBTTagFloat.a(entity.yaw)); - nbtTagCompound.set("Pitch", NBTTagFloat.a(entity.pitch)); - return CompoundTag.fromNBT(nbtTagCompound); - } - @Override @SuppressWarnings("ConstantConditions") public void spawnEntity(EntityType entityType, Location location, CompoundTag compoundTag) { diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java index dadc6dce43..7629d318f1 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java @@ -18,41 +18,31 @@ import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.spawners.TileEntityMobSpawnerNotifier; -import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.BlockStatesMapper; +import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.BlockPropertySlabType; -import net.minecraft.server.v1_16_R3.BlockStateBoolean; -import net.minecraft.server.v1_16_R3.BlockStateInteger; import net.minecraft.server.v1_16_R3.BlockStepAbstract; -import net.minecraft.server.v1_16_R3.EnumSkyBlock; import net.minecraft.server.v1_16_R3.IBlockData; -import net.minecraft.server.v1_16_R3.IBlockState; import net.minecraft.server.v1_16_R3.IChatBaseComponent; -import net.minecraft.server.v1_16_R3.LightEngine; -import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.PacketPlayOutBlockChange; import net.minecraft.server.v1_16_R3.PacketPlayOutWorldBorder; import net.minecraft.server.v1_16_R3.SoundCategory; import net.minecraft.server.v1_16_R3.SoundEffectType; import net.minecraft.server.v1_16_R3.TagsBlock; -import net.minecraft.server.v1_16_R3.TileEntity; import net.minecraft.server.v1_16_R3.TileEntityMobSpawner; import net.minecraft.server.v1_16_R3.TileEntitySign; import net.minecraft.server.v1_16_R3.World; import net.minecraft.server.v1_16_R3.WorldBorder; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.block.data.Waterlogged; @@ -66,7 +56,6 @@ import org.bukkit.entity.Player; import org.bukkit.event.block.SignChangeEvent; -import java.util.Map; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { @@ -190,71 +179,6 @@ public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } - @Override - public CompoundTag readBlockStates(Location location) { - World world = ((CraftWorld) location.getWorld()).getHandle(); - - IBlockData blockData; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockData = world.getType(blockPosition); - } - - CompoundTag compoundTag = null; - - for (Map.Entry, Comparable> entry : blockData.getStateMap().entrySet()) { - if (compoundTag == null) - compoundTag = new CompoundTag(); - - Tag value; - Class keyClass = entry.getKey().getClass(); - String name = BlockStatesMapper.getBlockStateName(entry.getKey()); - - if (keyClass.equals(BlockStateBoolean.class)) { - value = new ByteTag((Boolean) entry.getValue() ? (byte) 1 : 0); - } else if (keyClass.equals(BlockStateInteger.class)) { - BlockStateInteger key = (BlockStateInteger) entry.getKey(); - value = new IntArrayTag(new int[]{(Integer) entry.getValue(), key.min, key.max}); - } else { - value = new StringTag(((Enum) entry.getValue()).name()); - } - - compoundTag.setTag(name, value); - } - - return compoundTag; - } - - @Override - public byte[] getLightLevels(Location location) { - LightEngine lightEngine = ((CraftWorld) location.getWorld()).getHandle().e(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - return new byte[]{ - location.getWorld().getEnvironment() != org.bukkit.World.Environment.NORMAL ? 0 : - (byte) lightEngine.a(EnumSkyBlock.SKY).b(blockPosition), - (byte) lightEngine.a(EnumSkyBlock.BLOCK).b(blockPosition) - }; - } - } - - @Override - public CompoundTag readTileEntity(Location location) { - TileEntity tileEntity = NMSUtils.getTileEntityAt(location, TileEntity.class); - if (tileEntity == null) - return null; - - NBTTagCompound tileEntityCompound = tileEntity.save(new NBTTagCompound()); - - tileEntityCompound.remove("x"); - tileEntityCompound.remove("y"); - tileEntityCompound.remove("z"); - - return CompoundTag.fromNBT(tileEntityCompound); - } - @Override public boolean isWaterLogged(org.bukkit.block.Block block) { if (Materials.isWater(block.getType())) @@ -391,4 +315,9 @@ public WorldEditSession createEditSession(org.bukkit.World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } + } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..cc0ba844cd --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java @@ -0,0 +1,246 @@ +package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_16_R3.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.ByteTag; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.tag.IntArrayTag; +import com.bgsoftware.superiorskyblock.tag.StringTag; +import com.bgsoftware.superiorskyblock.tag.Tag; +import net.minecraft.server.v1_16_R3.Block; +import net.minecraft.server.v1_16_R3.BlockPosition; +import net.minecraft.server.v1_16_R3.BlockStateBoolean; +import net.minecraft.server.v1_16_R3.BlockStateInteger; +import net.minecraft.server.v1_16_R3.Blocks; +import net.minecraft.server.v1_16_R3.Chunk; +import net.minecraft.server.v1_16_R3.ChunkSection; +import net.minecraft.server.v1_16_R3.DataPaletteBlock; +import net.minecraft.server.v1_16_R3.Entity; +import net.minecraft.server.v1_16_R3.EnumSkyBlock; +import net.minecraft.server.v1_16_R3.GameProfileSerializer; +import net.minecraft.server.v1_16_R3.IBlockData; +import net.minecraft.server.v1_16_R3.IBlockState; +import net.minecraft.server.v1_16_R3.LightEngine; +import net.minecraft.server.v1_16_R3.NBTTagCompound; +import net.minecraft.server.v1_16_R3.NBTTagFloat; +import net.minecraft.server.v1_16_R3.NibbleArray; +import net.minecraft.server.v1_16_R3.SectionPosition; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_16_R3.CraftChunk; +import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final DataPaletteBlock EMPTY_BLOCKS = + new ChunkSection(0, null, null, true).getBlocks(); + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + private final int x; + private final int z; + + private final Map tileEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final DataPaletteBlock[] blockids; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(org.bukkit.Chunk bukkitChunk) { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + this.x = chunk.locX; + this.z = chunk.locZ; + + ChunkSection[] chunkSections = chunk.getSections(); + this.blockids = new DataPaletteBlock[chunkSections.length]; + this.skylight = new byte[chunkSections.length][]; + this.emitlight = new byte[chunkSections.length][]; + + LightEngine lightEngine = chunk.world.getChunkProvider().getLightEngine(); + + for (int i = 0; i < this.blockids.length; ++i) { + ChunkSection chunkSection = chunkSections[i]; + + if (chunkSection == null) { + this.blockids[i] = EMPTY_BLOCKS; + this.skylight[i] = EMPTY_LIGHT; + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.blockids[i] = copyDataPalette(chunkSection.getBlocks()); + + NibbleArray skyLightArray = lightEngine.a(EnumSkyBlock.SKY).a(SectionPosition.a(this.x, i, this.z)); + if (skyLightArray == null) { + this.skylight[i] = EMPTY_LIGHT; + } else { + this.skylight[i] = new byte[2048]; + System.arraycopy(skyLightArray.getIfSet(), 0, this.skylight[i], 0, 2048); + } + + NibbleArray emitLightArray = lightEngine.a(EnumSkyBlock.BLOCK).a(SectionPosition.a(this.x, i, this.z)); + if (emitLightArray == null) { + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.emitlight[i] = new byte[2048]; + System.arraycopy(emitLightArray.getIfSet(), 0, this.emitlight[i], 0, 2048); + } + } + } + + chunk.getTileEntities().forEach((blockPosition, tileEntity) -> { + NBTTagCompound tileEntityCompound = tileEntity.save(new NBTTagCompound()); + + tileEntityCompound.remove("x"); + tileEntityCompound.remove("y"); + tileEntityCompound.remove("z"); + + InventoryHolder inventoryHolder = tileEntity.getOwner(); + if (inventoryHolder != null) + tileEntityCompound.setString("inventoryType", inventoryHolder.getInventory().getType().name()); + + tileEntities.put(blockPosition, CompoundTag.fromNBT(tileEntityCompound)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return getBlockData(x, y, z).getBukkitMaterial(); + } + + @Override + public short getData(int x, int y, int z) { + return CraftMagicNumbers.toLegacyData(getBlockData(x, y, z)); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.setValues((this.x << 4) + x, y, (this.z << 4) + z); + return this.tileEntities.get(blockPosition); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + IBlockData blockData = getBlockData(x, y, z); + + if (blockData.getStateMap().isEmpty()) + return null; + + CompoundTag compoundTag = new CompoundTag(); + + for (Map.Entry, Comparable> entry : blockData.getStateMap().entrySet()) { + Tag value; + Class keyClass = entry.getKey().getClass(); + String name = BlockStatesMapper.getBlockStateName(entry.getKey()); + + if (keyClass.equals(BlockStateBoolean.class)) { + value = new ByteTag((Boolean) entry.getValue() ? (byte) 1 : 0); + } else if (keyClass.equals(BlockStateInteger.class)) { + BlockStateInteger key = (BlockStateInteger) entry.getKey(); + value = new IntArrayTag(new int[]{(Integer) entry.getValue(), key.min, key.max}); + } else { + value = new StringTag(((Enum) entry.getValue()).name()); + } + + compoundTag.setTag(name, value); + } + + return compoundTag; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[y >> 4][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[y >> 4][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private IBlockData getBlockData(int x, int y, int z) { + return this.blockids[y >> 4].a(x, y & 15, z); + } + + private static DataPaletteBlock copyDataPalette(DataPaletteBlock original) { + NBTTagCompound data = new NBTTagCompound(); + original.a(data, "Palette", "BlockStates"); + + DataPaletteBlock blockids = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID, + GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData(), null, false); + blockids.a(data.getList("Palette", 10), data.getLongArray("BlockStates")); + + return blockids; + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.locX(); + this.y = entity.locY(); + this.z = entity.locZ(); + this.yaw = entity.getBukkitYaw(); + this.pitch = entity.pitch; + this.entityType = entity.getBukkitEntity().getType(); + + NBTTagCompound nbtTagCompound = new NBTTagCompound(); + entity.save(nbtTagCompound); + nbtTagCompound.set("Yaw", NBTTagFloat.a(entity.yaw)); + nbtTagCompound.set("Pitch", NBTTagFloat.a(entity.pitch)); + + this.entityTag = CompoundTag.fromNBT(nbtTagCompound); + } + + } + +} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java index e1837076e9..1731b94bfc 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java @@ -14,13 +14,11 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; @@ -74,16 +72,6 @@ private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag com return CraftItemStack.asCraftMirror(itemStack); } - @Override - public CompoundTag getNBTTag(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - return CompoundTag.fromNBT(compoundTag); - } - @Override @SuppressWarnings("ConstantConditions") public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index be62cc0aab..0c35706015 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -18,11 +18,11 @@ import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_17.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_17.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_17.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_17.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_17.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.nms.v1_17.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; @@ -32,20 +32,15 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.border.WorldBorder; -import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; @@ -202,78 +197,6 @@ public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } - @Override - public CompoundTag readBlockStates(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(blockPos); - } - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = new CompoundTag(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return EMPTY_LIGHTS; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - return new byte[]{ - location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; - } - } - - @Override - public CompoundTag readTileEntity(Location location) { - BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); - if (blockEntity == null) - return null; - - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.save(new net.minecraft.nbt.CompoundTag()); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - return CompoundTag.fromNBT(compoundTag); - } - @Override public boolean isWaterLogged(org.bukkit.block.Block block) { if (Materials.isWater(block.getType())) @@ -404,4 +327,9 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } + } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..eb42169b4b --- /dev/null +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java @@ -0,0 +1,247 @@ +package com.bgsoftware.superiorskyblock.nms.v1_17.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final PalettedContainer EMPTY_STATES = + new LevelChunkSection(0, null, null, true).getStates(); + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + private final ServerLevel serverLevel; + private final int x; + private final int z; + + private final Map blockEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final PalettedContainer[] blockids; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(Chunk bukkitChunk) { + LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); + + this.serverLevel = levelChunk.level; + this.x = levelChunk.locX; + this.z = levelChunk.locZ; + + LevelChunkSection[] levelChunkSections = levelChunk.getSections(); + this.blockids = new PalettedContainer[levelChunkSections.length]; + this.skylight = new byte[levelChunkSections.length][]; + this.emitlight = new byte[levelChunkSections.length][]; + + LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); + + for (int i = 0; i < this.blockids.length; ++i) { + LevelChunkSection levelChunkSection = levelChunkSections[i]; + + if (LevelChunkSection.isEmpty(levelChunkSection)) { + this.blockids[i] = EMPTY_STATES; + this.skylight[i] = EMPTY_LIGHT; + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.blockids[i] = copyPalettedContainer(levelChunkSection.getStates()); + + DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) + .getDataLayerData(SectionPos.of(this.x, i, this.z)); + if (skyLightArray == null) { + this.skylight[i] = EMPTY_LIGHT; + } else { + this.skylight[i] = new byte[2048]; + System.arraycopy(skyLightArray.getIfSet(), 0, this.skylight[i], 0, 2048); + } + + DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) + .getDataLayerData(SectionPos.of(this.x, i, this.z)); + if (emitLightArray == null) { + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.emitlight[i] = new byte[2048]; + System.arraycopy(emitLightArray.getIfSet(), 0, this.emitlight[i], 0, 2048); + } + } + } + + levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { + net.minecraft.nbt.CompoundTag compoundTag = blockEntity.save(new net.minecraft.nbt.CompoundTag()); + + compoundTag.remove("x"); + compoundTag.remove("y"); + compoundTag.remove("z"); + + InventoryHolder inventoryHolder = blockEntity.getOwner(); + if (inventoryHolder != null) + compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); + + blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return getBlockState(x, y, z).getBukkitMaterial(); + } + + @Override + public short getData(int x, int y, int z) { + return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); + return this.blockEntities.get(blockPos); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + BlockState blockState = getBlockState(x, y, z); + + if (blockState.getValues().isEmpty()) + return null; + + CompoundTag compoundTag = new CompoundTag(); + + blockState.getValues().forEach((property, value) -> { + String name = PropertiesMapper.getPropertyName(property); + + if (property instanceof BooleanProperty) { + compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); + } else if (property instanceof IntegerProperty integerProperty) { + compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); + } else if (property instanceof EnumProperty) { + compoundTag.setString(name, ((Enum) value).name()); + } + }); + + return compoundTag; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private BlockState getBlockState(int x, int y, int z) { + return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); + } + + private int getSectionIndex(int y) { + int sectionIndex = SectionPos.blockToSectionCoord(y); + return sectionIndex - this.serverLevel.getMinSection(); + } + + private static PalettedContainer copyPalettedContainer(PalettedContainer original) { + net.minecraft.nbt.CompoundTag data = new net.minecraft.nbt.CompoundTag(); + original.write(data, "Palette", "BlockStates"); + + PalettedContainer blockids = new PalettedContainer<>(LevelChunkSection.GLOBAL_BLOCKSTATE_PALETTE, + Block.BLOCK_STATE_REGISTRY, NbtUtils::readBlockState, NbtUtils::writeBlockState, + Blocks.AIR.defaultBlockState(), null, false); + blockids.read(data.getList("Palette", CraftMagicNumbers.NBT.TAG_COMPOUND), data.getLongArray("BlockStates")); + + return blockids; + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.getX(); + this.y = entity.getY(); + this.z = entity.getZ(); + this.yaw = entity.getBukkitYaw(); + this.pitch = entity.getXRot(); + this.entityType = entity.getBukkitEntity().getType(); + + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + compoundTag.putFloat("Yaw", entity.getYRot()); + compoundTag.putFloat("Pitch", entity.getXRot()); + + this.entityTag = CompoundTag.fromNBT(compoundTag); + } + + } + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java index 0d81dc3e97..0dc7eb060e 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java @@ -14,13 +14,11 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; @@ -74,16 +72,6 @@ private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag com return CraftItemStack.asCraftMirror(itemStack); } - @Override - public CompoundTag getNBTTag(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - return CompoundTag.fromNBT(compoundTag); - } - @Override @SuppressWarnings("ConstantConditions") public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index ac9b7b87a4..3eeef98aaf 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -18,11 +18,11 @@ import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_18.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_18.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_18.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_18.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_18.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.nms.v1_18.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; @@ -32,20 +32,15 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.border.WorldBorder; -import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; @@ -203,75 +198,6 @@ public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } - @Override - public CompoundTag readBlockStates(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(blockPos); - } - - CompoundTag compoundTag = new CompoundTag(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return EMPTY_LIGHTS; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - return new byte[]{ - location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; - } - } - - @Override - public CompoundTag readTileEntity(Location location) { - BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); - if (blockEntity == null) - return null; - - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - return CompoundTag.fromNBT(compoundTag); - } - @Override public boolean isWaterLogged(org.bukkit.block.Block block) { if (Materials.isWater(block.getType())) @@ -403,4 +329,9 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } + } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..4cdc5c5610 --- /dev/null +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java @@ -0,0 +1,228 @@ +package com.bgsoftware.superiorskyblock.nms.v1_18.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; +import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + private final ServerLevel serverLevel; + private final int x; + private final int z; + + private final Map blockEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final PalettedContainer[] blockids; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(Chunk bukkitChunk) { + LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); + + this.serverLevel = levelChunk.level; + this.x = levelChunk.locX; + this.z = levelChunk.locZ; + + LevelChunkSection[] levelChunkSections = levelChunk.getSections(); + this.blockids = new PalettedContainer[levelChunkSections.length]; + this.skylight = new byte[levelChunkSections.length][]; + this.emitlight = new byte[levelChunkSections.length][]; + + LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); + + for (int i = 0; i < this.blockids.length; ++i) { + LevelChunkSection levelChunkSection = levelChunkSections[i]; + + this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); + + DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) + .getDataLayerData(SectionPos.of(this.x, i, this.z)); + if (skyLightArray == null) { + this.skylight[i] = EMPTY_LIGHT; + } else { + this.skylight[i] = new byte[2048]; + System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); + } + + DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) + .getDataLayerData(SectionPos.of(this.x, i, this.z)); + if (emitLightArray == null) { + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.emitlight[i] = new byte[2048]; + System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); + } + } + + levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { + net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(); + + compoundTag.remove("x"); + compoundTag.remove("y"); + compoundTag.remove("z"); + + InventoryHolder inventoryHolder = blockEntity.getOwner(); + if (inventoryHolder != null) + compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); + + blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return getBlockState(x, y, z).getBukkitMaterial(); + } + + @Override + public short getData(int x, int y, int z) { + return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); + return this.blockEntities.get(blockPos); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + BlockState blockState = getBlockState(x, y, z); + + if (blockState.getValues().isEmpty()) + return null; + + CompoundTag compoundTag = new CompoundTag(); + + blockState.getValues().forEach((property, value) -> { + String name = PropertiesMapper.getPropertyName(property); + + if (property instanceof BooleanProperty) { + compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); + } else if (property instanceof IntegerProperty integerProperty) { + compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); + } else if (property instanceof EnumProperty) { + compoundTag.setString(name, ((Enum) value).name()); + } + }); + + return compoundTag; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private BlockState getBlockState(int x, int y, int z) { + return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); + } + + private int getSectionIndex(int y) { + int sectionIndex = SectionPos.blockToSectionCoord(y); + return sectionIndex - this.serverLevel.getMinSection(); + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.getX(); + this.y = entity.getY(); + this.z = entity.getZ(); + this.yaw = entity.getBukkitYaw(); + this.pitch = entity.getXRot(); + this.entityType = entity.getBukkitEntity().getType(); + + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + compoundTag.putFloat("Yaw", entity.getYRot()); + compoundTag.putFloat("Pitch", entity.getXRot()); + + this.entityTag = CompoundTag.fromNBT(compoundTag); + } + + } + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java index 9b3b29171b..b8610a0bde 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java @@ -14,13 +14,11 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; @@ -74,16 +72,6 @@ private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag com return CraftItemStack.asCraftMirror(itemStack); } - @Override - public CompoundTag getNBTTag(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - return CompoundTag.fromNBT(compoundTag); - } - @Override @SuppressWarnings("ConstantConditions") public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index 91e1f3f8ae..3df134eb60 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -18,11 +18,11 @@ import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_19.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_19.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_19.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_19.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_19.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.nms.v1_19.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; @@ -32,20 +32,15 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.border.WorldBorder; -import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; @@ -203,75 +198,6 @@ public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } - @Override - public CompoundTag readBlockStates(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(blockPos); - } - - CompoundTag compoundTag = new CompoundTag(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return EMPTY_LIGHTS; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - return new byte[]{ - location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; - } - } - - @Override - public CompoundTag readTileEntity(Location location) { - BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); - if (blockEntity == null) - return null; - - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - return CompoundTag.fromNBT(compoundTag); - } - @Override public boolean isWaterLogged(org.bukkit.block.Block block) { if (Materials.isWater(block.getType())) @@ -403,4 +329,9 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } + } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..906f8d88b6 --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java @@ -0,0 +1,229 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; +import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + private final ServerLevel serverLevel; + private final int x; + private final int z; + + private final Map blockEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final PalettedContainerRO[] blockids; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(Chunk bukkitChunk) { + LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); + + this.serverLevel = levelChunk.level; + this.x = levelChunk.locX; + this.z = levelChunk.locZ; + + LevelChunkSection[] levelChunkSections = levelChunk.getSections(); + this.blockids = new PalettedContainerRO[levelChunkSections.length]; + this.skylight = new byte[levelChunkSections.length][]; + this.emitlight = new byte[levelChunkSections.length][]; + + LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); + + for (int i = 0; i < this.blockids.length; ++i) { + LevelChunkSection levelChunkSection = levelChunkSections[i]; + + this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); + + DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) + .getDataLayerData(SectionPos.of(this.x, i, this.z)); + if (skyLightArray == null) { + this.skylight[i] = EMPTY_LIGHT; + } else { + this.skylight[i] = new byte[2048]; + System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); + } + + DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) + .getDataLayerData(SectionPos.of(this.x, i, this.z)); + if (emitLightArray == null) { + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.emitlight[i] = new byte[2048]; + System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); + } + } + + levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { + net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(); + + compoundTag.remove("x"); + compoundTag.remove("y"); + compoundTag.remove("z"); + + InventoryHolder inventoryHolder = blockEntity.getOwner(); + if (inventoryHolder != null) + compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); + + blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return getBlockState(x, y, z).getBukkitMaterial(); + } + + @Override + public short getData(int x, int y, int z) { + return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); + return this.blockEntities.get(blockPos); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + BlockState blockState = getBlockState(x, y, z); + + if (blockState.getValues().isEmpty()) + return null; + + CompoundTag compoundTag = new CompoundTag(); + + blockState.getValues().forEach((property, value) -> { + String name = PropertiesMapper.getPropertyName(property); + + if (property instanceof BooleanProperty) { + compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); + } else if (property instanceof IntegerProperty integerProperty) { + compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); + } else if (property instanceof EnumProperty) { + compoundTag.setString(name, ((Enum) value).name()); + } + }); + + return compoundTag; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private BlockState getBlockState(int x, int y, int z) { + return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); + } + + private int getSectionIndex(int y) { + int sectionIndex = SectionPos.blockToSectionCoord(y); + return sectionIndex - this.serverLevel.getMinSection(); + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.getX(); + this.y = entity.getY(); + this.z = entity.getZ(); + this.yaw = entity.getBukkitYaw(); + this.pitch = entity.getXRot(); + this.entityType = entity.getBukkitEntity().getType(); + + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + compoundTag.putFloat("Yaw", entity.getYRot()); + compoundTag.putFloat("Pitch", entity.getXRot()); + + this.entityTag = CompoundTag.fromNBT(compoundTag); + } + + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java index ffc695eb94..bdc04ac1a9 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java @@ -14,13 +14,11 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; @@ -74,16 +72,6 @@ private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag com return CraftItemStack.asCraftMirror(itemStack); } - @Override - public CompoundTag getNBTTag(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - return CompoundTag.fromNBT(compoundTag); - } - @Override @SuppressWarnings("ConstantConditions") public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index 16e2daba02..0facc4df10 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -18,11 +18,11 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.v1_20_3.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_20_3.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -31,20 +31,15 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.border.WorldBorder; -import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; @@ -208,78 +203,6 @@ public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } - @Override - public CompoundTag readBlockStates(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(blockPos); - } - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = new CompoundTag(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return EMPTY_LIGHTS; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - return new byte[]{ - location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; - } - } - - @Override - public CompoundTag readTileEntity(Location location) { - BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); - if (blockEntity == null) - return null; - - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - return CompoundTag.fromNBT(compoundTag); - } - @Override public boolean isWaterLogged(org.bukkit.block.Block block) { if (Materials.isWater(block.getType())) @@ -410,4 +333,9 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } + } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..fcd68078e8 --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java @@ -0,0 +1,239 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + private static final byte[] FULL_LIGHT = new byte[2048]; + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + static { + Arrays.fill(FULL_LIGHT, (byte) 0xFF); + } + + private final ServerLevel serverLevel; + private final int x; + private final int z; + + private final Map blockEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final PalettedContainerRO[] blockids; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(Chunk bukkitChunk) { + LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); + + this.serverLevel = levelChunk.level; + this.x = levelChunk.locX; + this.z = levelChunk.locZ; + + LevelChunkSection[] levelChunkSections = levelChunk.getSections(); + this.blockids = new PalettedContainerRO[levelChunkSections.length]; + this.skylight = new byte[levelChunkSections.length][]; + this.emitlight = new byte[levelChunkSections.length][]; + + LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); + + for (int i = 0; i < this.blockids.length; ++i) { + LevelChunkSection levelChunkSection = levelChunkSections[i]; + + this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); + + DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (skyLightArray == null) { + this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; + } else { + this.skylight[i] = new byte[2048]; + System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); + } + + DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (emitLightArray == null) { + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.emitlight[i] = new byte[2048]; + System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); + } + } + + levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { + net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(); + + compoundTag.remove("x"); + compoundTag.remove("y"); + compoundTag.remove("z"); + + InventoryHolder inventoryHolder = blockEntity.getOwner(); + if (inventoryHolder != null) + compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); + + blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return getBlockState(x, y, z).getBukkitMaterial(); + } + + @Override + public short getData(int x, int y, int z) { + return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); + return this.blockEntities.get(blockPos); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + BlockState blockState = getBlockState(x, y, z); + + if (blockState.getValues().isEmpty()) + return null; + + CompoundTag compoundTag = new CompoundTag(); + + blockState.getValues().forEach((property, value) -> { + String name = PropertiesMapper.getPropertyName(property); + + if (property instanceof BooleanProperty) { + compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); + } else if (property instanceof IntegerProperty integerProperty) { + compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); + } else if (property instanceof EnumProperty) { + compoundTag.setString(name, ((Enum) value).name()); + } + }); + + return compoundTag; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private BlockState getBlockState(int x, int y, int z) { + return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); + } + + private int getSectionIndex(int y) { + int sectionIndex = SectionPos.blockToSectionCoord(y); + return sectionIndex - this.serverLevel.getMinSection(); + } + + private int getSectionYFromSectionIndex(int index) { + return index + this.serverLevel.getMinSection(); + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.getX(); + this.y = entity.getY(); + this.z = entity.getZ(); + this.yaw = entity.getBukkitYaw(); + this.pitch = entity.getXRot(); + this.entityType = entity.getBukkitEntity().getType(); + + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + compoundTag.putFloat("Yaw", entity.getYRot()); + compoundTag.putFloat("Pitch", entity.getXRot()); + + this.entityTag = CompoundTag.fromNBT(compoundTag); + } + + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java index 1568c3c6c7..455a785e8a 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java @@ -18,7 +18,6 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; @@ -26,7 +25,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftMagicNumbers; @@ -96,16 +94,6 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I return CraftItemStack.asBukkitCopy(itemStack); } - @Override - public CompoundTag getNBTTag(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - return CompoundTag.fromNBT(compoundTag); - } - @Override @SuppressWarnings("ConstantConditions") public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index 760c14f9b5..5c10e76010 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -18,34 +18,28 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.v1_20_4.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_20_4.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.border.WorldBorder; -import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; @@ -209,78 +203,6 @@ public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } - @Override - public CompoundTag readBlockStates(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(blockPos); - } - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = new CompoundTag(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return EMPTY_LIGHTS; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - return new byte[]{ - location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; - } - } - - @Override - public CompoundTag readTileEntity(Location location) { - BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); - if (blockEntity == null) - return null; - - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - return CompoundTag.fromNBT(compoundTag); - } - @Override public boolean isWaterLogged(org.bukkit.block.Block block) { if (Materials.isWater(block.getType())) @@ -411,4 +333,9 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } + } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..2576de2480 --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java @@ -0,0 +1,240 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + private static final byte[] FULL_LIGHT = new byte[2048]; + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + static { + Arrays.fill(FULL_LIGHT, (byte) 0xFF); + } + + private final ServerLevel serverLevel; + private final int x; + private final int z; + + private final Map blockEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final PalettedContainerRO[] blockids; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(Chunk bukkitChunk) { + LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); + + this.serverLevel = levelChunk.level; + this.x = levelChunk.locX; + this.z = levelChunk.locZ; + + LevelChunkSection[] levelChunkSections = levelChunk.getSections(); + this.blockids = new PalettedContainerRO[levelChunkSections.length]; + this.skylight = new byte[levelChunkSections.length][]; + this.emitlight = new byte[levelChunkSections.length][]; + + LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); + + for (int i = 0; i < this.blockids.length; ++i) { + LevelChunkSection levelChunkSection = levelChunkSections[i]; + + this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); + + DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (skyLightArray == null) { + this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; + } else { + this.skylight[i] = new byte[2048]; + System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); + } + + DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (emitLightArray == null) { + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.emitlight[i] = new byte[2048]; + System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); + } + } + + levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { + net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + + compoundTag.remove("x"); + compoundTag.remove("y"); + compoundTag.remove("z"); + + InventoryHolder inventoryHolder = blockEntity.getOwner(); + if (inventoryHolder != null) + compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); + + blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return getBlockState(x, y, z).getBukkitMaterial(); + } + + @Override + public short getData(int x, int y, int z) { + return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); + return this.blockEntities.get(blockPos); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + BlockState blockState = getBlockState(x, y, z); + + if (blockState.getValues().isEmpty()) + return null; + + CompoundTag compoundTag = new CompoundTag(); + + blockState.getValues().forEach((property, value) -> { + String name = PropertiesMapper.getPropertyName(property); + + if (property instanceof BooleanProperty) { + compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); + } else if (property instanceof IntegerProperty integerProperty) { + compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); + } else if (property instanceof EnumProperty) { + compoundTag.setString(name, ((Enum) value).name()); + } + }); + + return compoundTag; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private BlockState getBlockState(int x, int y, int z) { + return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); + } + + private int getSectionIndex(int y) { + int sectionIndex = SectionPos.blockToSectionCoord(y); + return sectionIndex - this.serverLevel.getMinSection(); + } + + private int getSectionYFromSectionIndex(int index) { + return index + this.serverLevel.getMinSection(); + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.getX(); + this.y = entity.getY(); + this.z = entity.getZ(); + this.yaw = entity.getBukkitYaw(); + this.pitch = entity.getXRot(); + this.entityType = entity.getBukkitEntity().getType(); + + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + compoundTag.putFloat("Yaw", entity.getYRot()); + compoundTag.putFloat("Pitch", entity.getXRot()); + + this.entityTag = CompoundTag.fromNBT(compoundTag); + } + + } + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java index 3738e9cbab..6564baad89 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java @@ -19,7 +19,6 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; @@ -27,7 +26,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.inventory.CraftItemStack; import java.util.Optional; @@ -96,16 +94,6 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I return CraftItemStack.asBukkitCopy(itemStack); } - @Override - public CompoundTag getNBTTag(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - return CompoundTag.fromNBT(compoundTag); - } - @Override @SuppressWarnings("ConstantConditions") public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index 49e411c051..7ae5b948b5 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -18,34 +18,28 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.v1_21.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_21.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_21.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_21.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.nms.v1_21.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.border.WorldBorder; -import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; @@ -209,75 +203,6 @@ public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } - @Override - public CompoundTag readBlockStates(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(blockPos); - } - - CompoundTag compoundTag = new CompoundTag(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return EMPTY_LIGHTS; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - return new byte[]{ - location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; - } - } - - @Override - public CompoundTag readTileEntity(Location location) { - BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); - if (blockEntity == null) - return null; - - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - return CompoundTag.fromNBT(compoundTag); - } - @Override public boolean isWaterLogged(org.bukkit.block.Block block) { if (Materials.isWater(block.getType())) @@ -408,4 +333,8 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..caef562acf --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java @@ -0,0 +1,240 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + private static final byte[] FULL_LIGHT = new byte[2048]; + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + static { + Arrays.fill(FULL_LIGHT, (byte) 0xFF); + } + + private final ServerLevel serverLevel; + private final int x; + private final int z; + + private final Map blockEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final PalettedContainerRO[] blockids; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(Chunk bukkitChunk) { + LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); + + this.serverLevel = levelChunk.level; + this.x = levelChunk.locX; + this.z = levelChunk.locZ; + + LevelChunkSection[] levelChunkSections = levelChunk.getSections(); + this.blockids = new PalettedContainerRO[levelChunkSections.length]; + this.skylight = new byte[levelChunkSections.length][]; + this.emitlight = new byte[levelChunkSections.length][]; + + LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); + + for (int i = 0; i < this.blockids.length; ++i) { + LevelChunkSection levelChunkSection = levelChunkSections[i]; + + this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); + + DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (skyLightArray == null) { + this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; + } else { + this.skylight[i] = new byte[2048]; + System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); + } + + DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (emitLightArray == null) { + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.emitlight[i] = new byte[2048]; + System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); + } + } + + levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { + net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + + compoundTag.remove("x"); + compoundTag.remove("y"); + compoundTag.remove("z"); + + InventoryHolder inventoryHolder = blockEntity.getOwner(); + if (inventoryHolder != null) + compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); + + blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return getBlockState(x, y, z).getBukkitMaterial(); + } + + @Override + public short getData(int x, int y, int z) { + return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); + return this.blockEntities.get(blockPos); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + BlockState blockState = getBlockState(x, y, z); + + if (blockState.getValues().isEmpty()) + return null; + + CompoundTag compoundTag = new CompoundTag(); + + blockState.getValues().forEach((property, value) -> { + String name = PropertiesMapper.getPropertyName(property); + + if (property instanceof BooleanProperty) { + compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); + } else if (property instanceof IntegerProperty integerProperty) { + compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); + } else if (property instanceof EnumProperty) { + compoundTag.setString(name, ((Enum) value).name()); + } + }); + + return compoundTag; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private BlockState getBlockState(int x, int y, int z) { + return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); + } + + private int getSectionIndex(int y) { + int sectionIndex = SectionPos.blockToSectionCoord(y); + return sectionIndex - this.serverLevel.getMinSection(); + } + + private int getSectionYFromSectionIndex(int index) { + return index + this.serverLevel.getMinSection(); + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.getX(); + this.y = entity.getY(); + this.z = entity.getZ(); + this.yaw = entity.getBukkitYaw(); + this.pitch = entity.getXRot(); + this.entityType = entity.getBukkitEntity().getType(); + + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + compoundTag.putFloat("Yaw", entity.getYRot()); + compoundTag.putFloat("Pitch", entity.getXRot()); + + this.entityTag = CompoundTag.fromNBT(compoundTag); + } + + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java index 55273d6a66..6742096e05 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java @@ -19,7 +19,6 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; @@ -28,7 +27,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.inventory.CraftItemStack; import java.util.Optional; @@ -97,16 +95,6 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I return CraftItemStack.asBukkitCopy(itemStack); } - @Override - public CompoundTag getNBTTag(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - return CompoundTag.fromNBT(compoundTag); - } - @Override @SuppressWarnings("ConstantConditions") public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index 949ee86d84..04f2dc83c4 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -18,34 +18,28 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.v1_21_3.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_21_3.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.border.WorldBorder; -import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; @@ -209,78 +203,6 @@ public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } - @Override - public CompoundTag readBlockStates(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(blockPos); - } - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = new CompoundTag(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return EMPTY_LIGHTS; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - return new byte[]{ - location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; - } - } - - @Override - public CompoundTag readTileEntity(Location location) { - BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); - if (blockEntity == null) - return null; - - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - return CompoundTag.fromNBT(compoundTag); - } - @Override public boolean isWaterLogged(org.bukkit.block.Block block) { if (Materials.isWater(block.getType())) @@ -411,4 +333,8 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..d294b442f4 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java @@ -0,0 +1,240 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + private static final byte[] FULL_LIGHT = new byte[2048]; + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + static { + Arrays.fill(FULL_LIGHT, (byte) 0xFF); + } + + private final ServerLevel serverLevel; + private final int x; + private final int z; + + private final Map blockEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final PalettedContainerRO[] blockids; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(Chunk bukkitChunk) { + LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); + + this.serverLevel = levelChunk.level; + this.x = levelChunk.locX; + this.z = levelChunk.locZ; + + LevelChunkSection[] levelChunkSections = levelChunk.getSections(); + this.blockids = new PalettedContainerRO[levelChunkSections.length]; + this.skylight = new byte[levelChunkSections.length][]; + this.emitlight = new byte[levelChunkSections.length][]; + + LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); + + for (int i = 0; i < this.blockids.length; ++i) { + LevelChunkSection levelChunkSection = levelChunkSections[i]; + + this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); + + DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (skyLightArray == null) { + this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; + } else { + this.skylight[i] = new byte[2048]; + System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); + } + + DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (emitLightArray == null) { + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.emitlight[i] = new byte[2048]; + System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); + } + } + + levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { + net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + + compoundTag.remove("x"); + compoundTag.remove("y"); + compoundTag.remove("z"); + + InventoryHolder inventoryHolder = blockEntity.getOwner(); + if (inventoryHolder != null) + compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); + + blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return getBlockState(x, y, z).getBukkitMaterial(); + } + + @Override + public short getData(int x, int y, int z) { + return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); + return this.blockEntities.get(blockPos); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + BlockState blockState = getBlockState(x, y, z); + + if (blockState.getValues().isEmpty()) + return null; + + CompoundTag compoundTag = new CompoundTag(); + + blockState.getValues().forEach((property, value) -> { + String name = PropertiesMapper.getPropertyName(property); + + if (property instanceof BooleanProperty) { + compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); + } else if (property instanceof IntegerProperty integerProperty) { + compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); + } else if (property instanceof EnumProperty) { + compoundTag.setString(name, ((Enum) value).name()); + } + }); + + return compoundTag; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private BlockState getBlockState(int x, int y, int z) { + return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); + } + + private int getSectionIndex(int y) { + int sectionIndex = SectionPos.blockToSectionCoord(y); + return sectionIndex - this.serverLevel.getMinSectionY(); + } + + private int getSectionYFromSectionIndex(int index) { + return index + this.serverLevel.getMinSectionY(); + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.getX(); + this.y = entity.getY(); + this.z = entity.getZ(); + this.yaw = entity.getBukkitYaw(); + this.pitch = entity.getXRot(); + this.entityType = entity.getBukkitEntity().getType(); + + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + compoundTag.putFloat("Yaw", entity.getYRot()); + compoundTag.putFloat("Pitch", entity.getXRot()); + + this.entityTag = CompoundTag.fromNBT(compoundTag); + } + + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java index c311e718e2..ded586dbfc 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java @@ -19,7 +19,6 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.util.datafix.DataFixers; import net.minecraft.util.datafix.fixes.References; -import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; @@ -28,7 +27,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.inventory.CraftItemStack; import java.util.Optional; @@ -97,16 +95,6 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I return CraftItemStack.asBukkitCopy(itemStack); } - @Override - public CompoundTag getNBTTag(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - return CompoundTag.fromNBT(compoundTag); - } - @Override @SuppressWarnings("ConstantConditions") public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index 618985699f..539d03e844 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -18,34 +18,28 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.v1_21_4.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_21_4.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.border.WorldBorder; -import net.minecraft.world.level.lighting.LevelLightEngine; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; @@ -209,83 +203,6 @@ public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } - @Override - public CompoundTag readBlockStates(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(blockPos); - } - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = new CompoundTag(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return EMPTY_LIGHTS; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - LevelLightEngine lightEngine = serverLevel.getLightEngine(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - return new byte[]{ - location.getWorld().getEnvironment() != World.Environment.NORMAL ? 0 : - (byte) lightEngine.getLayerListener(LightLayer.SKY).getLightValue(blockPos), - (byte) lightEngine.getLayerListener(LightLayer.BLOCK).getLightValue(blockPos) - }; - } - } - - @Override - public CompoundTag readTileEntity(Location location) { - BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); - if (blockEntity == null) - return null; - - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - return CompoundTag.fromNBT(compoundTag); - } - @Override public boolean isWaterLogged(org.bukkit.block.Block block) { if (Materials.isWater(block.getType())) @@ -416,4 +333,8 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..b345f6e3be --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java @@ -0,0 +1,240 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + private static final byte[] FULL_LIGHT = new byte[2048]; + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + static { + Arrays.fill(FULL_LIGHT, (byte) 0xFF); + } + + private final ServerLevel serverLevel; + private final int x; + private final int z; + + private final Map blockEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final PalettedContainerRO[] blockids; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(Chunk bukkitChunk) { + LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); + + this.serverLevel = levelChunk.level; + this.x = levelChunk.locX; + this.z = levelChunk.locZ; + + LevelChunkSection[] levelChunkSections = levelChunk.getSections(); + this.blockids = new PalettedContainerRO[levelChunkSections.length]; + this.skylight = new byte[levelChunkSections.length][]; + this.emitlight = new byte[levelChunkSections.length][]; + + LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); + + for (int i = 0; i < this.blockids.length; ++i) { + LevelChunkSection levelChunkSection = levelChunkSections[i]; + + this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); + + DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (skyLightArray == null) { + this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; + } else { + this.skylight[i] = new byte[2048]; + System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); + } + + DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (emitLightArray == null) { + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.emitlight[i] = new byte[2048]; + System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); + } + } + + levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { + net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + + compoundTag.remove("x"); + compoundTag.remove("y"); + compoundTag.remove("z"); + + InventoryHolder inventoryHolder = blockEntity.getOwner(); + if (inventoryHolder != null) + compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); + + blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return getBlockState(x, y, z).getBukkitMaterial(); + } + + @Override + public short getData(int x, int y, int z) { + return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); + return this.blockEntities.get(blockPos); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + BlockState blockState = getBlockState(x, y, z); + + if (blockState.getValues().isEmpty()) + return null; + + CompoundTag compoundTag = new CompoundTag(); + + blockState.getValues().forEach((property, value) -> { + String name = PropertiesMapper.getPropertyName(property); + + if (property instanceof BooleanProperty) { + compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); + } else if (property instanceof IntegerProperty integerProperty) { + compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); + } else if (property instanceof EnumProperty) { + compoundTag.setString(name, ((Enum) value).name()); + } + }); + + return compoundTag; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private BlockState getBlockState(int x, int y, int z) { + return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); + } + + private int getSectionIndex(int y) { + int sectionIndex = SectionPos.blockToSectionCoord(y); + return sectionIndex - this.serverLevel.getMinSectionY(); + } + + private int getSectionYFromSectionIndex(int index) { + return index + this.serverLevel.getMinSectionY(); + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.getX(); + this.y = entity.getY(); + this.z = entity.getZ(); + this.yaw = entity.getBukkitYaw(); + this.pitch = entity.getXRot(); + this.entityType = entity.getBukkitEntity().getType(); + + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + compoundTag.putFloat("Yaw", entity.getYRot()); + compoundTag.putFloat("Pitch", entity.getXRot()); + + this.entityTag = CompoundTag.fromNBT(compoundTag); + } + + } + +} diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSTagsImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSTagsImpl.java index 5754387031..535f42721a 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSTagsImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSTagsImpl.java @@ -24,7 +24,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; import org.bukkit.entity.EntityType; @@ -69,16 +68,6 @@ private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag com return CraftItemStack.asCraftMirror(itemStack); } - @Override - public CompoundTag getNBTTag(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); - NBTTagCompound nbtTagCompound = new NBTTagCompound(); - entity.c(nbtTagCompound); - nbtTagCompound.set("Yaw", new NBTTagFloat(entity.yaw)); - nbtTagCompound.set("Pitch", new NBTTagFloat(entity.pitch)); - return CompoundTag.fromNBT(nbtTagCompound); - } - @Override public void spawnEntity(EntityType entityType, Location location, CompoundTag compoundTag) { CraftWorld craftWorld = (CraftWorld) location.getWorld(); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java index 87897701ff..2cfa8a672f 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java @@ -15,29 +15,27 @@ import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.spawners.MobSpawnerAbstractNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockDoubleStep; import net.minecraft.server.v1_8_R3.BlockPosition; -import net.minecraft.server.v1_8_R3.Chunk; import net.minecraft.server.v1_8_R3.EnumParticle; -import net.minecraft.server.v1_8_R3.EnumSkyBlock; import net.minecraft.server.v1_8_R3.IBlockData; import net.minecraft.server.v1_8_R3.IChatBaseComponent; import net.minecraft.server.v1_8_R3.MobSpawnerAbstract; -import net.minecraft.server.v1_8_R3.NBTTagCompound; import net.minecraft.server.v1_8_R3.PacketPlayOutBlockChange; import net.minecraft.server.v1_8_R3.PacketPlayOutWorldBorder; -import net.minecraft.server.v1_8_R3.TileEntity; import net.minecraft.server.v1_8_R3.TileEntityMobSpawner; import net.minecraft.server.v1_8_R3.TileEntitySign; import net.minecraft.server.v1_8_R3.WorldBorder; import net.minecraft.server.v1_8_R3.WorldServer; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.Material; @@ -182,44 +180,6 @@ public ICachedBlock cacheBlock(org.bukkit.block.Block block) { return NMSCachedBlock.obtain(block); } - @Override - public CompoundTag readBlockStates(Location location) { - // Doesn't exist - return null; - } - - @Override - public byte[] getLightLevels(Location location) { - WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - Chunk chunk = worldServer.getChunkAtWorldCoords(blockPosition); - - return new byte[]{ - (byte) chunk.getBrightness(EnumSkyBlock.SKY, blockPosition), - (byte) chunk.getBrightness(EnumSkyBlock.BLOCK, blockPosition) - }; - } - } - - @Override - public CompoundTag readTileEntity(Location location) { - TileEntity tileEntity = NMSUtils.getTileEntityAt(location, TileEntity.class); - if (tileEntity == null) - return null; - - NBTTagCompound tileEntityCompound = new NBTTagCompound(); - tileEntity.b(tileEntityCompound); - - tileEntityCompound.remove("x"); - tileEntityCompound.remove("y"); - tileEntityCompound.remove("z"); - - return CompoundTag.fromNBT(tileEntityCompound); - } - @Override public boolean isWaterLogged(org.bukkit.block.Block block) { Material blockType = block.getType(); @@ -354,4 +314,9 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } + } diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/ChunkReaderImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..91b48eac75 --- /dev/null +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/ChunkReaderImpl.java @@ -0,0 +1,215 @@ +package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_8_R3.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.server.v1_8_R3.Block; +import net.minecraft.server.v1_8_R3.BlockPosition; +import net.minecraft.server.v1_8_R3.Chunk; +import net.minecraft.server.v1_8_R3.ChunkSection; +import net.minecraft.server.v1_8_R3.Entity; +import net.minecraft.server.v1_8_R3.IBlockData; +import net.minecraft.server.v1_8_R3.NBTTagCompound; +import net.minecraft.server.v1_8_R3.NBTTagFloat; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_8_R3.CraftChunk; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final short[] EMPTY_BLOCKS = new short[4096]; + private static final byte[] EMPTY_DATA = new byte[2048]; + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + private final int x; + private final int z; + + private final Map tileEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final short[][] blockids; + private final byte[][] blockdata; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(org.bukkit.Chunk bukkitChunk) { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + + this.x = chunk.locX; + this.z = chunk.locZ; + + ChunkSection[] chunkSections = chunk.getSections(); + this.blockids = new short[chunkSections.length][]; + this.blockdata = new byte[chunkSections.length][]; + this.skylight = new byte[chunkSections.length][]; + this.emitlight = new byte[chunkSections.length][]; + + for (int i = 0; i < this.blockids.length; ++i) { + ChunkSection chunkSection = chunkSections[i]; + + if (chunkSection == null) { + this.blockids[i] = EMPTY_BLOCKS; + this.blockdata[i] = EMPTY_DATA; + this.skylight[i] = EMPTY_LIGHT; + this.emitlight[i] = EMPTY_LIGHT; + } else { + copyBlockIds(chunkSection.getIdArray(), i); + + if (chunkSection.getSkyLightArray() == null) { + skylight[i] = EMPTY_LIGHT; + } else { + skylight[i] = new byte[2048]; + System.arraycopy(chunkSection.getSkyLightArray().a(), 0, skylight[i], 0, 2048); + } + + emitlight[i] = new byte[2048]; + System.arraycopy(chunkSection.getEmittedLightArray().a(), 0, emitlight[i], 0, 2048); + } + } + + chunk.getTileEntities().forEach((blockPosition, tileEntity) -> { + NBTTagCompound tileEntityCompound = new NBTTagCompound(); + tileEntity.b(tileEntityCompound); + + tileEntityCompound.remove("x"); + tileEntityCompound.remove("y"); + tileEntityCompound.remove("z"); + + InventoryHolder inventoryHolder = tileEntity.getOwner(); + if (inventoryHolder != null) + tileEntityCompound.setString("inventoryType", inventoryHolder.getInventory().getType().name()); + + tileEntities.put(blockPosition, CompoundTag.fromNBT(tileEntityCompound)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return Material.getMaterial(this.getBlockId(x, y, z)); + } + + @Override + public short getData(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + return (short) (this.blockdata[y >> 4][off] >> ((x & 1) << 2) & 15); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.c((this.x << 4) + x, y, (this.z << 4) + z); + return this.tileEntities.get(blockPosition); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + // Doesn't exist + return null; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[y >> 4][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[y >> 4][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private int getBlockId(int x, int y, int z) { + return this.blockids[y >> 4][(y & 15) << 8 | z << 4 | x]; + } + + private void copyBlockIds(char[] baseids, int i) { + short[] blockids = this.blockids[i] = new short[4096]; + byte[] dataValues = this.blockdata[i] = new byte[2048]; + + for (int j = 0; j < 4096; ++j) { + if (baseids[j] != 0) { + IBlockData blockData = Block.d.a(baseids[j]); + if (blockData != null) { + blockids[j] = (short) Block.getId(blockData.getBlock()); + int data = blockData.getBlock().toLegacyData(blockData); + int k = j >> 1; + if ((j & 1) == 0) { + dataValues[k] = (byte) (dataValues[k] & 240 | data & 15); + } else { + dataValues[k] = (byte) (dataValues[k] & 15 | (data & 15) << 4); + } + } + } + } + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.locX; + this.y = entity.locY; + this.z = entity.locZ; + this.yaw = entity.yaw; + this.pitch = entity.pitch; + this.entityType = entity.getBukkitEntity().getType(); + + NBTTagCompound nbtTagCompound = new NBTTagCompound(); + entity.c(nbtTagCompound); + nbtTagCompound.set("Yaw", new NBTTagFloat(entity.yaw)); + nbtTagCompound.set("Pitch", new NBTTagFloat(entity.pitch)); + + this.entityTag = CompoundTag.fromNBT(nbtTagCompound); + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSTags.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSTags.java index 9a2c66d757..53b60a1fdc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSTags.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSTags.java @@ -20,8 +20,6 @@ default ItemStack getSkullWithTexture(ItemStack itemStack, String texture) { return ItemSkulls.getPlayerHeadNoNMS(itemStack, texture); } - CompoundTag getNBTTag(Entity entity); - void spawnEntity(EntityType entityType, Location location, CompoundTag compoundTag); byte[] getNBTByteArrayValue(Object object); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java index a9a1f77dba..3b0b6cc830 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java @@ -5,9 +5,10 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; import org.bukkit.World; @@ -31,12 +32,6 @@ public interface NMSWorld { ICachedBlock cacheBlock(Block block); - CompoundTag readBlockStates(Location location); - - byte[] getLightLevels(Location location); - - CompoundTag readTileEntity(Location location); - boolean isWaterLogged(Block block); PistonPushReaction getPistonReaction(Block block); @@ -63,4 +58,6 @@ public interface NMSWorld { WorldEditSession createEditSession(World world); + ChunkReader createChunkReader(Chunk chunk); + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/world/ChunkReader.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/world/ChunkReader.java new file mode 100644 index 0000000000..0eb614b3b1 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/world/ChunkReader.java @@ -0,0 +1,35 @@ +package com.bgsoftware.superiorskyblock.nms.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; + +public interface ChunkReader { + + int getX(); + + int getZ(); + + Material getType(int x, int y, int z); + + short getData(int x, int y, int z); + + @Nullable + CompoundTag getTileEntity(int x, int y, int z); + + @Nullable + CompoundTag readBlockStates(int x, int y, int z); + + byte[] getLightLevels(int x, int y, int z); + + void forEachEntity(EntityConsumer consumer); + + interface EntityConsumer { + + void apply(EntityType entityType, CompoundTag entityTag, Location location); + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/WorldReader.java b/src/main/java/com/bgsoftware/superiorskyblock/world/WorldReader.java new file mode 100644 index 0000000000..eedd1e0e9d --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/WorldReader.java @@ -0,0 +1,80 @@ +package com.bgsoftware.superiorskyblock.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; +import org.bukkit.World; + +import java.util.HashMap; +import java.util.Map; + +public class WorldReader { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final World world; + private final ChunkLoadReason chunkLoadReason; + private final CompletableFutureList chunkReaderFutures = new CompletableFutureList<>(-1L); + + private final Map cachedChunkReaders = new HashMap<>(); + private boolean finishCalled = false; + private boolean inFinishCallback = false; + + public WorldReader(World world, ChunkLoadReason chunkLoadReason) { + this.world = world; + this.chunkLoadReason = chunkLoadReason; + } + + public void prepareChunk(ChunkPosition chunkPosition) { + if (this.finishCalled) + throw new IllegalStateException("Cannot call WorldReader#prepareChunk after WorldReader#finish was called"); + + chunkReaderFutures.add(ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, null) + .thenApply(chunk -> plugin.getNMSWorld().createChunkReader(chunk))); + } + + @Nullable + public ChunkReader getChunkReader(int blockX, int blockZ) { + if (!this.inFinishCallback) + throw new IllegalStateException("Cannot call WorldReader#getChunkReader from this state"); + + int chunkX = blockX >> 4; + int chunkZ = blockZ >> 4; + try (ChunkPosition chunkPosition = ChunkPosition.of(this.world, chunkX, chunkZ)) { + return this.cachedChunkReaders.get(chunkPosition); + } + } + + public void finish(Runnable onFinish) { + this.finishCalled = true; + + BukkitExecutor.async(() -> { + MutableBoolean failed = new MutableBoolean(false); + + chunkReaderFutures.forEachCompleted(chunkReader -> { + ChunkPosition chunkPosition = ChunkPosition.of(world, chunkReader.getX(), chunkReader.getZ(), false); + cachedChunkReaders.put(chunkPosition, chunkReader); + }, error -> { + failed.set(true); + Log.error(error, "An error occurred while waiting for chunks to load:"); + }); + + if (!failed.get()) { + try { + this.inFinishCallback = true; + onFinish.run(); + } finally { + this.inFinishCallback = true; + } + } + }); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunkLoadReason.java b/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunkLoadReason.java index f0b9a4ed43..7908c1fea7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunkLoadReason.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunkLoadReason.java @@ -3,6 +3,7 @@ public enum ChunkLoadReason { SCHEMATIC_PLACE, + SCHEMATIC_SAVE, ENTITY_TELEPORT, BLOCKS_RECALCULATE, ENTITIES_RECALCULATE, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java index 0ebeb35ac9..5a62624ce7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java @@ -2,7 +2,6 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.schematic.SchematicEntityFilter; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; @@ -13,8 +12,7 @@ import com.bgsoftware.superiorskyblock.tag.Tag; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; +import org.bukkit.entity.EntityType; import java.util.HashMap; import java.util.Map; @@ -30,9 +28,9 @@ public SchematicBuilder withBlockOffset(BlockOffset blockOffset) { return this; } - public SchematicBuilder withBlockType(Location location, Material blockType, int data) { + public SchematicBuilder withBlockType(Material blockType, int data) { if (ServerVersion.isLegacy()) { - compoundValue.put("combinedId", new IntTag(plugin.getNMSAlgorithms().getCombinedId(location))); + compoundValue.put("combinedId", new IntTag(plugin.getNMSAlgorithms().getCombinedId(blockType, (byte) data))); } else { compoundValue.put("type", new StringTag(blockType.name())); if (data != 0) @@ -62,16 +60,10 @@ public SchematicBuilder withTileEntity(CompoundTag tileEntity) { return this; } - public SchematicBuilder applyEntity(Entity entity, Location min) { - if (!(entity instanceof Player)) { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location offset = entity.getLocation(wrapper.getHandle()).subtract(min); - compoundValue.put("offset", new StringTag(Serializers.LOCATION_SERIALIZER.serialize(offset))); - } - - compoundValue.put("entityType", new StringTag(entity.getType().name())); - compoundValue.put("NBT", SchematicEntityFilter.filterNBTTag(plugin.getNMSTags().getNBTTag(entity))); - } + public SchematicBuilder applyEntity(EntityType entityType, CompoundTag entityTag, Location offset) { + compoundValue.put("offset", new StringTag(Serializers.LOCATION_SERIALIZER.serialize(offset))); + compoundValue.put("entityType", new StringTag(entityType.name())); + compoundValue.put("NBT", SchematicEntityFilter.filterNBTTag(entityTag)); return this; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index f8e3f1d175..f412464d1c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockOffset; @@ -19,12 +20,16 @@ import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.FloatTag; import com.bgsoftware.superiorskyblock.tag.IntTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.WorldReader; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.schematic.container.SchematicsContainer; import com.bgsoftware.superiorskyblock.world.schematic.impl.SuperiorSchematic; import com.bgsoftware.superiorskyblock.world.schematic.parser.DefaultSchematicParser; @@ -34,10 +39,9 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.block.Block; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryHolder; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -191,97 +195,112 @@ public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY Log.debug(Debug.SAVE_SCHEMATIC, pos1, pos2, offsetX, offsetY, offsetZ, yaw, pitch, schematicName); World world = pos1.getWorld(); - Location min = new Location(world, - Math.min(pos1.getX(), pos2.getX()), - Math.min(pos1.getY(), pos2.getY()), - Math.min(pos1.getZ(), pos2.getZ()) - ); - Location max = new Location(world, - Math.max(pos1.getX(), pos2.getX()), - Math.max(pos1.getY(), pos2.getY()), - Math.max(pos1.getZ(), pos2.getZ()) - ); - - int minBlockX = min.getBlockX(); - int minBlockY = min.getBlockY(); - int minBlockZ = min.getBlockZ(); - - int xSize = max.getBlockX() - minBlockX; - int ySize = max.getBlockY() - minBlockY; - int zSize = max.getBlockZ() - minBlockZ; - - List> blocks = new ArrayList<>(); - List> entities = new ArrayList<>(); - - for (int x = 0; x <= xSize; x++) { - int blockX = minBlockX + x; - for (int z = 0; z <= zSize; /* z increments inside loop */) { - int blockZ = minBlockZ + z; - // Check if we at start of new chunk - if ((blockX & 0xF) == 0 && (blockZ & 0xF) == 0) { - Chunk chunk = world.getChunkAt(blockX >> 4, blockZ >> 4); - if (plugin.getNMSChunks().isChunkEmpty(chunk)) { - // Skip empty chunk - z += 16; - continue; - } + + int minBlockX = Math.min(pos1.getBlockX(), pos2.getBlockX()); + int minBlockY = Math.min(pos1.getBlockY(), pos2.getBlockY()); + int minBlockZ = Math.min(pos1.getBlockZ(), pos2.getBlockZ()); + + int maxBlockX = Math.max(pos1.getBlockX(), pos2.getBlockX()); + int maxBlockY = Math.max(pos1.getBlockY(), pos2.getBlockY()); + int maxBlockZ = Math.max(pos1.getBlockZ(), pos2.getBlockZ()); + + int xSize = maxBlockX - minBlockX; + int ySize = maxBlockY - minBlockY; + int zSize = maxBlockZ - minBlockZ; + + WorldReader worldReader = new WorldReader(world, ChunkLoadReason.SCHEMATIC_SAVE); + + int minChunkX = minBlockX >> 4; + int minChunkZ = minBlockZ >> 4; + int maxChunkX = maxBlockX >> 4; + int maxChunkZ = maxBlockZ >> 4; + for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) { + for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) { + try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) { + worldReader.prepareChunk(chunkPosition); } + } + } - for (int y = 0; y <= ySize; y++) { - Block block = world.getBlockAt(blockX, minBlockY + y, blockZ); - Material blockType = block.getType(); - if (blockType == Material.AIR) - continue; + worldReader.finish(() -> { + List> entities = new ArrayList<>(); + List> blocks = new ArrayList<>(); - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location blockLocation = block.getLocation(wrapper.getHandle()); + for (int x = minBlockX; x <= maxBlockX; ++x) { + for (int z = minBlockZ; z <= maxBlockZ; ++z) { + ChunkReader chunkReader = worldReader.getChunkReader(x, z); - CompoundTag tileEntity = plugin.getNMSWorld().readTileEntity(blockLocation); - if (tileEntity != null && block.getState() instanceof InventoryHolder) - tileEntity.setString("inventoryType", ((InventoryHolder) block.getState()).getInventory().getType().name()); + int offsetBlockX = x - minBlockX; + int offsetBlockZ = z - minBlockZ; + + int chunkBlockX = x & 0xF; + int chunkBlockZ = z & 0xF; + + for (int chunkBlockY = minBlockY; chunkBlockY <= maxBlockY; ++chunkBlockY) { + Material blockType = chunkReader.getType(chunkBlockX, chunkBlockY, chunkBlockZ); + if (blockType == Material.AIR) + continue; + + short blockData = chunkReader.getData(chunkBlockX, chunkBlockY, chunkBlockZ); + CompoundTag blockStates = chunkReader.readBlockStates(chunkBlockX, chunkBlockY, chunkBlockZ); + byte[] lightLevels = chunkReader.getLightLevels(chunkBlockX, chunkBlockY, chunkBlockZ); + CompoundTag tileEntity = chunkReader.getTileEntity(chunkBlockX, chunkBlockY, chunkBlockZ); + + int offsetBlockY = chunkBlockY - minBlockY; - //noinspection deprecation blocks.add(new SchematicBuilder() - .withBlockOffset(SBlockOffset.fromOffsets(x, y, z)) - .withBlockType(blockLocation, blockType, block.getData()) - .withStates(plugin.getNMSWorld().readBlockStates(blockLocation)) - .withLightLevels(plugin.getNMSWorld().getLightLevels(blockLocation)) + .withBlockOffset(SBlockOffset.fromOffsets(offsetBlockX, offsetBlockY, offsetBlockZ)) + .withBlockType(blockType, blockData) + .withStates(blockStates) + .withLightLevels(lightLevels) .withTileEntity(tileEntity) .build() ); } } + } - ++z; + for (int x = minChunkX; x <= maxChunkX; ++x) { + for (int z = minChunkZ; z <= maxChunkZ; ++z) { + ChunkReader chunkReader = worldReader.getChunkReader(x << 4, z << 4); + if (chunkReader != null) { + chunkReader.forEachEntity((entityType, entityTag, location) -> { + if (entityType != EntityType.PLAYER && + location.getBlockX() >= minBlockX && location.getBlockX() <= maxBlockX && + location.getBlockY() >= minBlockY && location.getBlockY() <= maxBlockY && + location.getBlockZ() >= minBlockZ && location.getBlockZ() <= maxBlockZ) { + location.subtract(minBlockX, minBlockY, minBlockZ); + entities.add(new SchematicBuilder().applyEntity(entityType, entityTag, location).build()); + } + }); + } + } } - } - for (Entity livingEntity : getEntities(min, max)) { - entities.add(new SchematicBuilder().applyEntity(livingEntity, min).build()); - } + Map> compoundValue = new HashMap<>(); + compoundValue.put("xSize", new IntTag(xSize)); + compoundValue.put("ySize", new IntTag(ySize)); + compoundValue.put("zSize", new IntTag(zSize)); + compoundValue.put("blocks", new ListTag(CompoundTag.class, blocks)); + compoundValue.put("entities", new ListTag(CompoundTag.class, entities)); + compoundValue.put("offsetX", new IntTag(offsetX)); + compoundValue.put("offsetY", new IntTag(offsetY)); + compoundValue.put("offsetZ", new IntTag(offsetZ)); + compoundValue.put("yaw", new FloatTag(yaw)); + compoundValue.put("pitch", new FloatTag(pitch)); + compoundValue.put("version", new StringTag(ServerVersion.getBukkitVersion())); + if (!ServerVersion.isLegacy()) + compoundValue.put("minecraftDataVersion", new IntTag(plugin.getNMSAlgorithms().getDataVersion())); + + CompoundTag schematicTag = new CompoundTag(compoundValue); + SuperiorSchematic schematic = new SuperiorSchematic(schematicName, schematicTag); + this.schematicsContainer.addSchematic(schematic); + saveIntoFile(schematicName, schematicTag); + + if (runnable != null) + BukkitExecutor.sync(runnable); + }); - Map> compoundValue = new HashMap<>(); - compoundValue.put("xSize", new IntTag(xSize)); - compoundValue.put("ySize", new IntTag(ySize)); - compoundValue.put("zSize", new IntTag(zSize)); - compoundValue.put("blocks", new ListTag(CompoundTag.class, blocks)); - compoundValue.put("entities", new ListTag(CompoundTag.class, entities)); - compoundValue.put("offsetX", new IntTag(offsetX)); - compoundValue.put("offsetY", new IntTag(offsetY)); - compoundValue.put("offsetZ", new IntTag(offsetZ)); - compoundValue.put("yaw", new FloatTag(yaw)); - compoundValue.put("pitch", new FloatTag(pitch)); - compoundValue.put("version", new StringTag(ServerVersion.getBukkitVersion())); - if (!ServerVersion.isLegacy()) - compoundValue.put("minecraftDataVersion", new IntTag(plugin.getNMSAlgorithms().getDataVersion())); - - CompoundTag schematicTag = new CompoundTag(compoundValue); - SuperiorSchematic schematic = new SuperiorSchematic(schematicName, schematicTag); - this.schematicsContainer.addSchematic(schematic); - saveIntoFile(schematicName, schematicTag); - - if (runnable != null) - runnable.run(); } public String getDefaultSchematic(Dimension dimension) { From ede73be213bcd362e032b5cded82333f9dc2331b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Jan 2025 12:09:29 +0200 Subject: [PATCH 039/600] Adds Brazilian Portuguese as a default language for the plugin (#2332) --- .../core/messages/Message.java | 1 + src/main/resources/lang/pt-BR.yml | 763 ++++++++++++++++++ src/main/resources/menus/player-language.yml | 13 +- .../resources/menus/player-language1_13.yml | 12 +- 4 files changed, 783 insertions(+), 6 deletions(-) create mode 100644 src/main/resources/lang/pt-BR.yml diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index e225c59d8c..569700406b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -877,6 +877,7 @@ public static void reload() { plugin.saveResource("lang/it-IT.yml", false); plugin.saveResource("lang/iw-IL.yml", false); plugin.saveResource("lang/pl-PL.yml", false); + plugin.saveResource("lang/pt-BR.yml", false); plugin.saveResource("lang/ru-RU.yml", false); plugin.saveResource("lang/vi-VN.yml", false); plugin.saveResource("lang/zh-CN.yml", false); diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml new file mode 100644 index 0000000000..d277f1a73c --- /dev/null +++ b/src/main/resources/lang/pt-BR.yml @@ -0,0 +1,763 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +# If you wish to create a new language file, please copy this one. +# Make sure you give the name a correct language name. +# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html +# You can find a tutorial about configuring messages here: +# https://wiki.bg-software.com/superiorskyblock/messages + +ADMIN_ADD_PLAYER: '&e&lIlha | &7Jogador {0} adicionado com sucesso à ilha de {1}.' +ADMIN_ADD_PLAYER_NAME: '&e&lIlha | &7Jogador {0} adicionado com sucesso à ilha {1}.' +ADMIN_DEPOSIT_MONEY: '&e&lBanco | &7Você depositou R${0} no banco da ilha de {1}.' +ADMIN_DEPOSIT_MONEY_NAME: '&e&lBanco | &7Você depositou R${0} no banco da ilha {1}.' +ADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Desenvolvido por Ome_R' +ADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Lista de Comandos Admin [{0}/{1}]:' +ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' +ADMIN_HELP_NEXT_PAGE: '&e&lSkyblock &7Use /is admin {0} para a próxima página.' +ALREADY_IN_ISLAND: '&c&lErro | &7Você já está em uma ilha.' +ALREADY_IN_ISLAND_OTHER: '&c&lErro | &7Este jogador já é membro da sua ilha.' +BAN_ANNOUNCEMENT: '&e&lIlha | &7{0} foi BANIDO da ilha por {1}.' +BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lErro | &7Você só pode banir jogadores com um cargo inferior ao seu na ilha.' +BANK_DEPOSIT_CUSTOM: '&e&lBanco | &7Digite o valor que deseja depositar:' +BANK_DEPOSIT_COMPLETED: 'Depósito Concluído' +BANK_LIMIT_EXCEED: '&c&lErro | &7Você excedeu o limite do banco.' +BANK_WITHDRAW_CUSTOM: '&e&lBanco | &7Digite o valor que deseja sacar:' +BANK_WITHDRAW_COMPLETED: 'Saque Concluído' +BANNED_FROM_ISLAND: '&c&lErro | &7Você está banido desta ilha.' +BLOCK_COUNT_CHECK: '&e&lIlha | &7Esta ilha possui x{0} {1}.' +BLOCK_COUNTS_CHECK: | + &e&lIlha | &7Esta ilha possui os seguintes blocos: + &7{0} +BLOCK_COUNTS_CHECK_EMPTY: '&e&lIlha | &7Esta ilha não possui blocos registrados.' +BLOCK_COUNTS_CHECK_MATERIAL: 'x{0} {1}' +BLOCK_LEVEL: '&e&lNível | &7O nível do bloco {0} é {1}.' +BLOCK_LEVEL_WORTHLESS: '&e&lNível | &7O bloco {0} não possui valor.' +BLOCK_VALUE: '&e&lValor | &7O bloco {0} vale {1}.' +BLOCK_VALUE_WORTHLESS: '&e&lValor | &7O bloco {0} não possui valor.' +BONUS_SET_SUCCESS: '&e&lIlha | &7Bônus da ilha atualizado com sucesso para {0}.' +BONUS_SYNC_ALL: '&e&lIlha | &7Bônus sincronizado com sucesso para todas as ilhas.' +BONUS_SYNC_NAME: '&e&lIlha | &7Bônus sincronizado com sucesso para {0}.' +BONUS_SYNC: '&e&lIlha | &7Bônus sincronizado com sucesso para a ilha de {0}.' +BORDER_PLAYER_COLOR_NAME_BLUE: 'Azul' +BORDER_PLAYER_COLOR_NAME_RED: 'Vermelho' +BORDER_PLAYER_COLOR_NAME_GREEN: 'Verde' +BORDER_PLAYER_COLOR_UPDATED: '&e&lBorda | &7Cor da borda pessoal alterada com sucesso para {0}.' +BUILD_OUTSIDE_ISLAND: '&c&lErro | &7Você não pode construir fora do seu limite de proteção.' +CANNOT_SET_ROLE: '&c&lErro | &7Você não pode definir o cargo do jogador como {0}.' +CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lErro | &7Você só pode alterar permissões para cargos inferiores ao seu na ilha.' +CHANGED_BANK_LIMIT: '&e&lMelhorias | &7Limite do banco da ilha de {0} atualizado com sucesso.' +CHANGED_BANK_LIMIT_ALL: '&e&lMelhorias | &7Limite do banco de todas as ilhas atualizado com sucesso.' +CHANGED_BANK_LIMIT_NAME: '&e&lMelhorias | &7Limite do banco de {0} atualizado com sucesso.' +CHANGED_BIOME: '&e&lIlha | &7Bioma alterado com sucesso para {0}. Você pode precisar se reconectar ao servidor para ver as mudanças.' +CHANGED_BIOME_ALL: '&e&lIlha | &7Bioma alterado com sucesso para {0} em todas as ilhas.' +CHANGED_BIOME_NAME: '&e&lIlha | &7Bioma alterado com sucesso para {0} na ilha {1}.' +CHANGED_BIOME_OTHER: '&e&lIlha | &7Bioma alterado com sucesso para {0} na ilha de {1}.' +CHANGED_BLOCK_AMOUNT: '&e&lBlocos | &7Quantidade de blocos em {0} alterada para {1}.' +CHANGED_BLOCK_LIMIT: '&e&lMelhorias | &7Limite de blocos {0} atualizado na ilha de {1}.' +CHANGED_BLOCK_LIMIT_ALL: '&e&lMelhorias | &7Limite de blocos {0} atualizado em todas as ilhas.' +CHANGED_BLOCK_LIMIT_NAME: '&e&lMelhorias | &7Limite de blocos {0} atualizado em {1}.' +CHANGED_CHEST_SIZE: '&e&lBaú | &7As linhas da página #{0} foram atualizadas para {1} na ilha de {2}.' +CHANGED_CHEST_SIZE_ALL: '&e&lBaú | &7As linhas da página #{0} foram atualizadas para {1} em todas as ilhas.' +CHANGED_CHEST_SIZE_NAME: '&e&lBaú | &7As linhas da página #{0} foram atualizadas para {1} de {2}.' +CHANGED_COOP_LIMIT: '&e&lMelhorias | &7O limite de jogadores na cooperação da ilha de {0} foi atualizado com sucesso.' +CHANGED_COOP_LIMIT_ALL: '&e&lMelhorias | &7O limite de jogadores na cooperação de todas as ilhas foi atualizado com sucesso.' +CHANGED_COOP_LIMIT_NAME: '&e&lMelhorias | &7O limite de jogadores na cooperação de {0} foi atualizado com sucesso.' +CHANGED_CROP_GROWTH: '&e&lMelhorias | &7O multiplicador de crescimento das plantações da ilha de {0} foi atualizado com sucesso.' +CHANGED_CROP_GROWTH_ALL: '&e&lMelhorias | &7O multiplicador de crescimento das plantações de todas as ilhas foi atualizado com sucesso.' +CHANGED_CROP_GROWTH_NAME: '&e&lMelhorias | &7O multiplicador de crescimento das plantações de {0} foi atualizado com sucesso.' +CHANGED_DISCORD: '&e&lIlha | &7O Discord da ilha foi atualizado para {0}.' +CHANGED_ENTITY_LIMIT: '&e&lMelhorias | &7O limite de entidades {0} para a ilha de {1} foi atualizado com sucesso.' +CHANGED_ENTITY_LIMIT_ALL: '&e&lMelhorias | &7O limite de entidades {0} para todas as ilhas foi atualizado com sucesso.' +CHANGED_ENTITY_LIMIT_NAME: '&e&lMelhorias | &7O limite de entidades {0} para {1} foi atualizado com sucesso.' +CHANGED_ISLAND_EFFECT_LEVEL: '&e&lMelhorias | &7O nível do efeito da ilha {0} para a ilha de {1} foi atualizado com sucesso.' +CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lMelhorias | &7O nível do efeito da ilha {0} para todas as ilhas foi atualizado com sucesso.' +CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lMelhorias | &7O nível do efeito da ilha {0} para {1} foi atualizado com sucesso.' +CHANGED_ISLAND_SIZE: '&e&lMelhorias | &7O tamanho da ilha de {0} foi atualizado com sucesso.' +CHANGED_ISLAND_SIZE_ALL: '&e&lMelhorias | &7O tamanho de todas as ilhas foi atualizado com sucesso.' +CHANGED_ISLAND_SIZE_NAME: '&e&lMelhorias | &7O tamanho da ilha de {0} foi atualizado com sucesso.' +CHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oOs jogadores podem construir fora de sua ilha, então o tamanho da ilha não tem efeito. Você pode desativar essa função na configuração para que o tamanho da ilha volte a ter efeito.' +CHANGED_LANGUAGE: '&e&lIdioma | &7Seu idioma foi alterado com sucesso para Inglês.' +CHANGED_MOB_DROPS: '&e&lMelhorias | &7O multiplicador de drops de mobs da ilha de {0} foi atualizado com sucesso.' +CHANGED_MOB_DROPS_ALL: '&e&lMelhorias | &7O multiplicador de drops de mobs de todas as ilhas foi atualizado com sucesso.' +CHANGED_MOB_DROPS_NAME: '&e&lMelhorias | &7O multiplicador de drops de mobs de {0} foi atualizado com sucesso.' +CHANGED_NAME: '&e&lIlha | &7Você alterou o nome da sua ilha para {0}.' +CHANGED_NAME_OTHER: '&e&lIlha | &7Você alterou o nome da ilha de {0} para {1}.' +CHANGED_NAME_OTHER_NAME: '&e&lIlha | &7Você alterou o nome de {0} para {1}.' +CHANGED_PAYPAL: '&e&lIlha | &7O PayPal da ilha foi atualizado para {0}.' +CHANGED_ROLE_LIMIT: '&e&lMelhorias | &7O limite do cargo {0} para a ilha de {1} foi atualizado com sucesso.' +CHANGED_ROLE_LIMIT_ALL: '&e&lMelhorias | &7O limite do cargo {0} para todas as ilhas foi atualizado com sucesso.' +CHANGED_ROLE_LIMIT_NAME: '&e&lMelhorias | &7O limite do cargo {0} para {1} foi atualizado com sucesso.' +CHANGED_SPAWNER_RATES: '&e&lMelhorias | &7O multiplicador das taxas de geradores da ilha de {0} foi atualizado com sucesso.' +CHANGED_SPAWNER_RATES_ALL: '&e&lMelhorias | &7O multiplicador das taxas de geradores de todas as ilhas foi atualizado com sucesso.' +CHANGED_SPAWNER_RATES_NAME: '&e&lMelhorias | &7O multiplicador das taxas de geradores de {0} foi atualizado com sucesso.' +CHANGED_TEAM_LIMIT: '&e&lMelhorias | &7O limite de membros da equipe da ilha de {0} foi atualizado com sucesso.' +CHANGED_TEAM_LIMIT_ALL: '&e&lMelhorias | &7O limite de membros da equipe de todas as ilhas foi atualizado com sucesso.' +CHANGED_TEAM_LIMIT_NAME: '&e&lMelhorias | &7O limite de membros da equipe de {0} foi atualizado com sucesso.' +CHANGED_TELEPORT_LOCATION: '&e&lIlha | &7A localização de teletransporte foi atualizada com sucesso.' +CHANGED_WARPS_LIMIT: '&e&lMelhorias | &7O limite de warps da ilha de {0} foi atualizado com sucesso.' +CHANGED_WARPS_LIMIT_ALL: '&e&lMelhorias | &7O limite de warps de todas as ilhas foi atualizado com sucesso.' +CHANGED_WARPS_LIMIT_NAME: '&e&lMelhorias | &7O limite de warps de {0} foi atualizado com sucesso.' +COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_PLAYERS: '*' +COMMAND_ARGUMENT_AMOUNT: 'quantidade' +COMMAND_ARGUMENT_BIOME: 'bioma' +COMMAND_ARGUMENT_BORDER_COLOR: 'cor-da-borda' +COMMAND_ARGUMENT_COMMAND: 'comando...' +COMMAND_ARGUMENT_DISCORD: 'discord...' +COMMAND_ARGUMENT_EFFECT: 'efeito-de-poção' +COMMAND_ARGUMENT_EMAIL: 'email' +COMMAND_ARGUMENT_ENTITY: 'entidade' +COMMAND_ARGUMENT_ISLAND_NAME: 'nome-da-ilha' +COMMAND_ARGUMENT_ISLAND_ROLE: 'cargo-da-ilha' +COMMAND_ARGUMENT_LEADER: 'líder' +COMMAND_ARGUMENT_LEVEL: 'nível' +COMMAND_ARGUMENT_LIMIT: 'limite' +COMMAND_ARGUMENT_MATERIAL: 'material' +COMMAND_ARGUMENT_MENU: 'nome-do-menu' +COMMAND_ARGUMENT_MESSAGE: 'mensagem...' +COMMAND_ARGUMENT_MISSION_NAME: 'nome-da-missão' +COMMAND_ARGUMENT_MODULE_NAME: 'nome-do-módulo' +COMMAND_ARGUMENT_MULTIPLIER: 'multiplicador' +COMMAND_ARGUMENT_NAME: 'nome' +COMMAND_ARGUMENT_NEW_LEADER: 'novo-líder' +COMMAND_ARGUMENT_PAGE: 'página' +COMMAND_ARGUMENT_PATH: 'caminho' +COMMAND_ARGUMENT_PERMISSION: 'permissão' +COMMAND_ARGUMENT_PLAYER_NAME: 'nome-do-jogador' +COMMAND_ARGUMENT_PRIVATE: 'privado' +COMMAND_ARGUMENT_RATING: 'avaliação' +COMMAND_ARGUMENT_ROWS: 'linhas' +COMMAND_ARGUMENT_SCHEMATIC_NAME: 'nome-da-esquema' +COMMAND_ARGUMENT_SETTINGS: 'configurações' +COMMAND_ARGUMENT_SIZE: 'tamanho' +COMMAND_ARGUMENT_TIME: 'tempo' +COMMAND_ARGUMENT_TITLE_DURATION: 'duração' +COMMAND_ARGUMENT_TITLE_FADE_IN: 'fade-in' +COMMAND_ARGUMENT_TITLE_FADE_OUT: 'desaparecer' +COMMAND_ARGUMENT_UPGRADE_NAME: 'nome-do-upgrade' +COMMAND_ARGUMENT_VALUE: 'valor' +COMMAND_ARGUMENT_WARP_NAME: 'nome-do-warp' +COMMAND_ARGUMENT_WARP_CATEGORY: 'categoria-do-warp' +COMMAND_ARGUMENT_WORLD: 'mundo' +COMMAND_COOLDOWN_FORMAT: '&c&lErro | &7Você só pode usar o comando novamente em {0}.' +COMMAND_DESCRIPTION_ACCEPT: 'Aceite um convite de um jogador.' +COMMAND_DESCRIPTION_ADMIN: 'Use os comandos de administrador.' +COMMAND_DESCRIPTION_ADMIN_ADD: 'Adicione um usuário a uma ilha.' +COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Aumente o limite de blocos para a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Adicione um bônus a um jogador.' +COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Aumente o limite de jogadores na cooperação da ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: 'Aumente o multiplicador de crescimento das plantações da ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: 'Adicione um efeito à ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: 'Aumente o limite de entidades na ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: 'Adicione porcentagem de um material ao gerador de pedra.' +COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: 'Aumente o multiplicador de drops de mobs da ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: 'Expanda o tamanho da ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: 'Aumente o multiplicador das taxas dos geradores da ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: 'Aumente o limite de membros da equipe da ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: 'Aumente o limite de warps de uma ilha.' +COMMAND_DESCRIPTION_ADMIN_BONUS: 'Conceda um bônus a um jogador.' +COMMAND_DESCRIPTION_ADMIN_BYPASS: 'Alternar o modo bypass.' +COMMAND_DESCRIPTION_ADMIN_CHEST: 'Abrir o baú da ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: 'Limpar as taxas do gerador para uma ilha específica.' +COMMAND_DESCRIPTION_ADMIN_CLOSE: 'Fechar uma ilha para o público.' +COMMAND_DESCRIPTION_ADMIN_CMD_ALL: 'Executar um comando para todos os membros de ilhas.' +COMMAND_DESCRIPTION_ADMIN_COUNT: 'Verificar a contagem de blocos em uma ilha específica.' +COMMAND_DESCRIPTION_ADMIN_DATA: 'Interagir com dados persistentes de jogadores ou ilhas.' +COMMAND_DESCRIPTION_ADMIN_DEBUG: 'Alternar saídas de depuração.' +COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Excluir um warp de uma ilha.' +COMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Rebaixar um membro na ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Depositar dinheiro no banco da ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_DISBAND: 'Desfazer permanentemente a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Conceder dissoluções de ilhas a um jogador.' +COMMAND_DESCRIPTION_ADMIN_IGNORE: 'Ignorar uma ilha das melhores ilhas.' +COMMAND_DESCRIPTION_ADMIN_JOIN: 'Entrar em uma ilha sem convite.' +COMMAND_DESCRIPTION_ADMIN_KICK: 'Expulsar um jogador de sua ilha.' +COMMAND_DESCRIPTION_ADMIN_MODULES: 'Gerenciar módulos do plugin.' +COMMAND_DESCRIPTION_ADMIN_MISSION: 'Alterar o status de uma missão para um jogador.' +COMMAND_DESCRIPTION_ADMIN_MSG: 'Enviar uma mensagem a um jogador sem prefixos.' +COMMAND_DESCRIPTION_ADMIN_MSG_ALL: 'Enviar a todos os membros de uma ilha uma mensagem sem prefixos.' +COMMAND_DESCRIPTION_ADMIN_NAME: 'Alterar o nome de uma ilha.' +COMMAND_DESCRIPTION_ADMIN_OPEN: 'Abrir uma ilha para o público.' +COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: 'Abrir um menu personalizado para um jogador.' +COMMAND_DESCRIPTION_ADMIN_PROMOTE: 'Promover um membro na ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_PURGE: 'Remover ilhas.' +COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Subir o nível de um upgrade para uma ilha.' +COMMAND_DESCRIPTION_ADMIN_RECALC: 'Recalcular o valor de uma ilha.' +COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Recarregar todas as configurações e tarefas do plugin.' +COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remover o limite de blocos de uma ilha.' +COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Remover todas as avaliações dadas por um jogador.' +COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Redefinir um mundo para uma ilha.' +COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Criar esquemas para o plugin.' +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Definir o limite do banco para uma ilha.' +COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Definir o bioma de uma ilha.' +COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Definir a quantidade de blocos em um local específico.' +COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Definir o limite de blocos para a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: 'Definir as linhas do baú para a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: 'Definir o limite de cooperação para a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Definir o multiplicador de crescimento de plantações para a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Definir a quantidade de dissoluções de ilhas de um jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Definir o nível do efeito da ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Definir o limite de entidades para a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Transferir uma ilha para outra pessoa.' +COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Definir o multiplicador de drops de mobs para a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Definir uma permissão de função obrigatória para todas as ilhas.' +COMMAND_DESCRIPTION_ADMIN_SET_RATE: 'Definir a avaliação de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: 'Definir o limite de cargos para a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: 'Alternar configurações para uma ilha específica.' +COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: 'Alterar a porcentagem de um material no gerador de pedra.' +COMMAND_DESCRIPTION_ADMIN_SET_SIZE: 'Alterar o tamanho da ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: 'Definir o local de spawn do servidor.' +COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: 'Definir o multiplicador das taxas de spawner para a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: 'Definir o limite de membros da equipe para a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: 'Definir o nível de um upgrade para a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: 'Definir o limite de warps de uma ilha.' +COMMAND_DESCRIPTION_ADMIN_SETTINGS: 'Abrir o editor de configurações do plugin.' +COMMAND_DESCRIPTION_ADMIN_SHOW: 'Obter informações sobre uma ilha.' +COMMAND_DESCRIPTION_ADMIN_SPAWN: 'Teletransportar para o local de spawn.' +COMMAND_DESCRIPTION_ADMIN_SPY: 'Alternar o modo de espionagem de chat.' +COMMAND_DESCRIPTION_ADMIN_STATS: 'Exibir estatísticas sobre o plugin.' +COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sincronizar o bônus de uma ilha com os mundos gerados.' +COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: 'Sincronizar os valores de upgrades de uma ilha.' +COMMAND_DESCRIPTION_ADMIN_TELEPORT: 'Teletransportar para outras ilhas.' +COMMAND_DESCRIPTION_ADMIN_TITLE: 'Enviar um título para um jogador.' +COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: 'Enviar um título para todos os membros de uma ilha.' +COMMAND_DESCRIPTION_ADMIN_UNIGNORE: 'Remover uma ilha da lista de ignorados das melhores ilhas.' +COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: 'Desbloquear um mundo para uma ilha.' +COMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Retirar dinheiro do banco da ilha de outro jogador.' +COMMAND_DESCRIPTION_BALANCE: 'Verificar a quantidade de dinheiro no banco da ilha.' +COMMAND_DESCRIPTION_BAN: 'Banir um jogador de sua ilha.' +COMMAND_DESCRIPTION_BANK: 'Abrir o banco da ilha.' +COMMAND_DESCRIPTION_BIOME: 'Alterar o bioma da ilha.' +COMMAND_DESCRIPTION_BORDER: 'Alterar a cor da borda das ilhas.' +COMMAND_DESCRIPTION_CHEST: 'Abrir o baú da ilha.' +COMMAND_DESCRIPTION_CLOSE: 'Fechar a ilha para o público.' +COMMAND_DESCRIPTION_COOP: 'Adicionar um jogador como coop na sua ilha.' +COMMAND_DESCRIPTION_COOPS: 'Abrir o menu de coops.' +COMMAND_DESCRIPTION_COUNTS: 'Ver contagem de blocos na sua ilha.' +COMMAND_DESCRIPTION_CREATE: 'Criar uma nova ilha.' +COMMAND_DESCRIPTION_DEL_WARP: 'Excluir um warp da ilha.' +COMMAND_DESCRIPTION_DEMOTE: 'Rebaixar um membro na sua ilha.' +COMMAND_DESCRIPTION_DEPOSIT: 'Depositar dinheiro da sua conta pessoal no banco da ilha.' +COMMAND_DESCRIPTION_DISBAND: 'Dissolver sua ilha permanentemente.' +COMMAND_DESCRIPTION_EXPEL: 'Expulsar um visitante da sua ilha.' +COMMAND_DESCRIPTION_FLY: 'Alternar o modo de voo na ilha.' +COMMAND_DESCRIPTION_HELP: 'Lista de todos os comandos.' +COMMAND_DESCRIPTION_INVITE: 'Convidar um jogador para sua ilha.' +COMMAND_DESCRIPTION_KICK: 'Expulsar um jogador da sua ilha.' +COMMAND_DESCRIPTION_LANG: 'Alterar seu idioma pessoal.' +COMMAND_DESCRIPTION_LEAVE: 'Sair da sua ilha.' +COMMAND_DESCRIPTION_MEMBERS: 'Abrir o menu de membros.' +COMMAND_DESCRIPTION_MISSION: 'Completar uma missão.' +COMMAND_DESCRIPTION_MISSIONS: 'Abrir o menu de missões.' +COMMAND_DESCRIPTION_NAME: 'Alterar o nome da sua ilha.' +COMMAND_DESCRIPTION_OPEN: 'Abrir a ilha para o público.' +COMMAND_DESCRIPTION_PANEL: 'Abrir o painel da ilha.' +COMMAND_DESCRIPTION_PARDON: 'Desbanir um jogador da sua ilha.' +COMMAND_DESCRIPTION_PERMISSIONS: 'Exibir todas as permissões para um cargo da ilha.' +COMMAND_DESCRIPTION_PROMOTE: 'Promover um membro na sua ilha.' +COMMAND_DESCRIPTION_RANKUP: 'Subir de nível em um upgrade.' +COMMAND_DESCRIPTION_RATE: 'Avaliar uma ilha.' +COMMAND_DESCRIPTION_RATINGS: 'Exibir todas as avaliações das ilhas.' +COMMAND_DESCRIPTION_SETTINGS: 'Abrir o menu de configurações.' +COMMAND_DESCRIPTION_RECALC: 'Recalcular o valor da ilha.' +COMMAND_DESCRIPTION_SET_DISCORD: 'Definir o discord da ilha para prêmios de ilha.' +COMMAND_DESCRIPTION_SET_PAYPAL: 'Definir o e-mail do PayPal da ilha para prêmios de ilha.' +COMMAND_DESCRIPTION_SET_ROLE: 'Alterar o cargo de um jogador na sua ilha.' +COMMAND_DESCRIPTION_SET_TELEPORT: 'Alterar a localização de teleporte da sua ilha.' +COMMAND_DESCRIPTION_SET_WARP: 'Criar um novo warp da ilha.' +COMMAND_DESCRIPTION_SHOW: 'Obter informações sobre uma ilha.' +COMMAND_DESCRIPTION_TEAM: 'Obter informações sobre o status dos membros da ilha.' +COMMAND_DESCRIPTION_TEAM_CHAT: 'Alternar o modo de chat da equipe.' +COMMAND_DESCRIPTION_TELEPORT: 'Teletransportar para sua ilha.' +COMMAND_DESCRIPTION_TOGGLE: 'Alternar as bordas da ilha e o posicionamento de blocos empilhados.' +COMMAND_DESCRIPTION_TOP: 'Abrir o painel das melhores ilhas.' +COMMAND_DESCRIPTION_TRANSFER: 'Transferir a liderança da sua ilha.' +COMMAND_DESCRIPTION_UNCOOP: 'Remover um jogador como coop da sua ilha.' +COMMAND_DESCRIPTION_UPGRADE: 'Abrir o painel de upgrades.' +COMMAND_DESCRIPTION_VALUE: 'Obter o valor de um bloco.' +COMMAND_DESCRIPTION_VALUES: 'Abrir o menu de valores.' +COMMAND_DESCRIPTION_VISIT: 'Teletransportar para o local de visitantes de uma ilha.' +COMMAND_DESCRIPTION_VISITORS: 'Abrir o menu de visitantes.' +COMMAND_DESCRIPTION_WARP: 'Ir para um warp da ilha.' +COMMAND_DESCRIPTION_WARPS: 'Abrir o menu de warps.' +COMMAND_DESCRIPTION_WITHDRAW: 'Retirar dinheiro do banco da sua ilha para sua conta pessoal.' +COMMAND_USAGE: '&cUso: /{0}' +COOP_ANNOUNCEMENT: '&e&lIlha | &7{0} adicionou {1} como membro coop.' +COOP_BANNED_PLAYER: '&c&lErro | &7Este jogador está banido da ilha e não pode ser adicionado como coop.' +COOP_LIMIT_EXCEED: '&c&lErro | &7Você atingiu o número máximo de jogadores coop que a ilha pode ter.' +CREATE_ISLAND: '&e&lIlha | &7Criou uma nova ilha em {0} em {1}ms.' +CREATE_ISLAND_FAILURE: '&c&lErro | &7Ocorreu um erro ao criar sua ilha. Por favor, entre em contato com o administrador para investigar o problema.' +CREATE_WORLD_FAILURE: '&c&lErro | &7Ocorreu um erro ao gerar o mundo. Por favor, entre em contato com o administrador para investigar o problema.' +DEBUG_MODE_DISABLED: '&e&lDebug | &7Modo de debug alternado para &cDESATIVADO&7.' +DEBUG_MODE_ENABLED: '&e&lDebug | &7Modo de debug alternado para &aATIVADO&7.' +DEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Filtro de debug {0} alternado para &aATIVADO&7.' +DEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Todos os filtros de debug alternados para &cDESATIVADO&7.' +DEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Filtro de debug {0} alternado para &cDESATIVADO&7.' +DELETE_WARP: '&e&lIlha | &7Você excluiu o warp {0}.' +DELETE_WARP_SIGN_BROKE: '&7&oHavia uma placa para esse warp, ela foi quebrada...' +DEMOTE_LEADER: '&c&lErro | &7Você não pode rebaixar líderes da ilha.' +DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErro | &7Você só pode rebaixar jogadores com um cargo inferior ao seu.' +DEMOTED_MEMBER: '&e&lIlha | &7Você rebaixou {0} para {1} na ilha dele.' +DEPOSIT_ANNOUNCEMENT: '&e&lBanco | &7{0} depositou ${1} no banco da ilha!' +DEPOSIT_ERROR: '&c&lErro | &7{0}.' +DESTROY_OUTSIDE_ISLAND: '&c&lErro | &7Você não pode destruir fora da sua área de proteção.' +DISBAND_ANNOUNCEMENT: '&e&lIlha | &7Sua ilha foi apagada por {0}.' +DISBAND_GIVE: '&e&lIlha | &7Você recebeu {0} dissoluções.' +DISBAND_GIVE_ALL: '&e&lIlha | &7Você deu {0} dissoluções para todos os jogadores.' +DISBAND_GIVE_OTHER: '&e&lIlha | &7Você deu {0} dissoluções para {1}.' +DISBAND_ISLAND_BALANCE_REFUND: '&7&oSua ilha foi apagada, e ${0} foram reembolsados para sua conta a partir do banco da ilha.' +DISBAND_SET: '&e&lIlha | &7O número de dissoluções foi definido como {0}.' +DISBAND_SET_ALL: '&e&lIlha | &7Você definiu o número de dissoluções para todos os jogadores como {0}.' +DISBAND_SET_OTHER: '&e&lIlha | &7Você definiu o número de dissoluções de {0} para {1}.' +DISBANDED_ISLAND: '&e&lIlha | &7Você apagou sua ilha.' +DISBANDED_ISLAND_OTHER: '&e&lIlha | &7Você apagou a ilha de {0}.' +DISBANDED_ISLAND_OTHER_NAME: '&e&lIlha | &7Você apagou a ilha {0}.' +ENTER_PVP_ISLAND: '&7&oVocê foi teleportado para uma ilha com PVP ativado. Você está imune ao PVP pelos próximos 10 segundos...' +EXPELLED_PLAYER: '&e&lIlha | &7{0} foi expulso da ilha.' +FORMAT_QUAD: 'Q' +FORMAT_TRILLION: 'T' +FORMAT_BILLION: 'B' +FORMAT_MILLION: 'M' +FORMAT_THOUSANDS: 'K' +FORMAT_SECONDS_NAME: 'segundos' +FORMAT_SECOND_NAME: 'segundo' +FORMAT_MINUTES_NAME: 'minutos' +FORMAT_MINUTE_NAME: 'minuto' +FORMAT_HOURS_NAME: 'horas' +FORMAT_HOUR_NAME: 'hora' +FORMAT_DAYS_NAME: 'dias' +FORMAT_DAY_NAME: 'dia' +GENERATOR_CLEARED: '&e&lIlha | &7Os valores do gerador da ilha de {0} foram limpos com sucesso.' +GENERATOR_CLEARED_NAME: '&e&lIlha | &7Os valores do gerador da ilha de {0} foram limpos com sucesso.' +GENERATOR_CLEARED_ALL: '&e&lIlha | &7Os valores do gerador de todas as ilhas foram limpos com sucesso.' +GENERATOR_UPDATED: '&e&lIlha | &7A quantidade do gerador de {0} foi atualizada com sucesso para a ilha de {1}.' +GENERATOR_UPDATED_NAME: '&e&lIlha | &7A quantidade do gerador de {0} foi atualizada com sucesso para a ilha de {1}.' +GENERATOR_UPDATED_ALL: '&e&lIlha | &7A quantidade do gerador de {0} foi atualizada com sucesso para todas as ilhas.' +GLOBAL_COMMAND_EXECUTED: '&e&lIlha | &7Comando executado com sucesso nos membros da ilha de {0}!' +GLOBAL_COMMAND_EXECUTED_NAME: '&e&lIlha | &7Comando executado com sucesso nos membros da ilha de {0}!' +GLOBAL_MESSAGE_SENT: '&e&lIlha | &7Mensagem enviada com sucesso para os membros da ilha de {0}!' +GLOBAL_MESSAGE_SENT_NAME: '&e&lIlha | &7Mensagem enviada com sucesso para os membros da ilha de {0}!' +GLOBAL_TITLE_SENT: '&e&lIlha | &7Título enviado com sucesso para os membros da ilha de {0}!' +GLOBAL_TITLE_SENT_NAME: '&e&lIlha | &7Título enviado com sucesso para os membros da ilha de {0}!' +GOT_BANNED: '&e&lIlha | &7Você foi BANIDO da ilha de {0}.' +GOT_DEMOTED: '&e&lIlha | &7Você foi rebaixado para {0} na sua ilha.' +GOT_EXPELLED: '&e&lIlha | &7&oVocê foi expulso da ilha por {0}.' +GOT_INVITE: '&e&lIlha | &7{0} convidou você para a ilha dele.' +GOT_INVITE_TOOLTIP: '&7Clique na mensagem para aceitar o convite.' +GOT_KICKED: '&e&lIlha | &7Você foi expulso da sua ilha por {0}.' +GOT_PROMOTED: '&e&lIlha | &7Você foi promovido para {0} na sua ilha.' +GOT_REVOKED: '&e&lIlha | &7{0} revogou seu convite para a ilha dele.' +GOT_UNBANNED: '&e&lIlha | &7Você foi DESBANIDO da ilha de {0}.' +HIT_ISLAND_MEMBER: '&c&lErro | &7Você não pode atacar membros da sua ilha.' +HIT_PLAYER_IN_ISLAND: '&c&lErro | &7Você não pode atacar jogadores dentro de ilhas.' +IGNORED_ISLAND: '&e&lIlha | &7A ilha de {0} agora está ignorada no ranking das melhores ilhas.' +IGNORED_ISLAND_NAME: '&e&lIlha | &7A ilha {0} agora está ignorada no ranking das melhores ilhas.' +INTERACT_OUTSIDE_ISLAND: '&c&lErro | &7Você não pode interagir fora da sua área de proteção.' +INVALID_AMOUNT: '&c&lErro | &7Valor inválido {0}.' +INVALID_BIOME: '&c&lErro | &7Bioma inválido {0}.' +INVALID_BLOCK: '&c&lErro | &7Localização de bloco inválida {0}.' +INVALID_BORDER_COLOR: '&c&lErro | &7Cor da borda inválida {0}.' +INVALID_EFFECT: '&c&lErro | &7Efeito inválido {0}.' +INVALID_ENTITY: '&c&lErro | &7Entidade inválida {0}.' +INVALID_ENVIRONMENT: '&c&lErro | &7Mundo inválido {0}.' +INVALID_INTERVAL: '&c&lErro | &7Intervalo inválido {0}.' +INVALID_ISLAND: '&c&lErro | &7Você não tem uma ilha.' +INVALID_ISLAND_LOCATION: '&c&lErro | &7Não há ilha na sua localização.' +INVALID_ISLAND_OTHER: '&c&lErro | &7{0} não tem uma ilha.' +INVALID_ISLAND_OTHER_NAME: '&c&lErro | &7Não existe uma ilha com o nome {0}.' +INVALID_ISLAND_PERMISSION: | + &c&lErro | &7Não foi possível encontrar a permissão da ilha {0}. + &c&lErro | &7Permissões da ilha: {1} +INVALID_LEVEL: '&c&lErro | &7Nível inválido {0}.' +INVALID_LIMIT: '&c&lErro | &7Limite inválido {0}.' +INVALID_MATERIAL: '&c&lErro | &7Material inválido {0}.' +INVALID_MATERIAL_DATA: '&c&lErro | &7Material-dados inválido {0}.' +INVALID_MISSION: '&c&lErro | &7Missão inválida {0}.' +INVALID_MODULE: '&c&lErro | &7Módulo inválido {0}.' +INVALID_MULTIPLIER: '&c&lErro | &7Multiplicador inválido {0}.' +INVALID_PAGE: '&c&lErro | &7Página inválida {0}.' +INVALID_PERCENTAGE: '&c&lErro | &7A porcentagem deve estar entre 0 e 100.' +INVALID_PLAYER: '&c&lErro | &7Não foi possível encontrar um jogador chamado {0}.' +INVALID_RATE: | + &c&lErro | &7Não foi possível encontrar uma classificação com o nome {0}. + &c&lErro | &7Classificações da ilha: {1} +INVALID_ROWS: '&c&lErro | &7Quantidade inválida de linhas: {0}' +INVALID_ROLE: | + &c&lErro | &7Não foi possível encontrar a função da ilha {0}. + &c&lErro | &7Funções da ilha: {1} +INVALID_SCHEMATIC: '&c&lErro | &7Não foi possível encontrar um esquema com o nome {0}.' +INVALID_SETTINGS: | + &c&lErro | &7Não foi possível encontrar as configurações da ilha {0}. + &c&lErro | &7Configurações da ilha: {1} +INVALID_SIZE: '&c&lErro | &7Tamanho inválido {0}.' +INVALID_SLOT: '&c&lErro | &7Slot inválido {0}.' +INVALID_TITLE: '&c&lErro | &7Título inválido inserido.' +INVALID_TOGGLE_MODE: '&c&lErro | &7Não é possível alternar {0}.' +INVALID_UPGRADE: | + &c&lErro | &7Não foi possível encontrar uma atualização chamada {0}. + &c&lErro | &7Atualizações: {1} +INVALID_VISIT_LOCATION: '&c&lErro | &7Esta ilha não tem localização de visitantes.' +INVALID_VISIT_LOCATION_BYPASS: '&7&oVocê tem o modo bypass, teletransportando você para a ilha...' +INVALID_WARP: '&c&lErro | &7Warp inválido {0}.' +INVALID_WORLD: '&c&lErro | &7Mundo inválido {0}.' +INVITE_ANNOUNCEMENT: '&e&lIlha | &7{0} convidou {1} para a ilha.' +INVITE_BANNED_PLAYER: '&c&lErro | &7Este jogador foi banido da ilha e não pode ser convidado.' +INVITE_TO_FULL_ISLAND: '&c&lErro | &7Você não pode convidar mais membros para sua ilha.' +ISLAND_ALREADY_EXIST: '&c&lErro | &7Uma ilha com esse nome já existe.' +ISLAND_BANK_EMPTY: '&e&lBanco | &7O banco da ilha está vazio.' +ISLAND_BANK_SHOW: '&e&lBanco | &7Sua ilha tem ${0}.' +ISLAND_BANK_SHOW_OTHER: '&e&lBanco | &7A ilha de {0} tem ${1}.' +ISLAND_BANK_SHOW_OTHER_NAME: '&e&lBanco | &7A ilha {0} tem ${1}.' +ISLAND_BEING_CALCULATED: '&c&lErro | &7Você não pode interagir com blocos quando a ilha está sendo recalculada!' +ISLAND_CLOSED: '&e&lIsland | &7A ilha foi fechada com sucesso para o público.' +ISLAND_CREATE_PROCESS_FAIL: '&c&lErro | &7Você já tem uma tarefa de criação de ilha em andamento.' +ISLAND_CREATE_PROCCESS_REQUEST: '&e&lIlha | &7Processando sua solicitação...' +ISLAND_FLY_DISABLED: '&e&lVoar | &7Voar na ilha foi automaticamente &cdesabilitado&7.' +ISLAND_FLY_ENABLED: '&e&lVoar | &7Voar na ilha foi automaticamente &ahabilitado&7.' +ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIlha | &7&oVocê estava dentro de uma ilha que foi apagada, então você foi teletransportado de volta para spawn...' +ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lIlha | &7&oVocê estava dentro de uma ilha que havia ativado o PvP, então você foi teletransportado de volta para o spawn...' +ISLAND_HELP_FOOTER: '&e&lSkyblock &7Desenvolvido por Ome_R' +ISLAND_HELP_HEADER: '&e&lSkyblock &7Lista de Comandos [{0}/{1}]:' +ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' +ISLAND_HELP_NEXT_PAGE: '&e&lSkyblock &7Use /is help {0} para a próxima página.' +ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lIlha | &7Limite do Banco: {0}' +ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | + &e&lIlha | &7Blocos Limites: + {0} +ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lIlha | &7 {0}: {1}' +ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lIlha | &7Limite de coop: {0}' +ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lIlha | &7Multiplicador de colheitas: {0}' +ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lIlha | &7Multiplicador de gotas: {0}' +ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | + &e&lIlha | &7Efeitos da Ilha: + {0} +ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lIlha | &7 {0}: {1}' +ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | + &e&lIlha | Limites de &7Entidades: + {0} +ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lIlha | &7 {0}: {1}' +ISLAND_INFO_ADMIN_GENERATOR_RATES: | + &e&lIlha | &7Taxas de Geração ({1}): + {0} +ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lIlha | &7 {0}: {1}% ({2})' +ISLAND_INFO_ADMIN_ROLE_LIMITS: | + &e&lIlha | &7Limites de Função: + {0} +ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lIlha | &7 {0}: {1}' +ISLAND_INFO_ADMIN_SIZE: '&e&lIlha | &7Tamanho da Borda: {0}' +ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lIlha | &7Multiplicador de Geradores: {0}' +ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lIlha | &7Limite da Equipe: {0}' +ISLAND_INFO_ADMIN_UPGRADES: | + &e&lIlha | &7Melhorias: + {0} +ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lIlha | &7 {0}: {1}' +ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' +ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lIlha | &7Limite de Warps: {0}' +ISLAND_INFO_BANK: '&e&lIlha | &7Banco: {0}' +ISLAND_INFO_BONUS: '&e&lIlha | &7Bônus de valor: {0}' +ISLAND_INFO_BONUS_LEVEL: '&e&lIlha | &7Bônus de nível: {0}' +ISLAND_INFO_CREATION_TIME: '&e&lIlha | &7Hora da criação: {0}' +ISLAND_INFO_DISCORD: '&e&lIlha | &7Discord: {0}' +ISLAND_INFO_FOOTER: '' +ISLAND_INFO_HEADER: '' +ISLAND_INFO_LAST_TIME_UPDATED: '&e&lIlha | &7Última atualização: {0} atrás' +ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lIlha | &7Última atualização: &aAtualmente ativo' +ISLAND_INFO_LEVEL: '&e&lIlha | &7Nível: {0}' +ISLAND_INFO_LOCATION: '&e&lIlha | &7Casa: {0}' +ISLAND_INFO_NAME: '&e&lIlha | &7Nome: {0}' +ISLAND_INFO_OWNER: '&e&lIlha | &7Líder: {0}' +ISLAND_INFO_PAYPAL: '&e&lIlha | &7Paypal: {0}' +ISLAND_INFO_PLAYER_LINE: '&e&lIlha | &7 - {0}' +ISLAND_INFO_RATE: '&e&lIlha | &7Rate: {0} &7({1}/5) - {2} avaliações totais.' +ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' +ISLAND_INFO_RATE_SYMBOL: '✦' +ISLAND_INFO_RATE_ONE_COLOR: '&4' +ISLAND_INFO_RATE_TWO_COLOR: '&6' +ISLAND_INFO_RATE_THREE_COLOR: '&e' +ISLAND_INFO_RATE_FOUR_COLOR: '&a' +ISLAND_INFO_RATE_FIVE_COLOR: '&2' +ISLAND_INFO_ROLES: | + &e&lIlha | &7{0}s: + {1} +ISLAND_INFO_VISITORS_COUNT: '&e&lIlha | &7Contagem de visitantes: {0}' +ISLAND_INFO_WORTH: '&e&lIlha | &7Valor: {0}' +ISLAND_OPENED: '&e&lIlha | &7A ilha foi aberta com sucesso ao público.' +ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVisualizar | &7Você foi muito longe e não está mais no modo de visualização.' +ISLAND_PREVIEW_CANCEL: '&e&lVisualizar | &7Você cancelou o modo de visualização.' +ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRMAR' +ISLAND_PREVIEW_CANCEL_TEXT: 'CANCELAR' +ISLAND_PREVIEW_START: | + &e&lVisualizar | &7Você iniciou o modo de visualização para o esquema {0}. + &e&lVisualizar | &7Digite &a&lCONFIRM &7para criar uma nova ilha, ou &c&lCANCEL &7para cancelar o modo de pré-visualização. + &e&lPreview | &7Você não pode sair da área da ilha, caso contrário, o modo de pré-visualização será cancelado automaticamente. +ISLAND_PROTECTED: '&c&lErro | &7Esta ilha está protegida.' +ISLAND_PROTECTED_OPPED: '&7&oVocê pode ignorar esta restrição usando "/is admin bypass".' +ISLAND_TEAM_STATUS_FOOTER: '' +ISLAND_TEAM_STATUS_HEADER: '&e&lIlha | &7Membros da Ilha de {0} &8[&e{1}&8/&e{2}&8]&7:' +ISLAND_TEAM_STATUS_OFFLINE: '&c(Offline)' +ISLAND_TEAM_STATUS_ONLINE: '&a(Online)' +ISLAND_TEAM_STATUS_ROLES: '&e&lIlha | &7 * [{0}] {1} {2} &7({3})' +ISLAND_TOP_STATUS_OFFLINE: '&c(Offline)' +ISLAND_TOP_STATUS_ONLINE: '&a(Online)' +ISLAND_WARP_PUBLIC: '' +ISLAND_WARP_PRIVATE: '&c[Privado]' +ISLAND_WAS_CLOSED: '&e&lIlha | &7&oA ilha em que você estava foi fechada e você foi teletransportado de volta para o spawn...' +ISLAND_WORTH_ERROR: '&c&lErro | &7Ocorreu um erro inesperado ao calcular sua ilha. Entre em contato com os administradores se o problema persistir.' +ISLAND_WORTH_RESULT: '&e&lIlha | &7O valor da sua ilha é {0} [Nível {1}]' +ISLAND_WORTH_TIME_OUT: '&c&lErro | &7A tarefa de cálculo expirou. Tente novamente mais tarde...' +JOIN_ADMIN_ANNOUNCEMENT: '&e&lIlha | &7{0} entrou na sua ilha.' +JOIN_ANNOUNCEMENT: '&e&lIlha | &7{0} entrou na sua ilha.' +JOIN_FULL_ISLAND: '&c&lErro | &7Esta ilha atingiu a quantidade máxima de membros permitidos.' +JOIN_WHILE_IN_ISLAND: '&c&lErro | &7Você já está dentro de uma ilha.' +JOINED_ISLAND: '&e&lIlha | &7Você entrou na ilha de {0}.' +JOINED_ISLAND_NAME: '&e&lIlha | &7Você entrou na ilha {0}.' +JOINED_ISLAND_AS_COOP: '&e&lIlha | &7Você agora é um membro cooperativo da ilha de {0}.' +JOINED_ISLAND_AS_COOP_NAME: '&e&lIlha | &7Agora você é um membro cooperativo da ilha {0}.' +KICK_ANNOUNCEMENT: '&e&lIlha | &7{0} foi expulso da ilha por {1}.' +KICK_ISLAND_LEADER: '&c&lErro | &7Você não pode expulsar o líder da ilha, use /is admin disband em vez disso.' +KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lErro | &7Você só pode expulsar jogadores com uma função de ilha inferior à sua.' +LACK_CHANGE_PERMISSION: '&c&lErro | &7Você deve ter esta permissão para alterá-la para outras funções.' +LAST_ROLE_DEMOTE: '&c&lErro | &7Você não pode mais rebaixar este jogador.' +LAST_ROLE_PROMOTE: '&c&lErro | &7Você não pode mais promover este jogador.' +LEAVE_ANNOUNCEMENT: '&e&lIlha | &7{0} deixou a ilha.' +LEAVE_ISLAND_AS_LEADER: |- + &c&lErro | &7Você não pode deixar sua ilha quando você a possui. + &c&lErro | &7Você pode transferir a propriedade usando /is transfer. +LEFT_ISLAND: '&e&lIlha | &7Você saiu da sua ilha.' +LEFT_ISLAND_COOP: '&e&lIlha | &7Você não é mais um membro cooperativo da ilha de {0}.' +LEFT_ISLAND_COOP_NAME: '&e&lIlha | &7Você não é mais um membro cooperativo da ilha {0}.' +MATERIAL_NOT_SOLID: '&c&lErro | &7Você deve fornecer um material sólido.' +MAXIMUM_LEVEL: '&c&lErro | &7O nível máximo para esta atualização é {0}.' +MESSAGE_SENT: '&e&lIlha | &7A mensagem foi enviada com sucesso para {0}!' +MISSION_CANNOT_COMPLETE: '&c&lErro | &7Você não pode concluir esta missão ainda.' +MISSION_NO_AUTO_REWARD: '&e&lMissão | &7Você tem todos os materiais necessários para concluir {0} - use /is missions para concluir!' +MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lErro | &7Você deve concluir {0} antes de concluir esta missão.' +MISSION_STATUS_COMPLETE: '&e&lMissão | &7Alterou o status da missão {0} para concluída para {1}.' +MISSION_STATUS_COMPLETE_ALL: '&e&lMissão | &7Alterou o status de todas as missões para concluídas para {0}.' +MISSION_STATUS_RESET: '&e&lMissão | &7Redefiniu o status da missão {0} para {1}.' +MISSION_STATUS_RESET_ALL: '&e&lMissão | &7Redefiniu o status de todas as missões para {0}.' +MODULE_ALREADY_INITIALIZED: '&e&lMódulo | &7Este módulo já está carregado.' +MODULE_INFO: | + &e&lMódulo | &7{0} por {1} + &e&lMódulo | &7&m-------------------- + &e&lMódulo | &7{2} +MODULE_LOADED_SUCCESS: '&e&lMódulo | &7Carregou o módulo {0} com sucesso.' +MODULE_LOADED_FAILURE: '&e&lMódulo | &7Não foi possível carregar o módulo {0}. Verifique o console para obter mais informações.' +MODULE_UNLOADED_SUCCESS: '&e&lMódulo | &7Descarregado o módulo com sucesso.' +MODULES_LIST: '&fMódulos ({0}): {1}' +MODULES_LIST_MODULE_NAME: '&a{0}' +MODULES_LIST_SEPARATOR: '&f, ' +NAME_ANNOUNCEMENT: '&e&lIlha | &7{0} alterou o nome da ilha para {1}.' +NAME_BLACKLISTED: '&c&lErro | &7Você não pode usar esse nome.' +NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' +NAME_SAME_AS_PLAYER: '&c&lErro | &7Você não pode usar nomes de jogadores como nomes de ilhas.' +NAME_TOO_LONG: '&c&lErro | &7Os nomes de ilhas não podem ter mais de 16 caracteres.' +NAME_TOO_SHORT: '&c&lErro | &7Os nomes de ilhas não podem ter menos de 3 caracteres.' +NO_BAN_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para banir jogadores.' +NO_CLOSE_BYPASS: '&c&lErro | &7Esta ilha não está aberta ao público.' +NO_CLOSE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para fechar a ilha ao público.' +NO_COMMAND_PERMISSION: '&fComando desconhecido. Digite "/help" para obter ajuda.' +NO_COOP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para adicionar jogadores como membros cooperativos.' +NO_DELETE_WARP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para excluir warps.' +NO_DEMOTE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para rebaixar jogadores.' +NO_DEPOSIT_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para depositar dinheiro no banco da ilha.' +NO_DISBAND_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para dissolver sua ilha.' +NO_EXPEL_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para expulsar jogadores de sua ilha.' +NO_INVITE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para convidar jogadores.' +NO_ISLAND_CHEST_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para acessar o baú da ilha.' +NO_ISLAND_INVITE: '&c&lErro | &7Não foi possível encontrar nenhum convite desta ilha.' +NO_ISLANDS_TO_PURGE: '&c&lErro | &7Não havia ilhas para expurgar.' +NO_KICK_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para expulsar jogadores.' +NO_MORE_DISBANDS: '&c&lErro | &7Você não pode dissolver mais nenhuma ilha.' +NO_MORE_WARPS: '&c&lErro | &7Sua ilha não pode ter mais nenhuma teletransportação.' +NO_NAME_PERMISSION: '&c&lErro | &7Você não pode alterar o nome da sua ilha.' +NO_OPEN_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para abrir a ilha ao público.' +NO_PERMISSION_CHECK_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para obter informações sobre permissões.' +NO_PROMOTE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para promover jogadores.' +NO_RANKUP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para aumentar a classificação.' +NO_RATINGS_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para verificar as classificações.' +NO_SET_BIOME_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para alterar o bioma da ilha.' +NO_SET_DISCORD_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para alterar o discord da ilha.' +NO_SET_HOME_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para definir o local de teletransporte da ilha.' +NO_SET_PAYPAL_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para alterar o e-mail do PayPal da ilha.' +NO_SET_ROLE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para definir funções para os jogadores.' +NO_SET_SETTINGS_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para alterar as configurações da ilha.' +NO_SET_WARP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para poder definir teletransportes de ilha.' +NO_TRANSFER_PERMISSION: '&c&lErro | &7Você deve ser o líder da ilha para poder transferir a liderança.' +NO_UNCOOP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para remover jogadores de serem membros cooperativos.' +NO_UPGRADE_PERMISSION: '&c&lErro | &7Você não tem permissão para fazer upgrade para outro nível.' +NO_WITHDRAW_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para sacar dinheiro do banco da ilha.' +NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lErro | &7Você não tem dinheiro suficiente para depositar {0} dólares no banco da sua ilha.' +NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lErro | &7Você não tem dinheiro suficiente.' +NOT_ENOUGH_MONEY_TO_WARP: '&c&lErro | &7Você não tem dinheiro suficiente para usar os teleportes de ilha.' +OPEN_MENU_WHILE_SLEEPING: '&7&oVocê está cansado demais para interagir com os menus, não acha?' +PANEL_TOGGLE_OFF: |- + &e&lPainel | &7Painel da ilha desativado &cOFF&7. + &e&lPainel | &7Executar /is te teleportará para a ilha. +PANEL_TOGGLE_ON: |- + &e&lPainel | &7Painel da ilha ativado &aON&7. + &e&lPainel | &7Executar /is abrirá o painel para você. +PERMISSION_CHANGED: '&e&lIlha | &7Atualizada com sucesso a permissão {0} da ilha de {1}.' +PERMISSION_CHANGED_NAME: '&e&lIlha | &7Atualizada com sucesso a permissão {0} da ilha {1}.' +PERMISSION_CHANGED_ALL: '&e&lIlha | &7Atualizada com sucesso a permissão {0} para todas as ilhas.' +PERSISTENT_DATA_EMPTY: '&c&lErro | &7Nenhum dado foi encontrado para sua consulta.' +PERSISTENT_DATA_MODIFY: '&e&lDados | &7Definidos com sucesso os dados para {0} com {1}: {2}' +PERSISTENT_DATA_SHOW: '&e&lDados | &7Dados de {0}: &f{{1}}' +PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' +PERSISTENT_DATA_SHOW_SPACER: '&f, ' +PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' +PERSISTENT_DATA_REMOVED: '&e&lData | &7Dados removidos com sucesso para {0} do caminho {1}.' +PERMISSIONS_RESET_PLAYER: '&e&lIlha | &7Redefiniu com sucesso todas as permissões para {0} para os valores padrão!' +PERMISSIONS_RESET_ROLES: '&e&lIlha | &7Redefiniu com sucesso todas as permissões da ilha para os valores padrão!' +PLACEHOLDER_NO: 'Não' +PLACEHOLDER_YES: 'Sim' +PLAYER_ALREADY_BANNED: '&c&lErro | &7Este jogador já foi banido.' +PLAYER_ALREADY_COOP: '&c&lErro | &7Este jogador já é cooperativo.' +PLAYER_ALREADY_IN_ISLAND: '&c&lErro | &7Este jogador já está dentro de uma ilha.' +PLAYER_ALREADY_IN_ROLE: '&c&lErro | &7{0} já é um {1}.' +PLAYER_EXPEL_BYPASS: '&c&lErro | &7Este usuário não pode ser expulso da ilha.' +PLAYER_JOIN_ANNOUNCEMENT: '&e&lIlha | &7{0} entrou no servidor.' +PLAYER_NOT_BANNED: '&c&lErro | &7Este jogador não está banido.' +PLAYER_NOT_COOP: '&c&lErro | &7Este jogador não é cooperativo.' +PLAYER_NOT_INSIDE_ISLAND: '&c&lErro | &7Este jogador não está dentro da sua ilha.' +PLAYER_NOT_ONLINE: '&c&lErro | &7Este jogador não está online!' +PLAYER_QUIT_ANNOUNCEMENT: '&e&lIlha | &7{0} saiu do servidor.' +PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lErro | &7Você só pode promover jogadores com uma função de ilha inferior à sua.' +PROMOTED_MEMBER: '&e&lIlha | &7Você promoveu {0} para um {1} na ilha dele.' +PURGE_CLEAR: '&e&lIlha | &7Todas as ilhas na fila para serem expurgadas foram limpas com sucesso.' +PURGED_ISLANDS: |- + &e&lIlha | &7{0} ilhas serão purgadas quando o servidor reiniciar. + &e&lIlha | &7Você pode cancelar a qualquer momento usando /is admin purge cancel. +RANKUP_SUCCESS: '&e&lIlha | &7Atualizado com sucesso o nível da atualização {0} para a ilha de {1}.' +RANKUP_SUCCESS_ALL: '&e&lIlha | &7Atualizado com sucesso o nível da atualização {0} para todas as ilhas.' +RANKUP_SUCCESS_NAME: '&e&lIlha | &7Atualizado com sucesso o nível da atualização {0} para {1}.' +RATE_ANNOUNCEMENT: '&e&lIlha | &7{0} classificou sua ilha {1} de 5!.' +RATE_CHANGE_OTHER: '&e&lIlha | &7Você alterou a classificação de {0} para {1}.' +RATE_OWN_ISLAND: '&c&lErro | &7Você não pode classificar sua própria ilha.' +RATE_REMOVE_ALL: '&e&lIlha | &7Todas as classificações de {0} foram removidas com sucesso.' +RATE_REMOVE_ALL_ISLANDS: '&e&lIlha | &7Todas as classificações de todas as ilhas foram removidas com sucesso.' +RATE_SUCCESS: '&e&lIlha | &7Você classificou esta ilha com {0} estrelas!' +REACHED_BLOCK_LIMIT: '&e&lAtualizações | &7Você atingiu o limite da ilha para o bloco {0}.' +REACHED_ENTITY_LIMIT: '&e&lAtualizações | &7Você atingiu o limite da ilha para a entidade {0}.' +RECALC_ALREADY_RUNNING: '&c&lErro | &7Sua ilha já está sendo recalculada.' +RECALC_ALREADY_RUNNING_OTHER: '&c&lErro | &7Esta ilha já está sendo recalculada.' +RECALC_ALL_ISLANDS: '&e&lIlha | &7Recalculando todas as ilhas...' +RECALC_ALL_ISLANDS_DONE: '&e&lIlha | &7Concluída com sucesso a recalculação de todas as ilhas.' +RECALC_PROCCESS_REQUEST: '&e&lIlha | &7Processando sua solicitação...' +RELOAD_COMPLETED: '&e&lIlha | &7Recarregamento concluído!' +RELOAD_PROCCESS_REQUEST: '&e&lIlha | &7Começando a recarregar as configurações...' +REVOKE_INVITE_ANNOUNCEMENT: '&e&lIlha | &7{0} revogou o convite de {1} para a ilha.' +RESET_WORLD_SUCCEED: '&e&lIlha | &7Redefiniu com sucesso o mundo {0} para a ilha de {1}.' +RESET_WORLD_SUCCEED_ALL: '&e&lIlha | &7Redefinido com sucesso o mundo {0} para todas as ilhas.' +RESET_WORLD_SUCCEED_NAME: '&e&lIlha | &7Redefinido com sucesso o mundo {0} para {1}.' +SAME_NAME_CHANGE: '&c&lErro | &7Você deve digitar um nome diferente do nome atual da sua ilha.' +SCHEMATIC_LEFT_SELECT: '&e&lEsquemas | &7Posição selecionada nº 2 ({0})' +SCHEMATIC_NOT_READY: '&c&lErro | &7Você não selecionou duas posições.' +SCHEMATIC_PROCCESS_REQUEST: '&e&lEsquemas | &7Processando sua solicitação...' +SCHEMATIC_READY_TO_CREATE: | + &e&lschematic | &7Você selecionou duas posições. Execute /is admin schematic para criar um novo esquema. + &e&lschematic | &7Certifique-se de estar no local de teleportação ao executar o comando. +SCHEMATIC_RIGHT_SELECT: '&e&lschematic | &7Posição selecionada nº 1 ({0})' +SCHEMATIC_SAVED: '&e&lschematic | &7Esquema salvo com sucesso!' +SELF_ROLE_CHANGE: '&c&lErro | &7Você não pode alterar sua função.' +SET_UPGRADE_LEVEL: '&e&lAtualizações | &7Atualizou com sucesso o nível de {0} para a ilha de {1}.' +SET_UPGRADE_LEVEL_NAME: '&e&lAtualizações | &7Atualizou com sucesso o nível de {0} para {1}.' +SET_WARP: '&e&lIlha | &7Criou com sucesso um novo warp em {0}.' +SET_WARP_OUTSIDE: '&c&lErro | &7Você não pode definir warps fora da sua ilha.' +SETTINGS_UPDATED: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para a ilha de {1}.' +SETTINGS_UPDATED_NAME: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para a ilha {1}.' +SETTINGS_UPDATED_ALL: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para todas as ilhas.' +SIZE_BIGGER_MAX: '&c&lErro | &7Você não pode definir um tamanho maior que o tamanho máximo da ilha.' +SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Teletransportado com sucesso {0} para spawn.' +SPAWN_SET_SUCCESS: '&e&lSpawn | &7Atualizado com sucesso o local de spawn para {0}.' +SPY_TEAM_CHAT_FORMAT: '&7[Spy] &e[{0}] {1}&f: &7{2}' +SYNC_UPGRADES: '&e&lAtualizações | &7Todos os valores de atualização da ilha de {0} foram sincronizados com sucesso.' +SYNC_UPGRADES_ALL: '&e&lAtualizações | &7Todos os valores de atualização de todas as ilhas foram sincronizados com sucesso.' +SYNC_UPGRADES_NAME: '&e&lAtualizações | &7Todos os valores de atualização de {0} foram sincronizados com sucesso.' +TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' +TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lErro | &7Você não está dentro da sua ilha.' +TELEPORT_OUTSIDE_ISLAND: '&c&lErro | &7Você não pode se teletransportar para fora do seu alcance de proteção.' +TELEPORT_WARMUP: '&7&oVocê será teletransportado em {0}... Não se mova!' +TELEPORT_WARMUP_CANCEL: '&7&oVocê se moveu e então o teletransporte foi cancelado.' +TITLE_SENT: '&e&lIlha | &7Enviado com sucesso {0} o título!' +TELEPORTED_FAILED: '&e&lIlha | &7Parece que esta ilha não tem blocos seguros. Entre em contato com um membro da equipe.' +TELEPORTED_SUCCESS: '&e&lIlha | &7Você foi teletransportado para sua ilha.' +TELEPORTED_TO_WARP: '&e&lIlha | &7Teletransportado com sucesso para esta dobra de ilha.' +TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lIlha | &7O jogador {0} teletransportou-se para a ilha warp {1}.' +TOGGLED_BYPASS_OFF: '&e&lIgnorar | &7Modo de desvio alternado &cOFF&7.' +TOGGLED_BYPASS_ON: '&e&lIgnorar | &7Modo de desvio alternado &aON&7.' +TOGGLED_FLY_OFF: '&e&lVoar | &7Voar ilha alternado &cOFF&7.' +TOGGLED_FLY_ON: '&e&lVoar | &7Voar ilha alternado &aON&7.' +TOGGLED_SCHEMATIC_OFF: '&e&lEsquemas | &7Alternando modo esquemático &cOFF&7.' +TOGGLED_SCHEMATIC_ON: |- + &e&lschematic | &7Modo de esquemas ativado &aON&7. + &e&lschematic | &7Selecione uma área usando um machado dourado. +TOGGLED_SPY_OFF: '&e&lSpy | &7Alternado bate-papo espião &cOFF&7.' +TOGGLED_SPY_ON: '&e&lSpy | &7Alternado bate-papo espião &aON&7.' +TOGGLED_STACKED_BLOCKS_OFF: '&e&lStacker | &7Alternando empilhador de blocos &cOFF&7.' +TOGGLED_STACKED_BLOCKS_ON: '&e&lStacker | &7Alternando empilhador de blocos &aON&7.' +TOGGLED_TEAM_CHAT_OFF: '&e&lChat | &7Alternando bate-papo da equipe &cOFF&7.' +TOGGLED_TEAM_CHAT_ON: '&e&lChat | &7Alternando bate-papo da equipe &aON&7.' +TOGGLED_WORLD_BORDER_OFF: '&e&lBorder | &7Alternando borda do mundo &cOFF&7.' +TOGGLED_WORLD_BORDER_ON: '&e&lBorder | &7Alternando a fronteira mundial &aON&7.' +TRANSFER_ADMIN: '&e&lIlha | &7Você transferiu a liderança de {0} para {1}.' +TRANSFER_ADMIN_ALREADY_LEADER: '&c&lErro | &7{0} já é o líder de sua ilha.' +TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lErro | &7Estes jogadores não estão nas mesmas ilhas.' +TRANSFER_ADMIN_NOT_LEADER: '&c&lErro | &7Este jogador não é líder de nenhuma ilha.' +TRANSFER_ALREADY_LEADER: '&c&lErro | &7Você já é o líder desta ilha.' +TRANSFER_BROADCAST: '&e&lIlha | &7A liderança da ilha foi transferida para {0}.' +UNBAN_ANNOUNCEMENT: '&e&lIlha | &7{0} foi DESBANIDO da ilha por {1}.' +UNCOOP_ANNOUNCEMENT: '&e&lIlha | &7{0} removeu {1} de ser um membro cooperativo.' +UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIlha | &7Não há membros da ilha online e, portanto, você foi descoopado automaticamente.' +UNCOOP_LEFT_ANNOUNCEMENT: '&e&lIlha | &7{0} saiu do jogo e não é mais um membro cooperativo.' +UNIGNORED_ISLAND: A ilha de '&e&lIlha | &7{0}' agora não é mais ignorada das ilhas principais.' +UNIGNORED_ISLAND_NAME: '&e&lIlha | &7A ilha {0} agora não é mais ignorada das ilhas principais.' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lMundos | &7Seu mundo {0} agora está desbloqueado!' +UNSAFE_WARP: '&e&lIlha | &7&oParece que este warp não é seguro. Tente outro warp.' +UPDATED_PERMISSION: '&e&lIlha | &7Permissões atualizadas para {0}.' +UPDATED_SETTINGS: '&e&lIlha | &7Configurações da ilha [{0}] atualizado.' +UPGRADE_COOLDOWN_FORMAT: '&c&lErro | &7Você só pode atualizar novamente em {0}.' +VISITOR_BLOCK_COMMAND: '&c&lErro | &7Você não pode usar esse comando em outras ilhas.' +WARP_ALREADY_EXIST: '&c&lErro | &7Já existe um warp com este nome.' +WARP_CATEGORY_ICON_NEW_LORE: | + &e&lWarps | &7Digite uma nova lore (digite "-cancel" para cancelar): + &e&lWarps | &7Você pode separar linhas usando "\n". +WARP_CATEGORY_ICON_NEW_NAME: '&e&lWarps | &7Digite um nome (digite "-cancel" para cancelar):' +WARP_CATEGORY_ICON_NEW_TYPE: '&e&lWarps | &7Digite um novo tipo de material (digite "-cancel" para cancelar):' +WARP_CATEGORY_ICON_UPDATED: '&e&lWarps | &7O ícone da categoria foi atualizado com sucesso.' +WARP_CATEGORY_ILLEGAL_NAME: '&c&lErro | &7Os nomes das categorias de warp não podem estar vazios.' +WARP_CATEGORY_NAME_TOO_LONG: '&c&lErro | Os nomes de categorias do Warp não podem ter mais de 255 caracteres.' +WARP_CATEGORY_SLOT: '&e&lWarps | &7Digite um novo slot (digite "-cancel" para cancelar):' +WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lErro | &7Este slot já foi ocupado por outra categoria.' +WARP_CATEGORY_SLOT_SUCCESS: '&e&lWarps | &7O slot da categoria foi alterado com sucesso para {0}.' +WARP_CATEGORY_RENAME: '&e&lWarps | &7Digite um novo nome (digite "-cancel" para cancelar):' +WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lErro | &7Este nome já foi ocupado por outra categoria.' +WARP_CATEGORY_RENAME_SUCCESS: '&e&lWarps | &7Categoria renomeada com sucesso para {0}.' +WARP_ICON_NEW_LORE: | + &e&lWarps | &7Digite um novo lore (Digite "-cancel" para cancelar): + &e&lWarps | &7Você pode separar as linhas usando "\n". +WARP_ICON_NEW_NAME: '&e&lWarps | &7Digite um nome (digite "-cancel" para cancelar):' +WARP_ICON_NEW_TYPE: '&e&lWarps | &7Digite um novo tipo de material (digite "-cancel" para cancelar):' +WARP_ICON_UPDATED: '&e&lWarps | &7O ícone do warp foi atualizado com sucesso.' +WARP_ILLEGAL_NAME: '&c&lErro | &7Os nomes do warp não podem estar vazios.' +WARP_LOCATION_UPDATE: '&e&lWarps | &7Atualizou com sucesso a localização do warp para a sua localização.' +WARP_NAME_TOO_LONG: '&c&lErro | Os nomes do warp não podem ter mais de 255 caracteres.' +WARP_PUBLIC_UPDATE: '&e&lWarps | &7Abriu o warp com sucesso para o público.' +WARP_PRIVATE_UPDATE: '&e&lWarps | &7Fechou o warp com sucesso para o público.' +WARP_RENAME: '&e&lWarps | &7Digite um novo nome (digite "-cancel" para cancelar):' +WARP_RENAME_ALREADY_EXIST: '&c&lErro | &7Este nome já foi usado por outro warp.' +WARP_RENAME_SUCCESS: '&e&lWarps | &7Renomeou o warp com sucesso para {0}.' +WITHDRAW_ALL_MONEY: |- + &e&lBanco | &7O banco da ilha tem apenas {0} dólares dentro dele. + &e&lBanco | &7&oRetirando todo o dinheiro..." +WITHDRAW_ANNOUNCEMENT: '&e&lBanco | &7{0} retirou ${1} do banco da ilha!' +WITHDRAW_ERROR: '&c&lErro | &7{0}.' +WITHDRAWN_MONEY: '&e&lBanco | &7Você sacou ${0} do banco da ilha de {1}!' +WITHDRAWN_MONEY_NAME: '&e&lBanco | &7Você sacou ${0} do banco da ilha de {1}!' +WORLD_NOT_ENABLED: '&e&lWorlds | &7Este mundo não está habilitado no servidor.' +WORLD_NOT_UNLOCKED: '&e&lWorlds | &7O mundo {0} ainda não está desbloqueado!' \ No newline at end of file diff --git a/src/main/resources/menus/player-language.yml b/src/main/resources/menus/player-language.yml index 9046865f90..98182f3de5 100644 --- a/src/main/resources/menus/player-language.yml +++ b/src/main/resources/menus/player-language.yml @@ -10,9 +10,8 @@ previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - - '@ @ # @ % @ * @ @' - - '@ + @ ^ @ ~ @ 1 @' - - '@ @ - @ = @ ! @ @' + - '@ # % * + ^ ~ 1 @' + - '@ @ - = @ ! 2 @ @' - '@ @ @ @ @ @ @ @ @' items: @@ -48,6 +47,14 @@ items: name: '&ePolish' lore: - '&7Change language to Polish.' + '2': + language: 'pt-BR' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWE0NjQ3NWQ1ZGNjODE1ZjZjNWYyODU5ZWRiYjEwNjExZjNlODYxYzBlYjE0ZjA4ODE2MWIzYzBjY2IyYjBkOSJ9fX0=' + name: '&eBrazilian Portuguese' + lore: + - '&7Change language to Brazilian Portuguese.' '^': language: 'it-IT' type: SKULL_ITEM diff --git a/src/main/resources/menus/player-language1_13.yml b/src/main/resources/menus/player-language1_13.yml index b7c1bf1aba..fdd15362b9 100644 --- a/src/main/resources/menus/player-language1_13.yml +++ b/src/main/resources/menus/player-language1_13.yml @@ -10,9 +10,8 @@ previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - - '@ @ # @ % @ * @ @' - - '@ + @ ^ @ ~ @ 1 @' - - '@ @ - @ = @ ! @ @' + - '@ # % * + ^ ~ 1 @' + - '@ @ - = @ ! 2 @ @' - '@ @ @ @ @ @ @ @ @' items: @@ -44,6 +43,13 @@ items: name: '&ePolish' lore: - '&7Change language to Polish.' + '2': + language: 'pt-BR' + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWE0NjQ3NWQ1ZGNjODE1ZjZjNWYyODU5ZWRiYjEwNjExZjNlODYxYzBlYjE0ZjA4ODE2MWIzYzBjY2IyYjBkOSJ9fX0=' + name: '&eBrazilian Portuguese' + lore: + - '&7Change language to Brazilian Portuguese.' '^': language: 'it-IT' type: PLAYER_HEAD From 1d45bb3e13bb72d6fa942836c9d4b49a8342a127 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Jan 2025 12:50:57 +0200 Subject: [PATCH 040/600] Fixed errors regarding CustomKey --- .../core/key/collections/CustomKeyMap.java | 165 ++++++++++++++++++ .../core/key/collections/CustomKeySet.java | 124 +++++++++++++ .../key/collections/LazyLoadedKeyMap.java | 65 +++++-- .../key/collections/LazyLoadedKeySet.java | 65 +++++-- 4 files changed, 389 insertions(+), 30 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeyMap.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeySet.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeyMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeyMap.java new file mode 100644 index 0000000000..a192421f9c --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeyMap.java @@ -0,0 +1,165 @@ +package com.bgsoftware.superiorskyblock.core.key.collections; + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.key.BaseKey; +import com.bgsoftware.superiorskyblock.core.key.types.LazyKey; +import com.google.common.base.Preconditions; + +import java.util.AbstractMap; +import java.util.Collections; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; + +public class CustomKeyMap extends AbstractMap implements KeyMap { + + private final LazyReference> innerMap; + + protected CustomKeyMap(KeyMapStrategy strategy) { + this.innerMap = new LazyReference>() { + @Override + protected Map create() { + return strategy.create(false); + } + }; + } + + @Override + public int size() { + return this.innerMap.getIfPresent().map(Map::size).orElse(0); + } + + @Override + public boolean containsKey(Object key) { + return this.get(key) != null; + } + + @Override + public V get(Object obj) { + if (size() == 0) + return null; + + if (obj instanceof LazyKey) { + return get(((LazyKey) obj).getBaseKey()); + } + + return getInternal((Key) obj, true); + } + + private V getInternal(Key key, boolean tryGlobal) { + Preconditions.checkArgument(!(key instanceof LazyKey), "Cannot call getInternal on LazyKey directly."); + + V value = this.innerMap.getIfPresent().map(m -> m.get(key)).orElse(null); + + if (!tryGlobal || value != null) + return value; + + Key globalKey = ((BaseKey) key).toGlobalKey(); + + return globalKey == key ? null : getInternal(globalKey, false); + } + + @Override + public V put(Key key, V value) { + if (key instanceof LazyKey) { + return put(((LazyKey) key).getBaseKey(), value); + } + + return this.innerMap.get().put(key, value); + } + + @Override + public V remove(Object key) { + return size() == 0 ? null : removeNoSizeCheck(key); + } + + private V removeNoSizeCheck(Object key) { + if (key instanceof LazyKey) { + return removeNoSizeCheck(((LazyKey) key).getBaseKey()); + } + + return this.innerMap.getIfPresent().map(m -> m.remove(key)).orElse(null); + } + + @Override + public void clear() { + this.innerMap.getIfPresent().ifPresent(Map::clear); + } + + @NotNull + @Override + public Set> entrySet() { + return this.innerMap.getIfPresent().map(Map::entrySet).orElse(Collections.emptySet()); + } + + @Nullable + @Override + public Key getKey(Key original) { + return this.getKey(original, null); + } + + @Override + public Key getKey(Key original, @Nullable Key def) { + if (size() == 0) + return def; + + if (original instanceof LazyKey) { + return getKey(((LazyKey) original).getBaseKey()); + } + + Map map = this.innerMap.getIfPresent().orElse(null); + + if (map != null) { + if (map.containsKey(original)) + return original; + Key globalKey = ((BaseKey) original).toGlobalKey(); + if (globalKey != original && map.containsKey(globalKey)) + return globalKey; + } + + return def; + } + + @Override + public boolean removeIf(Predicate predicate) { + if (isEmpty()) + return false; + + return this.innerMap.getIfPresent().map(m -> + m.entrySet().removeIf(entry -> predicate.test(entry.getKey()))) + .orElse(false); + } + + @Override + public V getRaw(Key key, V def) { + if (size() == 0) + return def; + + return getRawNoSizeCheck(key, def); + } + + private V getRawNoSizeCheck(Key key, V def) { + if (key instanceof LazyKey) { + return getRawNoSizeCheck(((LazyKey) key).getBaseKey(), def); + } + + return Optional.ofNullable(getInternal(key, false)).orElse(def); + } + + @Override + public V getOrDefault(Object key, V defaultValue) { + V value = get(key); + return value == null ? defaultValue : value; + } + + @Override + public Map asMap() { + return this; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeySet.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeySet.java new file mode 100644 index 0000000000..0b19fca51e --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeySet.java @@ -0,0 +1,124 @@ +package com.bgsoftware.superiorskyblock.core.key.collections; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.key.BaseKey; +import com.bgsoftware.superiorskyblock.core.key.types.LazyKey; +import com.google.common.base.Preconditions; +import com.google.common.collect.Iterators; + +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Set; + +public class CustomKeySet extends AbstractSet implements KeySet { + + private final LazyReference> innerSet; + + public CustomKeySet(KeySetStrategy strategy) { + this.innerSet = new LazyReference>() { + @Override + protected Set create() { + return strategy.create(true); + } + }; + } + + @Override + public int size() { + return this.innerSet.getIfPresent().map(Set::size).orElse(0); + } + + @Override + public boolean contains(Object o) { + if (size() == 0) + return false; + + if (o instanceof LazyKey) { + return contains(((LazyKey) o).getBaseKey()); + } + + return containsInternal((Key) o, true); + } + + private boolean containsInternal(Key key, boolean tryGlobal) { + Preconditions.checkArgument(!(key instanceof LazyKey), "Cannot call getInternal on LazyKey directly."); + + boolean contained = this.innerSet.getIfPresent().map(s -> s.contains(key)).orElse(false); + + if (!tryGlobal || contained) + return contained; + + Key globalKey = ((BaseKey) key).toGlobalKey(); + + return globalKey != key && containsInternal(globalKey, false); + } + + @Override + public boolean add(Key key) { + if (key instanceof LazyKey) { + return add(((LazyKey) key).getBaseKey()); + } + + return this.innerSet.get().add(key); + } + + @Override + public boolean remove(Object key) { + return size() != 0 && removeNoSizeCheck(key); + } + + private boolean removeNoSizeCheck(Object key) { + if (key instanceof LazyKey) { + return remove(((LazyKey) key).getBaseKey()); + } + + return this.innerSet.getIfPresent().map(s -> s.remove(key)).orElse(false); + } + + @Override + public void clear() { + this.innerSet.getIfPresent().ifPresent(Set::clear); + } + + @Override + public Iterator iterator() { + return this.innerSet.getIfPresent().map(Set::iterator).orElse(Iterators.emptyIterator()); + } + + @Nullable + @Override + public Key getKey(Key original) { + return this.getKey(original, null); + } + + @Override + public Key getKey(Key original, @Nullable Key def) { + if (size() == 0) + return def; + + if (original instanceof LazyKey) { + return getKey(((LazyKey) original).getBaseKey()); + } + + Set set = this.innerSet.getIfPresent().orElse(null); + + if (set != null) { + if (set.contains(original)) + return original; + Key globalKey = ((BaseKey) original).toGlobalKey(); + if (globalKey != original && set.contains(globalKey)) + return globalKey; + } + + return def; + } + + @Override + public Set asSet() { + return this; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeyMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeyMap.java index 68f83023f3..d6523ef2db 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeyMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeyMap.java @@ -12,6 +12,8 @@ import java.util.Collections; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Predicate; public class LazyLoadedKeyMap extends AbstractMap implements KeyMap { @@ -19,6 +21,8 @@ public class LazyLoadedKeyMap extends AbstractMap implements KeyMap delegate; + @Nullable + private KeyMap pendingCustomKeys; public LazyLoadedKeyMap(KeyMapStrategy strategy) { this.strategy = strategy; @@ -26,17 +30,17 @@ public LazyLoadedKeyMap(KeyMapStrategy strategy) { @Override public int size() { - return this.delegate == null ? 0 : this.delegate.size(); + return runOnMap(KeyMap::size, 0); } @Override public boolean containsKey(Object o) { - return this.delegate != null && this.delegate.containsKey(o); + return runOnMap(m -> m.containsKey(o), false); } @Override public V get(Object obj) { - return this.delegate == null ? null : this.delegate.get(obj); + return runOnMap(m -> m.get(obj), null); } @Override @@ -54,10 +58,15 @@ private V putNoDelegate(Key key, V value) { if (key instanceof EntityTypeKey) { this.delegate = new EntityTypeKeyMap<>(this.strategy); + addPendingCustomKeys(); } else if (key instanceof MaterialKey) { this.delegate = new MaterialKeyMap<>(this.strategy); + addPendingCustomKeys(); } else { - throw new IllegalArgumentException("Cannot insert key of type " + key.getClass()); + if (this.pendingCustomKeys == null) + this.pendingCustomKeys = new CustomKeyMap<>(this.strategy); + + return this.pendingCustomKeys.put(key, value); } return this.delegate.put(key, value); @@ -65,56 +74,82 @@ private V putNoDelegate(Key key, V value) { @Override public V remove(Object key) { - return this.delegate == null ? null : this.delegate.remove(key); + return runOnMap(m -> m.remove(key), null); } @Override public void clear() { - if (this.delegate != null) - this.delegate.clear(); + runOnMap(KeyMap::clear); } @NotNull @Override public Set> entrySet() { - return this.delegate == null ? Collections.emptySet() : this.delegate.entrySet(); + return runOnMap(KeyMap::entrySet, Collections.emptySet()); } @Override public String toString() { - return this.delegate == null ? "LazyLoadedKeyMap{}" : this.delegate.toString(); + return runOnMap(KeyMap::toString, "LazyLoadedKeyMap{}"); } @Nullable @Override public Key getKey(Key original) { - return this.delegate == null ? null : this.delegate.getKey(original); + return runOnMap(m -> m.getKey(original), null); } @Override public Key getKey(Key original, @Nullable Key def) { - return this.delegate == null ? def : this.delegate.getKey(original, def); + return runOnMap(m -> m.getKey(original, def), def); } @Override public boolean removeIf(Predicate predicate) { - return this.delegate != null && this.delegate.removeIf(predicate); + return runOnMap(m -> m.removeIf(predicate), false); } @Override public V getRaw(Key key, V def) { - return this.delegate == null ? def : this.delegate.getRaw(key, def); + return runOnMap(m -> m.getRaw(key, def), def); } @Override public V getOrDefault(Object key, V defaultValue) { - return this.delegate == null ? defaultValue : this.delegate.getOrDefault(key, defaultValue); + return runOnMap(m -> m.getOrDefault(key, defaultValue), defaultValue); } @Override public Map asMap() { - return this.delegate == null ? this : this.delegate.asMap(); + return runOnMap(KeyMap::asMap, this); + } + + private T runOnMap(Function, T> function, T def) { + if (this.delegate != null) + return function.apply(this.delegate); + + else if (this.pendingCustomKeys != null) + return function.apply(this.pendingCustomKeys); + + else + return def; + } + + private void runOnMap(Consumer> consumer) { + if (this.delegate != null) + consumer.accept(this.delegate); + + else if (this.pendingCustomKeys != null) + consumer.accept(this.pendingCustomKeys); + } + + private void addPendingCustomKeys() { + if (this.pendingCustomKeys == null) + return; + + this.delegate.putAll(this.pendingCustomKeys); + this.pendingCustomKeys = null; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeySet.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeySet.java index 5e213cf4b7..19f25f88e0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeySet.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeySet.java @@ -11,30 +11,29 @@ import java.util.AbstractSet; import java.util.Iterator; import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; public class LazyLoadedKeySet extends AbstractSet implements KeySet { private final KeySetStrategy strategy; @Nullable private KeySet delegate; + @Nullable + private KeySet pendingCustomKeys; public LazyLoadedKeySet(KeySetStrategy strategy) { this.strategy = strategy; } - @Override - public Iterator iterator() { - return this.delegate == null ? Iterators.emptyIterator() : this.delegate.iterator(); - } - @Override public int size() { - return this.delegate == null ? 0 : this.delegate.size(); + return runOnSet(KeySet::size, 0); } @Override public boolean contains(Object o) { - return this.delegate != null && this.delegate.contains(o); + return runOnSet(s -> s.contains(o), false); } @Override @@ -52,10 +51,15 @@ public boolean addNoDelegate(Key key) { if (key instanceof EntityTypeKey) { this.delegate = new EntityTypeKeySet(this.strategy); + addPendingCustomKeys(); } else if (key instanceof MaterialKey) { this.delegate = new MaterialKeySet(this.strategy); + addPendingCustomKeys(); } else { - throw new IllegalArgumentException("Cannot insert key of type " + key.getClass()); + if (this.pendingCustomKeys == null) + this.pendingCustomKeys = new CustomKeySet(this.strategy); + + return this.pendingCustomKeys.add(key); } return this.delegate.add(key); @@ -63,34 +67,65 @@ public boolean addNoDelegate(Key key) { @Override public boolean remove(Object key) { - return this.delegate != null && this.delegate.remove(key); + return runOnSet(s -> s.remove(key), false); } @Override public void clear() { - if (this.delegate != null) - this.delegate.clear(); + runOnSet(Set::clear); + } + + @Override + public Iterator iterator() { + return runOnSet(Set::iterator, Iterators.emptyIterator()); } @Nullable @Override public Key getKey(Key original) { - return this.delegate == null ? null : this.delegate.getKey(original); + return runOnSet(s -> s.getKey(original), null); } @Override public Key getKey(Key original, Key def) { - return this.delegate == null ? def : this.delegate.getKey(original, def); + return runOnSet(s -> s.getKey(original, def), def); } @Override public String toString() { - return this.delegate == null ? "LazyLoadedKeySet[]" : this.delegate.toString(); + return runOnSet(Object::toString, "LazyLoadedKeySet[]"); } @Override public Set asSet() { - return this.delegate == null ? this : this.delegate.asSet(); + return runOnSet(KeySet::asSet, this); + } + + private T runOnSet(Function function, T def) { + if (this.delegate != null) + return function.apply(this.delegate); + + else if (this.pendingCustomKeys != null) + return function.apply(this.pendingCustomKeys); + + else + return def; + } + + private void runOnSet(Consumer consumer) { + if (this.delegate != null) + consumer.accept(this.delegate); + + else if (this.pendingCustomKeys != null) + consumer.accept(this.pendingCustomKeys); + } + + private void addPendingCustomKeys() { + if (this.pendingCustomKeys == null) + return; + + this.delegate.addAll(this.pendingCustomKeys); + this.pendingCustomKeys = null; } } From 3712856d40a556d972ee291a122f0addb51cbffd Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Jan 2025 13:03:47 +0200 Subject: [PATCH 041/600] Clean code --- .../superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_17/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_18/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_19/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_20_3/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_20_4/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_21/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_21_3/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_21_4/NMSChunksImpl.java | 2 +- .../superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java | 2 +- .../superiorskyblock/config/SettingsContainer.java | 4 ++-- .../v0/deserializer/EmptyParameterGuardDeserializer.java | 2 +- .../sql/upgrade/v0/deserializer/JsonDeserializer.java | 2 +- .../sql/upgrade/v0/deserializer/RawDeserializer.java | 2 +- .../superiorskyblock/core/key/KeysManagerImpl.java | 6 ++++-- .../core/key/{collections => map}/AbstractKeyMap.java | 2 +- .../core/key/{collections => map}/CustomKeyMap.java | 2 +- .../core/key/{collections => map}/EntityTypeKeyMap.java | 2 +- .../core/key/{collections => map}/KeyMapStrategy.java | 2 +- .../superiorskyblock/core/key/{ => map}/KeyMaps.java | 7 ++----- .../core/key/{collections => map}/LazyLoadedKeyMap.java | 2 +- .../core/key/{collections => map}/MaterialKeyMap.java | 2 +- .../core/key/{collections => set}/AbstractKeySet.java | 2 +- .../core/key/{collections => set}/CustomKeySet.java | 2 +- .../core/key/{collections => set}/EntityTypeKeySet.java | 2 +- .../core/key/{collections => set}/KeySetStrategy.java | 2 +- .../superiorskyblock/core/key/{ => set}/KeySets.java | 8 +++----- .../core/key/{collections => set}/LazyLoadedKeySet.java | 2 +- .../core/key/{collections => set}/MaterialKeySet.java | 2 +- .../superiorskyblock/core/key/types/SpawnerKey.java | 2 +- .../superiorskyblock/core/menu/impl/MenuIslandValues.java | 2 +- .../core/values/BlockValuesManagerImpl.java | 4 ++-- .../core/values/container/BlockValuesContainer.java | 2 +- .../com/bgsoftware/superiorskyblock/island/SIsland.java | 2 +- .../bgsoftware/superiorskyblock/island/SpawnIsland.java | 2 +- .../algorithm/DefaultIslandBlocksTrackerAlgorithm.java | 2 +- .../algorithm/DefaultIslandCalculationAlgorithm.java | 2 +- .../algorithm/DefaultIslandEntitiesTrackerAlgorithm.java | 2 +- .../island/builder/IslandBuilderImpl.java | 2 +- .../superiorskyblock/island/upgrade/SUpgrade.java | 2 +- .../superiorskyblock/listener/BlockChangesListener.java | 2 +- .../superiorskyblock/module/upgrades/UpgradesModule.java | 2 +- .../service/region/RegionManagerServiceImpl.java | 2 +- .../StackedBlocksInteractionServiceImpl.java | 2 +- .../superiorskyblock/world/schematic/BaseSchematic.java | 2 +- 46 files changed, 54 insertions(+), 57 deletions(-) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{collections => map}/AbstractKeyMap.java (99%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{collections => map}/CustomKeyMap.java (98%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{collections => map}/EntityTypeKeyMap.java (85%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{collections => map}/KeyMapStrategy.java (95%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{ => map}/KeyMaps.java (95%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{collections => map}/LazyLoadedKeyMap.java (98%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{collections => map}/MaterialKeyMap.java (85%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{collections => set}/AbstractKeySet.java (99%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{collections => set}/CustomKeySet.java (98%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{collections => set}/EntityTypeKeySet.java (85%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{collections => set}/KeySetStrategy.java (92%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{ => set}/KeySets.java (95%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{collections => set}/LazyLoadedKeySet.java (98%) rename src/main/java/com/bgsoftware/superiorskyblock/core/key/{collections => set}/MaterialKeySet.java (84%) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java index b9a6e9454e..01c4845b2f 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java @@ -10,7 +10,7 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java index 48b1ac1766..52a7a5b7aa 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java index f3e60f1371..6b84f980fc 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java @@ -13,7 +13,7 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java index fc5b0b52ce..14d0acb848 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java @@ -10,7 +10,7 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java index 7152b2185e..928d34b1f9 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java index 7246593bc8..db2ac8ddaa 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java @@ -12,7 +12,7 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java index 948ad6d3cb..942e6d259a 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java index 8aa75c753e..b8694e5c2e 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java index c954235eeb..419b8164b1 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java index a2fa388f80..4b358d4ae6 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java index a4c86044e8..b61d42f7f2 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java @@ -10,7 +10,7 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 319f769913..516685bcbe 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -23,8 +23,8 @@ import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.io.Resources; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; -import com.bgsoftware.superiorskyblock.core.key.KeySets; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/EmptyParameterGuardDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/EmptyParameterGuardDeserializer.java index 1b010bd020..85028a8931 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/EmptyParameterGuardDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/EmptyParameterGuardDeserializer.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.IslandWarpAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import org.bukkit.World; import org.bukkit.potion.PotionEffectType; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/JsonDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/JsonDeserializer.java index 3acdd843f0..648a696d24 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/JsonDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/JsonDeserializer.java @@ -14,7 +14,7 @@ import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.PlayerAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.WarpCategoryAttributes; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/RawDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/RawDeserializer.java index cbe93b025c..a124d6c24f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/RawDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/deserializer/RawDeserializer.java @@ -18,7 +18,7 @@ import com.bgsoftware.superiorskyblock.core.database.serialization.IslandsSerializer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/KeysManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/KeysManagerImpl.java index 65cf9c2659..7ffd2fbd82 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/KeysManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/KeysManagerImpl.java @@ -6,8 +6,10 @@ import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.core.Manager; -import com.bgsoftware.superiorskyblock.core.key.collections.KeyMapStrategy; -import com.bgsoftware.superiorskyblock.core.key.collections.KeySetStrategy; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMapStrategy; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.set.KeySetStrategy; +import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import com.google.common.base.Preconditions; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/AbstractKeyMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java similarity index 99% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/AbstractKeyMap.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java index 6cd136f238..cb21560c28 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/AbstractKeyMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.core.key.collections; +package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeyMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/CustomKeyMap.java similarity index 98% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeyMap.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/map/CustomKeyMap.java index a192421f9c..38bff28c96 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeyMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/CustomKeyMap.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.core.key.collections; +package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/EntityTypeKeyMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/EntityTypeKeyMap.java similarity index 85% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/EntityTypeKeyMap.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/map/EntityTypeKeyMap.java index 856915a158..364d171142 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/EntityTypeKeyMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/EntityTypeKeyMap.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.core.key.collections; +package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/KeyMapStrategy.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/KeyMapStrategy.java similarity index 95% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/KeyMapStrategy.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/map/KeyMapStrategy.java index 4fcf0925f1..9eb8651d24 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/KeyMapStrategy.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/KeyMapStrategy.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.core.key.collections; +package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/KeyMaps.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/KeyMaps.java similarity index 95% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/KeyMaps.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/map/KeyMaps.java index 0f834465c5..7348cd0cd9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/KeyMaps.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/KeyMaps.java @@ -1,13 +1,10 @@ -package com.bgsoftware.superiorskyblock.core.key; +package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; -import com.bgsoftware.superiorskyblock.core.key.collections.EntityTypeKeyMap; -import com.bgsoftware.superiorskyblock.core.key.collections.KeyMapStrategy; -import com.bgsoftware.superiorskyblock.core.key.collections.LazyLoadedKeyMap; -import com.bgsoftware.superiorskyblock.core.key.collections.MaterialKeyMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import java.util.Collection; import java.util.Collections; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeyMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/LazyLoadedKeyMap.java similarity index 98% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeyMap.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/map/LazyLoadedKeyMap.java index d6523ef2db..8257f98754 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeyMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/LazyLoadedKeyMap.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.core.key.collections; +package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/MaterialKeyMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/MaterialKeyMap.java similarity index 85% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/MaterialKeyMap.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/map/MaterialKeyMap.java index b050df3ef3..a800dc65ac 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/MaterialKeyMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/MaterialKeyMap.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.core.key.collections; +package com.bgsoftware.superiorskyblock.core.key.map; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/AbstractKeySet.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/AbstractKeySet.java similarity index 99% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/AbstractKeySet.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/set/AbstractKeySet.java index ef7346dbea..5f9e2cfc2a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/AbstractKeySet.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/AbstractKeySet.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.core.key.collections; +package com.bgsoftware.superiorskyblock.core.key.set; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeySet.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/CustomKeySet.java similarity index 98% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeySet.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/set/CustomKeySet.java index 0b19fca51e..ced23640cd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/CustomKeySet.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/CustomKeySet.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.core.key.collections; +package com.bgsoftware.superiorskyblock.core.key.set; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/EntityTypeKeySet.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/EntityTypeKeySet.java similarity index 85% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/EntityTypeKeySet.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/set/EntityTypeKeySet.java index e7aaac7aca..f0996ac8a8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/EntityTypeKeySet.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/EntityTypeKeySet.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.core.key.collections; +package com.bgsoftware.superiorskyblock.core.key.set; import com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/KeySetStrategy.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySetStrategy.java similarity index 92% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/KeySetStrategy.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySetStrategy.java index edeedd50e1..4867675850 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/KeySetStrategy.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySetStrategy.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.core.key.collections; +package com.bgsoftware.superiorskyblock.core.key.set; import java.util.HashSet; import java.util.Map; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/KeySets.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySets.java similarity index 95% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/KeySets.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySets.java index d9a7442bc8..97b58147a4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/KeySets.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySets.java @@ -1,13 +1,11 @@ -package com.bgsoftware.superiorskyblock.core.key; +package com.bgsoftware.superiorskyblock.core.key.set; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; -import com.bgsoftware.superiorskyblock.core.key.collections.EntityTypeKeySet; -import com.bgsoftware.superiorskyblock.core.key.collections.KeySetStrategy; -import com.bgsoftware.superiorskyblock.core.key.collections.LazyLoadedKeySet; -import com.bgsoftware.superiorskyblock.core.key.collections.MaterialKeySet; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.Keys; import com.google.common.collect.Iterators; import java.util.Collection; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeySet.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/LazyLoadedKeySet.java similarity index 98% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeySet.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/set/LazyLoadedKeySet.java index 19f25f88e0..9be9a8778c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/LazyLoadedKeySet.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/LazyLoadedKeySet.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.core.key.collections; +package com.bgsoftware.superiorskyblock.core.key.set; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/MaterialKeySet.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/MaterialKeySet.java similarity index 84% rename from src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/MaterialKeySet.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/key/set/MaterialKeySet.java index b48517586c..75b2b896b5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/collections/MaterialKeySet.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/MaterialKeySet.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.core.key.collections; +package com.bgsoftware.superiorskyblock.core.key.set; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/SpawnerKey.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/SpawnerKey.java index e2293c6d7f..8be612030c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/SpawnerKey.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/SpawnerKey.java @@ -5,7 +5,7 @@ import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.MaterialKeySource; import com.google.common.base.Objects; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandValues.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandValues.java index 06df3d9ef2..7e5cb1af32 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandValues.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandValues.java @@ -14,7 +14,7 @@ import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemSkulls; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeySets; +import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/values/BlockValuesManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/values/BlockValuesManagerImpl.java index 0dd86b4af9..0310f08905 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/values/BlockValuesManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/values/BlockValuesManagerImpl.java @@ -11,8 +11,8 @@ import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; -import com.bgsoftware.superiorskyblock.core.key.KeySets; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/values/container/BlockValuesContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/values/container/BlockValuesContainer.java index b48eae4798..11bfe2ffb6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/values/container/BlockValuesContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/values/container/BlockValuesContainer.java @@ -3,7 +3,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.values.BlockValue; import javax.annotation.Nullable; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index a14d15f541..378e832338 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -55,7 +55,7 @@ import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import com.bgsoftware.superiorskyblock.core.logging.Debug; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 3dfa4dd8d2..aab4f4390a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -42,7 +42,7 @@ import com.bgsoftware.superiorskyblock.core.database.bridge.EmptyDatabaseBridge; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.persistence.EmptyPersistentDataContainer; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java index 69cfb2a342..045c8c7a5c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java @@ -8,7 +8,7 @@ import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.MaterialKeySource; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import com.bgsoftware.superiorskyblock.core.logging.Debug; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java index 19cc038b5a..0932be9099 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java @@ -14,7 +14,7 @@ import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.SpawnerKey; import com.bgsoftware.superiorskyblock.core.logging.Debug; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java index fa6dc3f2cf..84859793a8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java @@ -10,7 +10,7 @@ import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java index e271101c94..a2657beebe 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java @@ -23,7 +23,7 @@ import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.value.DoubleValue; import com.bgsoftware.superiorskyblock.core.value.IntValue; import com.bgsoftware.superiorskyblock.core.value.Value; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java index fcc6a9aad1..abddd131fc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java @@ -4,7 +4,7 @@ import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.core.collections.view.EmptyInt2IntMapView; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.value.DoubleValue; import com.bgsoftware.superiorskyblock.core.value.IntValue; import com.bgsoftware.superiorskyblock.core.value.Value; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index 7188006829..1a3cf53997 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -16,7 +16,7 @@ import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java index a51ad7f9bb..71b65970fb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java @@ -16,7 +16,7 @@ import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.value.DoubleValue; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index eb725eb28c..9b118a821d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -22,7 +22,7 @@ import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeySets; +import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java index 4eeb21efb5..c7effd5df3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java @@ -19,7 +19,7 @@ import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.service.IService; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java index 53c4ecef35..9c93c9c72a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java @@ -7,7 +7,7 @@ import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import java.util.Collections; import java.util.List; From b875a0ab9026c65972212bd81bf8a945f356d601 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Jan 2025 13:14:30 +0200 Subject: [PATCH 042/600] Fixed errors regarding IllegalAccessError --- .../superiorskyblock/core/key/set/CustomKeySet.java | 4 ++-- .../com/bgsoftware/superiorskyblock/core/key/set/KeySets.java | 4 ++-- .../superiorskyblock/core/key/set/LazyLoadedKeySet.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/CustomKeySet.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/CustomKeySet.java index ced23640cd..bb89fc61a8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/CustomKeySet.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/CustomKeySet.java @@ -7,9 +7,9 @@ import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.types.LazyKey; import com.google.common.base.Preconditions; -import com.google.common.collect.Iterators; import java.util.AbstractSet; +import java.util.Collections; import java.util.Iterator; import java.util.Set; @@ -85,7 +85,7 @@ public void clear() { @Override public Iterator iterator() { - return this.innerSet.getIfPresent().map(Set::iterator).orElse(Iterators.emptyIterator()); + return this.innerSet.getIfPresent().map(Set::iterator).orElse(Collections.emptyIterator()); } @Nullable diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySets.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySets.java index 97b58147a4..5579f81642 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySets.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/KeySets.java @@ -6,9 +6,9 @@ import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.google.common.collect.Iterators; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.Set; import java.util.Spliterator; @@ -110,7 +110,7 @@ public boolean containsAll(@NotNull Collection c) { @NotNull @Override public Iterator iterator() { - return Iterators.emptyIterator(); + return Collections.emptyIterator(); } @NotNull diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/LazyLoadedKeySet.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/LazyLoadedKeySet.java index 9be9a8778c..46edcbc2a0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/LazyLoadedKeySet.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/set/LazyLoadedKeySet.java @@ -6,9 +6,9 @@ import com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey; import com.bgsoftware.superiorskyblock.core.key.types.LazyKey; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; -import com.google.common.collect.Iterators; import java.util.AbstractSet; +import java.util.Collections; import java.util.Iterator; import java.util.Set; import java.util.function.Consumer; @@ -77,7 +77,7 @@ public void clear() { @Override public Iterator iterator() { - return runOnSet(Set::iterator, Iterators.emptyIterator()); + return runOnSet(Set::iterator, Collections.emptyIterator()); } @Nullable From 6b367baf7d138fc89f4c243023fc06b5a2c91f88 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Jan 2025 13:18:28 +0200 Subject: [PATCH 043/600] Add debug message to when id is missing in block tile entity data (#2326) --- .../superiorskyblock/core/schematic/SchematicBlock.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java index b938fdbecc..4a079a0e42 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ServerVersion; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import org.bukkit.Location; @@ -72,6 +73,11 @@ public void doPrePlace(Island island) { this.tileEntityData = new CompoundTag(originalTileEntity); String id = this.tileEntityData.getString("id"); + if (id == null) { + Log.warn("Weird tile-entity data detected: " + this.tileEntityData.getValue()); + throw new RuntimeException("Detected tile-entity data with no 'id' key."); + } + if (id.equalsIgnoreCase(ServerVersion.isLegacy() ? "Sign" : "minecraft:sign")) { boolean needSignFormat = false; for (int i = 1; i <= 4; i++) { From e0f9270fbc5750f37f7c85898cff041d633534bd Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Jan 2025 13:53:38 +0200 Subject: [PATCH 044/600] Fixed complex messages losing colors and other stuff --- .../component/impl/ComplexMessageComponent.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java index 9873bc07cd..9a4c162290 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.command.CommandSender; @@ -58,7 +59,7 @@ private static IWrappedComponent[] parseComponents(BaseComponent[] baseComponent private static MessageContent findTextComponentContent(BaseComponent[] baseComponents) { for (BaseComponent baseComponent : baseComponents) { if (baseComponent instanceof TextComponent) - return MessageContent.parse(((TextComponent) baseComponent).getText()); + return MessageContent.parse(baseComponent.toLegacyText()); } return MessageContent.EMPTY; @@ -117,18 +118,23 @@ private static class ContentComponent implements IWrappedComponent { private final MessageContent content; @Nullable private final HoverEventContents hoverEventContents; + @Nullable + private final ClickEvent clickEvent; ContentComponent(TextComponent textComponent) { - this.content = MessageContent.parse(textComponent.getText()); + this.content = MessageContent.parse(textComponent.toLegacyText()); this.hoverEventContents = textComponent.getHoverEvent() == null ? null : new HoverEventContents(textComponent.getHoverEvent()); + this.clickEvent = textComponent.getClickEvent(); } @Override public BaseComponent parse(Object... args) { - TextComponent textComponent = new TextComponent(this.content.getContent(args).orElse("")); + TextComponent textComponent = (TextComponent) TextComponent.fromLegacyText(this.content.getContent(args).orElse(""))[0]; if (this.hoverEventContents != null) textComponent.setHoverEvent(this.hoverEventContents.parse(args)); + if (this.clickEvent != null) + textComponent.setClickEvent(this.clickEvent); return textComponent; } From 9db63dca9b57ef2e3d0fb9f0a2f1e1d1d1c2a998 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Jan 2025 15:15:13 +0200 Subject: [PATCH 045/600] Removed debug log --- .../superiorskyblock/external/AdvancedSlimePaperHook.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Hooks/AdvancedSlimePaper/src/main/java/com/bgsoftware/superiorskyblock/external/AdvancedSlimePaperHook.java b/Hooks/AdvancedSlimePaper/src/main/java/com/bgsoftware/superiorskyblock/external/AdvancedSlimePaperHook.java index 19e1c504fc..9ea3d3a663 100644 --- a/Hooks/AdvancedSlimePaper/src/main/java/com/bgsoftware/superiorskyblock/external/AdvancedSlimePaperHook.java +++ b/Hooks/AdvancedSlimePaper/src/main/java/com/bgsoftware/superiorskyblock/external/AdvancedSlimePaperHook.java @@ -31,7 +31,6 @@ public static boolean isCompatible() { } public static void register(SuperiorSkyblockPlugin plugin) { - Bukkit.getLogger().info("AdvancedSlimePaperHook::register"); slimeWorldPlugin = Bukkit.getPluginManager().getPlugin("SlimeWorldManager"); plugin.getProviders().registerWorldsListener(AdvancedSlimePaperHook::loadWorld); } From 6ea9785e8be001613387b65b19f80beed21c377f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Jan 2025 19:23:56 +0200 Subject: [PATCH 046/600] Adds support to Nexo --- Hooks/Nexo/build.gradle | 24 +++ .../superiorskyblock/external/NexoHook.java | 174 ++++++++++++++++++ settings.gradle | 1 + 3 files changed, 199 insertions(+) create mode 100644 Hooks/Nexo/build.gradle create mode 100644 Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java diff --git a/Hooks/Nexo/build.gradle b/Hooks/Nexo/build.gradle new file mode 100644 index 0000000000..dd3e4db83d --- /dev/null +++ b/Hooks/Nexo/build.gradle @@ -0,0 +1,24 @@ +group 'Hooks:Nexo' + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } +} + +repositories { + mavenCentral() + maven { url 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' } +} + +dependencies { + compileOnly "com.nexomc:Nexo:0.9" + compileOnly "org.spigotmc:spigot-api:1.21.1-R0.1-SNAPSHOT" + compileOnly project(":API") + compileOnly rootProject +} + +if (project.hasProperty('hook.compile_nexo') && + !Boolean.valueOf(project.findProperty("hook.compile_nexo").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java b/Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java new file mode 100644 index 0000000000..e215f56e72 --- /dev/null +++ b/Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java @@ -0,0 +1,174 @@ +package com.bgsoftware.superiorskyblock.external; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; +import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; +import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; +import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.nexomc.nexo.api.NexoBlocks; +import com.nexomc.nexo.api.NexoItems; +import com.nexomc.nexo.api.events.furniture.NexoFurnitureBreakEvent; +import com.nexomc.nexo.api.events.furniture.NexoFurniturePlaceEvent; +import com.nexomc.nexo.items.ItemBuilder; +import com.nexomc.nexo.mechanics.Mechanic; +import com.nexomc.nexo.mechanics.MechanicFactory; +import com.nexomc.nexo.mechanics.MechanicsManager; +import com.nexomc.nexo.mechanics.custom_block.noteblock.NoteBlockMechanicFactory; +import com.nexomc.nexo.mechanics.custom_block.stringblock.StringBlockMechanicFactory; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; + +public class NexoHook { + + private static final String NEXO_PREFIX = "NEXO"; + private static final Key BLOCK_ITEM_KEY = Keys.of(Material.PAPER); + private static final Key BLOCK_KEY = Keys.of(Material.NOTE_BLOCK); + + private static final List AVAILABLE_MECHANICS = new LinkedList<>(); + + private static final LazyReference worldRecordService = new LazyReference<>() { + @Override + protected WorldRecordService create() { + return plugin.getServices().getService(WorldRecordService.class); + } + }; + + private static SuperiorSkyblockPlugin plugin; + + public static void register(SuperiorSkyblockPlugin plugin) { + NexoHook.plugin = plugin; + plugin.getBlockValues().registerKeyParser(new NexoKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY); + plugin.getServer().getPluginManager().registerEvents(new NexoListener(), plugin); + BukkitExecutor.sync(NexoHook::initializeMechanics, 1L); + } + + private static void initializeMechanics() { + MechanicsManager mechanicsManager = MechanicsManager.INSTANCE; + AVAILABLE_MECHANICS.add(new MechanicData(mechanicsManager.getMechanicFactory("noteblock"), NoteBlockMechanicFactory.Companion::setBlockModel)); + AVAILABLE_MECHANICS.add(new MechanicData(mechanicsManager.getMechanicFactory("stringblock"), StringBlockMechanicFactory.Companion::setBlockModel)); + } + + private static class NexoListener implements Listener { + + @WorldRecordFlags + private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS; + @WorldRecordFlags + private static final int ALL_RECORD_FLAGS = REGULAR_RECORD_FLAGS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS; + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onNexoBlockBreak(BlockBreakEvent e) { + Key blockKey = Keys.of(e.getBlock()); + if (blockKey.getGlobalKey().equals(NEXO_PREFIX)) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + worldRecordService.get().recordBlockBreak(blockKey, + e.getBlock().getLocation(wrapper.getHandle()), 1, ALL_RECORD_FLAGS); + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onFurniturePlace(NexoFurniturePlaceEvent e) { + Key blockKey = Keys.of(NEXO_PREFIX, e.getMechanic().getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + worldRecordService.get().recordBlockPlace(blockKey, e.getBlock().getLocation(wrapper.getHandle()), + 1, null, REGULAR_RECORD_FLAGS); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onFurnitureBreak(NexoFurnitureBreakEvent e) { + Key blockKey = Keys.of(NEXO_PREFIX, e.getMechanic().getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + worldRecordService.get().recordBlockBreak(blockKey, + e.getBaseEntity().getLocation(wrapper.getHandle()), 1, ALL_RECORD_FLAGS); + } + } + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onIslandGenerateBlock(IslandGenerateBlockEvent event) { + if (!event.getBlock().getGlobalKey().equals(NEXO_PREFIX)) + return; + + String itemId = event.getBlock().getSubKey().toLowerCase(Locale.ENGLISH); + + if (!NexoItems.exists(itemId)) { + event.setCancelled(true); + return; + } + + for (MechanicData mechanic : AVAILABLE_MECHANICS) { + if (mechanic.mechanicFactory != null && !mechanic.mechanicFactory.isNotImplementedIn(itemId)) { + event.setPlaceBlock(false); + mechanic.setBlockModelFunction.setBlockModel(event.getLocation().getBlock(), itemId); + return; + } + } + + // No mechanic was found + event.setCancelled(true); + } + + } + + private static class NexoKeyParser implements CustomKeyParser { + + @Override + public Key getCustomKey(Location location) { + Mechanic mechanic = NexoBlocks.customBlockMechanic(location); + if (mechanic == null) + return BLOCK_KEY; + return Keys.of(NEXO_PREFIX, mechanic.getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + } + + @Override + public Key getCustomKey(ItemStack itemStack, Key def) { + String itemId = NexoItems.idFromItem(itemStack); + if (itemId == null) + return def; + return Keys.of(NEXO_PREFIX, itemId.toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + } + + @Override + public boolean isCustomKey(Key key) { + return key.getGlobalKey().equals(NEXO_PREFIX); + } + + @Override + @Nullable + public ItemStack getCustomKeyItem(Key key) { + ItemBuilder itemBuilder = NexoItems.itemFromId(key.getSubKey().toLowerCase(Locale.ENGLISH)); + if (itemBuilder == null) + return null; + return itemBuilder.build(); + } + + } + + private record MechanicData(MechanicFactory mechanicFactory, SetBlockModelFunction setBlockModelFunction) { + + } + + private interface SetBlockModelFunction { + + void setBlockModel(Block block, String itemId); + + } + +} diff --git a/settings.gradle b/settings.gradle index 9a8fecb0bb..b8d199cd5d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -25,6 +25,7 @@ include 'Hooks:JetsMinions' include 'Hooks:LuckPerms' include 'Hooks:MergedSpawner' include 'Hooks:MVdWPlaceholderAPI' +include 'Hooks:Nexo' include 'Hooks:OpenJdkNashornEngine' include 'Hooks:Oraxen' include 'Hooks:PaperMC' From 285a8d4836550bb76e899609d87cb4789a2bfcc6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Jan 2025 19:58:57 +0200 Subject: [PATCH 047/600] Better support for furnitures in Oraxen and Nexo --- .../superiorskyblock/external/NexoHook.java | 39 ++++++ Hooks/Oraxen/build.gradle | 4 +- .../superiorskyblock/external/OraxenHook.java | 130 ++++++++++++++---- .../external/ProvidersManagerImpl.java | 13 ++ .../blocks/ICustomBlocksProvider.java | 12 ++ .../DefaultIslandCalculationAlgorithm.java | 49 +++++-- 6 files changed, 201 insertions(+), 46 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/external/blocks/ICustomBlocksProvider.java diff --git a/Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java b/Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java index e215f56e72..7b174d8b44 100644 --- a/Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java +++ b/Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java @@ -5,14 +5,19 @@ import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.external.blocks.ICustomBlocksProvider; import com.nexomc.nexo.api.NexoBlocks; +import com.nexomc.nexo.api.NexoFurniture; import com.nexomc.nexo.api.NexoItems; import com.nexomc.nexo.api.events.furniture.NexoFurnitureBreakEvent; import com.nexomc.nexo.api.events.furniture.NexoFurniturePlaceEvent; @@ -22,9 +27,14 @@ import com.nexomc.nexo.mechanics.MechanicsManager; import com.nexomc.nexo.mechanics.custom_block.noteblock.NoteBlockMechanicFactory; import com.nexomc.nexo.mechanics.custom_block.stringblock.StringBlockMechanicFactory; +import com.nexomc.nexo.mechanics.furniture.FurnitureMechanic; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -55,6 +65,7 @@ protected WorldRecordService create() { public static void register(SuperiorSkyblockPlugin plugin) { NexoHook.plugin = plugin; plugin.getBlockValues().registerKeyParser(new NexoKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY); + plugin.getProviders().registerCustomBlocksProvider(new NexuCustomBlocksProvider()); plugin.getServer().getPluginManager().registerEvents(new NexoListener(), plugin); BukkitExecutor.sync(NexoHook::initializeMechanics, 1L); } @@ -65,6 +76,34 @@ private static void initializeMechanics() { AVAILABLE_MECHANICS.add(new MechanicData(mechanicsManager.getMechanicFactory("stringblock"), StringBlockMechanicFactory.Companion::setBlockModel)); } + private static class NexuCustomBlocksProvider implements ICustomBlocksProvider { + + @Nullable + @Override + public KeyMap getBlockCountsForChunk(ChunkPosition chunkPosition) { + if (!Bukkit.isPrimaryThread()) + return null; + + World world = chunkPosition.getWorld(); + if (!world.isChunkLoaded(chunkPosition.getX(), chunkPosition.getZ())) + return KeyMaps.createEmptyMap(); + + KeyMap blockCounts = KeyMaps.createHashMap(KeyIndicator.CUSTOM); + + Chunk chunk = world.getChunkAt(chunkPosition.getX(), chunkPosition.getZ()); + + for (Entity entity : chunk.getEntities()) { + FurnitureMechanic mechanic = NexoFurniture.furnitureMechanic(entity); + if (mechanic != null) { + Key blockKey = Keys.of(NEXO_PREFIX, mechanic.getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + blockCounts.put(blockKey, blockCounts.getRaw(blockKey, 0) + 1); + } + } + + return blockCounts; + } + } + private static class NexoListener implements Listener { @WorldRecordFlags diff --git a/Hooks/Oraxen/build.gradle b/Hooks/Oraxen/build.gradle index 5fa0a07828..593f01754f 100644 --- a/Hooks/Oraxen/build.gradle +++ b/Hooks/Oraxen/build.gradle @@ -2,12 +2,12 @@ group 'Hooks:Oraxen' java { toolchain { - languageVersion.set(JavaLanguageVersion.of(17)) + languageVersion.set(JavaLanguageVersion.of(21)) } } dependencies { - compileOnly 'io.th0rgal:Oraxen:1.155.1' + compileOnly 'io.th0rgal:Oraxen:1.187.0' compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" compileOnly project(":API") compileOnly rootProject diff --git a/Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java b/Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java index c555fecad0..6f690257c8 100644 --- a/Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java +++ b/Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java @@ -7,25 +7,36 @@ import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.bgsoftware.superiorskyblock.external.blocks.ICustomBlocksProvider; import io.th0rgal.oraxen.api.OraxenBlocks; +import io.th0rgal.oraxen.api.OraxenFurniture; import io.th0rgal.oraxen.api.OraxenItems; +import io.th0rgal.oraxen.api.events.furniture.OraxenFurnitureBreakEvent; +import io.th0rgal.oraxen.api.events.furniture.OraxenFurniturePlaceEvent; import io.th0rgal.oraxen.items.ItemBuilder; import io.th0rgal.oraxen.mechanics.Mechanic; import io.th0rgal.oraxen.mechanics.MechanicFactory; import io.th0rgal.oraxen.mechanics.MechanicsManager; import io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanicFactory; +import io.th0rgal.oraxen.mechanics.provided.gameplay.furniture.FurnitureMechanic; import io.th0rgal.oraxen.mechanics.provided.gameplay.noteblock.NoteBlockMechanicFactory; import io.th0rgal.oraxen.mechanics.provided.gameplay.stringblock.StringBlockMechanicFactory; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -43,34 +54,41 @@ public class OraxenHook { private static final Key BLOCK_ITEM_KEY = Keys.of(Material.PAPER); private static final Key BLOCK_KEY = Keys.of(Material.NOTE_BLOCK); - private static final List> AVAILABLE_MECHANICS; + private static final List AVAILABLE_MECHANICS = initializeMechanics(); - static { - List> availableMechanics = new LinkedList<>(); + private static List initializeMechanics() { + List mechanics = new LinkedList<>(); try { Class.forName("io.th0rgal.oraxen.mechanics.provided.gameplay.block.BlockMechanicFactory"); - availableMechanics.add(new Pair<>(MechanicsManager.getMechanicFactory("block"), BlockMechanicFactory::setBlockModel)); - availableMechanics.add(new Pair<>(MechanicsManager.getMechanicFactory("noteblock"), NoteBlockMechanicFactory::setBlockModel)); - availableMechanics.add(new Pair<>(MechanicsManager.getMechanicFactory("stringblock"), StringBlockMechanicFactory::setBlockModel)); + mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory("block"), BlockMechanicFactory::setBlockModel)); + mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory("noteblock"), NoteBlockMechanicFactory::setBlockModel)); + mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory("stringblock"), StringBlockMechanicFactory::setBlockModel)); } catch (Throwable error) { - availableMechanics.add(new Pair<>(MechanicsManager.getMechanicFactory("block"), (block, itemId) -> { + { ReflectMethod setBlockModel = new ReflectMethod<>( new ClassInfo("io.th0rgal.oraxen.mechanics.provided.block.BlockMechanicFactory", ClassInfo.PackageType.UNKNOWN), "setBlockModel", Block.class, String.class); - if (setBlockModel.isValid()) - setBlockModel.invoke(null, block, itemId); - })); - availableMechanics.add(new Pair<>(MechanicsManager.getMechanicFactory("noteblock"), (block, itemId) -> { + + mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory("block"), (block, itemId) -> { + if (setBlockModel.isValid()) + setBlockModel.invoke(null, block, itemId); + })); + } + + { ReflectMethod setBlockModel = new ReflectMethod<>( new ClassInfo("io.th0rgal.oraxen.mechanics.provided.noteblock.NoteBlockMechanicFactory", ClassInfo.PackageType.UNKNOWN), "setBlockModel", Block.class, String.class); - if (setBlockModel.isValid()) - setBlockModel.invoke(null, block, itemId); - })); + + mechanics.add(new MechanicData(MechanicsManager.getMechanicFactory("noteblock"), (block, itemId) -> { + if (setBlockModel.isValid()) + setBlockModel.invoke(null, block, itemId); + })); + } } - AVAILABLE_MECHANICS = Collections.unmodifiableList(availableMechanics); + return Collections.unmodifiableList(mechanics); } private static final LazyReference worldRecordService = new LazyReference() { @@ -85,10 +103,44 @@ protected WorldRecordService create() { public static void register(SuperiorSkyblockPlugin plugin) { OraxenHook.plugin = plugin; plugin.getBlockValues().registerKeyParser(new OraxenKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY); - plugin.getServer().getPluginManager().registerEvents(new GeneratorListener(), plugin); + plugin.getProviders().registerCustomBlocksProvider(new OraxenCustomBlocksProvider()); + plugin.getServer().getPluginManager().registerEvents(new OraxenListener(), plugin); } - private static class GeneratorListener implements Listener { + private static class OraxenCustomBlocksProvider implements ICustomBlocksProvider { + + @Nullable + @Override + public KeyMap getBlockCountsForChunk(ChunkPosition chunkPosition) { + if (!Bukkit.isPrimaryThread()) + return null; + + World world = chunkPosition.getWorld(); + if (!world.isChunkLoaded(chunkPosition.getX(), chunkPosition.getZ())) + return KeyMaps.createEmptyMap(); + + KeyMap blockCounts = KeyMaps.createHashMap(KeyIndicator.CUSTOM); + + Chunk chunk = world.getChunkAt(chunkPosition.getX(), chunkPosition.getZ()); + + for (Entity entity : chunk.getEntities()) { + FurnitureMechanic mechanic = OraxenFurniture.getFurnitureMechanic(entity); + if (mechanic != null) { + Key blockKey = Keys.of(ORAXEN_PREFIX, mechanic.getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + blockCounts.put(blockKey, blockCounts.getRaw(blockKey, 0) + 1); + } + } + + return blockCounts; + } + } + + private static class OraxenListener implements Listener { + + @WorldRecordFlags + private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS; + @WorldRecordFlags + private static final int ALL_RECORD_FLAGS = REGULAR_RECORD_FLAGS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS; @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onOraxenBlockBreak(BlockBreakEvent e) { @@ -96,14 +148,31 @@ public void onOraxenBlockBreak(BlockBreakEvent e) { if (blockKey.getGlobalKey().equals(ORAXEN_PREFIX)) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { worldRecordService.get().recordBlockBreak(blockKey, - e.getBlock().getLocation(wrapper.getHandle()), 1, - WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS); + e.getBlock().getLocation(wrapper.getHandle()), 1, ALL_RECORD_FLAGS); } } } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onFurniturePlace(OraxenFurniturePlaceEvent e) { + Key blockKey = Keys.of(ORAXEN_PREFIX, e.getMechanic().getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + worldRecordService.get().recordBlockPlace(blockKey, e.getBlock().getLocation(wrapper.getHandle()), + 1, null, REGULAR_RECORD_FLAGS); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onFurnitureBreak(OraxenFurnitureBreakEvent e) { + Key blockKey = Keys.of(ORAXEN_PREFIX, e.getMechanic().getItemID().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + worldRecordService.get().recordBlockBreak(blockKey, + e.getBaseEntity().getLocation(wrapper.getHandle()), 1, ALL_RECORD_FLAGS); + } + } + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onIslandGenerateBlock(IslandGenerateBlockEvent event) { if (!event.getBlock().getGlobalKey().equals(ORAXEN_PREFIX)) @@ -116,17 +185,16 @@ public void onIslandGenerateBlock(IslandGenerateBlockEvent event) { return; } - Pair mechanic = AVAILABLE_MECHANICS.stream() - .filter(pair -> pair.getKey() != null && !pair.getKey().isNotImplementedIn(itemId)) - .findFirst().orElse(null); - - if (mechanic == null) { - event.setCancelled(true); - return; + for (MechanicData mechanic : AVAILABLE_MECHANICS) { + if (mechanic.mechanicFactory != null && !mechanic.mechanicFactory.isNotImplementedIn(itemId)) { + event.setPlaceBlock(false); + mechanic.setBlockModelFunction.setBlockModel(event.getLocation().getBlock(), itemId); + return; + } } - event.setPlaceBlock(false); - mechanic.getValue().setBlockModel(event.getLocation().getBlock(), itemId); + // No mechanic was found + event.setCancelled(true); } } @@ -165,6 +233,10 @@ public ItemStack getCustomKeyItem(Key key) { } + private record MechanicData(MechanicFactory mechanicFactory, SetBlockModelFunction setBlockModelFunction) { + + } + private interface SetBlockModelFunction { void setBlockModel(Block block, String itemId); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java index 20c0f01271..3c7c8356b0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java @@ -34,6 +34,7 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.external.async.AsyncProvider; import com.bgsoftware.superiorskyblock.external.async.AsyncProvider_Default; +import com.bgsoftware.superiorskyblock.external.blocks.ICustomBlocksProvider; import com.bgsoftware.superiorskyblock.external.chunks.ChunksProvider_Default; import com.bgsoftware.superiorskyblock.external.economy.EconomyProvider_Default; import com.bgsoftware.superiorskyblock.external.menus.MenusProvider_Default; @@ -97,6 +98,7 @@ protected PlaceholdersService create() { private final List skinsListeners = new LinkedList<>(); private final List stackedBlocksListeners = new LinkedList<>(); private final List worldsListeners = new LinkedList<>(); + private final List customBlocksProviders = new LinkedList<>(); public ProvidersManagerImpl(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -288,6 +290,14 @@ public void unregisterStackedBlocksListener(IStackedBlocksListener stackedBlocks this.stackedBlocksListeners.remove(stackedBlocksListener); } + public void registerCustomBlocksProvider(ICustomBlocksProvider customBlocksProvider) { + this.customBlocksProviders.add(customBlocksProvider); + } + + public List getCustomBlocksProviders() { + return customBlocksProviders; + } + public void addPricesLoadCallback(Runnable callback) { if (this.pricesLoadCallbacks == null) { callback.run(); @@ -448,6 +458,9 @@ private void registerGeneralHooks() { if (Bukkit.getPluginManager().isPluginEnabled("Oraxen")) registerHook("OraxenHook"); + if (Bukkit.getPluginManager().isPluginEnabled("Nexo")) + registerHook("NexoHook"); + if (Bukkit.getPluginManager().isPluginEnabled("ItemsAdder")) registerHook("ItemsAdderHook"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/blocks/ICustomBlocksProvider.java b/src/main/java/com/bgsoftware/superiorskyblock/external/blocks/ICustomBlocksProvider.java new file mode 100644 index 0000000000..927123a134 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/blocks/ICustomBlocksProvider.java @@ -0,0 +1,12 @@ +package com.bgsoftware.superiorskyblock.external.blocks; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; + +public interface ICustomBlocksProvider { + + @Nullable + KeyMap getBlockCountsForChunk(ChunkPosition chunkPosition); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java index 0932be9099..9add5e24d0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java @@ -14,8 +14,8 @@ import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.types.SpawnerKey; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.core.profiler.Profiler; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.bgsoftware.superiorskyblock.external.blocks.ICustomBlocksProvider; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import org.bukkit.Location; @@ -113,16 +114,8 @@ public CompletableFuture calculateIsland(Island island) } ChunkPosition chunkPosition = calculatedChunk.getPosition(); - - // Load stacked blocks - Collection> stackedBlocks = plugin.getProviders().getStackedBlocksProvider() - .getBlocks(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ()); - - if (stackedBlocks == null) { - chunksToCheck.add(calculatedChunk.getPosition()); - } else for (Pair pair : stackedBlocks) { - blockCounts.addCounts(pair.getKey(), pair.getValue() - 1); - } + if (!loadExternalBlocksForChunk(chunkPosition, blockCounts)) + chunksToCheck.add(chunkPosition); // Load built-in stacked blocks plugin.getStackedBlocks().forEach(calculatedChunk.getPosition(), stackedBlock -> @@ -160,10 +153,7 @@ public CompletableFuture calculateIsland(Island island) // Calculate stacked block counts for (ChunkPosition chunkPosition : chunksToCheck) { - for (Pair pair : plugin.getProviders().getStackedBlocksProvider() - .getBlocks(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ())) { - blockCounts.addCounts(pair.getKey(), pair.getValue() - 1); - } + loadExternalBlocksForChunk(chunkPosition, blockCounts); } // Calculate minecart block counts @@ -196,6 +186,34 @@ private static List> createMinecartBlockTypes() { return Collections.unmodifiableList(minecartBlockTypes); } + private boolean loadExternalBlocksForChunk(ChunkPosition chunkPosition, BlockCountsTracker blockCounts) { + // Load stacked blocks + Collection> stackedBlocks = plugin.getProviders().getStackedBlocksProvider() + .getBlocks(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ()); + + if (stackedBlocks == null) + return false; + + BlockCountsTracker chunkBlockCounts = new BlockCountsTracker(); + + for (ICustomBlocksProvider customBlocksProvider : plugin.getProviders().getCustomBlocksProviders()) { + KeyMap customBlocksCounts = customBlocksProvider.getBlockCountsForChunk(chunkPosition); + if (customBlocksCounts == null) + return false; + + customBlocksCounts.forEach(chunkBlockCounts::addCounts); + } + + chunkBlockCounts.blockCounts.forEach((block, count) -> + blockCounts.addCounts(block, count.intValue())); + + for (Pair pair : stackedBlocks) { + blockCounts.addCounts(pair.getKey(), pair.getValue() - 1); + } + + return true; + } + private static class BlockCountsTracker implements IslandCalculationResult { private final KeyMap blockCounts = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL); @@ -212,6 +230,7 @@ public void addCounts(Key blockKey, int amount) { public void addCounts(KeyMap other) { other.forEach((key, counter) -> addCounts(key, counter.get())); } + } private static class SpawnerInfo { From ebd41863e0f6fdddf06ea98b401267bf4ec2253d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Jan 2025 20:27:24 +0200 Subject: [PATCH 048/600] [CI SKIP] Updated README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 62acc201e6..590aa71c14 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@


- +

From e259f3ac113725c3bddb091b71d0e85bebcefc7f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 25 Jan 2025 11:42:30 +0200 Subject: [PATCH 049/600] Fix skeleton & zombie horses are considered animals (#2219) --- .../world/BukkitEntities.java | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java index 46382256a2..f0911d54e7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java @@ -37,19 +37,14 @@ import java.util.Optional; import java.util.UUID; import java.util.function.Predicate; -import java.util.function.Supplier; public class BukkitEntities { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Map> entityContent = new HashMap<>(); - private static final Class HOGLIN_CLASS = ((Supplier>) () -> { - try { - return Class.forName("org.bukkit.entity.Hoglin"); - } catch (ClassNotFoundException error) { - return null; - } - }).get(); + private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); + private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); + private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); private BukkitEntities() { @@ -185,7 +180,11 @@ public enum EntityCategory { Flying.class.isAssignableFrom(entityClass) || // In Bukkit, Hoglins are considered as Animals for no reason. // We want to explicitly tell the plugin its monster type. - entityClass == HOGLIN_CLASS + entityClass == HOGLIN_CLASS || + // In Bukkit, Skeleton and Zombie horses are considered Horses, + // and therefore they are animals. We want to explicit tell the plugin + // they are monsters. + entityClass == SKELETON_HORSE_CLASS || entityClass == ZOMBIE_HORSE_CLASS ); }); @@ -205,7 +204,9 @@ boolean isFromCategory(EntityType entityType) { // We check that the entity type is whether a Creature or an Ambient (Creature.class.isAssignableFrom(entityClass) || Ambient.class.isAssignableFrom(entityClass)) && // We make sure this is not Hoglin; In Bukkit, they are considered Animals. - entityClass != HOGLIN_CLASS; + entityClass != HOGLIN_CLASS && + // We make sure this is not Skeleton/Zombie horses; In Bukkit, they are considered Animals. + entityClass != SKELETON_HORSE_CLASS && entityClass != ZOMBIE_HORSE_CLASS; }); @Override @@ -264,4 +265,12 @@ public IslandPrivilege getSpawnPrivilege() { } + private static Class getEntityTypeClass(String clazz) { + try { + return Class.forName(clazz); + } catch (ClassNotFoundException error) { + return null; + } + } + } From 32da0fa21c38fb92e04128ec4a03ed1eef772961 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 25 Jan 2025 12:05:49 +0200 Subject: [PATCH 050/600] Optimize natural spawn reasons checks --- .../listener/IslandFlagsListener.java | 86 +++++++++++-------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java index 8b125d46a7..2c549ca3ca 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; +import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; @@ -43,11 +44,14 @@ import java.util.EnumSet; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; public class IslandFlagsListener implements Listener { + private static final EnumSet NATURAL_SPAWN_REASONS = initializeNaturalSpawnReasons(); + private final Map originalFireballsDamager = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS); private final SuperiorSkyblockPlugin plugin; @@ -68,46 +72,31 @@ private void onEntitySpawn(CreatureSpawnEvent e) { public boolean preventEntitySpawn(Location location, CreatureSpawnEvent.SpawnReason spawnReason, EntityType entityType) { IslandFlag actionFlag; - switch (spawnReason.name()) { - case "JOCKEY": - case "CHUNK_GEN": - case "NATURAL": - case "TRAP": - case "MOUNT": - case "VILLAGE_INVASION": - case "VILLAGE_DEFENSE": - case "PATROL": - case "BEEHIVE": - case "LIGHTNING": - case "DEFAULT": { - switch (BukkitEntities.getCategory(entityType)) { - case ANIMAL: - actionFlag = IslandFlags.NATURAL_ANIMALS_SPAWN; - break; - case MONSTER: - actionFlag = IslandFlags.NATURAL_MONSTER_SPAWN; - break; - default: - return false; - } - break; + if (spawnReason == CreatureSpawnEvent.SpawnReason.SPAWNER || + spawnReason == CreatureSpawnEvent.SpawnReason.SPAWNER_EGG) { + switch (BukkitEntities.getCategory(entityType)) { + case ANIMAL: + actionFlag = IslandFlags.SPAWNER_ANIMALS_SPAWN; + break; + case MONSTER: + actionFlag = IslandFlags.SPAWNER_MONSTER_SPAWN; + break; + default: + return false; } - case "SPAWNER": - case "SPAWNER_EGG": { - switch (BukkitEntities.getCategory(entityType)) { - case ANIMAL: - actionFlag = IslandFlags.SPAWNER_ANIMALS_SPAWN; - break; - case MONSTER: - actionFlag = IslandFlags.SPAWNER_MONSTER_SPAWN; - break; - default: - return false; - } - break; + } else if (NATURAL_SPAWN_REASONS.contains(spawnReason)) { + switch (BukkitEntities.getCategory(entityType)) { + case ANIMAL: + actionFlag = IslandFlags.NATURAL_ANIMALS_SPAWN; + break; + case MONSTER: + actionFlag = IslandFlags.NATURAL_MONSTER_SPAWN; + break; + default: + return false; } - default: - return false; + } else { + return false; } return preventAction(location, actionFlag); @@ -311,6 +300,27 @@ private void registerPaperListener() { } } + private static EnumSet initializeNaturalSpawnReasons() { + EnumSet naturalSpawnReasons = EnumSet.noneOf(CreatureSpawnEvent.SpawnReason.class); + + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "JOCKEY")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "CHUNK_GEN")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "NATURAL")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "TRAP")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "MOUNT")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "VILLAGE_INVASION")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "VILLAGE_DEFENSE")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "PATROL")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "BEEHIVE")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "LIGHTNING")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "DEFAULT")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "JOCKEY")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "JOCKEY")).ifPresent(naturalSpawnReasons::add); + Optional.ofNullable(EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "JOCKEY")).ifPresent(naturalSpawnReasons::add); + + return naturalSpawnReasons; + } + private class PaperListener implements Listener { @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) From 8c0b038758940a4415ac06c119bfc1852b9a0f4c Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 25 Jan 2025 12:11:24 +0200 Subject: [PATCH 051/600] Fixed hangings cannot be broken by players when TNT_EXPLOSION is disabled (#2339) --- .../superiorskyblock/listener/IslandFlagsListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java index 2c549ca3ca..4ce1791373 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java @@ -109,7 +109,7 @@ private void onHangingBreakByEntity(HangingBreakByEntityEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = e.getEntity().getLocation(wrapper.getHandle()); - if (e.getCause() != HangingBreakEvent.RemoveCause.EXPLOSION) { + if (e.getCause() == HangingBreakEvent.RemoveCause.EXPLOSION) { if (e.getRemover() instanceof Player) { // Explosion was set by TNT. if (preventAction(entityLocation, IslandFlags.TNT_EXPLOSION)) { From d0bd03d47ef466fc4d3e181ca521201434399062 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 25 Jan 2025 12:47:21 +0200 Subject: [PATCH 052/600] Fix GlowEnchantment errors in regular Spigot 1.21.4 --- .../nms/v1_21_4/NMSAlgorithmsImpl.java | 2 +- .../v1_21_4/enchantment/GlowEnchantment.java | 56 +++++++++++++++++-- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index db5754a08f..0e136f86a6 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -181,7 +181,7 @@ public String getMinecraftKey(ItemStack itemStack) { @Override public Enchantment getGlowEnchant() { - return new GlowEnchantment(); + return GlowEnchantment.createEnchantment(); } @Override diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java index 1bd25d1d18..390ee22ba1 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java @@ -13,14 +13,16 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.tags.TagKey; import net.minecraft.world.item.enchantment.Enchantment; +import org.bukkit.NamespacedKey; import org.bukkit.craftbukkit.enchantments.CraftEnchantment; import javax.annotation.Nullable; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Map; -public class GlowEnchantment extends CraftEnchantment { +public class GlowEnchantment { private static final ReflectField REGISTRY_FROZEN = new ReflectField<>( MappedRegistry.class, boolean.class, Modifier.PRIVATE, 1); @@ -43,10 +45,12 @@ public class GlowEnchantment extends CraftEnchantment { private static final String GLOW_ENCHANTMENT_NAME = "superiorskyblock_glowing_enchant"; - private static final Holder HANDLE = initializeHandle(); + private static final HandleType HANDLE_TYPE = findHandleType(); + + private static final Object HANDLE = initializeHandle(); @Nullable - private static Holder initializeHandle() { + private static Object initializeHandle() { Registry registry = MinecraftServer.getServer().registryAccess() .lookup(Registries.ENCHANTMENT).orElse(null); @@ -80,7 +84,11 @@ private static Holder initializeHandle() { freezeRegistry(registry); } - return holder; + return switch (HANDLE_TYPE) { + case HOLDER -> holder; + case RAW -> handle; + default -> throw new IllegalStateException("Cannot find valid handle type for enchantments"); + }; } private static void freezeRegistry(Registry registry) { @@ -114,8 +122,44 @@ private static void freezeRegistryUnsafe(Registry registry) throws Exception REGISTRY_ALL_TAGS.set(registry, allTags); } - public GlowEnchantment() { - super(HANDLE); + private static HandleType findHandleType() { + Constructor constructor = CraftEnchantment.class.getConstructors()[0]; + + if (constructor.getParameterCount() == 1 && constructor.getParameterTypes()[0] == Holder.class) { + return HandleType.HOLDER; + } else if (constructor.getParameterCount() == 2 && constructor.getParameterTypes()[0] == NamespacedKey.class && + constructor.getParameterTypes()[1] == Enchantment.class) { + return HandleType.RAW; + } else { + return HandleType.UNKNOWN; + } + } + + public static CraftEnchantment createEnchantment() { + Constructor constructor = CraftEnchantment.class.getConstructors()[0]; + + try { + return switch (HANDLE_TYPE) { + case HOLDER -> (CraftEnchantment) constructor.newInstance(HANDLE); + case RAW -> + (CraftEnchantment) constructor.newInstance(NamespacedKey.minecraft(GLOW_ENCHANTMENT_NAME), HANDLE); + default -> throw new IllegalStateException("Cannot find valid handle type for enchantments"); + }; + } catch (Throwable error) { + throw new RuntimeException(error); + } + } + + private GlowEnchantment() { + + } + + private enum HandleType { + + HOLDER, + RAW, + UNKNOWN + } } From 1617008779ffa10658b5b9d442658caa50746314 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 25 Jan 2025 12:47:39 +0200 Subject: [PATCH 053/600] Fixed errors when disbanding islands in Spigot 1.21.4 --- .../superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java index aafe5a9e31..a478242f40 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java @@ -17,6 +17,7 @@ import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; import net.minecraft.world.level.Level; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -34,6 +35,8 @@ public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); + private static final ReflectMethod ENTITY_SET_LEVEL = new ReflectMethod<>( + Entity.class, 1, Level.class); private final SuperiorSkyblockPlugin plugin; @@ -70,7 +73,7 @@ public void clearInventory(OfflinePlayer offlinePlayer) { Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); if (spawnLocation != null) { - serverPlayer.setLevel(serverLevel); + ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); serverPlayer.absMoveTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), spawnLocation.getYaw(), spawnLocation.getPitch()); } From 104f6f1ca74ad4e938d97201c1c86653bf007c7a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 25 Jan 2025 12:52:35 +0200 Subject: [PATCH 054/600] Reuse glow-enchantment if it already exists in registry --- .../superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java | 6 +++++- .../nms/v1_21_4/enchantment/GlowEnchantment.java | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index 0e136f86a6..f67eb43fe2 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -186,7 +186,11 @@ public Enchantment getGlowEnchant() { @Override public Enchantment createGlowEnchantment() { - Enchantment enchantment = getGlowEnchant(); + Enchantment enchantment = Registry.ENCHANTMENT.get(GlowEnchantment.GLOW_ENCHANTMENT_KEY); + if (enchantment != null) + return enchantment; + + enchantment = getGlowEnchant(); Registry registry = Registry.ENCHANTMENT; try { diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java index 390ee22ba1..42b04eb573 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java @@ -44,6 +44,7 @@ public class GlowEnchantment { } private static final String GLOW_ENCHANTMENT_NAME = "superiorskyblock_glowing_enchant"; + public static final NamespacedKey GLOW_ENCHANTMENT_KEY = NamespacedKey.minecraft(GLOW_ENCHANTMENT_NAME); private static final HandleType HANDLE_TYPE = findHandleType(); From 5b8275d0582375f0d0e855ba672b94b27e2eb9ef Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 25 Jan 2025 13:56:40 +0200 Subject: [PATCH 055/600] Disable the ability to create island warps with hanging signs (#2343) --- .../nms/v1_12_R1/NMSWorldImpl.java | 6 +++ .../nms/v1_16_R3/NMSWorldImpl.java | 13 ++++++ .../nms/v1_17/NMSWorldImpl.java | 13 ++++++ .../nms/v1_18/NMSWorldImpl.java | 13 ++++++ .../nms/v1_19/NMSWorldImpl.java | 19 +++++++++ .../nms/v1_20_3/NMSWorldImpl.java | 19 +++++++++ .../nms/v1_20_4/NMSWorldImpl.java | 19 +++++++++ .../nms/v1_21/NMSWorldImpl.java | 19 +++++++++ .../nms/v1_21_3/NMSWorldImpl.java | 19 +++++++++ .../nms/v1_21_4/NMSWorldImpl.java | 19 +++++++++ .../nms/v1_8_R3/NMSWorldImpl.java | 6 +++ .../listener/SignsListener.java | 42 +++++++++++++------ .../superiorskyblock/nms/NMSWorld.java | 7 ++++ .../superiorskyblock/world/SignType.java | 11 +++++ 14 files changed, 213 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/SignType.java diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java index 964a86538d..69f33c8479 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java @@ -20,6 +20,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockDoubleStep; @@ -182,6 +183,11 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { return blockType == Material.WATER || blockType == Material.STATIONARY_WATER; } + @Override + public SignType getSignType(Object sign) { + throw new UnsupportedOperationException("Not supported"); + } + @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle(); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java index 7629d318f1..bc742a27eb 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.server.v1_16_R3.Block; @@ -47,6 +48,8 @@ import org.bukkit.Location; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlockState; @@ -190,6 +193,16 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); } + @Override + public SignType getSignType(Object sign) { + if (sign instanceof WallSign) + return SignType.WALL_SIGN; + else if (sign instanceof Sign) + return SignType.STANDING_SIGN; + else + return SignType.UNKNOWN; + } + @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { IBlockData blockData = ((CraftBlock) block).getNMS(); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index 0c35706015..ec726df486 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_17.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; @@ -46,6 +47,8 @@ import org.bukkit.World; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlockState; @@ -208,6 +211,16 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); } + @Override + public SignType getSignType(Object sign) { + if (sign instanceof WallSign) + return SignType.WALL_SIGN; + else if (sign instanceof Sign) + return SignType.STANDING_SIGN; + else + return SignType.UNKNOWN; + } + @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { BlockState blockState = ((CraftBlock) block).getNMS(); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index 3eeef98aaf..0e35556c62 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_18.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; @@ -47,6 +48,8 @@ import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlockState; @@ -209,6 +212,16 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); } + @Override + public SignType getSignType(Object sign) { + if (sign instanceof WallSign) + return SignType.WALL_SIGN; + else if (sign instanceof Sign) + return SignType.STANDING_SIGN; + else + return SignType.UNKNOWN; + } + @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { BlockState blockState = ((CraftBlock) block).getNMS(); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index 3df134eb60..c9033be449 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_19.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; @@ -47,6 +48,10 @@ import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockState; @@ -209,6 +214,20 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); } + @Override + public SignType getSignType(Object sign) { + if (sign instanceof WallSign) + return SignType.WALL_SIGN; + else if (sign instanceof Sign) + return SignType.STANDING_SIGN; + else if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return SignType.UNKNOWN; + } + @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { BlockState blockState = ((CraftBlock) block).getNMS(); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index 0facc4df10..575d633558 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -46,6 +47,10 @@ import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockState; @@ -214,6 +219,20 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); } + @Override + public SignType getSignType(Object sign) { + if (sign instanceof WallSign) + return SignType.WALL_SIGN; + else if (sign instanceof Sign) + return SignType.STANDING_SIGN; + else if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return SignType.UNKNOWN; + } + @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { BlockState blockState = ((CraftBlock) block).getNMS(); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index 5c10e76010..5102cada6f 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -46,6 +47,10 @@ import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockState; @@ -214,6 +219,20 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); } + @Override + public SignType getSignType(Object sign) { + if (sign instanceof WallSign) + return SignType.WALL_SIGN; + else if (sign instanceof Sign) + return SignType.STANDING_SIGN; + else if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return SignType.UNKNOWN; + } + @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { BlockState blockState = ((CraftBlock) block).getNMS(); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index 7ae5b948b5..f3e401f35b 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -46,6 +47,10 @@ import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockState; @@ -214,6 +219,20 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); } + @Override + public SignType getSignType(Object sign) { + if (sign instanceof WallSign) + return SignType.WALL_SIGN; + else if (sign instanceof Sign) + return SignType.STANDING_SIGN; + else if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return SignType.UNKNOWN; + } + @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { BlockState blockState = ((CraftBlock) block).getNMS(); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index 04f2dc83c4..fb1f679190 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -46,6 +47,10 @@ import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockState; @@ -214,6 +219,20 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); } + @Override + public SignType getSignType(Object sign) { + if (sign instanceof WallSign) + return SignType.WALL_SIGN; + else if (sign instanceof Sign) + return SignType.STANDING_SIGN; + else if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return SignType.UNKNOWN; + } + @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { BlockState blockState = ((CraftBlock) block).getNMS(); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index 539d03e844..e0f0d21319 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; @@ -46,6 +47,10 @@ import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockState; @@ -214,6 +219,20 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); } + @Override + public SignType getSignType(Object sign) { + if (sign instanceof WallSign) + return SignType.WALL_SIGN; + else if (sign instanceof Sign) + return SignType.STANDING_SIGN; + else if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return SignType.UNKNOWN; + } + @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { BlockState blockState = ((CraftBlock) block).getNMS(); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java index 2cfa8a672f..15731b28a0 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java @@ -20,6 +20,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockDoubleStep; @@ -186,6 +187,11 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { return blockType == Material.WATER || blockType == Material.STATIONARY_WATER; } + @Override + public SignType getSignType(Object sign) { + throw new UnsupportedOperationException("Not supported"); + } + @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { Block nmsBlock = CraftMagicNumbers.getBlock(block); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java index 44812ca075..12089aed3a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java @@ -6,11 +6,13 @@ import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; +import com.bgsoftware.superiorskyblock.world.SignType; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; +import org.bukkit.block.data.Directional; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -35,13 +37,21 @@ public SignsListener(SuperiorSkyblockPlugin plugin) { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) private void onSignPlace(SignChangeEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - String[] signLines = e.getLines().clone(); + String[] signLines; IslandSigns.Result result; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - result = IslandSigns.handleSignPlace(superiorPlayer, - e.getBlock().getLocation(wrapper.getHandle()), signLines, true); + Location warpLocation = e.getBlock().getLocation(wrapper.getHandle()); + SignType signType = plugin.getNMSWorld().getSignType(e.getBlock()); + + // Hanging signs are not allowed + if (signType == SignType.HANGING_SIGN || signType == SignType.HANGING_WALL_SIGN) + return; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + signLines = e.getLines().clone(); + + result = IslandSigns.handleSignPlace(superiorPlayer, warpLocation, signLines, true); } switch (result.getReason()) { case NOT_IN_ISLAND: @@ -92,14 +102,22 @@ public void onSignBreak(BlockBreakEvent e) { isSignGonnaBreak = sign.getAttachedFace().getOppositeFace() == blockFace; } else { Object blockData = plugin.getNMSWorld().getBlockData(faceBlock); - if (blockData instanceof org.bukkit.block.data.type.WallSign) { - // Wall signs will only be broken if they are attached to the block - isSignGonnaBreak = ((org.bukkit.block.data.type.WallSign) blockData).getFacing() == blockFace; - } else if (blockData instanceof org.bukkit.block.data.type.Sign) { - // Standing signs will only be broken if they are placed on top of the block - isSignGonnaBreak = blockFace == BlockFace.UP; - } else { - throw new RuntimeException("Found sign that cannot be handled: " + blockData); + switch (plugin.getNMSWorld().getSignType(blockData)) { + case WALL_SIGN: + // Wall signs will only be broken if they are attached to the block + isSignGonnaBreak = ((Directional) blockData).getFacing() == blockFace; + break; + case STANDING_SIGN: + // Standing signs will only be broken if they are placed on top of the block + isSignGonnaBreak = blockFace == BlockFace.UP; + break; + case HANGING_WALL_SIGN: + case HANGING_SIGN: + // Hanging signs are not allowed as warp signs + isSignGonnaBreak = false; + break; + default: + throw new RuntimeException("Found sign that cannot be handled: " + blockData); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java index 3b0b6cc830..fde0a0f48f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; @@ -34,6 +35,12 @@ public interface NMSWorld { boolean isWaterLogged(Block block); + default SignType getSignType(Block block) { + return getSignType(getBlockData(block)); + } + + SignType getSignType(Object sign); + PistonPushReaction getPistonReaction(Block block); int getDefaultAmount(Block block); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/SignType.java b/src/main/java/com/bgsoftware/superiorskyblock/world/SignType.java new file mode 100644 index 0000000000..da2c477f85 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/SignType.java @@ -0,0 +1,11 @@ +package com.bgsoftware.superiorskyblock.world; + +public enum SignType { + + STANDING_SIGN, + WALL_SIGN, + HANGING_WALL_SIGN, + HANGING_SIGN, + UNKNOWN + +} From e9114925d122df615dfd44e7b478924910a327cf Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 25 Jan 2025 17:19:21 +0200 Subject: [PATCH 056/600] Fix ender dragons that are not spawned naturally fly away from island (#2341) --- .../dragon/IslandEntityEnderDragon.java | 44 ++++++++++++------ .../dragon/IslandEntityEnderDragon.java | 45 +++++++++++++----- .../v1_17/dragon/IslandEntityEnderDragon.java | 46 ++++++++++++++----- .../v1_18/dragon/IslandEntityEnderDragon.java | 46 +++++++++++++------ .../v1_19/dragon/IslandEntityEnderDragon.java | 44 +++++++++++++----- .../dragon/IslandEntityEnderDragon.java | 44 +++++++++++++----- .../dragon/IslandEntityEnderDragon.java | 43 ++++++++++++----- .../v1_21/dragon/IslandEntityEnderDragon.java | 43 ++++++++++++----- .../dragon/IslandEntityEnderDragon.java | 43 ++++++++++++----- .../dragon/IslandEntityEnderDragon.java | 43 ++++++++++++----- 10 files changed, 317 insertions(+), 124 deletions(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java index 31fb5cb178..c4124f9334 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java @@ -1,13 +1,16 @@ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.server.v1_12_R1.BlockPosition; +import net.minecraft.server.v1_12_R1.DifficultyDamageScaler; import net.minecraft.server.v1_12_R1.EnderDragonBattle; import net.minecraft.server.v1_12_R1.EntityEnderDragon; +import net.minecraft.server.v1_12_R1.GroupDataEntity; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_12_R1.World; import net.minecraft.server.v1_12_R1.WorldProviderTheEnd; @@ -26,20 +29,41 @@ public class IslandEntityEnderDragon extends EntityEnderDragon { public IslandEntityEnderDragon(World world) { // Used when loading entities to the world. super(world); - this.islandBlockPosition = BlockPosition.ZERO; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world.getWorld()); } public IslandEntityEnderDragon(WorldServer worldServer, BlockPosition islandBlockPosition) { - super(worldServer); + this(worldServer); this.islandBlockPosition = islandBlockPosition; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld()); + } + + @Nullable + @Override + public GroupDataEntity prepare(DifficultyDamageScaler difficultydamagescaler, + @Nullable GroupDataEntity groupdataentity) { + if (this.islandBlockPosition == null) + finalizeIslandEnderDragon(); + + return super.prepare(difficultydamagescaler, groupdataentity); } @Override public void a(NBTTagCompound nbtTagCompound) { super.a(nbtTagCompound); + finalizeIslandEnderDragon(); + } + @Override + public void n() { + DragonUtils.runWithPodiumPosition(this.islandBlockPosition, super::n); + } + + @Override + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + + private void finalizeIslandEnderDragon() { if (!(world.worldProvider instanceof WorldProviderTheEnd) || !plugin.getGrid().isIslandsWorld(world.getWorld())) return; @@ -67,18 +91,8 @@ public void a(NBTTagCompound nbtTagCompound) { this.islandBlockPosition = new BlockPosition(middleBlock.getX(), middleBlock.getY(), middleBlock.getZ()); - dragonBattleHandler.addDragonBattle(island.getUniqueId(), new IslandEnderDragonBattle(island, - (WorldServer) world, this.islandBlockPosition, this)); - } - - @Override - public void n() { - DragonUtils.runWithPodiumPosition(this.islandBlockPosition, super::n); - } - - @Override - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); + IslandEnderDragonBattle dragonBattle = new IslandEnderDragonBattle(island, (WorldServer) world, this.islandBlockPosition, this); + dragonBattleHandler.addDragonBattle(island.getUniqueId(), dragonBattle); } } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java index 0465a99b06..bc186835c7 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java @@ -1,15 +1,20 @@ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.server.v1_16_R3.BlockPosition; +import net.minecraft.server.v1_16_R3.DifficultyDamageScaler; import net.minecraft.server.v1_16_R3.EntityEnderDragon; import net.minecraft.server.v1_16_R3.EntityTypes; +import net.minecraft.server.v1_16_R3.EnumMobSpawn; +import net.minecraft.server.v1_16_R3.GroupDataEntity; import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.World; +import net.minecraft.server.v1_16_R3.WorldAccess; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEnderDragon; @@ -36,10 +41,36 @@ private IslandEntityEnderDragon(World world) { this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world.getWorld()); } + @Nullable + @Override + public GroupDataEntity prepare(WorldAccess worldaccess, + DifficultyDamageScaler difficultydamagescaler, + EnumMobSpawn enummobspawn, + @Nullable GroupDataEntity groupdataentity, + @Nullable NBTTagCompound nbttagcompound) { + if (this.islandBlockPosition == null) + finalizeIslandEnderDragon(); + + return super.prepare(worldaccess, difficultydamagescaler, enummobspawn, groupdataentity, nbttagcompound); + } + @Override public void loadData(NBTTagCompound nbtTagCompound) { super.loadData(nbtTagCompound); + finalizeIslandEnderDragon(); + } + + @Override + public void movementTick() { + DragonUtils.runWithPodiumPosition(this.islandBlockPosition, super::movementTick); + } + + @Override + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + private void finalizeIslandEnderDragon() { if (!(world instanceof WorldServer) || !(((WorldServer) world).getDragonBattle() instanceof EndWorldEnderDragonBattleHandler)) return; @@ -62,18 +93,8 @@ public void loadData(NBTTagCompound nbtTagCompound) { this.islandBlockPosition = new BlockPosition(middleBlock.getX(), middleBlock.getY(), middleBlock.getZ()); - dragonBattleHandler.addDragonBattle(island.getUniqueId(), new IslandEnderDragonBattle(island, - (WorldServer) world, this.islandBlockPosition, this)); - } - - @Override - public void movementTick() { - DragonUtils.runWithPodiumPosition(this.islandBlockPosition, super::movementTick); - } - - @Override - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); + IslandEnderDragonBattle dragonBattle = new IslandEnderDragonBattle(island, (WorldServer) world, this.islandBlockPosition, this); + dragonBattleHandler.addDragonBattle(island.getUniqueId(), dragonBattle); } } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java index 84275be852..9bb1d3cf96 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.nms.v1_17.dragon; import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -9,9 +10,13 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobSpawnType; +import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEnderDragon; @@ -40,10 +45,37 @@ private IslandEntityEnderDragon(Level level) { this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); } + @Nullable @Override - public void readAdditionalSaveData(CompoundTag compoundTag) { + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, + DifficultyInstance difficulty, + MobSpawnType spawnReason, + @Nullable SpawnGroupData entityData, + @Nullable CompoundTag entityNbt) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); + } + + @Override + public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { + // loadData super.readAdditionalSaveData(compoundTag); + finalizeIslandEnderDragon(); + } + + @Override + public void aiStep() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); + } + + @Override + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + private void finalizeIslandEnderDragon() { if (!(this.serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; @@ -62,20 +94,10 @@ public void readAdditionalSaveData(CompoundTag compoundTag) { middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); } - this.islandBlockPos = new BlockPos(middleBlock.getX(), middleBlock.getY(), middleBlock.getZ()); + this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java index 6c0730b063..bd6f9bfa5d 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.nms.v1_18.dragon; import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -9,9 +10,13 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobSpawnType; +import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEnderDragon; @@ -40,12 +45,38 @@ private IslandEntityEnderDragon(Level level) { this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); } + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, + DifficultyInstance difficulty, + MobSpawnType spawnReason, + @Nullable SpawnGroupData entityData, + @Nullable CompoundTag entityNbt) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); + } + @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData - super.readAdditionalSaveData(compoundTag); + finalizeIslandEnderDragon(); + } + + @Override + public void aiStep() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); + } + @Override + @NotNull + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + + private void finalizeIslandEnderDragon() { if (!(this.serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; @@ -64,21 +95,10 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); } - this.islandBlockPos = new BlockPos(middleBlock.getX(), middleBlock.getY(), middleBlock.getZ()); + this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java index 91458b9c6a..eba35bc0cd 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.nms.v1_19.dragon; import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -9,9 +10,13 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobSpawnType; +import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEnderDragon; @@ -40,12 +45,38 @@ private IslandEntityEnderDragon(Level level) { this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); } + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, + DifficultyInstance difficulty, + MobSpawnType spawnReason, + @Nullable SpawnGroupData entityData, + @Nullable CompoundTag entityNbt) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); + } + @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData - super.readAdditionalSaveData(compoundTag); + finalizeIslandEnderDragon(); + } + + @Override + public void aiStep() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); + } + @Override + @NotNull + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + + private void finalizeIslandEnderDragon() { if (!(this.serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; @@ -70,15 +101,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java index 73b1e0a12e..fa065d33d9 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon; import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -9,9 +10,13 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobSpawnType; +import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEnderDragon; @@ -40,12 +45,38 @@ private IslandEntityEnderDragon(Level level) { this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); } + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, + DifficultyInstance difficulty, + MobSpawnType spawnReason, + @Nullable SpawnGroupData entityData, + @Nullable CompoundTag entityNbt) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt); + } + @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData - super.readAdditionalSaveData(compoundTag); + finalizeIslandEnderDragon(); + } + + @Override + public void aiStep() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); + } + @Override + @NotNull + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + + private void finalizeIslandEnderDragon() { if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; @@ -70,15 +101,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java index 81d872c157..21e0019736 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon; import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -9,9 +10,13 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobSpawnType; +import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; import org.bukkit.Location; import org.bukkit.craftbukkit.entity.CraftEnderDragon; @@ -40,12 +45,37 @@ private IslandEntityEnderDragon(Level level) { this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); } + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, + DifficultyInstance difficulty, + MobSpawnType spawnReason, + @Nullable SpawnGroupData entityData) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(world, difficulty, spawnReason, entityData); + } + @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData - super.readAdditionalSaveData(compoundTag); + finalizeIslandEnderDragon(); + } + + @Override + public void aiStep() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); + } + @Override + @NotNull + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + + private void finalizeIslandEnderDragon() { if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; @@ -70,15 +100,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java index 7744728076..54989c98cd 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.nms.v1_21.dragon; import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -9,9 +10,13 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobSpawnType; +import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; import org.bukkit.Location; import org.bukkit.craftbukkit.entity.CraftEnderDragon; @@ -40,12 +45,37 @@ private IslandEntityEnderDragon(Level level) { this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); } + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, + DifficultyInstance difficulty, + MobSpawnType spawnReason, + @Nullable SpawnGroupData entityData) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(world, difficulty, spawnReason, entityData); + } + @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData - super.readAdditionalSaveData(compoundTag); + finalizeIslandEnderDragon(); + } + + @Override + public void aiStep() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); + } + @Override + @NotNull + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + + private void finalizeIslandEnderDragon() { if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; @@ -70,15 +100,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java index de18b783f5..4ce6ede51f 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon; import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -9,9 +10,13 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; import org.bukkit.Location; import org.bukkit.craftbukkit.entity.CraftEnderDragon; @@ -40,12 +45,37 @@ private IslandEntityEnderDragon(Level level) { this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); } + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, + DifficultyInstance difficulty, + EntitySpawnReason spawnReason, + @Nullable SpawnGroupData spawnGroupData) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + } + @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData - super.readAdditionalSaveData(compoundTag); + finalizeIslandEnderDragon(); + } + + @Override + public void aiStep() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); + } + @Override + @NotNull + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + + private void finalizeIslandEnderDragon() { if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; @@ -70,15 +100,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java index f605697413..2cb6571990 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -9,9 +10,13 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; import org.bukkit.Location; import org.bukkit.craftbukkit.entity.CraftEnderDragon; @@ -40,12 +45,37 @@ private IslandEntityEnderDragon(Level level) { this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); } + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, + DifficultyInstance difficulty, + EntitySpawnReason spawnReason, + @Nullable SpawnGroupData spawnGroupData) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + } + @Override public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { // loadData - super.readAdditionalSaveData(compoundTag); + finalizeIslandEnderDragon(); + } + + @Override + public void aiStep() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); + } + @Override + @NotNull + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + + private void finalizeIslandEnderDragon() { if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) return; @@ -70,15 +100,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - } From 6f093412c7e5c34352cadc5dc40d0b0520ff48b3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 30 Jan 2025 22:26:45 +0200 Subject: [PATCH 057/600] Change glow effect to work with enchantment_glint_override instead of actual enchantment --- .../nms/v1_12_R1/NMSAlgorithmsImpl.java | 72 +++++++- .../v1_12_R1/algorithms/GlowEnchantment.java | 60 ------- .../nms/v1_16_R3/NMSAlgorithmsImpl.java | 36 +++- .../nms/v1_17/NMSAlgorithmsImpl.java | 36 +++- .../nms/v1_18/NMSAlgorithmsImpl.java | 36 +++- .../nms/v1_19/NMSAlgorithmsImpl.java | 36 +++- .../nms/v1_20_3/NMSAlgorithmsImpl.java | 37 ++-- .../nms/v1_20_4/NMSAlgorithmsImpl.java | 12 +- .../nms/v1_21/NMSAlgorithmsImpl.java | 25 +-- .../v1_21/enchantment/GlowEnchantment.java | 62 ------- .../nms/v1_21_3/NMSAlgorithmsImpl.java | 25 +-- .../v1_21_3/enchantment/GlowEnchantment.java | 113 ------------ .../nms/v1_21_4/NMSAlgorithmsImpl.java | 37 +--- .../v1_21_4/enchantment/GlowEnchantment.java | 166 ------------------ .../nms/v1_8_R3/NMSAlgorithmsImpl.java | 62 ++++++- .../v1_8_R3/algorithms/GlowEnchantment.java | 52 ------ .../SuperiorSkyblockPlugin.java | 3 - .../core/io/MenuParserImpl.java | 5 +- .../core/itemstack/GlowEnchantment.java | 28 --- .../core/itemstack/ItemBuilder.java | 5 + .../core/menu/button/impl/BiomeButton.java | 12 +- .../button/impl/ChangeSortingTypeButton.java | 12 +- .../superiorskyblock/nms/NMSAlgorithms.java | 28 +-- 23 files changed, 289 insertions(+), 671 deletions(-) delete mode 100644 NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/algorithms/GlowEnchantment.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/enchantment/GlowEnchantment.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/enchantment/GlowEnchantment.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java delete mode 100644 NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/algorithms/GlowEnchantment.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/GlowEnchantment.java diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java index 65fcc03e29..3449a12dfc 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java @@ -5,7 +5,6 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_12_R1.algorithms.GlowEnchantment; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.KeyBlocksCache; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockPosition; @@ -28,6 +27,7 @@ import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_12_R1.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; +import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.entity.FallingBlock; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; @@ -35,10 +35,13 @@ import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionEffect; +import java.lang.reflect.Field; import java.util.Optional; public class NMSAlgorithmsImpl implements NMSAlgorithms { + private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); + private final SuperiorSkyblockPlugin plugin; public NMSAlgorithmsImpl(SuperiorSkyblockPlugin plugin) { @@ -114,8 +117,8 @@ public String getMinecraftKey(org.bukkit.inventory.ItemStack itemStack) { } @Override - public Enchantment getGlowEnchant() { - return GlowEnchantment.createEnchantment(); + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Override @@ -144,4 +147,67 @@ public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHo return defaultHolder; } + private static Enchantment initializeGlowEnchantment() { + int enchantId = 100; + while (Enchantment.getById(enchantId) != null) + ++enchantId; + + Enchantment glowEnchant = new Enchantment(enchantId) { + @Override + public String getName() { + return "WildBusterGlow"; + } + + @Override + public int getMaxLevel() { + return 1; + } + + @Override + public int getStartLevel() { + return 0; + } + + @Override + public EnchantmentTarget getItemTarget() { + return null; + } + + @Override + public boolean isTreasure() { + return false; + } + + @Override + public boolean isCursed() { + return false; + } + + @Override + public boolean conflictsWith(Enchantment enchantment) { + return false; + } + + @Override + public boolean canEnchantItem(org.bukkit.inventory.ItemStack itemStack) { + return true; + } + }; + + try { + Field field = Enchantment.class.getDeclaredField("acceptingNew"); + field.setAccessible(true); + field.set(null, true); + field.setAccessible(false); + } catch (Exception ignored) { + } + + try { + Enchantment.registerEnchantment(glowEnchant); + } catch (Exception ignored) { + } + + return glowEnchant; + } + } diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/algorithms/GlowEnchantment.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/algorithms/GlowEnchantment.java deleted file mode 100644 index b0a529cc2c..0000000000 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/algorithms/GlowEnchantment.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_12_R1.algorithms; - -import org.bukkit.enchantments.Enchantment; -import org.bukkit.enchantments.EnchantmentTarget; - -public class GlowEnchantment extends Enchantment { - - private GlowEnchantment(int id) { - super(id); - } - - public static GlowEnchantment createEnchantment() { - int id = 100; - - //noinspection deprecation, StatementWithEmptyBody - while (Enchantment.getById(++id) != null) { - } - - return new GlowEnchantment(id); - } - - @Override - public String getName() { - return "SuperiorSkyblockGlow"; - } - - @Override - public int getMaxLevel() { - return 1; - } - - @Override - public int getStartLevel() { - return 0; - } - - @Override - public EnchantmentTarget getItemTarget() { - return null; - } - - public boolean isTreasure() { - return false; - } - - public boolean isCursed() { - return false; - } - - @Override - public boolean conflictsWith(Enchantment enchantment) { - return false; - } - - @Override - public boolean canEnchantItem(org.bukkit.inventory.ItemStack itemStack) { - return true; - } - -} diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java index c9c890c93c..72c0388fcb 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java @@ -52,6 +52,7 @@ import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; +import java.lang.reflect.Field; import java.util.EnumMap; import java.util.function.BiFunction; @@ -59,6 +60,8 @@ public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { @@ -160,12 +163,8 @@ public String getMinecraftKey(ItemStack itemStack) { } @Override - public Enchantment getGlowEnchant() { - try { - return new PaperGlowEnchantment("superior_glowing_enchant"); - } catch (Throwable error) { - return new SpigotGlowEnchantment("superior_glowing_enchant"); - } + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Override @@ -208,6 +207,31 @@ public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHo return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); } + private static Enchantment initializeGlowEnchantment() { + Enchantment glowEnchant; + + try { + glowEnchant = new PaperGlowEnchantment("superiorskyblock_glowing_enchant"); + } catch (Throwable error) { + glowEnchant = new SpigotGlowEnchantment("superiorskyblock_glowing_enchant"); + } + + try { + Field field = Enchantment.class.getDeclaredField("acceptingNew"); + field.setAccessible(true); + field.set(null, true); + field.setAccessible(false); + } catch (Exception ignored) { + } + + try { + Enchantment.registerEnchantment(glowEnchant); + } catch (Exception ignored) { + } + + return glowEnchant; + } + private interface MenuCreator extends BiFunction { } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java index 8a9cfa2280..ea79670fbe 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java @@ -51,6 +51,7 @@ import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; +import java.lang.reflect.Field; import java.util.EnumMap; import java.util.function.BiFunction; @@ -58,6 +59,8 @@ public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { @@ -164,12 +167,8 @@ public String getMinecraftKey(ItemStack itemStack) { } @Override - public Enchantment getGlowEnchant() { - try { - return new PaperGlowEnchantment("superior_glowing_enchant"); - } catch (Throwable error) { - return new SpigotGlowEnchantment("superior_glowing_enchant"); - } + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Override @@ -212,6 +211,31 @@ public void handlePaperChatRenderer(Object event) { asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); } + private static Enchantment initializeGlowEnchantment() { + Enchantment glowEnchant; + + try { + glowEnchant = new PaperGlowEnchantment("superiorskyblock_glowing_enchant"); + } catch (Throwable error) { + glowEnchant = new SpigotGlowEnchantment("superiorskyblock_glowing_enchant"); + } + + try { + Field field = Enchantment.class.getDeclaredField("acceptingNew"); + field.setAccessible(true); + field.set(null, true); + field.setAccessible(false); + } catch (Exception ignored) { + } + + try { + Enchantment.registerEnchantment(glowEnchant); + } catch (Exception ignored) { + } + + return glowEnchant; + } + private interface MenuCreator extends BiFunction { } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java index 8721bf7172..ba31eb7c78 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java @@ -52,6 +52,7 @@ import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; +import java.lang.reflect.Field; import java.util.EnumMap; import java.util.function.BiFunction; @@ -59,6 +60,8 @@ public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { @@ -165,12 +168,8 @@ public String getMinecraftKey(ItemStack itemStack) { } @Override - public Enchantment getGlowEnchant() { - try { - return new PaperGlowEnchantment("superior_glowing_enchant"); - } catch (Throwable error) { - return new SpigotGlowEnchantment("superior_glowing_enchant"); - } + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Override @@ -214,6 +213,31 @@ public void handlePaperChatRenderer(Object event) { asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); } + private static Enchantment initializeGlowEnchantment() { + Enchantment glowEnchant; + + try { + glowEnchant = new PaperGlowEnchantment("superiorskyblock_glowing_enchant"); + } catch (Throwable error) { + glowEnchant = new SpigotGlowEnchantment("superiorskyblock_glowing_enchant"); + } + + try { + Field field = Enchantment.class.getDeclaredField("acceptingNew"); + field.setAccessible(true); + field.set(null, true); + field.setAccessible(false); + } catch (Exception ignored) { + } + + try { + Enchantment.registerEnchantment(glowEnchant); + } catch (Exception ignored) { + } + + return glowEnchant; + } + private interface MenuCreator extends BiFunction { } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java index fc2feacb91..32922cf711 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java @@ -52,6 +52,7 @@ import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; +import java.lang.reflect.Field; import java.util.EnumMap; import java.util.function.BiFunction; @@ -59,6 +60,8 @@ public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { @@ -165,12 +168,8 @@ public String getMinecraftKey(ItemStack itemStack) { } @Override - public Enchantment getGlowEnchant() { - try { - return new PaperGlowEnchantment("superior_glowing_enchant"); - } catch (Throwable error) { - return new SpigotGlowEnchantment("superior_glowing_enchant"); - } + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Nullable @@ -214,6 +213,31 @@ public void handlePaperChatRenderer(Object event) { asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); } + private static Enchantment initializeGlowEnchantment() { + Enchantment glowEnchant; + + try { + glowEnchant = new PaperGlowEnchantment("superiorskyblock_glowing_enchant"); + } catch (Throwable error) { + glowEnchant = new SpigotGlowEnchantment("superiorskyblock_glowing_enchant"); + } + + try { + Field field = Enchantment.class.getDeclaredField("acceptingNew"); + field.setAccessible(true); + field.set(null, true); + field.setAccessible(false); + } catch (Exception ignored) { + } + + try { + Enchantment.registerEnchantment(glowEnchant); + } catch (Exception ignored) { + } + + return glowEnchant; + } + private interface MenuCreator extends BiFunction { } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java index b47e1c7e92..2d51e5de22 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java @@ -67,6 +67,8 @@ public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final ReflectField> REGISTRY_CACHE = new ReflectField<>(CraftRegistry.class, Map.class, "cache"); + private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { @@ -173,23 +175,8 @@ public String getMinecraftKey(ItemStack itemStack) { } @Override - public Enchantment getGlowEnchant() { - try { - return new PaperGlowEnchantment("superior_glowing_enchant"); - } catch (Throwable error) { - return new SpigotGlowEnchantment("superior_glowing_enchant"); - } - } - - @Override - public Enchantment createGlowEnchantment() { - Enchantment enchantment = getGlowEnchant(); - - Map registryCache = REGISTRY_CACHE.get(Registry.ENCHANTMENT); - - registryCache.put(enchantment.getKey(), enchantment); - - return enchantment; + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Nullable @@ -233,6 +220,22 @@ public void handlePaperChatRenderer(Object event) { asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); } + private static Enchantment initializeGlowEnchantment() { + Enchantment glowEnchant; + + try { + glowEnchant = new PaperGlowEnchantment("superiorskyblock_glowing_enchant"); + } catch (Throwable error) { + glowEnchant = new SpigotGlowEnchantment("superiorskyblock_glowing_enchant"); + } + + Map registryCache = REGISTRY_CACHE.get(Registry.ENCHANTMENT); + + registryCache.put(glowEnchant.getKey(), glowEnchant); + + return glowEnchant; + } + private interface MenuCreator extends BiFunction { } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java index bf950823a2..c5d677135c 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java @@ -43,7 +43,6 @@ import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; @@ -170,15 +169,8 @@ public String getMinecraftKey(ItemStack itemStack) { } @Override - public Enchantment getGlowEnchant() { - // Not supported anymore - return null; - } - - @Override - public Enchantment createGlowEnchantment() { - // Not supported anymore - return null; + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.setEnchantmentGlintOverride(true); } @Nullable diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java index 6dfea17088..e109371b2e 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_21; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -11,7 +10,6 @@ import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_21.enchantment.GlowEnchantment; import com.bgsoftware.superiorskyblock.nms.v1_21.menu.MenuBrewingStandBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21.menu.MenuFurnaceBlockEntity; @@ -36,12 +34,9 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Registry; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.entity.CraftFallingBlock; @@ -49,7 +44,6 @@ import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; @@ -61,16 +55,12 @@ import org.jetbrains.annotations.NotNull; import java.util.EnumMap; -import java.util.Map; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectField> REGISTRY_CACHE = - new ReflectField<>(CraftRegistry.class, Map.class, "cache"); - private static final Multimap EMPTY_ATTRIBUTES_MAP = MultimapBuilder.hashKeys().hashSetValues().build(); @@ -180,19 +170,8 @@ public String getMinecraftKey(ItemStack itemStack) { } @Override - public Enchantment getGlowEnchant() { - return new GlowEnchantment(); - } - - @Override - public Enchantment createGlowEnchantment() { - Enchantment enchantment = getGlowEnchant(); - - Map registryCache = REGISTRY_CACHE.get(Registry.ENCHANTMENT); - - registryCache.put(enchantment.getKey(), enchantment); - - return enchantment; + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.setEnchantmentGlintOverride(true); } @Nullable diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/enchantment/GlowEnchantment.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/enchantment/GlowEnchantment.java deleted file mode 100644 index 00e260e300..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/enchantment/GlowEnchantment.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.enchantment; - -import com.bgsoftware.common.reflection.ReflectField; -import net.minecraft.core.HolderSet; -import net.minecraft.core.MappedRegistry; -import net.minecraft.core.Registry; -import net.minecraft.core.component.DataComponentMap; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.world.item.enchantment.Enchantment; -import org.bukkit.NamespacedKey; -import org.bukkit.craftbukkit.enchantments.CraftEnchantment; - -import java.lang.reflect.Modifier; - -public class GlowEnchantment extends CraftEnchantment { - - private static final ReflectField REGISTRY_FROZEN = new ReflectField<>( - MappedRegistry.class, boolean.class, Modifier.PRIVATE, 1); - - private static final String GLOW_ENCHANTMENT_NAME = "superiorskyblock_glowing_enchant"; - - private static final Enchantment HANDLE = initializeHandle(); - - private static Enchantment initializeHandle() { - Enchantment handle = new Enchantment( - Component.empty(), - Enchantment.definition( - HolderSet.empty(), - 1, - 1, - Enchantment.constantCost(0), - Enchantment.constantCost(0), - 0), - HolderSet.empty(), - DataComponentMap.EMPTY - ); - - MinecraftServer.getServer().registryAccess().registry(Registries.ENCHANTMENT).ifPresent(registry -> { - try { - REGISTRY_FROZEN.set(registry, false); - try { - // This may throw IllegalStateException which we don't care about. - registry.createIntrusiveHolder(handle); - } catch (Throwable ignored) { - } - Registry.register(registry, ResourceLocation.withDefaultNamespace(GLOW_ENCHANTMENT_NAME), handle); - } finally { - registry.freeze(); - } - }); - - return handle; - } - - public GlowEnchantment() { - super(NamespacedKey.minecraft(GLOW_ENCHANTMENT_NAME), HANDLE); - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java index f4b5fddef9..627c534dec 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_3; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -11,7 +10,6 @@ import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.enchantment.GlowEnchantment; import com.bgsoftware.superiorskyblock.nms.v1_21_3.menu.MenuBrewingStandBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_3.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_3.menu.MenuFurnaceBlockEntity; @@ -36,12 +34,9 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Registry; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.entity.CraftFallingBlock; @@ -49,7 +44,6 @@ import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; @@ -61,16 +55,12 @@ import org.jetbrains.annotations.NotNull; import java.util.EnumMap; -import java.util.Map; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectField> REGISTRY_CACHE = - new ReflectField<>(CraftRegistry.class, Map.class, "cache"); - private static final Multimap EMPTY_ATTRIBUTES_MAP = MultimapBuilder.hashKeys().hashSetValues().build(); @@ -180,19 +170,8 @@ public String getMinecraftKey(ItemStack itemStack) { } @Override - public Enchantment getGlowEnchant() { - return new GlowEnchantment(); - } - - @Override - public Enchantment createGlowEnchantment() { - Enchantment enchantment = getGlowEnchant(); - - Map registryCache = REGISTRY_CACHE.get(Registry.ENCHANTMENT); - - registryCache.put(enchantment.getKey(), enchantment); - - return enchantment; + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.setEnchantmentGlintOverride(true); } @Nullable diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/enchantment/GlowEnchantment.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/enchantment/GlowEnchantment.java deleted file mode 100644 index dadbe5e5a2..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/enchantment/GlowEnchantment.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.enchantment; - -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; -import net.minecraft.core.HolderSet; -import net.minecraft.core.MappedRegistry; -import net.minecraft.core.Registry; -import net.minecraft.core.component.DataComponentMap; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.tags.TagKey; -import net.minecraft.world.item.enchantment.Enchantment; -import org.bukkit.NamespacedKey; -import org.bukkit.craftbukkit.enchantments.CraftEnchantment; - -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.Map; - -public class GlowEnchantment extends CraftEnchantment { - - private static final ReflectField REGISTRY_FROZEN = new ReflectField<>( - MappedRegistry.class, boolean.class, Modifier.PRIVATE, 1); - - private static final ReflectField REGISTRY_ALL_TAGS = new ReflectField<>( - MappedRegistry.class, Object.class, "k"); - - private static final ReflectField, HolderSet.Named>> REGISTRY_FROZEN_TAGS = new ReflectField<>( - MappedRegistry.class, Map.class, Modifier.PRIVATE | Modifier.FINAL, 6); - - private static final ReflectMethod REGISTRY_TAG_SET_UNBOUND; - - static { - Class tagSetClass = MappedRegistry.class.getDeclaredClasses()[0]; - if (!tagSetClass.isInterface()) - throw new IllegalStateException("TagSet was not found, but " + tagSetClass); - - REGISTRY_TAG_SET_UNBOUND = new ReflectMethod<>(tagSetClass, tagSetClass, 1, new Class[0]); - } - - private static final String GLOW_ENCHANTMENT_NAME = "superiorskyblock_glowing_enchant"; - - private static final Enchantment HANDLE = initializeHandle(); - - private static Enchantment initializeHandle() { - Enchantment handle = new Enchantment( - Component.empty(), - Enchantment.definition( - HolderSet.empty(), - 1, - 1, - Enchantment.constantCost(0), - Enchantment.constantCost(0), - 0), - HolderSet.empty(), - DataComponentMap.EMPTY - ); - - MinecraftServer.getServer().registryAccess().lookup(Registries.ENCHANTMENT).ifPresent(registry -> { - try { - REGISTRY_FROZEN.set(registry, false); - try { - // This may throw IllegalStateException which we don't care about. - registry.createIntrusiveHolder(handle); - } catch (Throwable ignored) { - } - Registry.register(registry, ResourceLocation.withDefaultNamespace(GLOW_ENCHANTMENT_NAME), handle); - } finally { - freezeRegistry(registry); - } - }); - - return handle; - } - - private static void freezeRegistry(Registry registry) { - try { - freezeRegistryUnsafe(registry); - } catch (Throwable error) { - throw new RuntimeException(error); - } - } - - private static void freezeRegistryUnsafe(Registry registry) throws Exception { - Object allTags = REGISTRY_ALL_TAGS.get(registry); - - Field tagSetMapsField = allTags.getClass().getDeclaredFields()[0]; - tagSetMapsField.setAccessible(true); - - Map, HolderSet.Named> tagsMap = - (Map, HolderSet.Named>) tagSetMapsField.get(allTags); - Map, HolderSet.Named> frozenTags = REGISTRY_FROZEN_TAGS.get(registry); - - tagsMap.forEach(frozenTags::putIfAbsent); - - Object unboundTagSet = REGISTRY_TAG_SET_UNBOUND.invoke(registry); - REGISTRY_ALL_TAGS.set(registry, unboundTagSet); - - registry.freeze(); - - frozenTags.forEach(tagsMap::putIfAbsent); - - tagSetMapsField.set(allTags, tagsMap); - REGISTRY_ALL_TAGS.set(registry, allTags); - } - - public GlowEnchantment() { - super(NamespacedKey.minecraft(GLOW_ENCHANTMENT_NAME), HANDLE); - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index f67eb43fe2..bc113cc6a8 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_4; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -11,7 +10,6 @@ import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.enchantment.GlowEnchantment; import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuBrewingStandBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuFurnaceBlockEntity; @@ -36,12 +34,9 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Registry; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.CraftRegistry; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.entity.CraftFallingBlock; @@ -49,7 +44,6 @@ import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; @@ -61,16 +55,12 @@ import org.jetbrains.annotations.NotNull; import java.util.EnumMap; -import java.util.Map; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectField> REGISTRY_CACHE = - new ReflectField<>(CraftRegistry.class, Map.class, "cache"); - private static final Multimap EMPTY_ATTRIBUTES_MAP = MultimapBuilder.hashKeys().hashSetValues().build(); @@ -180,31 +170,8 @@ public String getMinecraftKey(ItemStack itemStack) { } @Override - public Enchantment getGlowEnchant() { - return GlowEnchantment.createEnchantment(); - } - - @Override - public Enchantment createGlowEnchantment() { - Enchantment enchantment = Registry.ENCHANTMENT.get(GlowEnchantment.GLOW_ENCHANTMENT_KEY); - if (enchantment != null) - return enchantment; - - enchantment = getGlowEnchant(); - - Registry registry = Registry.ENCHANTMENT; - try { - if (registry instanceof io.papermc.paper.registry.legacy.DelayedRegistry) { - registry = ((io.papermc.paper.registry.legacy.DelayedRegistry) registry).delegate(); - } - } catch (Throwable ignored) { - } - - Map registryCache = REGISTRY_CACHE.get(registry); - - registryCache.put(enchantment.getKey(), enchantment); - - return enchantment; + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.setEnchantmentGlintOverride(true); } @Nullable diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java deleted file mode 100644 index 42b04eb573..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/enchantment/GlowEnchantment.java +++ /dev/null @@ -1,166 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.enchantment; - -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; -import net.minecraft.core.Holder; -import net.minecraft.core.HolderSet; -import net.minecraft.core.MappedRegistry; -import net.minecraft.core.Registry; -import net.minecraft.core.component.DataComponentMap; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.minecraft.tags.TagKey; -import net.minecraft.world.item.enchantment.Enchantment; -import org.bukkit.NamespacedKey; -import org.bukkit.craftbukkit.enchantments.CraftEnchantment; - -import javax.annotation.Nullable; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.Map; - -public class GlowEnchantment { - - private static final ReflectField REGISTRY_FROZEN = new ReflectField<>( - MappedRegistry.class, boolean.class, Modifier.PRIVATE, 1); - - private static final ReflectField REGISTRY_ALL_TAGS = new ReflectField<>( - MappedRegistry.class, Object.class, "k"); - - private static final ReflectField, HolderSet.Named>> REGISTRY_FROZEN_TAGS = new ReflectField<>( - MappedRegistry.class, Map.class, Modifier.PRIVATE | Modifier.FINAL, 6); - - private static final ReflectMethod REGISTRY_TAG_SET_UNBOUND; - - static { - Class tagSetClass = MappedRegistry.class.getDeclaredClasses()[0]; - if (!tagSetClass.isInterface()) - throw new IllegalStateException("TagSet was not found, but " + tagSetClass); - - REGISTRY_TAG_SET_UNBOUND = new ReflectMethod<>(tagSetClass, tagSetClass, 1, new Class[0]); - } - - private static final String GLOW_ENCHANTMENT_NAME = "superiorskyblock_glowing_enchant"; - public static final NamespacedKey GLOW_ENCHANTMENT_KEY = NamespacedKey.minecraft(GLOW_ENCHANTMENT_NAME); - - private static final HandleType HANDLE_TYPE = findHandleType(); - - private static final Object HANDLE = initializeHandle(); - - @Nullable - private static Object initializeHandle() { - Registry registry = MinecraftServer.getServer().registryAccess() - .lookup(Registries.ENCHANTMENT).orElse(null); - - if (registry == null) - return null; - - Enchantment handle = new Enchantment( - Component.empty(), - Enchantment.definition( - HolderSet.empty(), - 1, - 1, - Enchantment.constantCost(0), - Enchantment.constantCost(0), - 0), - HolderSet.empty(), - DataComponentMap.EMPTY - ); - - Holder holder; - - try { - REGISTRY_FROZEN.set(registry, false); - try { - // This may throw IllegalStateException which we don't care about. - registry.createIntrusiveHolder(handle); - } catch (Throwable ignored) { - } - holder = Registry.registerForHolder(registry, ResourceLocation.withDefaultNamespace(GLOW_ENCHANTMENT_NAME), handle); - } finally { - freezeRegistry(registry); - } - - return switch (HANDLE_TYPE) { - case HOLDER -> holder; - case RAW -> handle; - default -> throw new IllegalStateException("Cannot find valid handle type for enchantments"); - }; - } - - private static void freezeRegistry(Registry registry) { - try { - freezeRegistryUnsafe(registry); - } catch (Throwable error) { - throw new RuntimeException(error); - } - } - - private static void freezeRegistryUnsafe(Registry registry) throws Exception { - Object allTags = REGISTRY_ALL_TAGS.get(registry); - - Field tagSetMapsField = allTags.getClass().getDeclaredFields()[0]; - tagSetMapsField.setAccessible(true); - - Map, HolderSet.Named> tagsMap = - (Map, HolderSet.Named>) tagSetMapsField.get(allTags); - Map, HolderSet.Named> frozenTags = REGISTRY_FROZEN_TAGS.get(registry); - - tagsMap.forEach(frozenTags::putIfAbsent); - - Object unboundTagSet = REGISTRY_TAG_SET_UNBOUND.invoke(registry); - REGISTRY_ALL_TAGS.set(registry, unboundTagSet); - - registry.freeze(); - - frozenTags.forEach(tagsMap::putIfAbsent); - - tagSetMapsField.set(allTags, tagsMap); - REGISTRY_ALL_TAGS.set(registry, allTags); - } - - private static HandleType findHandleType() { - Constructor constructor = CraftEnchantment.class.getConstructors()[0]; - - if (constructor.getParameterCount() == 1 && constructor.getParameterTypes()[0] == Holder.class) { - return HandleType.HOLDER; - } else if (constructor.getParameterCount() == 2 && constructor.getParameterTypes()[0] == NamespacedKey.class && - constructor.getParameterTypes()[1] == Enchantment.class) { - return HandleType.RAW; - } else { - return HandleType.UNKNOWN; - } - } - - public static CraftEnchantment createEnchantment() { - Constructor constructor = CraftEnchantment.class.getConstructors()[0]; - - try { - return switch (HANDLE_TYPE) { - case HOLDER -> (CraftEnchantment) constructor.newInstance(HANDLE); - case RAW -> - (CraftEnchantment) constructor.newInstance(NamespacedKey.minecraft(GLOW_ENCHANTMENT_NAME), HANDLE); - default -> throw new IllegalStateException("Cannot find valid handle type for enchantments"); - }; - } catch (Throwable error) { - throw new RuntimeException(error); - } - } - - private GlowEnchantment() { - - } - - private enum HandleType { - - HOLDER, - RAW, - UNKNOWN - - } - -} diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java index 10a90bd311..a7c7f1c8d2 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java @@ -5,7 +5,6 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_8_R3.algorithms.GlowEnchantment; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.KeyBlocksCache; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockPosition; @@ -28,6 +27,7 @@ import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_8_R3.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; +import org.bukkit.enchantments.EnchantmentTarget; import org.bukkit.entity.FallingBlock; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; @@ -35,10 +35,13 @@ import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionEffect; +import java.lang.reflect.Field; import java.util.Optional; public class NMSAlgorithmsImpl implements NMSAlgorithms { + private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); + private final SuperiorSkyblockPlugin plugin; public NMSAlgorithmsImpl(SuperiorSkyblockPlugin plugin) { @@ -112,8 +115,8 @@ public String getMinecraftKey(org.bukkit.inventory.ItemStack itemStack) { } @Override - public Enchantment getGlowEnchant() { - return GlowEnchantment.createEnchantment(); + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } @Override @@ -137,4 +140,57 @@ public int getDataVersion() { return -1; } + private static Enchantment initializeGlowEnchantment() { + int enchantId = 100; + while (Enchantment.getById(enchantId) != null) + ++enchantId; + + Enchantment glowEnchant = new Enchantment(enchantId) { + @Override + public String getName() { + return "SuperiorSkyblockGlow"; + } + + @Override + public int getMaxLevel() { + return 1; + } + + @Override + public int getStartLevel() { + return 0; + } + + @Override + public EnchantmentTarget getItemTarget() { + return null; + } + + @Override + public boolean conflictsWith(Enchantment enchantment) { + return false; + } + + @Override + public boolean canEnchantItem(org.bukkit.inventory.ItemStack itemStack) { + return true; + } + }; + + try { + Field field = Enchantment.class.getDeclaredField("acceptingNew"); + field.setAccessible(true); + field.set(null, true); + field.setAccessible(false); + } catch (Exception ignored) { + } + + try { + Enchantment.registerEnchantment(glowEnchant); + } catch (Exception ignored) { + } + + return glowEnchant; + } + } diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/algorithms/GlowEnchantment.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/algorithms/GlowEnchantment.java deleted file mode 100644 index f0570c2305..0000000000 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/algorithms/GlowEnchantment.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_8_R3.algorithms; - -import org.bukkit.enchantments.Enchantment; -import org.bukkit.enchantments.EnchantmentTarget; - -public class GlowEnchantment extends Enchantment { - - private GlowEnchantment(int id) { - super(id); - } - - public static GlowEnchantment createEnchantment() { - int id = 100; - - //noinspection deprecation, StatementWithEmptyBody - while (Enchantment.getById(++id) != null) { - } - - return new GlowEnchantment(id); - } - - @Override - public String getName() { - return "SuperiorSkyblockGlow"; - } - - @Override - public int getMaxLevel() { - return 1; - } - - @Override - public int getStartLevel() { - return 0; - } - - @Override - public EnchantmentTarget getItemTarget() { - return null; - } - - @Override - public boolean conflictsWith(Enchantment enchantment) { - return false; - } - - @Override - public boolean canEnchantItem(org.bukkit.inventory.ItemStack itemStack) { - return true; - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index d8c67b7ab7..9c4265eeb6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -28,7 +28,6 @@ import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; import com.bgsoftware.superiorskyblock.core.events.EventsBus; import com.bgsoftware.superiorskyblock.core.factory.FactoriesManagerImpl; -import com.bgsoftware.superiorskyblock.core.itemstack.GlowEnchantment; import com.bgsoftware.superiorskyblock.core.itemstack.ItemSkulls; import com.bgsoftware.superiorskyblock.core.key.KeysManagerImpl; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -211,8 +210,6 @@ public void onEnable() { loadUpgradeCostLoaders(); - GlowEnchantment.registerGlowEnchantment(this); - try { settingsHandler.loadData(); } catch (ManagerLoadException ex) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java index bae579d8d0..15a30babb6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java @@ -13,7 +13,6 @@ import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.itemstack.GlowEnchantment; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.itemstack.MinecraftNamesMapper; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -342,9 +341,7 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec } if (section.getBoolean("glow", false)) { - Enchantment glowEnchant = GlowEnchantment.getGlowEnchant(); - if (glowEnchant != null) - itemBuilder.withEnchant(glowEnchant, 1); + itemBuilder.makeItemGlow(); } if (section.contains("flags")) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/GlowEnchantment.java b/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/GlowEnchantment.java deleted file mode 100644 index 2e7af9159b..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/GlowEnchantment.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.itemstack; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import org.bukkit.enchantments.Enchantment; - -public class GlowEnchantment { - - private static Enchantment glowEnchant; - - private GlowEnchantment() { - - } - - public static void registerGlowEnchantment(SuperiorSkyblockPlugin plugin) { - try { - glowEnchant = plugin.getNMSAlgorithms().createGlowEnchantment(); - } catch (Throwable error) { - Log.error(error, "Failed to create glow enchantment"); - } - } - - @Nullable - public static Enchantment getGlowEnchant() { - return glowEnchant; - } -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java b/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java index cabc2bab90..bc4128b619 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java @@ -192,6 +192,11 @@ public ItemBuilder withEnchant(Enchantment enchant, int level) { return this; } + public ItemBuilder makeItemGlow() { + plugin.getNMSAlgorithms().makeItemGlow(itemMeta); + return this; + } + public ItemBuilder withFlags(ItemFlag... itemFlags) { if (itemMeta != null) { itemMeta.addItemFlags(itemFlags); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java index db9c592938..745143a2ea 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.events.EventResult; -import com.bgsoftware.superiorskyblock.core.itemstack.GlowEnchantment; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; @@ -19,7 +18,6 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.Bukkit; import org.bukkit.block.Biome; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; @@ -63,13 +61,9 @@ public ItemStack createViewItem() { if (island == null || island.getBiome() != getTemplate().biome) return buttonItem; - ItemBuilder itemBuilder = new ItemBuilder(buttonItem); - - Enchantment glowEnchant = GlowEnchantment.getGlowEnchant(); - if (glowEnchant != null) - itemBuilder.withEnchant(glowEnchant, 1); - - return itemBuilder.build(); + return new ItemBuilder(buttonItem) + .makeItemGlow() + .build(); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ChangeSortingTypeButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ChangeSortingTypeButton.java index 1094782865..4f740c292a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ChangeSortingTypeButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ChangeSortingTypeButton.java @@ -4,7 +4,6 @@ import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; -import com.bgsoftware.superiorskyblock.core.itemstack.GlowEnchantment; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; @@ -12,7 +11,6 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuTopIslands; -import org.bukkit.enchantments.Enchantment; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; @@ -38,13 +36,9 @@ public ItemStack createViewItem() { menuView.getSortingType() != getTemplate().sortingType) return buttonItem; - ItemBuilder itemBuilder = new ItemBuilder(buttonItem); - - Enchantment glowEnchant = GlowEnchantment.getGlowEnchant(); - if (glowEnchant != null) - itemBuilder.withEnchant(glowEnchant, 1); - - return itemBuilder.build(); + return new ItemBuilder(buttonItem) + .makeItemGlow() + .build(); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java index c2ddb03383..d0cc0cd82e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java @@ -6,7 +6,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Minecart; import org.bukkit.event.inventory.InventoryType; @@ -16,8 +15,6 @@ import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionEffect; -import java.lang.reflect.Field; - public interface NMSAlgorithms { void registerCommand(BukkitCommand command); @@ -42,30 +39,7 @@ public interface NMSAlgorithms { String getMinecraftKey(ItemStack itemStack); - @Nullable - Enchantment getGlowEnchant(); - - @Nullable - default Enchantment createGlowEnchantment() { - Enchantment glowEnchant = getGlowEnchant(); - - if (glowEnchant != null) { - try { - Field field = Enchantment.class.getDeclaredField("acceptingNew"); - field.setAccessible(true); - field.set(null, true); - field.setAccessible(false); - } catch (Exception ignored) { - } - - try { - Enchantment.registerEnchantment(glowEnchant); - } catch (Exception ignored) { - } - } - - return glowEnchant; - } + void makeItemGlow(ItemMeta itemMeta); @Nullable Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title); From b5de20c5fb54f005ed14c51d08dd370e281dbb0d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 31 Jan 2025 11:51:44 +0200 Subject: [PATCH 058/600] Fix tracking of blocks in missions not working properly (#2328) --- .../resources/modules/missions/BlocksMissions | Bin 40213 -> 40265 bytes .../modules/missions/BrewingMissions | Bin 28802 -> 28830 bytes .../modules/missions/CraftingMissions | Bin 24865 -> 24892 bytes .../modules/missions/EnchantingMissions | Bin 28964 -> 28992 bytes .../modules/missions/FarmingMissions | Bin 37488 -> 37532 bytes .../modules/missions/FishingMissions | Bin 24781 -> 24809 bytes .../resources/modules/missions/IslandMissions | Bin 27266 -> 27294 bytes .../resources/modules/missions/ItemsMissions | Bin 23297 -> 23327 bytes .../resources/modules/missions/KillsMissions | Bin 22023 -> 22054 bytes .../modules/missions/StatisticsMissions | Bin 23148 -> 23178 bytes 10 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/modules/missions/BlocksMissions b/src/main/resources/modules/missions/BlocksMissions index 52cdbd5285bcc2bf62acd07e9421580c9226194f..583cb8eff94d2a2bfc6e4bb3ee2e562b11809804 100644 GIT binary patch delta 15694 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 Y7$8j9SRjxe6z=*fe2GTJ{dB~C0p3mcw*UYD diff --git a/src/main/resources/modules/missions/CraftingMissions b/src/main/resources/modules/missions/CraftingMissions index 6d03234fc084fb46a829de02082ee0b861f17b45..9b4bbc449b16527fbd0cf5b8f0e18bcd117db6b1 100644 GIT binary patch delta 2815 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 delta 2779 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 QyitH|=oU$1-;FE&2I+#)$p8QV diff --git a/src/main/resources/modules/missions/EnchantingMissions b/src/main/resources/modules/missions/EnchantingMissions index 39ccafe7d8d57c006a076b0040c0698a7f7d6528..64cc7cbf38a382fd7269a68a8c9be5b0903dea46 100644 GIT binary patch delta 2975 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 Sn7S8*NXh~H9MK+ov;GC>;pnme diff --git a/src/main/resources/modules/missions/FarmingMissions b/src/main/resources/modules/missions/FarmingMissions index 05b2f481fd8368a6d5ba6ebdf4e9b91639885707..aeb316815785a2813fa532f4ac9e897c3c196d04 100644 GIT binary patch delta 12643 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 delta 12559 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 diff --git a/src/main/resources/modules/missions/FishingMissions b/src/main/resources/modules/missions/FishingMissions index 2818e7a57dff674bc266493d75bb456b40698cad..5996c77fa874d12617f36827c5a13180870e55b3 100644 GIT binary patch delta 2875 zcmZXWc{tQ-8^>n`W1BIu4jM}$TQX$HE+i&PW|Vx-QNnHZw15cFl_8RAP^T9 zXxhc71`Y+YrQnSK5%7t@CX<}?Sm`Wh67C^eLYQw z68pqRFTGF2w=r<<)0AHTU%A_~^$B|VX!Og+pJeH`Unhzx0hV3FiQ-G=7}ze^eAO^>^(S{t>JyY&UBrffH?dNHMqVw$`<0^xAnxwoT<(pUqWi)D!*;Bv3A`GozBL%wX*j8!r!jQ~NZ5=+X)qtlII)`FduksYuL2523AU5;R$OBY&gu0cBNyi;xMTyE{#)sL~GaM^0?wHHk!0$4CreOVq^{7pF$Y!g>_}6QnakkLkrzW4_U*)k4I+UQ5^*nYC%<88wujX%RIYROR8=f~*Qh#!`=O94(d(5}(&xv54-SGb`NT^@W(`oo_!Vb+1Md7&lQL zs=Jn)vxs_f{)$Q0%_mavmXlWLMCjm~;;IGu?XSA3122ku<16zaqvvw+DSeAmcy^++ zf$78K7zT3fD_{GCACd}<`32YHsbZEXYh8Fxm!}OY>=}n^zDR9vBnM&;?gLc5f!R5` zTMi*BgS8+VWiX^}8^3DzX@p@LggAXjsxW^@z>`E+kSzcrCnJJXK*~NuDfb)iN76qe zHDG>b!!%N(c8(q=8b3-r#TP5oTD2az$pxpzN_59{oA%eOCsv@}w5+Q1D^MVwEwVlb z(JljppH&U@Y)qPrMr^d4ojsqvMJs|7fpDZ+cu0dE1Js20Leo5B%-a_Mv z7aG|*tF+X`lS`h47*4LIL`dSk^s}V2lUoWNvHb4MlIxOmFU5mT`EBXsE3s~hirJl8 zSfL6O^NSZpR*j^>99#%@o?M(-8{`Nz?64~cJ{N*`aKN>^pmRF%L%u_yF4;mT&B$S! z_aCstn?88=vt$>1-(et-IS2$g7aVxR(u!QHVy`fUY&H|=BIuODV z6&m$iEOPGFfFOGZ2v|O#4OkQ4wNLct*!JDP8{r95k0TXqAkY>!2!sU&^i6<8V_{<5 z8RrPBxzKhg+&Wj%`XnZRc2)WnU>0rnHKFVz_jL!GGOaparg!?OAsIkpnGnK!duS&a z@zXwoQGsuP=}GZ0pPD2YS+v9Z<-=2;_)!laHoe-o*E3vz67& z1xE;FE>(KIO5+Q7gZU_Xy}UYQngMbCl8R%j=t;-b#F>~8YxJA_x<0MQE7kdkFl0#M z{Dx}q24;ucy*apW!{o(-@W#&SjcH3Sibu8>chs`#vo0}_whsF{A;n>~5!dTfe;JIs zGHsl>mnt4z)}HgBceOy|9&1)LV`goP&$99NuuCDuYNBbI6a& z((;oTPB~kTSPwk9B!GKFhP02x^E&Ign8ea(q=Jh5K1l7}Q7G)x?CG{sGD(84E-6!U ztzt`^FqjYD_23oP+I~gu*sRAD<0c|2Ff5G?-0oJoRi#dlun$;QeO0#>L2|yXmjs-;&;8(@Rjdd$Z{}=kCcfXzuZGAmGRW&mqH@$>c90-db-9>ch4ZphliWT zT^$z4r4#57zT~KsR?ipfF@v&g^o`0Cm?~}GvBGJC_8#6GY0_ICPNLb{EXnK50(xFL z!KDeROKLbQ(rX#rSX|#!cnMHWPe}_`-w!o33FOJDHVbUHFnWyPy!#{Wo#wGrj3Pt@ zpe&viy)y&HtrNK=x3`OUa^dUNW>`svo zr{|(F?#to>n;Poi=39*06*#H)gNEYw#^hxcWZ!n#iN%^u>UUpUz1tQmu%Q!PbQv-! zuXX>V!@&bp`jA?znHF^K-2*9B4y^ajw94jWiL3T)V3sh)QU4G-XEgp;z%(6ktVJxv zF@P0+I!3bMWhXyY#gvmC_}|-?65d;SZz20Pmso^h9ka^7fV}Z8mIPVG6PQ4y4KN5~ zy9=?if4g?ok{ZjHjFtf6oMC$tffQ#6h?~Z4+6b6)7GR~ec2h|G-IT^IyR;$U|C4Z_ zlW-gYGh%%)a8Z%|KcM|%n7#3zE#P~M114OQAi-vT)Vf+ic24{$#Q=;2AHog;h6sWF z+E{^QR|&{%E0#stoeQvZgR!o*eGzG?!3hGn2!cRX|CqM=x4GI4#kvQ>O#*V${?8r? atQ5vw0)oT+)%GS%2%x(2Ltzekz5WYdWe@NG delta 2811 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 H)XB_W@NwwI diff --git a/src/main/resources/modules/missions/IslandMissions b/src/main/resources/modules/missions/IslandMissions index 6081ea90debad7e2945644db71b980388b3e8fd9..54f6ce343899f12d6b7424161d3a6a8f7382177c 100644 GIT binary patch delta 2757 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 delta 2770 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 NvVi5|_=MgQ{}1{a`w{>E delta 2764 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 DN3hv9 diff --git a/src/main/resources/modules/missions/KillsMissions b/src/main/resources/modules/missions/KillsMissions index 1d3dc007afbb5a05a3158c089042578029618aed..4f75dd0612e1616f80371c6dece20971936ea0a9 100644 GIT binary patch delta 2816 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 Date: Fri, 31 Jan 2025 12:45:15 +0200 Subject: [PATCH 059/600] Fix issues with placeholders and progress exceeding their limits in missions --- .../resources/modules/missions/BlocksMissions | Bin 40265 -> 40145 bytes .../modules/missions/BrewingMissions | Bin 28830 -> 28709 bytes .../modules/missions/CraftingMissions | Bin 24892 -> 24768 bytes .../modules/missions/EnchantingMissions | Bin 28992 -> 28920 bytes .../modules/missions/FarmingMissions | Bin 37532 -> 37409 bytes .../modules/missions/FishingMissions | Bin 24809 -> 24687 bytes .../resources/modules/missions/IslandMissions | Bin 27294 -> 27173 bytes .../resources/modules/missions/ItemsMissions | Bin 23327 -> 23207 bytes .../resources/modules/missions/KillsMissions | Bin 22054 -> 21930 bytes .../modules/missions/StatisticsMissions | Bin 23178 -> 23054 bytes 10 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/modules/missions/BlocksMissions b/src/main/resources/modules/missions/BlocksMissions index 583cb8eff94d2a2bfc6e4bb3ee2e562b11809804..5ed2942865c67b9d78f96ed80dc58cb06f9e802f 100644 GIT binary patch delta 7028 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 KFuPO!eEENKS@$Xc delta 7091 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 Oq&*7@kvINN-v0o(crE<^ diff --git a/src/main/resources/modules/missions/BrewingMissions b/src/main/resources/modules/missions/BrewingMissions index 7771616c6ad0d1934559de42b91ee4a80f3d4cc9..71a5eb2f84350260e59bf33c8f1fb0c52d962343 100644 GIT binary patch delta 7010 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 diff --git a/src/main/resources/modules/missions/CraftingMissions b/src/main/resources/modules/missions/CraftingMissions index 9b4bbc449b16527fbd0cf5b8f0e18bcd117db6b1..76a1a3c49ca31ed5a401898726241655af54c1ca 100644 GIT binary patch delta 6950 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 b;BU3{PZjv`pX%OAAe7aH0Dau>FaN&);xOc2 delta 7124 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 WGW$Qqf&AteKw1|RC{2rhE&VS~!i|&w delta 15095 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 NoTCYNuG!z-{|`{Z)9nBN diff --git a/src/main/resources/modules/missions/FarmingMissions b/src/main/resources/modules/missions/FarmingMissions index aeb316815785a2813fa532f4ac9e897c3c196d04..6d844c3e14dfd7cd5bc4e3f83419b991eb798f39 100644 GIT binary patch delta 6948 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 J!Xp3h{tsTEIB5U? diff --git a/src/main/resources/modules/missions/FishingMissions b/src/main/resources/modules/missions/FishingMissions index 5996c77fa874d12617f36827c5a13180870e55b3..be8262a41fe6f97b68a249c1f0cadd20b5e32ae2 100644 GIT binary patch delta 7024 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 delta 7141 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 diff --git a/src/main/resources/modules/missions/IslandMissions b/src/main/resources/modules/missions/IslandMissions index 54f6ce343899f12d6b7424161d3a6a8f7382177c..c1d06e6d24e3f51b4d9f8bbaa56ba171e2a85ad3 100644 GIT binary patch delta 6988 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

>m{_Vho<70h203`K(rI#XFZmA($G+WMd(WoT zXX`{9W8U6EQp4m#TvuPN;s5wvB{^#;ly)i$Tok4P&CQ0KXi8K+Q>o{2T}-mFAF!J> z!H!}V*jpzzO+U|f<~EDx?2ssV%vs++Modg(PE+5I>j6|*^NV86KWP0*rpf6DrDYcK zn4_6!&z(akj$TSv?u2sUTZ%Ljf7D^yFR!2e)uv9D^wT@WdThTiTn&04j}-dxT&_(` zfF!MQjx#lm)(UaO`=dU~KfKb*q!a>z%Itwlvs_A3Y%3v*?{?Z;IFNl|En| zWZplyiv|p3z=M<@>1Bq5=KEJ+G>F{t{pRkMb-2o`RW!ml6K1%Hg%O!lC5#?&1lE-B zSo(K$Xp?H+k=~{;`*LAozBOby(B~|VnAY9JdTESaJQICy2{g2TUSWP4j(gY;C~7Gv zpyJ6SW{Mqx%bKLO(>KqtqW%Rbs|P_Q-3RHBwgWh!eMA}${PpOR>bps~B4qm>49Jxf z5KonPE43nUH|#8Iy&pb6hG!<3^NQ;5?$VdZ(Qe$H4Hnl9<{2p*ONN+1>HN7DUKQ9}iw~8) zWC3t_)@-o0ES({>bw=vYX)t0mHR77X8(6Mt!M9P(S(q2ppLO(mlVJW*c$Q z=Vd8I7ew`TD}9SF%ww&RrMIJ^vy4I&UrMLRO)X!0*J2`|UWj^VV0dcvV4#`}V&Zh! z^=-(!=f%x;{d@rmA#c;I@FW?@S8x``5@56>?UMm~-zvALVyDXGb7wfuX=*f&o3e}~ zR))hvT_;*BA>W@>)Snax-VYfaQlE!uZV57lf z-(~(zo<{Vz1nP18MwPE$tET+*T#L%k{iu=ZR4pP$CvLAELAq?~4EJNJ&Oi){>H;93 z5$t^smq@+gds7qnW!E@qfcfJtzopL4yf0(SQY;1ChiudfzuxVkMC!j{eQs`E>G`>0 z&-9#Or!|2vBq1GDX!IjQML_bCT37((MKSIw%k1tI5HD+QbAzM``B5Au z;T#86mYsNf$v0wZ!s7Eswh8vsvNmlIC;>n63>khmd}LWtclj{rUR<1@quVj^0ZQv*;}HjdZjaBKW8Kw>=&UToUcN+7@|GoaKF)^<=}n&&;*`T@ za?$c~(a+=p_lT1<4}Th8{`?7Z@LeWrez-m^V{`EF9Fl+bfIMb|BT%>C>8wuxy?)Vn z>IW*1Q!}Ramt=|%l6fFROcHK~J-E(#EIOESuJaVq+iIO$dWLj~mq^=zwNg8F;eak9 zB)LwjqMWdAor?}y0*YUqfEi4Cs@hKe)9L@!=r^Vr_M(Fx+B6y(x1xi7=RFeBU9A6e zGIP(`p7Bq%`~Q>6-^0s)u3!8p3nc&V=>X$j;J@Yu|6%@mPKf*i5}+h(*#Cn6H9hzj zEFt&xPQ*rk?4W-j@qfVzvcF+Tl%OpqsQB+?zO4*MSmCd?%t&$c0F*fr zK!1r^MFxUcG*D|uRg{AUAxujZ9Yl)upEId{@9^kfJ9KIP70#awPiGJQEB1fo|9`=x zI{yo+=n$g_9sYJ8b=_4l{5?@&#Xv(-` delta 7094 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 assE8@D*x~vwSR@HoBnaOKtnPAYyE$m={>vv diff --git a/src/main/resources/modules/missions/ItemsMissions b/src/main/resources/modules/missions/ItemsMissions index 196305857228a6b8930a050f566da0656ba62e97..15d64ca4daed819e21050b334b112b28442da586 100644 GIT binary patch delta 7000 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 diff --git a/src/main/resources/modules/missions/KillsMissions b/src/main/resources/modules/missions/KillsMissions index 4f75dd0612e1616f80371c6dece20971936ea0a9..61c88194b924251af6061f065b6eb5c489fd0bd8 100644 GIT binary patch delta 6857 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 delta 7026 zcmY*eWmptk(*~qjnnjj|rArzKr5lu5y1PR_nx(s!l5UjlSP5wX>5}g51`+(!?|t5w zA7`$axo56({+zk5nX+=kk_tqCisCb5OaugUbc79qS^yd%Qj9JPh$#D8)f*z#KS$ay zs3!!`AY*J8i0V={VOovAUQt+}62_WPn_$5{Qm{Z#<%-jZq*srZTstnaw?~bB{d__T zAae$Vx%(*Ujlgf`tnDRM5)*fTnwb7>5PqbllX_Rw`RagdvE3E%ab(I0y z4T5s-au$o3SdY360Jo&?Le@X`#_;9=MS7+!yAY~}T)QV2S_aZ^c0N2yVQ8*f zDA*;@4fhNZb%}AU6Lg zJ-7iJI{P#*%&Ce~4Pprg44*mjv_$f_bU+b@V8bl7s#>w=x*F4k;-f2S6A=u8c4iR_ zMc+`|dQ}78grzr|;Jxw~g;+n^a#z&!%%4nmJ7QPhLCs-`^{T7j`#SD|I)Yinsd47J zLdU7qW4xm!5PD*fRIJAWKR3i)>4St_mFHcwkg%neFspt`DqA(Ak3mFkn&OqI0 zK~X{uiJvI1W~pO43Nqb_@^bTs&O&-#W!BXx$=D~O zk)=6QPe35mx+b=xX+pQt{o+U@p$&_|4u{znqL>6TxP#YH0{zN6H5K%2lKxGS zKIC9s{o#6xH@Vht7;M#Ta=52MtDryjmmU-r^L?pNVoMx$G4B(kQD3QQqIKJF<)#Ua zDcAkH8qot`s`6WS(JHdbbwsEhps?&%U>Db_B&UUI0hg>I77txfrnbsUjODTnGyAGO zX?F*|B(7Cb7Kxe1Rbic{Y{r@nv@eag4&}b&qKCnv9FKnb>2+yo;D>*C`w1Gs3|w6^ zAvfB@=h~g86nN$$BWq+#|AxX}xes8uZU3msyKKdm&nO})qH zUI$YeHDJYYFkq|at{jI(T(e=TF?%F-S^ zt1-sGQR3|}k@Ev+AUffX%;3i=Pby~`-BBj$)W6sw1%`2;!ToXU
p?YybxXzvII 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 JHI@EU`9DjAFG~Ob diff --git a/src/main/resources/modules/missions/StatisticsMissions b/src/main/resources/modules/missions/StatisticsMissions index 59c5dd783eadb9657bec6197004e3a1189cbc132..c63dad017df7a477ad40f71fcb4e22460eccd643 100644 GIT binary patch delta 7050 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 Y+asv?pW;XoO>*RwF$wmm)}KoM0=+ Date: Fri, 31 Jan 2025 14:32:03 +0200 Subject: [PATCH 060/600] Do not call WorldsProvider#getIslandsWorld when not needed --- .../com/bgsoftware/superiorskyblock/island/SIsland.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 378e832338..0b5eaa69ff 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -55,8 +55,8 @@ import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -1436,11 +1436,8 @@ private boolean isIslandWorld(@Nullable World world) { if (dimension == null) return false; - World islandWorld = plugin.getGrid().getIslandsWorld(this, dimension); - if (!Objects.equals(world, islandWorld)) - return false; - - return true; + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); + return worldInfo.getName().equals(world.getName()); } @Override From b1a5aedc7db698da30bd003c6ac0325024f47ceb Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 31 Jan 2025 15:56:45 +0200 Subject: [PATCH 061/600] Load worlds lazy whenever possible --- .../commands/admin/CmdAdminResetWorld.java | 50 +++++----- .../commands/admin/CmdAdminShow.java | 9 +- .../commands/admin/CmdAdminTeleport.java | 2 +- .../commands/player/CmdShow.java | 9 +- .../commands/player/CmdVisit.java | 41 ++++++--- .../superiorskyblock/core/IslandWorlds.java | 39 ++++++++ .../core/formatting/Formatters.java | 14 ++- .../core/formatting/IBiFormatter.java | 7 ++ .../core/formatting/ILocaleFormatter.java | 9 -- .../impl/BlockPositionFormatter.java | 23 +++++ .../formatting/impl/BooleanFormatter.java | 4 +- .../formatting/impl/BorderColorFormatter.java | 4 +- .../formatting/impl/FancyNumberFormatter.java | 4 +- .../core/formatting/impl/RatingFormatter.java | 4 +- .../core/formatting/impl/TimeFormatter.java | 4 +- .../island/GridManagerImpl.java | 9 ++ .../superiorskyblock/island/IslandUtils.java | 15 ++- .../superiorskyblock/island/SIsland.java | 66 +++++++++----- .../superiorskyblock/island/SpawnIsland.java | 10 +- .../listener/ChunksListener.java | 5 +- .../listener/PortalsListener.java | 21 ++++- .../DefaultPlayerTeleportAlgorithm.java | 34 ++++--- .../dragon/DragonBattleServiceImpl.java | 12 ++- .../placeholders/PlaceholdersServiceImpl.java | 16 ++-- .../portals/PortalsManagerServiceImpl.java | 91 ++++++++++--------- .../world/EntityTeleports.java | 21 +++-- 26 files changed, 337 insertions(+), 186 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/formatting/IBiFormatter.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/formatting/ILocaleFormatter.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BlockPositionFormatter.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java index 78b13aa51f..3675898026 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java @@ -9,8 +9,8 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.World; import org.bukkit.command.CommandSender; @@ -23,6 +23,8 @@ public class CmdAdminResetWorld implements IAdminIslandCommand { + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + @Override public List getAliases() { return Arrays.asList("resetworld", "rworld"); @@ -81,33 +83,14 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab boolean anyIslandChanged = false; for (Island island : islands) { - World world; - - try { - world = island.getCenter(dimension).getWorld(); - } catch (NullPointerException error) { - Log.entering("ENTER", island.getOwner().getName(), dimension.getName()); - Log.error(error, "An unexpected error occurred while resetting world:"); - return; - } - if (!plugin.getEventsBus().callIslandWorldResetEvent(sender, island, dimension)) continue; anyIslandChanged = true; - // Sending the players that are in that world to the main island. - // If the world that will be reset is the normal world, they will be teleported to spawn. - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - assert superiorPlayer.getWorld() != null; - if (superiorPlayer.getWorld().equals(world)) - superiorPlayer.teleport(island); - } - - // Resetting the chunks - island.resetChunks(dimension, IslandChunkFlags.ONLY_PROTECTED, () -> island.calcIslandWorth(null)); - - island.setSchematicGenerate(dimension, false); + IslandWorlds.accessIslandWorldAsync(island, dimension, islandWorldResult -> { + islandWorldResult.ifLeft(world -> resetChunksInternal(island, world, dimension)); + }); } if (!anyIslandChanged) @@ -116,11 +99,30 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (islands.size() > 1) Message.RESET_WORLD_SUCCEED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3])); else if (targetPlayer == null) - Message.RESET_WORLD_SUCCEED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3]), islands.get(0).getName()); + Message.RESET_WORLD_SUCCEED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3]), islands.get(0). + + getName()); else Message.RESET_WORLD_SUCCEED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3]), targetPlayer.getName()); } + private static void resetChunksInternal(Island island, World world, Dimension dimension) { + + + // Sending the players that are in that world to the main island. + // If the world that will be reset is the normal world, they will be teleported to spawn. + for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { + assert superiorPlayer.getWorld() != null; + if (superiorPlayer.getWorld().equals(world)) + superiorPlayer.teleport(island); + } + + // Resetting the chunks + island.resetChunks(dimension, IslandChunkFlags.ONLY_PROTECTED, () -> island.calcIslandWorth(null)); + + island.setSchematicGenerate(dimension, false); + } + @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { if (args.length != 4) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java index ef47a2bfbb..63baf20ff2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; @@ -95,9 +96,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab infoMessage.append(Message.ISLAND_INFO_NAME.getMessage(locale, island.getName())).append("\n"); // Island location - if (!Message.ISLAND_INFO_LOCATION.isEmpty(locale)) - infoMessage.append(Message.ISLAND_INFO_LOCATION.getMessage(locale, Formatters.LOCATION_FORMATTER.format( - island.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension())))).append("\n"); + if (!Message.ISLAND_INFO_LOCATION.isEmpty(locale)) { + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension()); + infoMessage.append(Message.ISLAND_INFO_LOCATION.getMessage(locale, + Formatters.BLOCK_POSITION_FORMATTER.format(island.getCenterPosition(), worldInfo))).append("\n"); + } // Island last time updated if (lastTime != -1) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java index 380a351c7a..80d7eecd6c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java @@ -88,7 +88,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; } - if (plugin.getGrid().getIslandsWorld(island, dimension) == null) { + if (plugin.getGrid().getIslandsWorldInfo(island, dimension) == null) { Message.WORLD_NOT_ENABLED.send(sender); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdShow.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdShow.java index 8aeb52b82c..8e12a44990 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdShow.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdShow.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; @@ -79,9 +80,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ infoMessage.append(Message.ISLAND_INFO_OWNER.getMessage(locale, island.getOwner().getName())).append("\n"); if (!Message.ISLAND_INFO_NAME.isEmpty(locale) && !island.getName().isEmpty()) infoMessage.append(Message.ISLAND_INFO_NAME.getMessage(locale, island.getName())).append("\n"); - if (!Message.ISLAND_INFO_LOCATION.isEmpty(locale)) - infoMessage.append(Message.ISLAND_INFO_LOCATION.getMessage(locale, Formatters.LOCATION_FORMATTER.format( - island.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension())))).append("\n"); + if (!Message.ISLAND_INFO_LOCATION.isEmpty(locale)) { + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension()); + infoMessage.append(Message.ISLAND_INFO_LOCATION.getMessage(locale, + Formatters.BLOCK_POSITION_FORMATTER.format(island.getCenterPosition(), worldInfo))).append("\n"); + } if (!Message.ISLAND_INFO_CREATION_TIME.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_CREATION_TIME.getMessage(locale, island.getCreationTimeDate())).append("\n"); if (!Message.ISLAND_INFO_RATE.isEmpty(locale)) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java index 9afa24f679..fa7339a65e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; @@ -20,6 +21,8 @@ public class CmdVisit implements ISuperiorCommand { + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + @Override public List getAliases() { return Collections.singletonList("visit"); @@ -65,19 +68,38 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); + Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); + + IslandWorlds.accessIslandWorldAsync(targetIsland, dimension, islandWorldResult -> { + islandWorldResult.ifLeft(world -> teleportPlayerInternal(targetIsland, superiorPlayer)); + }); + } + @Override + public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); + return args.length == 2 ? CommandTabCompletes.getOnlinePlayersWithIslands(plugin, args[1], + plugin.getSettings().isTabCompleteHideVanished(), + (onlinePlayer, onlineIsland) -> onlineIsland != null && ( + (!plugin.getSettings().getVisitorsSign().isRequiredForVisit() || + onlineIsland.getVisitorsLocation((Dimension) null /* unused */) != null) || + superiorPlayer.hasBypassModeEnabled()) && (!onlineIsland.isLocked() || + onlineIsland.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS))) : Collections.emptyList(); + } + + private static void teleportPlayerInternal(Island targetIsland, SuperiorPlayer superiorPlayer) { Location visitLocation = plugin.getSettings().getVisitorsSign().isRequiredForVisit() ? targetIsland.getVisitorsLocation((Dimension) null /* unused */) : targetIsland.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()); if (visitLocation == null) { - Message.INVALID_VISIT_LOCATION.send(sender); + Message.INVALID_VISIT_LOCATION.send(superiorPlayer); if (!superiorPlayer.hasBypassModeEnabled()) return; visitLocation = targetIsland.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()); - Message.INVALID_VISIT_LOCATION_BYPASS.send(sender); + Message.INVALID_VISIT_LOCATION_BYPASS.send(superiorPlayer); } if (targetIsland.isLocked() && !targetIsland.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS)) { @@ -99,19 +121,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ } } - @Override - public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - return args.length == 2 ? CommandTabCompletes.getOnlinePlayersWithIslands(plugin, args[1], - plugin.getSettings().isTabCompleteHideVanished(), - (onlinePlayer, onlineIsland) -> onlineIsland != null && ( - (!plugin.getSettings().getVisitorsSign().isRequiredForVisit() || - onlineIsland.getVisitorsLocation((Dimension) null /* unused */) != null) || - superiorPlayer.hasBypassModeEnabled()) && (!onlineIsland.isLocked() || - onlineIsland.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS))) : Collections.emptyList(); - } - - private void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island island, Location visitLocation, boolean checkIslandLock) { + private static void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island island, + Location visitLocation, boolean checkIslandLock) { superiorPlayer.setTeleportTask(null); if (checkIslandLock && island.isLocked() && !island.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS)) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java new file mode 100644 index 0000000000..55ae490aba --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java @@ -0,0 +1,39 @@ +package com.bgsoftware.superiorskyblock.core; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider; +import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import org.bukkit.World; + +import java.util.function.Consumer; + +public class IslandWorlds { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + public static void accessIslandWorldAsync(Island island, Dimension dimension, Consumer> consumer) { + WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); + if (worldsProvider instanceof LazyWorldsProvider) { + ((LazyWorldsProvider) worldsProvider).prepareWorld(island, dimension, () -> + loadedWorldCallback(island, dimension, consumer)); + } else { + loadedWorldCallback(island, dimension, consumer); + } + } + + private static void loadedWorldCallback(Island island, Dimension dimension, Consumer> consumer) { + World world = plugin.getGrid().getIslandsWorld(island, dimension); + if (world != null) { + consumer.accept(Either.left(world)); + } else { + consumer.accept(Either.right(new NullPointerException("World does not exist"))); + } + } + + private IslandWorlds() { + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/Formatters.java b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/Formatters.java index fb3939061e..18069ba6b4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/Formatters.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/Formatters.java @@ -1,6 +1,9 @@ package com.bgsoftware.superiorskyblock.core.formatting; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; +import com.bgsoftware.superiorskyblock.core.formatting.impl.BlockPositionFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.BooleanFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.BorderColorFormatter; import com.bgsoftware.superiorskyblock.core.formatting.impl.CapitalizedFormatter; @@ -26,20 +29,21 @@ public class Formatters { - public static final ILocaleFormatter BOOLEAN_FORMATTER = BooleanFormatter.getInstance(); - public static final ILocaleFormatter BORDER_COLOR_FORMATTER = BorderColorFormatter.getInstance(); + public static final IBiFormatter BOOLEAN_FORMATTER = BooleanFormatter.getInstance(); + public static final IBiFormatter BORDER_COLOR_FORMATTER = BorderColorFormatter.getInstance(); public static final IFormatter CAPITALIZED_FORMATTER = CapitalizedFormatter.getInstance(); public static final IFormatter COLOR_FORMATTER = ColorFormatter.getInstance(); public static final IFormatter> COMMA_FORMATTER = CommaFormatter.getInstance(); public static final IFormatter DATE_FORMATTER = DateFormatter.getInstance(); - public static final ILocaleFormatter FANCY_NUMBER_FORMATTER = FancyNumberFormatter.getInstance(); + public static final IBiFormatter FANCY_NUMBER_FORMATTER = FancyNumberFormatter.getInstance(); public static final IFormatter LOCALE_FORMATTER = LocaleFormatter.getInstance(); public static final IFormatter LOCATION_FORMATTER = LocationFormatter.getInstance(); public static final IFormatter NUMBER_FORMATTER = NumberFormatter.getInstance(); - public static final ILocaleFormatter RATING_FORMATTER = RatingFormatter.getInstance(); + public static final IBiFormatter RATING_FORMATTER = RatingFormatter.getInstance(); public static final IFormatter STRIP_COLOR_FORMATTER = StripColorFormatter.getInstance(); - public static final ILocaleFormatter TIME_FORMATTER = TimeFormatter.getInstance(); + public static final IBiFormatter TIME_FORMATTER = TimeFormatter.getInstance(); public static final IFormatter CHAT_FORMATTER = ChatFormatter.getInstance(); + public static final IBiFormatter BLOCK_POSITION_FORMATTER = BlockPositionFormatter.getInstance(); private Formatters() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/IBiFormatter.java b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/IBiFormatter.java new file mode 100644 index 0000000000..163f9d2e04 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/IBiFormatter.java @@ -0,0 +1,7 @@ +package com.bgsoftware.superiorskyblock.core.formatting; + +public interface IBiFormatter { + + String format(T value, K value2); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/ILocaleFormatter.java b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/ILocaleFormatter.java deleted file mode 100644 index 32699d30ff..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/ILocaleFormatter.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.formatting; - -import java.util.Locale; - -public interface ILocaleFormatter { - - String format(T value, Locale locale); - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BlockPositionFormatter.java b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BlockPositionFormatter.java new file mode 100644 index 0000000000..a194b67574 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BlockPositionFormatter.java @@ -0,0 +1,23 @@ +package com.bgsoftware.superiorskyblock.core.formatting.impl; + +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; +import com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter; + +public class BlockPositionFormatter implements IBiFormatter { + + private static final BlockPositionFormatter INSTANCE = new BlockPositionFormatter(); + + public static BlockPositionFormatter getInstance() { + return INSTANCE; + } + + private BlockPositionFormatter() { + + } + + @Override + public String format(BlockPosition value, WorldInfo worldInfo) { + return worldInfo.getName() + ", " + value.getX() + ", " + value.getY() + ", " + value.getZ(); + } +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BooleanFormatter.java b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BooleanFormatter.java index 38d7d688df..2ca09dd880 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BooleanFormatter.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BooleanFormatter.java @@ -1,11 +1,11 @@ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.core.formatting.ILocaleFormatter; +import com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter; import java.util.Locale; -public class BooleanFormatter implements ILocaleFormatter { +public class BooleanFormatter implements IBiFormatter { private static final BooleanFormatter INSTANCE = new BooleanFormatter(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BorderColorFormatter.java b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BorderColorFormatter.java index 77ee49bed0..1b996a6dbe 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BorderColorFormatter.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/BorderColorFormatter.java @@ -2,12 +2,12 @@ import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.core.formatting.ILocaleFormatter; +import com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter; import java.util.EnumMap; import java.util.Locale; -public class BorderColorFormatter implements ILocaleFormatter { +public class BorderColorFormatter implements IBiFormatter { private static final BorderColorFormatter INSTANCE = new BorderColorFormatter(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/FancyNumberFormatter.java b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/FancyNumberFormatter.java index cbebe8d2c0..2e498adfe9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/FancyNumberFormatter.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/FancyNumberFormatter.java @@ -2,11 +2,11 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.formatting.ILocaleFormatter; +import com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter; import java.util.Locale; -public class FancyNumberFormatter implements ILocaleFormatter { +public class FancyNumberFormatter implements IBiFormatter { private static final FancyNumberFormatter INSTANCE = new FancyNumberFormatter(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/RatingFormatter.java b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/RatingFormatter.java index 019495576c..142e4ab70b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/RatingFormatter.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/RatingFormatter.java @@ -1,11 +1,11 @@ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.core.formatting.ILocaleFormatter; +import com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter; import java.util.Locale; -public class RatingFormatter implements ILocaleFormatter { +public class RatingFormatter implements IBiFormatter { private static final RatingFormatter INSTANCE = new RatingFormatter(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/TimeFormatter.java b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/TimeFormatter.java index 1a5eb0e64a..93bb5ba520 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/TimeFormatter.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/TimeFormatter.java @@ -1,13 +1,13 @@ package com.bgsoftware.superiorskyblock.core.formatting.impl; +import com.bgsoftware.superiorskyblock.core.formatting.IBiFormatter; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; -import com.bgsoftware.superiorskyblock.core.formatting.ILocaleFormatter; import java.time.Duration; import java.util.Locale; -public class TimeFormatter implements ILocaleFormatter { +public class TimeFormatter implements IBiFormatter { private static final TimeFormatter INSTANCE = new TimeFormatter(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index 269dfebf97..ab16cc447e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -699,6 +699,9 @@ public World getIslandsWorld(Island island, Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); if (island.isSpawn()) { + if (island instanceof SpawnIsland) + return ((SpawnIsland) island).getSpawnWorld(); + return island.getIslandHome(dimension).getWorld(); } @@ -730,6 +733,9 @@ public WorldInfo getIslandsWorldInfo(Island island, Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); if (island.isSpawn()) { + if (island instanceof SpawnIsland) + return ((SpawnIsland) island).getSpawnWorldInfo(); + return WorldInfo.of(island.getIslandHome(dimension).getWorld()); } @@ -755,6 +761,9 @@ public WorldInfo getIslandsWorldInfo(Island island, String worldName) { Preconditions.checkNotNull(worldName, "worldName parameter cannot be null."); if (island.isSpawn()) { + if (island instanceof SpawnIsland) + return ((SpawnIsland) island).getSpawnWorldInfo(); + return WorldInfo.of(island.getIslandHome(Dimensions.NORMAL).getWorld()); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java index 4e55a3d597..27ab8a3a89 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.island; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags; @@ -15,8 +14,8 @@ import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; +import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -31,8 +30,6 @@ import java.util.Collection; import java.util.Collections; -import java.util.EnumMap; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -117,12 +114,12 @@ public static Map> getChunkCoords(Island island, return chunkCoords; } - public static List> getAllChunksAsync(Island island, World world, @IslandChunkFlags int flags, + public static List> getAllChunksAsync(Island island, WorldInfo worldInfo, @IslandChunkFlags int flags, ChunkLoadReason chunkLoadReason, Consumer onChunkLoad) { return new SequentialListBuilder>() .mutable() - .build(IslandUtils.getChunkCoords(island, WorldInfo.of(world), flags), chunkPosition -> + .build(IslandUtils.getChunkCoords(island, worldInfo, flags), chunkPosition -> ChunksProvider.loadChunk(chunkPosition, chunkLoadReason, onChunkLoad)); } @@ -133,13 +130,13 @@ public static List> getAllChunksAsync(Island island, @I for (Dimension dimension : Dimension.values()) { if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && island.wasSchematicGenerated(dimension)) { - World world = island.getCenter(dimension).getWorld(); - chunkCoords.addAll(getAllChunksAsync(island, world, flags, chunkLoadReason, onChunkLoad)); + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); + chunkCoords.addAll(getAllChunksAsync(island, worldInfo, flags, chunkLoadReason, onChunkLoad)); } } for (World registeredWorld : plugin.getGrid().getRegisteredWorlds()) { - chunkCoords.addAll(getAllChunksAsync(island, registeredWorld, flags, chunkLoadReason, onChunkLoad)); + chunkCoords.addAll(getAllChunksAsync(island, WorldInfo.of(registeredWorld), flags, chunkLoadReason, onChunkLoad)); } return chunkCoords; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 0b5eaa69ff..f50aa7dbd3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -39,6 +39,7 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.IslandArea; +import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.LegacyMasks; import com.bgsoftware.superiorskyblock.core.LocationKey; @@ -1180,8 +1181,8 @@ public List> getAllChunksAsync(Dimension dimension, @Is @Nullable Consumer onChunkLoad) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); - World world = getCenter(dimension).getWorld(); - return IslandUtils.getAllChunksAsync(this, world, flags, ChunkLoadReason.API_REQUEST, onChunkLoad); + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); + return IslandUtils.getAllChunksAsync(this, worldInfo, flags, ChunkLoadReason.API_REQUEST, onChunkLoad); } @Override @@ -1948,35 +1949,50 @@ public void setPaypal(String paypal) { @Override public Biome getBiome() { if (biome == null) { - biomeGetterTask.set(task -> { - if (task != null) - return task; - - Dimension defaultWorldDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); - WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, defaultWorldDimension); - Location centerBlock = getCenter(defaultWorldDimension); - - try (ChunkPosition centerChunkPosition = ChunkPosition.of(worldInfo, - centerBlock.getBlockX() >> 4, centerBlock.getBlockZ() >> 4)) { - return ChunksProvider.loadChunk(centerChunkPosition, ChunkLoadReason.BIOME_REQUEST, null) - .thenApply(chunk -> centerBlock.getBlock().getBiome()) - .whenComplete((biome, error) -> { - if (error != null) - error.printStackTrace(); - else { - this.biome = biome; - biomeGetterTask.set((CompletableFuture) null); - } - }); - } - }); - + biomeGetterTask.set(this::getBiomeAsyncTask); return IslandUtils.getDefaultWorldBiome(plugin.getSettings().getWorlds().getDefaultWorldDimension()); } return biome; } + private CompletableFuture getBiomeAsyncTask(CompletableFuture currentTask) { + if (currentTask != null) + return currentTask; + + Dimension defaultWorldDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); + BlockPosition centerBlockPosition = getCenterPosition(); + + CompletableFuture newTask = new CompletableFuture<>(); + + IslandWorlds.accessIslandWorldAsync(this, defaultWorldDimension, islandWorldResult -> { + if (islandWorldResult.getRight() != null) { + newTask.completeExceptionally(islandWorldResult.getRight()); + return; + } + + World world = islandWorldResult.getLeft(); + + try (ChunkPosition centerChunkPosition = ChunkPosition.of(world, + centerBlockPosition.getX() >> 4, centerBlockPosition.getZ() >> 4)) { + ChunksProvider.loadChunk(centerChunkPosition, ChunkLoadReason.BIOME_REQUEST, null) + .thenApply(chunk -> centerBlockPosition.parse(world).getBlock().getBiome()) + .whenComplete((biome, error) -> { + if (error != null) + newTask.completeExceptionally(error); + else { + this.biome = biome; + biomeGetterTask.set((CompletableFuture) null); + newTask.complete(biome); + } + }); + } + }); + + return newTask; + } + + @Override public void setBiome(Biome biome) { setBiome(biome, true); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index aab4f4390a..51c55994e7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -344,6 +344,14 @@ public BlockPosition getCenterPosition() { return this.center; } + public World getSpawnWorld() { + return spawnWorld; + } + + public WorldInfo getSpawnWorldInfo() { + return spawnWorldInfo; + } + @Override @Deprecated public Location getTeleportLocation(World.Environment unused) { @@ -639,7 +647,7 @@ public List> getAllChunksAsync(Dimension unused, public List> getAllChunksAsync(Dimension unused, @IslandChunkFlags int flags, @Nullable Consumer onChunkLoad) { - return IslandUtils.getAllChunksAsync(this, center.getWorld(), flags, ChunkLoadReason.API_REQUEST, onChunkLoad); + return IslandUtils.getAllChunksAsync(this, spawnWorldInfo, flags, ChunkLoadReason.API_REQUEST, onChunkLoad); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java index 263315b215..3250ca8a3c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; @@ -137,12 +138,12 @@ private void handleIslandChunkLoad(Island island, Chunk chunk, ChunkPosition chu if (!plugin.getNMSChunks().isChunkEmpty(chunk)) island.markChunkDirty(world, chunk.getX(), chunk.getZ(), true); - Location islandCenter = island.getCenter(dimension); + BlockPosition islandCenter = island.getCenterPosition(); boolean entityLimitsEnabled = BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class); MutableBoolean recalculateEntities = new MutableBoolean(false); - if (chunk.getX() == (islandCenter.getBlockX() >> 4) && chunk.getZ() == (islandCenter.getBlockZ() >> 4)) { + if (chunk.getX() == (islandCenter.getX() >> 4) && chunk.getZ() == (islandCenter.getZ() >> 4)) { if (dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { Block chunkBlock = chunk.getBlock(0, 100, 0); island.setBiome(world.getBiome(chunkBlock.getX(), chunkBlock.getZ()), false); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java index 96532af9c6..06f56bdbcc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java @@ -5,7 +5,9 @@ import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; import com.bgsoftware.superiorskyblock.api.service.portals.EntityPortalResult; import com.bgsoftware.superiorskyblock.api.service.portals.PortalsManagerService; +import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; @@ -100,11 +102,20 @@ public void onEntityPortalEnter(EntityPortalEnterEvent e) { teleportedPlayer.setPlayerStatus(PlayerStatus.LEAVING_ISLAND); BukkitExecutor.sync(() -> { - EntityTeleports.teleportUntilSuccess(e.getEntity(), - island.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()), 5, () -> { - if (teleportedPlayer != null) - teleportedPlayer.removePlayerStatus(PlayerStatus.LEAVING_ISLAND); - }); + Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); + IslandWorlds.accessIslandWorldAsync(island, dimension, islandWorldResult -> { + islandWorldResult.ifRight(error -> { + if (teleportedPlayer != null) + teleportedPlayer.removePlayerStatus(PlayerStatus.LEAVING_ISLAND); + }).ifLeft(unused -> { + EntityTeleports.teleportUntilSuccess(e.getEntity(), + island.getIslandHome(dimension), 5, () -> { + if (teleportedPlayer != null) + teleportedPlayer.removePlayerStatus(PlayerStatus.LEAVING_ISLAND); + }); + }); + }); + }, 5L); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java index 5bd5d70af7..f535d11ae4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.world.Dimensions; @@ -43,6 +44,21 @@ public CompletableFuture teleport(Player player, Island island) { @Override public CompletableFuture teleport(Player player, Island island, Dimension dimension) { + CompletableFuture result = new CompletableFuture<>(); + IslandWorlds.accessIslandWorldAsync(island, dimension, islandWorldResult -> { + islandWorldResult.ifRight(result::completeExceptionally).ifLeft(world -> + teleportInternal(player, island, dimension, result)); + }); + return result; + } + + @Override + @Deprecated + public CompletableFuture teleport(Player player, Island island, World.Environment environment) { + return teleport(player, island, Dimensions.fromEnvironment(environment)); + } + + public void teleportInternal(Player player, Island island, Dimension dimension, CompletableFuture result) { Location homeLocation = island.getIslandHome(dimension); Preconditions.checkNotNull(homeLocation, "Cannot find a suitable home location for island " + @@ -50,36 +66,26 @@ public CompletableFuture teleport(Player player, Island island, Dimensi Log.debug(Debug.TELEPORT_PLAYER, player.getName(), island.getOwner().getName(), dimension); - CompletableFuture teleportResult = new CompletableFuture<>(); - EntityTeleports.findIslandSafeLocation(island, dimension).whenComplete((safeSpot, error) -> { if (error != null) { Log.debugResult(Debug.TELEPORT_PLAYER, "Teleport Location", null); - teleportResult.completeExceptionally(error); + result.completeExceptionally(error); } else if (safeSpot == null) { Log.debugResult(Debug.TELEPORT_PLAYER, "Teleport Location", null); - teleportResult.complete(false); + result.complete(false); } else { Log.debugResult(Debug.TELEPORT_PLAYER, "Teleport Location", safeSpot); teleport(player, safeSpot).whenComplete((teleport, teleportError) -> { if (teleportError != null) { Log.debugResult(Debug.TELEPORT_PLAYER, "Teleport Result", false); - teleportResult.completeExceptionally(teleportError); + result.completeExceptionally(teleportError); } else { Log.debugResult(Debug.TELEPORT_PLAYER, "Teleport Result", true); - teleportResult.complete(teleport); + result.complete(teleport); } }); } }); - - return teleportResult; - } - - @Override - @Deprecated - public CompletableFuture teleport(Player player, Island island, World.Environment environment) { - return teleport(player, island, Dimensions.fromEnvironment(environment)); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java index e127f20c56..0a31e016c6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleResetResult; import com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.service.IService; import com.bgsoftware.superiorskyblock.world.Dimensions; import com.google.common.base.Preconditions; @@ -84,10 +85,13 @@ public DragonBattleResetResult resetEnderDragonBattle(Island island, Dimension d stopEnderDragonBattle(island, dimension); - Location islandCenter = island.getCenter(dimension); - - plugin.getNMSDragonFight().startDragonBattle(island, - dimensionConfig.getPortalOffset().applyToLocation(islandCenter)); + IslandWorlds.accessIslandWorldAsync(island, dimension, islandWorldResult -> { + islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { + Location islandCenter = island.getCenter(dimension); + plugin.getNMSDragonFight().startDragonBattle(island, + dimensionConfig.getPortalOffset().applyToLocation(islandCenter)); + }); + }); return DragonBattleResetResult.SUCCESS; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index 935af07ea7..ef43980414 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.api.service.placeholders.IslandPlaceholderParser; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlayerPlaceholderParser; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; @@ -91,15 +92,14 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { private static final Map ISLAND_PARSES = new ImmutableMap.Builder() .put("center", (island, superiorPlayer) -> - Formatters.LOCATION_FORMATTER.format(island.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()))) + Formatters.BLOCK_POSITION_FORMATTER.format(island.getCenterPosition(), getDefaultWorldInfo(island))) .put("x", (island, superiorPlayer) -> - island.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getBlockX() + "") + island.getCenterPosition().getX() + "") .put("y", (island, superiorPlayer) -> - island.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getBlockY() + "") + island.getCenterPosition().getY() + "") .put("z", (island, superiorPlayer) -> - island.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getBlockZ() + "") - .put("world", (island, superiorPlayer) -> - island.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getWorld().getName()) + island.getCenterPosition().getZ() + "") + .put("world", (island, superiorPlayer) -> getDefaultWorldInfo(island).getName()) .put("schematic", (island, superiorPlayer) -> island.getSchematicName()) .put("team_size", (island, superiorPlayer) -> island.getIslandMembers(true).size() + "") .put("team_size_online", (island, superiorPlayer) -> @@ -509,4 +509,8 @@ private static Optional handleMembersPlaceholder(@NotNull Island island, return Optional.of(members.get(targetMemberIndex).getName()); } + private static WorldInfo getDefaultWorldInfo(Island island) { + return plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension()); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java index 95530a546a..15b76c4bd1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.api.service.portals.PortalsManagerService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; import com.bgsoftware.superiorskyblock.core.events.EventResult; @@ -231,51 +232,55 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island return EntityPortalResult.SUCCEED; } - Location schematicPlacementLocation = island.getCenter(destination).subtract(0, 1, 0); - schematicPlacementLocation.setY(plugin.getSettings().getIslandHeight()); - - BigDecimal originalWorth = island.getRawWorth(); - BigDecimal originalLevel = island.getRawLevel(); - - schematic.pasteSchematic(island, schematicPlacementLocation, () -> { - generatingSchematicsIslands.remove(island.getUniqueId()); - island.setSchematicGenerate(destination); - - SettingsManager.Worlds.DimensionConfig destinationConfig = plugin.getSettings().getWorlds().getDimensionConfig(destination); - if (destinationConfig != null && destinationConfig.isSchematicOffset()) { - { - BigDecimal schematicWorth = island.getRawWorth().subtract(originalWorth); - EventResult bonusEventResult = plugin.getEventsBus().callIslandChangeWorthBonusEvent(null, island, - IslandChangeWorthBonusEvent.Reason.SCHEMATIC, island.getBonusWorth().subtract(schematicWorth)); - if (!bonusEventResult.isCancelled()) - island.setBonusWorth(bonusEventResult.getResult()); - } - { - BigDecimal schematicLevel = island.getRawLevel().subtract(originalLevel); - EventResult bonusEventResult = plugin.getEventsBus().callIslandChangeLevelBonusEvent(null, island, - IslandChangeLevelBonusEvent.Reason.SCHEMATIC, island.getBonusLevel().subtract(schematicLevel)); - if (!bonusEventResult.isCancelled()) - island.setBonusLevel(bonusEventResult.getResult()); - } - } - - Location destinationLocation = island.getIslandHome(destination); + IslandWorlds.accessIslandWorldAsync(island, destination, islandWorldResult -> { + islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { + Location schematicPlacementLocation = island.getCenter(destination).subtract(0, 1, 0); + schematicPlacementLocation.setY(plugin.getSettings().getIslandHeight()); - if (destination.getEnvironment() == World.Environment.THE_END && superiorPlayer != null) { - plugin.getNMSDragonFight().awardTheEndAchievement((Player) entity); - this.dragonBattleService.get().resetEnderDragonBattle(island, destination); - } + BigDecimal originalWorth = island.getRawWorth(); + BigDecimal originalLevel = island.getRawLevel(); - if (superiorPlayer != null) { - superiorPlayer.teleport(schematic.adjustRotation(destinationLocation)); - } else { - EntityTeleports.teleport(entity, schematic.adjustRotation(destinationLocation)); - } - }, error -> { - generatingSchematicsIslands.remove(island.getUniqueId()); - error.printStackTrace(); - if (superiorPlayer != null) - Message.CREATE_WORLD_FAILURE.send(superiorPlayer); + schematic.pasteSchematic(island, schematicPlacementLocation, () -> { + generatingSchematicsIslands.remove(island.getUniqueId()); + island.setSchematicGenerate(destination); + + SettingsManager.Worlds.DimensionConfig destinationConfig = plugin.getSettings().getWorlds().getDimensionConfig(destination); + if (destinationConfig != null && destinationConfig.isSchematicOffset()) { + { + BigDecimal schematicWorth = island.getRawWorth().subtract(originalWorth); + EventResult bonusEventResult = plugin.getEventsBus().callIslandChangeWorthBonusEvent(null, island, + IslandChangeWorthBonusEvent.Reason.SCHEMATIC, island.getBonusWorth().subtract(schematicWorth)); + if (!bonusEventResult.isCancelled()) + island.setBonusWorth(bonusEventResult.getResult()); + } + { + BigDecimal schematicLevel = island.getRawLevel().subtract(originalLevel); + EventResult bonusEventResult = plugin.getEventsBus().callIslandChangeLevelBonusEvent(null, island, + IslandChangeLevelBonusEvent.Reason.SCHEMATIC, island.getBonusLevel().subtract(schematicLevel)); + if (!bonusEventResult.isCancelled()) + island.setBonusLevel(bonusEventResult.getResult()); + } + } + + Location destinationLocation = island.getIslandHome(destination); + + if (destination.getEnvironment() == World.Environment.THE_END && superiorPlayer != null) { + plugin.getNMSDragonFight().awardTheEndAchievement((Player) entity); + this.dragonBattleService.get().resetEnderDragonBattle(island, destination); + } + + if (superiorPlayer != null) { + superiorPlayer.teleport(schematic.adjustRotation(destinationLocation)); + } else { + EntityTeleports.teleport(entity, schematic.adjustRotation(destinationLocation)); + } + }, error -> { + generatingSchematicsIslands.remove(island.getUniqueId()); + error.printStackTrace(); + if (superiorPlayer != null) + Message.CREATE_WORLD_FAILURE.send(superiorPlayer); + }); + }); }); } catch (NullPointerException ignored) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java index 3808506780..8a46f5ea50 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.EventResult; import com.bgsoftware.superiorskyblock.core.logging.Debug; @@ -68,6 +69,15 @@ public static void teleportUntilSuccess(Entity entity, Location location, long c } public static CompletableFuture findIslandSafeLocation(Island island, Dimension dimension) { + CompletableFuture result = new CompletableFuture<>(); + IslandWorlds.accessIslandWorldAsync(island, dimension, islandWorldResult -> { + islandWorldResult.ifRight(result::completeExceptionally).ifLeft(world -> + findIslandSafeLocation(island, dimension, result)); + }); + return result; + } + + public static void findIslandSafeLocation(Island island, Dimension dimension, CompletableFuture result) { Location homeLocation = island.getIslandHome(dimension); Preconditions.checkNotNull(homeLocation, "Cannot find a suitable home location for island " + @@ -84,7 +94,8 @@ public static CompletableFuture findIslandSafeLocation(Island island, Block homeLocationBlock = homeLocation.getBlock(); if (island.isSpawn() || WorldBlocks.isSafeBlock(homeLocationBlock)) { Log.debugResult(Debug.FIND_SAFE_TELEPORT, "Result Location", homeLocation); - return CompletableFuture.completedFuture(homeLocation); + result.complete(homeLocation); + return; } } @@ -92,13 +103,11 @@ public static CompletableFuture findIslandSafeLocation(Island island, { Block teleportLocationHighestBlock = islandsWorld.getHighestBlockAt(homeLocation).getRelative(BlockFace.UP); if (WorldBlocks.isSafeBlock(teleportLocationHighestBlock)) { - return CompletableFuture.completedFuture(adjustLocationToHome(island, - teleportLocationHighestBlock, rotationYaw, rotationPitch)); + result.complete(adjustLocationToHome(island, teleportLocationHighestBlock, rotationYaw, rotationPitch)); + return; } } - CompletableFuture result = new CompletableFuture<>(); - // The teleport location is not safe. We check for a safe spot in the center of the island. Location islandCenterLocation = island.getCenter(dimension); @@ -128,8 +137,6 @@ public static CompletableFuture findIslandSafeLocation(Island island, } else { findNewSafeSpotOnIsland(island, islandsWorld, homeLocation, rotationYaw, rotationPitch, result); } - - return result; } private static void findNewSafeSpotOnIsland(Island island, World islandsWorld, Location homeLocation, From 74c6f11caae7a03d48657ac8c0450f886e2b46ad Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 7 Feb 2025 12:08:39 +0200 Subject: [PATCH 062/600] Adds support to placeholders in some admin commands (#2350) - /is admin msg - /is admin msgall - /is admin title - /is admin titleall - /is admin cmdall --- .../commands/admin/CmdAdminMsg.java | 14 +++++- .../commands/admin/CmdAdminTitle.java | 24 ++++++++-- .../superiorskyblock/island/SIsland.java | 47 ++++++++++++++++--- 3 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminMsg.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminMsg.java index de58032287..9b575623ea 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminMsg.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminMsg.java @@ -1,10 +1,13 @@ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import org.bukkit.command.CommandSender; import java.util.Collections; @@ -12,6 +15,13 @@ public class CmdAdminMsg implements IAdminPlayerCommand { + private static final LazyReference placeholdersService = new LazyReference() { + @Override + protected PlaceholdersService create() { + return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class); + } + }; + @Override public List getAliases() { return Collections.singletonList("msg"); @@ -57,6 +67,8 @@ public boolean supportMultiplePlayers() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { String message = CommandArguments.buildLongString(args, 3, true); + if (!Text.isBlank(message)) + message = placeholdersService.get().parsePlaceholders(targetPlayer.asOfflinePlayer(), message); Message.CUSTOM.send(targetPlayer, message, false); Message.MESSAGE_SENT.send(sender, targetPlayer.getName()); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTitle.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTitle.java index 253bb81abe..019818b74e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTitle.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTitle.java @@ -1,13 +1,17 @@ package com.bgsoftware.superiorskyblock.commands.admin; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; +import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import java.util.Collections; import java.util.List; @@ -15,6 +19,13 @@ public class CmdAdminTitle implements IAdminPlayerCommand { + private static final LazyReference placeholdersService = new LazyReference() { + @Override + protected PlaceholdersService create() { + return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class); + } + }; + @Override public List getAliases() { return Collections.singletonList("title"); @@ -93,7 +104,14 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, Superio return; } - plugin.getNMSPlayers().sendTitle(targetPlayer.asPlayer(), + Player player = targetPlayer.asPlayer(); + + if (!Text.isBlank(title)) + title = placeholdersService.get().parsePlaceholders(player, title); + if (!Text.isBlank(subtitle)) + subtitle = placeholdersService.get().parsePlaceholders(player, subtitle); + + plugin.getNMSPlayers().sendTitle(player, title == null ? null : Formatters.COLOR_FORMATTER.format(title), subtitle == null ? null : Formatters.COLOR_FORMATTER.format(subtitle), fadeIn.getNumber(), diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index f50aa7dbd3..8fa25ed120 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -30,6 +30,7 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; +import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.world.Dimension; @@ -40,12 +41,14 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.IslandArea; import com.bgsoftware.superiorskyblock.core.IslandWorlds; +import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.LegacyMasks; import com.bgsoftware.superiorskyblock.core.LocationKey; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; @@ -149,6 +152,12 @@ public class SIsland implements Island { private static final UUID CONSOLE_UUID = new UUID(0, 0); private static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final LazyReference placeholdersService = new LazyReference() { + @Override + protected PlaceholdersService create() { + return plugin.getServices().getService(PlaceholdersService.class); + } + }; private static EnumerateSet DEFAULT_FLAGS_CACHE; @@ -2083,7 +2092,14 @@ public void sendMessage(String message, UUID... ignoredMembers) { Log.debug(Debug.SEND_MESSAGE, owner.getName(), message, ignoredList); - forEachIslandMember(ignoredList, false, islandMember -> Message.CUSTOM.send(islandMember, message, false)); + forEachIslandMember(ignoredList, false, islandMember -> { + String playerMessage = message; + + if (!Text.isBlank(playerMessage)) + playerMessage = placeholdersService.get().parsePlaceholders(islandMember.asOfflinePlayer(), playerMessage); + + Message.CUSTOM.send(islandMember, playerMessage, false); + }); } @Override @@ -2110,9 +2126,19 @@ public void sendTitle(@Nullable String title, @Nullable String subtitle, int fad Log.debug(Debug.SEND_TITLE, owner.getName(), title, subtitle, fadeIn, duration, fadeOut, ignoredList); - forEachIslandMember(ignoredList, true, islandMember -> - plugin.getNMSPlayers().sendTitle(islandMember.asPlayer(), title, subtitle, fadeIn, duration, fadeOut) - ); + forEachIslandMember(ignoredList, true, islandMember -> { + String playerTitle = title; + String playerSubtitle = subtitle; + + Player player = islandMember.asPlayer(); + + if (!Text.isBlank(playerTitle)) + playerTitle = placeholdersService.get().parsePlaceholders(player, playerTitle); + if (!Text.isBlank(playerSubtitle)) + playerSubtitle = placeholdersService.get().parsePlaceholders(player, playerSubtitle); + + plugin.getNMSPlayers().sendTitle(player, playerTitle, playerSubtitle, fadeIn, duration, fadeOut); + }); } @Override @@ -2124,9 +2150,16 @@ public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ig Log.debug(Debug.EXECUTE_ISLAND_COMMANDS, owner.getName(), command, onlyOnlineMembers, ignoredList); - forEachIslandMember(ignoredList, onlyOnlineMembers, islandMember -> - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command.replace("{player-name}", islandMember.getName())) - ); + forEachIslandMember(ignoredList, onlyOnlineMembers, islandMember -> { + String playerCommand = command; + + if (!Text.isBlank(playerCommand)) { + playerCommand = placeholdersService.get().parsePlaceholders(islandMember.asOfflinePlayer(), playerCommand) + .replace("{player-name}", islandMember.getName()); + } + + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), playerCommand); + }); } @Override From dcb1904781f159443416b431090443e2284087bf Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 7 Feb 2025 13:50:54 +0200 Subject: [PATCH 063/600] Aged blocks should have data values with their keys --- .../nms/v1_12_R1/NMSAlgorithmsImpl.java | 16 ++++++++++ .../nms/v1_16_R3/NMSAlgorithmsImpl.java | 24 +++++++++++++++ .../nms/v1_17/NMSAlgorithmsImpl.java | 23 +++++++++++++++ .../nms/v1_18/NMSAlgorithmsImpl.java | 23 +++++++++++++++ .../nms/v1_19/NMSAlgorithmsImpl.java | 23 +++++++++++++++ .../nms/v1_20_3/NMSAlgorithmsImpl.java | 23 +++++++++++++++ .../nms/v1_20_4/NMSAlgorithmsImpl.java | 23 +++++++++++++++ .../nms/v1_21/NMSAlgorithmsImpl.java | 23 +++++++++++++++ .../nms/v1_21_3/NMSAlgorithmsImpl.java | 23 +++++++++++++++ .../nms/v1_21_4/NMSAlgorithmsImpl.java | 23 +++++++++++++++ .../nms/v1_8_R3/NMSAlgorithmsImpl.java | 16 ++++++++++ .../superiorskyblock/core/key/Keys.java | 4 +-- .../core/key/types/MaterialKey.java | 29 +++++++++++++++---- .../superiorskyblock/nms/NMSAlgorithms.java | 8 +++++ 14 files changed, 273 insertions(+), 8 deletions(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java index 3449a12dfc..72baa2c14e 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java @@ -19,6 +19,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.BlockState; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_12_R1.CraftServer; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; @@ -80,6 +81,21 @@ public int compareMaterials(Material o1, Material o2) { return Integer.compare(o1.ordinal(), o2.ordinal()); } + @Override + public short getBlockDataValue(BlockState blockState) { + return blockState.getRawData(); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + return block.getData(); + } + + @Override + public short getMaxBlockDataValue(Material material) { + return 0; + } + @Override public Key getBlockKey(int combinedId) { IBlockData blockData = Block.getByCombinedId(combinedId); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java index 72c0388fcb..f7dd7ab84a 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java @@ -33,6 +33,9 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_16_R3.CraftServer; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; @@ -125,6 +128,27 @@ public int compareMaterials(Material o1, Material o2) { return Integer.compare(firstMaterial, secondMaterial); } + @Override + public short getBlockDataValue(BlockState blockState) { + BlockData blockData = blockState.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + BlockData blockData = block.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getMaxBlockDataValue(Material material) { + if (!material.isBlock()) + return 0; + + BlockData blockData = Bukkit.createBlockData(material); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); + } + @Override public Key getBlockKey(int combinedId) { Block block = Block.getByCombinedId(combinedId).getBlock(); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java index ea79670fbe..0d8eeed2da 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java @@ -32,6 +32,8 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_17_R1.CraftServer; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; @@ -129,6 +131,27 @@ public int compareMaterials(Material o1, Material o2) { return Integer.compare(firstMaterial, secondMaterial); } + @Override + public short getBlockDataValue(org.bukkit.block.BlockState blockState) { + BlockData blockData = blockState.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + BlockData blockData = block.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getMaxBlockDataValue(Material material) { + if (!material.isBlock()) + return 0; + + BlockData blockData = Bukkit.createBlockData(material); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); + } + @Override public Key getBlockKey(int combinedId) { Block block = Block.stateById(combinedId).getBlock(); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java index ba31eb7c78..f62b188afb 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java @@ -33,6 +33,8 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_18_R2.CraftServer; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; @@ -130,6 +132,27 @@ public int compareMaterials(Material o1, Material o2) { return Integer.compare(firstMaterial, secondMaterial); } + @Override + public short getBlockDataValue(org.bukkit.block.BlockState blockState) { + BlockData blockData = blockState.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + BlockData blockData = block.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getMaxBlockDataValue(Material material) { + if (!material.isBlock()) + return 0; + + BlockData blockData = Bukkit.createBlockData(material); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); + } + @Override public Key getBlockKey(int combinedId) { Block block = Block.stateById(combinedId).getBlock(); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java index 32922cf711..e671b2e8ba 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java @@ -33,6 +33,8 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_19_R3.CraftServer; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; @@ -130,6 +132,27 @@ public int compareMaterials(Material o1, Material o2) { return Integer.compare(firstMaterial, secondMaterial); } + @Override + public short getBlockDataValue(org.bukkit.block.BlockState blockState) { + BlockData blockData = blockState.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + BlockData blockData = block.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getMaxBlockDataValue(Material material) { + if (!material.isBlock()) + return 0; + + BlockData blockData = Bukkit.createBlockData(material); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); + } + @Override public Key getBlockKey(int combinedId) { Block block = Block.stateById(combinedId).getBlock(); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java index 2d51e5de22..ccb7432cb2 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java @@ -36,6 +36,8 @@ import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_20_R3.CraftRegistry; import org.bukkit.craftbukkit.v1_20_R3.CraftServer; @@ -137,6 +139,27 @@ public int compareMaterials(Material o1, Material o2) { return Integer.compare(firstMaterial, secondMaterial); } + @Override + public short getBlockDataValue(org.bukkit.block.BlockState blockState) { + BlockData blockData = blockState.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + BlockData blockData = block.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getMaxBlockDataValue(Material material) { + if (!material.isBlock()) + return 0; + + BlockData blockData = Bukkit.createBlockData(material); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); + } + @Override public Key getBlockKey(int combinedId) { Block block = Block.stateById(combinedId).getBlock(); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java index c5d677135c..5a4b9ac6de 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java @@ -35,6 +35,8 @@ import org.bukkit.Material; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; @@ -131,6 +133,27 @@ public int compareMaterials(Material o1, Material o2) { return Integer.compare(firstMaterial, secondMaterial); } + @Override + public short getBlockDataValue(org.bukkit.block.BlockState blockState) { + BlockData blockData = blockState.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + BlockData blockData = block.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getMaxBlockDataValue(Material material) { + if (!material.isBlock()) + return 0; + + BlockData blockData = Bukkit.createBlockData(material); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); + } + @Override public Key getBlockKey(int combinedId) { Block block = Block.stateById(combinedId).getBlock(); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java index e109371b2e..034e940a4a 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java @@ -36,6 +36,8 @@ import org.bukkit.Material; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; @@ -132,6 +134,27 @@ public int compareMaterials(Material o1, Material o2) { return Integer.compare(firstMaterial, secondMaterial); } + @Override + public short getBlockDataValue(org.bukkit.block.BlockState blockState) { + BlockData blockData = blockState.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + BlockData blockData = block.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getMaxBlockDataValue(Material material) { + if (!material.isBlock()) + return 0; + + BlockData blockData = Bukkit.createBlockData(material); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); + } + @Override public Key getBlockKey(int combinedId) { Block block = Block.stateById(combinedId).getBlock(); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java index 627c534dec..8d9851249e 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java @@ -36,6 +36,8 @@ import org.bukkit.Material; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; @@ -132,6 +134,27 @@ public int compareMaterials(Material o1, Material o2) { return Integer.compare(firstMaterial, secondMaterial); } + @Override + public short getBlockDataValue(org.bukkit.block.BlockState blockState) { + BlockData blockData = blockState.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + BlockData blockData = block.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getMaxBlockDataValue(Material material) { + if (!material.isBlock()) + return 0; + + BlockData blockData = Bukkit.createBlockData(material); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); + } + @Override public Key getBlockKey(int combinedId) { Block block = Block.stateById(combinedId).getBlock(); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index bc113cc6a8..5bf94eaa52 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -36,6 +36,8 @@ import org.bukkit.Material; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; @@ -132,6 +134,27 @@ public int compareMaterials(Material o1, Material o2) { return Integer.compare(firstMaterial, secondMaterial); } + @Override + public short getBlockDataValue(org.bukkit.block.BlockState blockState) { + BlockData blockData = blockState.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + BlockData blockData = block.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getMaxBlockDataValue(Material material) { + if (!material.isBlock()) + return 0; + + BlockData blockData = Bukkit.createBlockData(material); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); + } + @Override public Key getBlockKey(int combinedId) { Block block = Block.stateById(combinedId).getBlock(); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java index a7c7f1c8d2..00efa7d6d2 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java @@ -19,6 +19,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.BlockState; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_8_R3.CraftServer; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; @@ -80,6 +81,21 @@ public int compareMaterials(Material o1, Material o2) { return Integer.compare(o1.ordinal(), o2.ordinal()); } + @Override + public short getBlockDataValue(BlockState blockState) { + return blockState.getRawData(); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + return block.getData(); + } + + @Override + public short getMaxBlockDataValue(Material material) { + return 0; + } + @Override public Key getBlockKey(int combinedId) { IBlockData blockData = Block.getByCombinedId(combinedId); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/Keys.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/Keys.java index fc96b088a6..f5c6aa6d5e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/Keys.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/Keys.java @@ -69,7 +69,7 @@ public static Key of(Block block) { CreatureSpawner creatureSpawner = (CreatureSpawner) block.getState(); baseKey = getSpawnerKeyFromCreatureSpawner(creatureSpawner); } else { - short data = ServerVersion.isLegacy() ? block.getData() : 0; + short data = plugin.getNMSAlgorithms().getBlockDataValue(block); baseKey = MaterialKey.of(blockType, data, MaterialKeySource.BLOCK); } @@ -83,7 +83,7 @@ public static Key of(BlockState blockState) { if (blockState instanceof CreatureSpawner) { baseKey = getSpawnerKeyFromCreatureSpawner((CreatureSpawner) blockState); } else { - short data = ServerVersion.isLegacy() ? blockState.getRawData() : 0; + short data = plugin.getNMSAlgorithms().getBlockDataValue(blockState); baseKey = MaterialKey.of(blockState.getType(), data, MaterialKeySource.BLOCK); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java index 35f4eb1e0b..92b77397dd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.core.key.types; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.MaterialKeySource; @@ -11,8 +12,10 @@ public class MaterialKey extends BaseKey { + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final EnumMap GLOBAL_MATERIAL_KEYS_CACHE = new EnumMap<>(Material.class); - private static final EnumMap ID_0_MATERIAL_KEYS_CACHE = new EnumMap<>(Material.class); + private static final EnumMap ID_MATERIAL_KEYS_CACHE = new EnumMap<>(Material.class); static { // Load all material type keys @@ -20,8 +23,12 @@ public class MaterialKey extends BaseKey { if (material != Materials.SPAWNER.toBukkitType()) { MaterialKey globalKey = of(material); globalKey.loadLazyCaches(); - MaterialKey id0Key = of(material, (short) 0, MaterialKeySource.BLOCK); - id0Key.loadLazyCaches(); + + int maxDataValue = plugin.getNMSAlgorithms().getMaxBlockDataValue(material) + 1; + for (int i = 0; i < maxDataValue; ++i) { + MaterialKey materialKey = of(material, (short) i, MaterialKeySource.BLOCK); + materialKey.loadLazyCaches(); + } } } } @@ -35,9 +42,12 @@ public class MaterialKey extends BaseKey { public static MaterialKey of(Material type, short durability, MaterialKeySource materialKeySource) { Preconditions.checkArgument(type != Materials.SPAWNER.toBukkitType()); - if (durability == 0 && materialKeySource == MaterialKeySource.BLOCK) - return ID_0_MATERIAL_KEYS_CACHE.computeIfAbsent(type, unused -> - new MaterialKey(type, (short) 0, false, MaterialKeySource.BLOCK)); + if (materialKeySource == MaterialKeySource.BLOCK) { + MaterialKey[] cachedIds = ID_MATERIAL_KEYS_CACHE.computeIfAbsent(type, MaterialKey::createMaterialKeyCacheForType); + if (durability < cachedIds.length) { + return cachedIds[durability]; + } + } return new MaterialKey(type, durability, false, materialKeySource); } @@ -103,4 +113,11 @@ public short getDurability() { return this.durability; } + private static MaterialKey[] createMaterialKeyCacheForType(Material type) { + MaterialKey[] cache = new MaterialKey[plugin.getNMSAlgorithms().getMaxBlockDataValue(type) + 1]; + for (int i = 0; i < cache.length; ++i) + cache[i] = new MaterialKey(type, (short) i, false, MaterialKeySource.BLOCK); + return cache; + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java index d0cc0cd82e..0919f69d39 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java @@ -5,6 +5,8 @@ import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Minecart; @@ -27,6 +29,12 @@ public interface NMSAlgorithms { int compareMaterials(Material o1, Material o2); + short getBlockDataValue(BlockState blockState); + + short getBlockDataValue(Block block); + + short getMaxBlockDataValue(Material material); + Key getBlockKey(int combinedId); Key getMinecartBlock(Minecart minecart); From 8c7ea138bb54ccafbbd613554ffb041f4ff847fe Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 7 Feb 2025 13:51:39 +0200 Subject: [PATCH 064/600] Fix grown crops not removing their last crop stage from block counts (#2348) --- .../superiorskyblock/listener/BlockChangesListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index 1a3cf53997..352f71f3ec 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -143,7 +143,7 @@ private void onBlockGrow(BlockGrowEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.worldRecordService.get().recordBlockPlace(Keys.of(e.getNewState()), e.getBlock().getLocation(wrapper.getHandle()), - 1, null, REGULAR_RECORD_FLAGS); + 1, e.getBlock().getState(), REGULAR_RECORD_FLAGS); } } From c89532a7b0a4868852d786dcccd68ff48543d6bc Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 7 Feb 2025 14:54:31 +0200 Subject: [PATCH 065/600] Fix issues when calling Key#of --- .../superiorskyblock/core/key/BaseKey.java | 13 +++++++---- .../core/key/types/CustomKey.java | 22 +++++++++++++++--- .../core/key/types/EntityTypeKey.java | 22 +++++++++++++++++- .../core/key/types/LazyKey.java | 7 +++++- .../core/key/types/MaterialKey.java | 23 ++++++++++++++++++- 5 files changed, 77 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/BaseKey.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/BaseKey.java index 532ae6c7e4..4e76bbdcf6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/BaseKey.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/BaseKey.java @@ -21,10 +21,11 @@ protected Integer create() { }; private final Class baseKeyClass; - private boolean apiKey = false; + private final boolean apiKey; - protected BaseKey(Class baseKeyClass) { + protected BaseKey(Class baseKeyClass, boolean apiKey) { this.baseKeyClass = baseKeyClass; + this.apiKey = apiKey; } @Override @@ -43,9 +44,13 @@ protected BaseKey(Class baseKeyClass) { protected abstract int compareToInternal(T other); + public abstract T createAPIKeyInternal(); + public final T markAPIKey() { - this.apiKey = true; - return (T) this; + if (this.apiKey) + return (T) this; + + return createAPIKeyInternal(); } public boolean isAPIKey() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/CustomKey.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/CustomKey.java index 88be958b54..0769b71b79 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/CustomKey.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/CustomKey.java @@ -2,6 +2,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.EnumHelper; +import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; @@ -14,6 +15,16 @@ public class CustomKey extends BaseKey { + private final LazyReference apiKeyCache = new LazyReference() { + @Override + protected CustomKey create() { + if (CustomKey.this.isAPIKey()) + throw new UnsupportedOperationException(); + + return new CustomKey(CustomKey.this.globalKey, CustomKey.this.subKey, true); + } + }; + private final String globalKey; private final String subKey; @@ -29,11 +40,11 @@ public static CustomKey of(String globalKey, @Nullable String subKey, KeyIndicat break; } - return new CustomKey(globalKey, subKey); + return new CustomKey(globalKey, subKey, false); } - private CustomKey(String globalKey, @Nullable String subKey) { - super(CustomKey.class); + private CustomKey(String globalKey, @Nullable String subKey, boolean apiKey) { + super(CustomKey.class, apiKey); this.globalKey = Preconditions.checkNotNull(globalKey, "globalKey cannot be null").toUpperCase(Locale.ENGLISH); this.subKey = Text.isBlank(subKey) ? null : subKey.toUpperCase(Locale.ENGLISH); } @@ -73,4 +84,9 @@ protected int compareToInternal(CustomKey other) { return toString().compareTo(other.toString()); } + @Override + public CustomKey createAPIKeyInternal() { + return this.apiKeyCache.get(); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/EntityTypeKey.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/EntityTypeKey.java index fa25216b1a..e993fa1cd4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/EntityTypeKey.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/EntityTypeKey.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.core.key.types; +import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.google.common.base.Preconditions; import org.bukkit.entity.EntityType; @@ -18,6 +19,16 @@ public class EntityTypeKey extends BaseKey { } } + private final LazyReference apiKeyCache = new LazyReference() { + @Override + protected EntityTypeKey create() { + if (EntityTypeKey.this.isAPIKey()) + throw new UnsupportedOperationException(); + + return new EntityTypeKey(EntityTypeKey.this.entityType, true); + } + }; + private final EntityType entityType; public static EntityTypeKey of(EntityType entityType) { @@ -25,7 +36,11 @@ public static EntityTypeKey of(EntityType entityType) { } private EntityTypeKey(EntityType entityType) { - super(EntityTypeKey.class); + this(entityType, false); + } + + private EntityTypeKey(EntityType entityType, boolean apiKey) { + super(EntityTypeKey.class, apiKey); this.entityType = Preconditions.checkNotNull(entityType, "entityType cannot be null"); } @@ -64,4 +79,9 @@ protected boolean equalsInternal(EntityTypeKey other) { return this.entityType == other.entityType; } + @Override + public EntityTypeKey createAPIKeyInternal() { + return this.apiKeyCache.get(); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/LazyKey.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/LazyKey.java index 682233276b..0e2c056c4f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/LazyKey.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/LazyKey.java @@ -10,7 +10,7 @@ public class LazyKey extends BaseKey { private final LazyReference baseKeyLoader; public LazyKey(Class baseKeyClass, LazyReference baseKeyLoader) { - super(baseKeyClass); + super(baseKeyClass, false); Preconditions.checkArgument(baseKeyClass != BaseKey.class); this.baseKeyLoader = baseKeyLoader; } @@ -54,4 +54,9 @@ protected final int compareToInternal(T other) { return getBaseKey().compareTo(other); } + @Override + public T createAPIKeyInternal() { + return ((BaseKey) getBaseKey()).createAPIKeyInternal(); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java index 92b77397dd..f1a7b3c726 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.core.key.types; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.MaterialKeySource; @@ -33,6 +34,17 @@ public class MaterialKey extends BaseKey { } } + private final LazyReference apiKeyCache = new LazyReference() { + @Override + protected MaterialKey create() { + if (MaterialKey.this.isAPIKey()) + throw new UnsupportedOperationException(); + + return new MaterialKey(MaterialKey.this.type, MaterialKey.this.durability, MaterialKey.this.isGlobalType, + MaterialKey.this.materialKeySource, true); + } + }; + protected final Material type; private final short durability; private final String durabilityAsString; @@ -58,7 +70,11 @@ public static MaterialKey of(Material type) { } protected MaterialKey(Material type, short durability, boolean isGlobalType, MaterialKeySource materialKeySource) { - super(MaterialKey.class); + this(type, durability, isGlobalType, materialKeySource, false); + } + + protected MaterialKey(Material type, short durability, boolean isGlobalType, MaterialKeySource materialKeySource, boolean apiKey) { + super(MaterialKey.class, apiKey); this.type = Preconditions.checkNotNull(type, "type parameter cannot be null"); this.durability = durability; this.durabilityAsString = isGlobalType ? "" : String.valueOf(this.durability); @@ -105,6 +121,11 @@ protected int compareToInternal(MaterialKey other) { return this.toString().compareTo(other.toString()); } + @Override + public MaterialKey createAPIKeyInternal() { + return this.apiKeyCache.get(); + } + public Material getMaterial() { return this.type; } From 4d0803d2ff794cede21a276fa6d7abaa2c26eb89 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 7 Feb 2025 15:16:55 +0200 Subject: [PATCH 066/600] Fix getBlockKey doesn't return the correct value for keys created by the API --- .../core/values/BlockValuesManagerImpl.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/values/BlockValuesManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/values/BlockValuesManagerImpl.java index 0310f08905..ba63077bc7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/values/BlockValuesManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/values/BlockValuesManagerImpl.java @@ -11,9 +11,9 @@ import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; -import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.values.container.BlockValuesContainer; @@ -151,8 +151,8 @@ private BlockValue getBlockValue(Key key, boolean checkPrices) { public Key getBlockKey(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); - if (((BaseKey) key).isAPIKey() || isValuesMenu(key)) { - return getValuesKey(key); + if (isValuesMenu(key)) { + return markAsAPIIfNeeded(key, getValuesKey(key)); } if (blockValuesContainer.containsKeyRaw(key)) { @@ -162,15 +162,22 @@ public Key getBlockKey(Key key) { if (plugin.getSettings().getSyncWorth() != SyncWorthStatus.NONE) { Key newKey = plugin.getProviders().getPricesProvider().getBlockKey(key); if (newKey != null) { - return newKey; + return markAsAPIIfNeeded(key, newKey); } } Key blockValuesKey = blockValuesContainer.getBlockValueKey(key); if (blockValuesKey != key) - return blockValuesKey; + return markAsAPIIfNeeded(key, blockValuesKey); + + return markAsAPIIfNeeded(key, customBlockKeys.getKey(key, key)); + } + + private Key markAsAPIIfNeeded(Key original, Key newKey) { + if (original != newKey && ((BaseKey) original).isAPIKey()) + newKey = ((BaseKey) newKey).markAPIKey(); - return customBlockKeys.getKey(key, key); + return newKey; } @Override From ce79cb14860bf1702ef1486f0e874fa3552bc9ff Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 7 Feb 2025 15:36:13 +0200 Subject: [PATCH 067/600] Fixed minecarts still count towards entity count even if their limit is reached (#2354) --- .../listener/EntityTrackingListener.java | 9 ++++++--- .../service/world/WorldRecordServiceImpl.java | 3 +++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java index 78a82b209f..e364716772 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java @@ -35,17 +35,20 @@ public EntityTrackingListener(SuperiorSkyblockPlugin plugin) { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) private void onEntitySpawn(CreatureSpawnEvent e) { - this.worldRecordService.get().recordEntitySpawn(e.getEntity()); + if (!e.getEntity().isDead()) + this.worldRecordService.get().recordEntitySpawn(e.getEntity()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) private void onHangingPlace(HangingPlaceEvent e) { - this.worldRecordService.get().recordEntitySpawn(e.getEntity()); + if (!e.getEntity().isDead()) + this.worldRecordService.get().recordEntitySpawn(e.getEntity()); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) private void onVehicleSpawn(VehicleCreateEvent e) { - this.worldRecordService.get().recordEntitySpawn(e.getVehicle()); + if (!e.getVehicle().isDead()) + this.worldRecordService.get().recordEntitySpawn(e.getVehicle()); } /* INTERNAL */ diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java index 139dd40c99..8f32ce5714 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java @@ -252,6 +252,9 @@ private void recordBlockBreakInternal(Island island, Key blockKey, Location bloc public RecordResult recordEntitySpawn(Entity entity) { Preconditions.checkNotNull(entity, "entity parameter cannot be null"); + if (entity.isDead()) + return RecordResult.ENTITY_CANNOT_BE_TRACKED; + if (BukkitEntities.canBypassEntityLimit(entity)) return RecordResult.ENTITY_CANNOT_BE_TRACKED; From de123190010943b9b7cba5665f358df935d02079 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 7 Feb 2025 15:45:36 +0200 Subject: [PATCH 068/600] Fixed detection of blocks placed with minecarts (#2354) --- .../listener/BlockChangesListener.java | 91 ++++--------------- 1 file changed, 17 insertions(+), 74 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index 352f71f3ec..43408bca6b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -16,8 +16,8 @@ import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.world.BukkitEntities; @@ -38,7 +38,6 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.BlockDispenseEvent; import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockFromToEvent; import org.bukkit.event.block.BlockGrowEvent; @@ -54,11 +53,10 @@ import org.bukkit.event.player.PlayerBucketEmptyEvent; import org.bukkit.event.player.PlayerBucketFillEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.vehicle.VehicleCreateEvent; import org.bukkit.event.vehicle.VehicleDestroyEvent; import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.inventory.ItemStack; -import org.bukkit.material.Directional; -import org.bukkit.material.MaterialData; import org.bukkit.metadata.FixedMetadataValue; import java.util.Collection; @@ -156,12 +154,6 @@ private void onBlockFrom(BlockFormEvent e) { } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerInteract(PlayerInteractEvent e) { - onMinecartPlace(e); - onSpawnerChange(e); - } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockSpread(BlockSpreadEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { @@ -171,33 +163,22 @@ public void onBlockSpread(BlockSpreadEvent e) { } } - private void onMinecartPlace(PlayerInteractEvent e) { - if (e.getAction() != Action.RIGHT_CLICK_BLOCK || !Materials.isRail(e.getClickedBlock().getType())) - return; - - PlayerHand playerHand = BukkitItems.getHand(e); - if (playerHand != PlayerHand.MAIN_HAND) - return; - - ItemStack handItem = BukkitItems.getHandItem(e.getPlayer(), playerHand); - - if (handItem == null) - return; - - Material handItemType = handItem.getType(); - if (!Materials.isMinecart(handItemType)) + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onMinecartPlace(VehicleCreateEvent e) { + if (e.getVehicle().isDead() || !(e.getVehicle() instanceof Minecart)) return; - Key minecartBlockKey = getMinecartBlockKey(handItemType); + Key minecartBlockKey = getMinecartBlockKey(e.getVehicle().getType()); if (minecartBlockKey != null) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.worldRecordService.get().recordBlockPlace(minecartBlockKey, - e.getClickedBlock().getLocation(wrapper.getHandle()), + e.getVehicle().getLocation(wrapper.getHandle()), 1, null, REGULAR_RECORD_FLAGS); } } } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) private void onSpawnerChange(PlayerInteractEvent e) { if (e.getAction() != Action.RIGHT_CLICK_BLOCK || e.getClickedBlock().getType() != Materials.SPAWNER.toBukkitType()) @@ -232,42 +213,6 @@ private void onSpawnerChange(PlayerInteractEvent e) { }, 1L); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onMinecartPlaceByDispenser(BlockDispenseEvent e) { - Material dispenseItemType = e.getItem().getType(); - - if (!Materials.isMinecart(dispenseItemType) || e.getBlock().getType() != Material.DISPENSER) - return; - - Block targetBlock = null; - - if (ServerVersion.isLegacy()) { - MaterialData materialData = e.getBlock().getState().getData(); - if (materialData instanceof Directional) { - targetBlock = e.getBlock().getRelative(((Directional) materialData).getFacing()); - } - } else { - Object blockData = plugin.getNMSWorld().getBlockData(e.getBlock()); - if (blockData instanceof org.bukkit.block.data.Directional) { - targetBlock = e.getBlock().getRelative(((org.bukkit.block.data.Directional) blockData).getFacing()); - } - } - - if (targetBlock == null) - return; - - if (!Materials.isRail(targetBlock.getType())) - return; - - Key minecartBlockKey = getMinecartBlockKey(dispenseItemType); - if (minecartBlockKey != null) { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockPlace(minecartBlockKey, targetBlock.getLocation(wrapper.getHandle()), - 1, null, REGULAR_RECORD_FLAGS); - } - } - } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) private void onEntityChangeBlock(EntityChangeBlockEvent e) { Key blockKey; @@ -423,22 +368,20 @@ private void registerBlockDestroyListener() { } @Nullable - private static Key getMinecartBlockKey(Material minecartType) { - switch (minecartType.name()) { - case "HOPPER_MINECART": + private static Key getMinecartBlockKey(EntityType minecartType) { + switch (minecartType) { + case MINECART_HOPPER: return ConstantKeys.HOPPER; - case "COMMAND_MINECART": - case "COMMAND_BLOCK_MINECART": + case MINECART_COMMAND: return ConstantKeys.COMMAND_BLOCK; - case "EXPLOSIVE_MINECART": - case "TNT_MINECART": + case MINECART_TNT: return ConstantKeys.TNT; - case "POWERED_MINECART": - case "FURNACE_MINECART": + case MINECART_FURNACE: return ConstantKeys.FURNACE; - case "STORAGE_MINECART": - case "CHEST_MINECART": + case MINECART_CHEST: return ConstantKeys.CHEST; + case MINECART_MOB_SPAWNER: + return ConstantKeys.MOB_SPAWNER; } return null; From e6671690e2752334b20bdc1a41a6ce480cdf897f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 7 Feb 2025 15:55:16 +0200 Subject: [PATCH 069/600] Fix NPE errors when some events are called in IslandMissions (#2355) --- .../resources/modules/missions/IslandMissions | Bin 27173 -> 27227 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/modules/missions/IslandMissions b/src/main/resources/modules/missions/IslandMissions index c1d06e6d24e3f51b4d9f8bbaa56ba171e2a85ad3..799d0c7b632c8c76f6bd6542d089d72875067c25 100644 GIT binary patch delta 5259 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 I{^#}o0WrPe6aWAK From 19dde66f9c923229c0f559aed565d4288d68a2d8 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 13:29:34 +0200 Subject: [PATCH 070/600] Disable collisions with vehicles in other islands (#2358) --- .../listener/ProtectionListener.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index d37cfdfb54..89f5c16557 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -69,6 +69,7 @@ import org.bukkit.event.raid.RaidTriggerEvent; import org.bukkit.event.vehicle.VehicleDamageEvent; import org.bukkit.event.vehicle.VehicleEnterEvent; +import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; @@ -453,6 +454,22 @@ public void onVehicleOpen(InventoryOpenEvent e) { e.setCancelled(true); } + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onPlayerCollideWithVehicle(VehicleEntityCollisionEvent e) { + if (!(e.getEntity() instanceof Player)) + return; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getEntity()); + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location vehicleLocation = e.getVehicle().getLocation(wrapper.getHandle()); + interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, + vehicleLocation, IslandPrivileges.MINECART_ENTER); + } + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, false)) + e.setCancelled(true); + } + /* ITEMS */ @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) From 5bf6e5d490245f878efefdc6343aef63c3a6c0b3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 13:59:14 +0200 Subject: [PATCH 071/600] Fixed the ability to open boat chests on other islands (#2358) --- .../superiorskyblock/listener/ProtectionListener.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 89f5c16557..a340e1dc71 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -30,9 +30,9 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.FishHook; -import org.bukkit.entity.Minecart; import org.bukkit.entity.Player; import org.bukkit.entity.Trident; +import org.bukkit.entity.Vehicle; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -440,13 +440,13 @@ public void onVehicleEnter(VehicleEnterEvent e) { public void onVehicleOpen(InventoryOpenEvent e) { InventoryHolder inventoryHolder = e.getInventory().getHolder(); - if (!(inventoryHolder instanceof Minecart)) + if (!(inventoryHolder instanceof Vehicle)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location minecartLocation = ((Minecart) inventoryHolder).getLocation(wrapper.getHandle()); + Location minecartLocation = ((Vehicle) inventoryHolder).getLocation(wrapper.getHandle()); interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, minecartLocation, IslandPrivileges.MINECART_OPEN); } From 8f1b6eddcaeb1b781f98564b7cc7bff7ac4fbab4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 14:01:54 +0200 Subject: [PATCH 072/600] Fixed the ability to fuel minecart furnaces on other islands (#2358) --- .../nms/v1_12_R1/NMSEntitiesImpl.java | 13 +++++++++++++ .../nms/v1_16_R3/NMSEntitiesImpl.java | 13 +++++++++++++ .../superiorskyblock/nms/v1_17/NMSEntitiesImpl.java | 12 ++++++++++++ .../superiorskyblock/nms/v1_18/NMSEntitiesImpl.java | 11 +++++++++++ .../superiorskyblock/nms/v1_19/NMSEntitiesImpl.java | 11 +++++++++++ .../nms/v1_20_3/NMSEntitiesImpl.java | 11 +++++++++++ .../nms/v1_20_4/NMSEntitiesImpl.java | 11 +++++++++++ .../superiorskyblock/nms/v1_21/NMSEntitiesImpl.java | 12 ++++++++++++ .../nms/v1_21_3/NMSEntitiesImpl.java | 9 +++++++++ .../nms/v1_21_4/NMSEntitiesImpl.java | 9 +++++++++ .../nms/v1_8_R3/NMSEntitiesImpl.java | 7 +++++++ .../superiorskyblock/nms/NMSEntities.java | 3 +++ .../service/region/RegionManagerServiceImpl.java | 6 +++++- 13 files changed, 127 insertions(+), 1 deletion(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSEntitiesImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSEntitiesImpl.java index 80b34dfdc9..f526a579a0 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSEntitiesImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSEntitiesImpl.java @@ -3,17 +3,23 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.server.v1_12_R1.Entity; +import net.minecraft.server.v1_12_R1.EntityMinecartFurnace; +import net.minecraft.server.v1_12_R1.Items; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftAnimals; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_12_R1.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack; import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; public class NMSEntitiesImpl implements NMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>(Entity.class, int.class, "al"); + private static final ReflectField MINECART_FURNACE_FUEL = new ReflectField<>( + EntityMinecartFurnace.class, int.class, "d"); @Override public ItemStack[] getEquipment(EntityEquipment entityEquipment) { @@ -35,6 +41,13 @@ public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().e(CraftItemStack.asNMSCopy(itemStack)); } + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + EntityMinecartFurnace minecartFurnace = (EntityMinecartFurnace) ((CraftMinecartFurnace) minecart).getHandle(); + return MINECART_FURNACE_FUEL.get(minecartFurnace) + 3600 <= 32000 && + CraftItemStack.asNMSCopy(bukkitItem).getItem() == Items.COAL; + } + @Override public int getPortalTicks(org.bukkit.entity.Entity entity) { return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSEntitiesImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSEntitiesImpl.java index 2479ab51ee..df5bf15520 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSEntitiesImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSEntitiesImpl.java @@ -3,17 +3,24 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.server.v1_16_R3.Entity; +import net.minecraft.server.v1_16_R3.EntityMinecartFurnace; +import net.minecraft.server.v1_16_R3.IMaterial; +import net.minecraft.server.v1_16_R3.Items; +import net.minecraft.server.v1_16_R3.RecipeItemStack; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftAnimals; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_16_R3.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack; import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; public class NMSEntitiesImpl implements NMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>(Entity.class, int.class, "portalTicks"); + private static final RecipeItemStack MINECART_FURNACE_FUEL_RECIPE = RecipeItemStack.a(Items.COAL, Items.CHARCOAL); @Override public ItemStack[] getEquipment(EntityEquipment entityEquipment) { @@ -35,6 +42,12 @@ public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().k(CraftItemStack.asNMSCopy(itemStack)); } + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + MINECART_FURNACE_FUEL_RECIPE.test(CraftItemStack.asNMSCopy(bukkitItem)); + } + @Override public int getPortalTicks(org.bukkit.entity.Entity entity) { return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSEntitiesImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSEntitiesImpl.java index bab4a7108d..5ebfd9f4a4 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSEntitiesImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSEntitiesImpl.java @@ -3,11 +3,16 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.Ingredient; +import net.minecraft.world.level.ItemLike; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftAnimals; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_17_R1.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; @@ -17,6 +22,7 @@ public class NMSEntitiesImpl implements NMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); + private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override public ItemStack[] getEquipment(EntityEquipment entityEquipment) { @@ -38,6 +44,12 @@ public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); } + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); + } + @Override public int getPortalTicks(org.bukkit.entity.Entity entity) { return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSEntitiesImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSEntitiesImpl.java index a476350170..83dbf8f5b2 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSEntitiesImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSEntitiesImpl.java @@ -3,11 +3,15 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.Ingredient; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftAnimals; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_18_R2.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; @@ -17,6 +21,7 @@ public class NMSEntitiesImpl implements NMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); + private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override public ItemStack[] getEquipment(EntityEquipment entityEquipment) { @@ -38,6 +43,12 @@ public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); } + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); + } + @Override public int getPortalTicks(org.bukkit.entity.Entity entity) { return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSEntitiesImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSEntitiesImpl.java index dbde42d409..bc5ef35a58 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSEntitiesImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSEntitiesImpl.java @@ -3,11 +3,15 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.Ingredient; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftAnimals; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_19_R3.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; @@ -17,6 +21,7 @@ public class NMSEntitiesImpl implements NMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); + private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override public ItemStack[] getEquipment(EntityEquipment entityEquipment) { @@ -38,6 +43,12 @@ public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); } + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); + } + @Override public int getPortalTicks(org.bukkit.entity.Entity entity) { return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSEntitiesImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSEntitiesImpl.java index 13c7b967ce..950a5490ac 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSEntitiesImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSEntitiesImpl.java @@ -3,11 +3,15 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.Ingredient; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftAnimals; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; @@ -17,6 +21,7 @@ public class NMSEntitiesImpl implements NMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); + private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override public ItemStack[] getEquipment(EntityEquipment entityEquipment) { @@ -38,6 +43,12 @@ public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); } + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); + } + @Override public int getPortalTicks(org.bukkit.entity.Entity entity) { return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSEntitiesImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSEntitiesImpl.java index 530e51e68b..b36262b712 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSEntitiesImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSEntitiesImpl.java @@ -3,11 +3,15 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.Ingredient; import org.bukkit.Material; import org.bukkit.craftbukkit.entity.CraftAnimals; import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; @@ -17,6 +21,7 @@ public class NMSEntitiesImpl implements NMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); + private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override public ItemStack[] getEquipment(EntityEquipment entityEquipment) { @@ -38,6 +43,12 @@ public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); } + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); + } + @Override public int getPortalTicks(org.bukkit.entity.Entity entity) { return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSEntitiesImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSEntitiesImpl.java index 95ccf4af81..e36a9e15d2 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSEntitiesImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSEntitiesImpl.java @@ -3,16 +3,22 @@ import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.Ingredient; import org.bukkit.Material; import org.bukkit.craftbukkit.entity.CraftAnimals; import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; public class NMSEntitiesImpl implements NMSEntities { + private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); + @Override public ItemStack[] getEquipment(EntityEquipment entityEquipment) { ItemStack[] itemStacks = new ItemStack[7]; @@ -33,6 +39,12 @@ public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); } + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); + } + @Override public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { Entity entity = ((CraftEntity) bukkitEntity).getHandle(); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSEntitiesImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSEntitiesImpl.java index ae9c5242e7..939b28b0d9 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSEntitiesImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSEntitiesImpl.java @@ -1,13 +1,16 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_3; import com.bgsoftware.superiorskyblock.nms.NMSEntities; +import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; import org.bukkit.Material; import org.bukkit.craftbukkit.entity.CraftAnimals; import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; @@ -33,6 +36,12 @@ public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); } + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); + } + @Override public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { Entity entity = ((CraftEntity) bukkitEntity).getHandle(); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java index 6ac72430e4..35f6fdba88 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java @@ -1,13 +1,16 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_4; import com.bgsoftware.superiorskyblock.nms.NMSEntities; +import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; import org.bukkit.Material; import org.bukkit.craftbukkit.entity.CraftAnimals; import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; @@ -33,6 +36,12 @@ public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); } + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); + } + @Override public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { Entity entity = ((CraftEntity) bukkitEntity).getHandle(); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSEntitiesImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSEntitiesImpl.java index ce8497b8e2..40d5cd49b5 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSEntitiesImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSEntitiesImpl.java @@ -3,11 +3,13 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.server.v1_8_R3.Entity; +import net.minecraft.server.v1_8_R3.Items; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftAnimals; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftItemStack; import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; @@ -34,6 +36,11 @@ public boolean isAnimalFood(ItemStack itemStack, Animals animals) { return ((CraftAnimals) animals).getHandle().d(CraftItemStack.asNMSCopy(itemStack)); } + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + return CraftItemStack.asNMSCopy(bukkitItem).getItem() == Items.COAL; + } + @Override public int getPortalTicks(org.bukkit.entity.Entity entity) { return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSEntities.java index d3c614cfff..9a9fd7f69f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSEntities.java @@ -2,6 +2,7 @@ import org.bukkit.entity.Animals; import org.bukkit.entity.Entity; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; @@ -11,6 +12,8 @@ public interface NMSEntities { boolean isAnimalFood(ItemStack itemStack, Animals animals); + boolean isMinecartFuel(ItemStack itemStack, PoweredMinecart minecart); + int getPortalTicks(Entity entity); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 9b118a821d..f1664ce264 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -22,8 +22,8 @@ import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -55,6 +55,7 @@ import org.bukkit.entity.Painting; import org.bukkit.entity.Player; import org.bukkit.entity.Villager; +import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.event.block.Action; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; @@ -258,6 +259,9 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent islandPrivilege = IslandPrivileges.PAINTING; } else if (entity instanceof Fish && !ServerVersion.isLegacy()) { islandPrivilege = IslandPrivileges.PICKUP_FISH; + } else if (usedItem != null && entity instanceof PoweredMinecart && + plugin.getNMSEntities().isMinecartFuel(usedItem, (PoweredMinecart) entity)) { + islandPrivilege = IslandPrivileges.MINECART_OPEN; } else { return InteractionResult.SUCCESS; } From a6b64e67d596bada6f28f20a84899d965587cfb4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 14:06:27 +0200 Subject: [PATCH 073/600] Add all type of candles to interactables (#2358) --- src/main/resources/interactables.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index 65d25d40aa..4601f24a05 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -43,16 +43,20 @@ interactables: - 'BIRCH_WALL_HANGING_SIGN' - 'BIRCH_WALL_SIGN' - 'BLACK_BED' + - 'BLACK_CANDLE' - 'BLACK_SHULKER_BOX' - 'BLAST_FURNACE' - 'BLUE_BED' + - 'BLUE_CANDLE' - 'BLUE_SHULKER_BOX' - 'BREWING_STAND' - 'BROWN_BED' + - 'BROWN_CANDLE' - 'BROWN_SHULKER_BOX' - 'BURNING_FURNACE' - 'CAKE' - 'CAKE_BLOCK' + - 'CANDLE' - 'CARTOGRAPHER_TABLE' - 'CAULDRON' - 'CAVE_VINES_PLANT' @@ -88,6 +92,7 @@ interactables: - 'CRIMSON_WALL_HANGING_SIGN' - 'CRIMSON_WALL_SIGN' - 'CYAN_BED' + - 'CYAN_CANDLE' - 'CYAN_SHULKER_BOX' - 'DAMAGED_ANVIL' - 'DARK_OAK_BUTTON' @@ -122,8 +127,10 @@ interactables: - 'GLOWING_REDSTONE_ORE' - 'GOLD_PLATE' - 'GRAY_BED' + - 'GRAY_CANDLE' - 'GRAY_SHULKER_BOX' - 'GREEN_BED' + - 'GREEN_CANDLE' - 'GREEN_SHULKER_BOX' - 'GRINDSTONE' - 'HEAVY_WEIGHTED_PRESSURE_PLATE' @@ -147,15 +154,19 @@ interactables: - 'LECTERN' - 'LEVER' - 'LIGHT_BLUE_BED' + - 'LIGHT_BLUE_CANDLE' - 'LIGHT_BLUE_SHULKER_BOX' - 'LIGHT_GRAY_BED' + - 'LIGHT_GRAY_CANDLE' - 'LIGHT_GRAY_SHULKER_BOX' - 'LIGHT_WEIGHTED_PRESSURE_PLATE' - 'LIME_BED' + - 'LIME_CANDLE' - 'LIME_SHULKER_BOX' - 'LODESTONE' - 'LOOM' - 'MAGENTA_BED' + - 'MAGENTA_CANDLE' - 'MAGENTA_SHULKER_BOX' - 'MANGROVE_HANGING_SIGN' - 'MANGROVE_SIGN' @@ -176,10 +187,12 @@ interactables: - 'OAK_WALL_HANGING_SIGN' - 'OAK_WALL_SIGN' - 'ORANGE_BED' + - 'ORANGE_CANDLE' - 'ORANGE_SHULKER_BOX' - 'OXIDIZED_COPPER_DOOR' - 'OXIDIZED_COPPER_TRAPDOOR' - 'PINK_BED' + - 'PINK_CANDLE' - 'PINK_SHULKER_BOX' - 'POLISHED_BLACKSTONE_BUTTON' - 'POLISHED_BLACKSTONE_PRESSURE_PLATE' @@ -217,11 +230,13 @@ interactables: - 'POTTED_WITHER_ROSE' - 'PUMPKIN' - 'PURPLE_BED' + - 'PURPLE_CANDLE' - 'PURPLE_SHULKER_BOX' - 'REDSTONE_COMPARATOR_OFF' - 'REDSTONE_COMPARATOR_ON' - 'REDSTONE_ORE' - 'RED_BED' + - 'RED_CANDLE' - 'RED_SHULKER_BOX' - 'REPEATER' - 'REPEATING_COMMAND_BLOCK' @@ -276,9 +291,11 @@ interactables: - 'WEATHERED_COPPER_DOOR' - 'WEATHERED_COPPER_TRAPDOOR' - 'WHITE_BED' + - 'WHITE_CANDLE' - 'WHITE_SHULKER_BOX' - 'WOODEN_DOOR' - 'WOOD_BUTTON' - 'WORKBENCH' - 'YELLOW_BED' + - 'YELLOW_CANDLE' - 'YELLOW_SHULKER_BOX' \ No newline at end of file From 297816a9d35c60c37ad0d4f5b2dda780cb470ee8 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 15:19:08 +0200 Subject: [PATCH 074/600] Trials vaults and spawners should not be interactables on other islands (#2358) --- .../nms/v1_21/NMSWorldImpl.java | 51 ++++++++++++++++++ .../nms/v1_21/trial/IslandPlayerDetector.java | 53 ++++++++++++++++++ .../nms/v1_21_3/NMSWorldImpl.java | 51 ++++++++++++++++++ .../v1_21_3/trial/IslandPlayerDetector.java | 53 ++++++++++++++++++ .../nms/v1_21_4/NMSWorldImpl.java | 53 +++++++++++++++++- .../v1_21_4/trial/IslandPlayerDetector.java | 53 ++++++++++++++++++ .../listener/FeaturesListener.java | 54 +++++++++++++++++++ .../superiorskyblock/nms/NMSWorld.java | 4 ++ .../region/RegionManagerServiceImpl.java | 8 +++ 9 files changed, 378 insertions(+), 2 deletions(-) create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index f3e401f35b..e1026bcbb7 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.v1_21.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_21.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_21.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_21.world.WorldEditSessionImpl; @@ -34,9 +35,15 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; +import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; +import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import org.bukkit.Bukkit; @@ -127,6 +134,50 @@ public void listenSpawner(Location location, IntFunction delayChangeCal blockEntityTickers.addAll(tickersToAdd); } + @Override + public void replaceTrialBlockPlayerDetector(Island island, Location location) { + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); + if (blockEntity == null) + return; + + if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { + VaultConfig vaultConfig = vaultBlockEntity.getConfig(); + + PlayerDetector playerDetector = vaultConfig.playerDetector(); + if (playerDetector instanceof IslandPlayerDetector) + return; + + VaultConfig newConfig = new VaultConfig( + vaultConfig.lootTable(), + vaultConfig.activationRange(), + vaultConfig.deactivationRange(), + vaultConfig.keyItem(), + vaultConfig.overrideLootTableToDisplay(), + IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), + vaultConfig.entitySelector() + ); + + vaultBlockEntity.setConfig(newConfig); + } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { + TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); + PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); + + if (playerDetector instanceof IslandPlayerDetector) + return; + + trialSpawnerBlockEntity.trialSpawner = new TrialSpawner( + trialSpawner.normalConfig, + trialSpawner.ominousConfig, + trialSpawner.getData(), + trialSpawner.getTargetCooldownLength(), + trialSpawner.getRequiredPlayerRange(), + trialSpawner.stateAccessor, + IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector), + trialSpawner.getEntitySelector() + ); + } + } + @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java new file mode 100644 index 0000000000..a8634c37c1 --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java @@ -0,0 +1,53 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.trial; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +public class IslandPlayerDetector implements PlayerDetector { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final PlayerDetector original; + private final IslandPrivilege requiredPrivilege; + + public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + } + + public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + } + + private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + this.island = island; + this.original = original; + this.requiredPrivilege = requiredPrivilege; + } + + @Override + public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { + List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); + if (!players.isEmpty()) { + players = new LinkedList<>(players); + players.removeIf(uuid -> { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); + return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + }); + players = Collections.unmodifiableList(players); + } + return players; + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index fb1f679190..5481f814d9 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.v1_21_3.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_21_3.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.WorldEditSessionImpl; @@ -34,9 +35,15 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; +import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; +import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import org.bukkit.Bukkit; @@ -127,6 +134,50 @@ public void listenSpawner(Location location, IntFunction delayChangeCal blockEntityTickers.addAll(tickersToAdd); } + @Override + public void replaceTrialBlockPlayerDetector(Island island, Location location) { + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); + if (blockEntity == null) + return; + + if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { + VaultConfig vaultConfig = vaultBlockEntity.getConfig(); + + PlayerDetector playerDetector = vaultConfig.playerDetector(); + if (playerDetector instanceof IslandPlayerDetector) + return; + + VaultConfig newConfig = new VaultConfig( + vaultConfig.lootTable(), + vaultConfig.activationRange(), + vaultConfig.deactivationRange(), + vaultConfig.keyItem(), + vaultConfig.overrideLootTableToDisplay(), + IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), + vaultConfig.entitySelector() + ); + + vaultBlockEntity.setConfig(newConfig); + } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { + TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); + PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); + + if (playerDetector instanceof IslandPlayerDetector) + return; + + trialSpawnerBlockEntity.trialSpawner = new TrialSpawner( + trialSpawner.normalConfig, + trialSpawner.ominousConfig, + trialSpawner.getData(), + trialSpawner.getTargetCooldownLength(), + trialSpawner.getRequiredPlayerRange(), + trialSpawner.stateAccessor, + IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector), + trialSpawner.getEntitySelector() + ); + } + } + @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java new file mode 100644 index 0000000000..0b7f8e1264 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java @@ -0,0 +1,53 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.trial; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +public class IslandPlayerDetector implements PlayerDetector { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final PlayerDetector original; + private final IslandPrivilege requiredPrivilege; + + public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + } + + public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + } + + private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + this.island = island; + this.original = original; + this.requiredPrivilege = requiredPrivilege; + } + + @Override + public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { + List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); + if (!players.isEmpty()) { + players = new LinkedList<>(players); + players.removeIf(uuid -> { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); + return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + }); + players = Collections.unmodifiableList(players); + } + return players; + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index e0f0d21319..f941823291 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.v1_21_4.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_21_4.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.WorldEditSessionImpl; @@ -34,9 +35,15 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; +import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; +import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import org.bukkit.Bukkit; @@ -68,8 +75,6 @@ public class NMSWorldImpl implements NMSWorld { - private static final byte[] EMPTY_LIGHTS = new byte[0]; - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); @@ -127,6 +132,50 @@ public void listenSpawner(Location location, IntFunction delayChangeCal blockEntityTickers.addAll(tickersToAdd); } + @Override + public void replaceTrialBlockPlayerDetector(Island island, Location location) { + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); + if (blockEntity == null) + return; + + if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { + VaultConfig vaultConfig = vaultBlockEntity.getConfig(); + + PlayerDetector playerDetector = vaultConfig.playerDetector(); + if (playerDetector instanceof IslandPlayerDetector) + return; + + VaultConfig newConfig = new VaultConfig( + vaultConfig.lootTable(), + vaultConfig.activationRange(), + vaultConfig.deactivationRange(), + vaultConfig.keyItem(), + vaultConfig.overrideLootTableToDisplay(), + IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), + vaultConfig.entitySelector() + ); + + vaultBlockEntity.setConfig(newConfig); + } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { + TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); + PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); + + if (playerDetector instanceof IslandPlayerDetector) + return; + + trialSpawnerBlockEntity.trialSpawner = new TrialSpawner( + trialSpawner.normalConfig, + trialSpawner.ominousConfig, + trialSpawner.getData(), + trialSpawner.getTargetCooldownLength(), + trialSpawner.getRequiredPlayerRange(), + trialSpawner.stateAccessor, + IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector), + trialSpawner.getEntitySelector() + ); + } + } + @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java new file mode 100644 index 0000000000..665907d4a3 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java @@ -0,0 +1,53 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.trial; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +public class IslandPlayerDetector implements PlayerDetector { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final PlayerDetector original; + private final IslandPrivilege requiredPrivilege; + + public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + } + + public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + } + + private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + this.island = island; + this.original = original; + this.requiredPrivilege = requiredPrivilege; + } + + @Override + public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { + List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); + if (!players.isEmpty()) { + players = new LinkedList<>(players); + players.removeIf(uuid -> { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); + return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + }); + players = Collections.unmodifiableList(players); + } + return players; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java index 5cb47eeb50..732b52151f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.listener; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandCreateEvent; @@ -13,6 +14,7 @@ import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; @@ -23,14 +25,17 @@ import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.inventory.ItemStack; import java.util.HashMap; @@ -43,6 +48,12 @@ public class FeaturesListener implements Listener { private final Map, EventMethods> CACHED_EVENT_METHODS = new ArrayMap<>(); + @Nullable + private static final Material VAULT = EnumHelper.getEnum(Material.class, "VAULT"); + + @Nullable + private static final Material TRIAL_SPAWNER = EnumHelper.getEnum(Material.class, "TRIAL_SPAWNER"); + private final SuperiorSkyblockPlugin plugin; private final LazyReference protectionManager = new LazyReference() { @Override @@ -53,6 +64,8 @@ protected RegionManagerService create() { public FeaturesListener(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; + if (VAULT != null && TRIAL_SPAWNER != null) + plugin.getServer().getPluginManager().registerEvents(new TrialsTracker(), plugin); } /* EVENT COMMANDS */ @@ -183,6 +196,47 @@ public void onPlayerCommand(PlayerCommandPreprocessEvent e) { } } + /* VAULTS & TRIAL SPAWNERS */ + + private class TrialsTracker implements Listener { + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onBlockPlace(BlockPlaceEvent e) { + Material blockType = e.getBlock().getType(); + + if (blockType != VAULT && blockType != TRIAL_SPAWNER) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = e.getBlock().getLocation(wrapper.getHandle()); + + Island island = plugin.getGrid().getIslandAt(blockLocation); + + if (island == null) + return; + + plugin.getNMSWorld().replaceTrialBlockPlayerDetector(island, blockLocation); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onChunkLoad(ChunkLoadEvent e) { + List chunkIslands = plugin.getGrid().getIslandsAt(e.getChunk()); + chunkIslands.forEach(island -> handleIslandChunkLoad(island, e.getChunk())); + } + + private void handleIslandChunkLoad(Island island, Chunk chunk) { + List blockEntities = plugin.getNMSChunks().getBlockEntities(chunk); + + if (blockEntities.isEmpty()) + return; + + blockEntities.forEach(blockEntity -> + plugin.getNMSWorld().replaceTrialBlockPlayerDetector(island, blockEntity)); + } + + } + /* INTERNAL */ private static class EventMethods { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java index fde0a0f48f..c17dc5089d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java @@ -25,6 +25,10 @@ public interface NMSWorld { void listenSpawner(Location location, IntFunction delayChangeCallback); + default void replaceTrialBlockPlayerDetector(Island island, Location location) { + // Does not exist. + } + void setWorldBorder(SuperiorPlayer superiorPlayer, Island island); Object getBlockData(Block block); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index f1664ce264..eb8403924f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -75,6 +75,12 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService @Nullable private static final Material LECTERN = EnumHelper.getEnum(Material.class, "LECTERN"); @Nullable + private static final Material VAULT = EnumHelper.getEnum(Material.class, "VAULT"); + @Nullable + private static final Material TRIAL_KEY = EnumHelper.getEnum(Material.class, "TRIAL_KEY"); + @Nullable + private static final Material OMINOUS_TRIAL_KEY = EnumHelper.getEnum(Material.class, "OMINOUS_TRIAL_KEY"); + @Nullable private static final EntityType AXOLOTL_TYPE = getSafeEntityType("AXOLOTL"); private static final int MAX_PICKUP_DISTANCE = 1; private static EnumerateSet WORLD_PERMISSIONS_CACHE; @@ -184,6 +190,8 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc islandPrivilege = IslandPrivileges.CHEST_ACCESS; } else if (blockState instanceof InventoryHolder) { islandPrivilege = IslandPrivileges.USE; + } else if (usedItem != null && blockType == VAULT && (usedItem.getType() == TRIAL_KEY || usedItem.getType() == OMINOUS_TRIAL_KEY)) { + islandPrivilege = IslandPrivileges.USE; } else if (blockState instanceof Sign) { islandPrivilege = IslandPrivileges.SIGN_INTERACT; } else if (blockType == Materials.SPAWNER.toBukkitType()) { From 19bf9d52cd1e69498e4e3bf86fffc1faaf0fdc18 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 15:35:19 +0200 Subject: [PATCH 075/600] Fixed the ability to throw chicken eggs on other islands (#2358) --- .../listener/ProtectionListener.java | 49 +++++++------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index a340e1dc71..121576298f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -21,17 +21,17 @@ import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Bukkit; -import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; +import org.bukkit.entity.Egg; +import org.bukkit.entity.EnderPearl; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.FishHook; import org.bukkit.entity.Player; -import org.bukkit.entity.Trident; import org.bukkit.entity.Vehicle; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -64,7 +64,6 @@ import org.bukkit.event.player.PlayerPickupItemEvent; import org.bukkit.event.player.PlayerShearEntityEvent; import org.bukkit.event.player.PlayerTakeLecternBookEvent; -import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerUnleashEntityEvent; import org.bukkit.event.raid.RaidTriggerEvent; import org.bukkit.event.vehicle.VehicleDamageEvent; @@ -92,6 +91,8 @@ public class ProtectionListener implements Listener { private static final EntityType WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "WIND_CHARGE"); @Nullable private static final Material POINTED_DRIPSTONE = EnumHelper.getEnum(Material.class, "POINTED_DRIPSTONE"); + @Nullable + private static final EntityType TRIDENT = EnumHelper.getEnum(EntityType.class, "TRIDENT"); private final SuperiorSkyblockPlugin plugin; private final LazyReference protectionManager = new LazyReference() { @@ -491,41 +492,29 @@ public void onPlayerPickupItem(PlayerPickupItemEvent e) { /* PROJECTILE INTERACTS */ @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPearlTeleport(PlayerTeleportEvent e) { - if (e.getCause() != PlayerTeleportEvent.TeleportCause.ENDER_PEARL) - return; - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handlePlayerEnderPearl(superiorPlayer, e.getTo()); - - if (!ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - return; - - e.setCancelled(true); + public void onPlayerLaunchProjectile(ProjectileLaunchEvent e) { + BukkitEntities.getPlayerSource(e.getEntity()).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(launcherPlayer -> { + IslandPrivilege islandPrivilege; - if (e.getPlayer().getGameMode() != GameMode.CREATIVE) { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - BukkitItems.addItem(new ItemStack(Material.ENDER_PEARL), e.getPlayer().getInventory(), - e.getPlayer().getLocation(wrapper.getHandle())); + if (e.getEntity() instanceof FishHook && !ServerVersion.isLegacy()) { + islandPrivilege = IslandPrivileges.FISH; + } else if (e.getEntityType() == TRIDENT) { + islandPrivilege = IslandPrivileges.PICKUP_DROPS; + } else if (e.getEntity() instanceof Egg) { + islandPrivilege = IslandPrivileges.ANIMAL_SPAWN; + } else if (e.getEntity() instanceof EnderPearl) { + islandPrivilege = IslandPrivileges.ENDER_PEARL; + } else { + return; } - } - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerFish(ProjectileLaunchEvent e) { - if (!(e.getEntity() instanceof FishHook) && (ServerVersion.isLegacy() || !(e.getEntity() instanceof Trident))) - return; - - BukkitEntities.getPlayerSource(e.getEntity()).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(fisherPlayer -> { - IslandPrivilege islandPrivilege = e.getEntity() instanceof FishHook ? IslandPrivileges.FISH : IslandPrivileges.PICKUP_DROPS; InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = e.getEntity().getLocation(wrapper.getHandle()); - interactionResult = this.protectionManager.get().handleCustomInteraction(fisherPlayer, + interactionResult = this.protectionManager.get().handleCustomInteraction(launcherPlayer, entityLocation, islandPrivilege); } - if (ProtectionHelper.shouldPreventInteraction(interactionResult, fisherPlayer, true)) + if (ProtectionHelper.shouldPreventInteraction(interactionResult, launcherPlayer, true)) e.setCancelled(true); }); } From c4dd8cc1966ebb0198984318165a6cf0dcc3c949 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 17:18:53 +0200 Subject: [PATCH 076/600] Fixed the ability to trigger sculk sensors on other islands (#2358) --- .../nms/v1_17/NMSWorldImpl.java | 14 +++ .../IslandSculkSensorBlockEntity.java | 41 +++++++++ .../nms/v1_18/NMSWorldImpl.java | 14 +++ .../IslandSculkSensorBlockEntity.java | 41 +++++++++ .../nms/v1_19/NMSWorldImpl.java | 16 +++- .../IslandSculkSensorBlockEntity.java | 39 ++++++++ .../nms/v1_20_3/NMSWorldImpl.java | 18 +++- .../vibration/IslandVibrationUser.java | 89 ++++++++++++++++++ .../nms/v1_20_4/NMSWorldImpl.java | 16 +++- .../vibration/IslandVibrationUser.java | 90 +++++++++++++++++++ .../nms/v1_21/NMSWorldImpl.java | 18 +++- .../v1_21/vibration/IslandVibrationUser.java | 90 +++++++++++++++++++ .../nms/v1_21_3/NMSWorldImpl.java | 18 +++- .../vibration/IslandVibrationUser.java | 90 +++++++++++++++++++ .../nms/v1_21_4/NMSWorldImpl.java | 16 +++- .../vibration/IslandVibrationUser.java | 90 +++++++++++++++++++ .../island/privilege/IslandPrivileges.java | 2 + .../listener/FeaturesListener.java | 54 ++++++++--- .../listener/ProtectionListener.java | 6 +- .../superiorskyblock/nms/NMSWorld.java | 4 + src/main/resources/config.yml | 1 + src/main/resources/menus/permissions1_17.yml | 33 +++++++ src/main/resources/menus/permissions1_20.yml | 33 +++++++ src/main/resources/menus/permissions1_21.yml | 33 +++++++ 24 files changed, 834 insertions(+), 32 deletions(-) create mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/vibration/IslandSculkSensorBlockEntity.java create mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/vibration/IslandSculkSensorBlockEntity.java create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/vibration/IslandSculkSensorBlockEntity.java create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/vibration/IslandVibrationUser.java create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/vibration/IslandVibrationUser.java create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/vibration/IslandVibrationUser.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/vibration/IslandVibrationUser.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/vibration/IslandVibrationUser.java diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index ec726df486..9c780c371f 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_17.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_17.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_17.vibration.IslandSculkSensorBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_17.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_17.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_17.world.WorldEditSessionImpl; @@ -35,6 +36,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; @@ -119,6 +121,18 @@ public void listenSpawner(Location location, IntFunction delayChangeCal blockEntityTickers.addAll(tickersToAdd); } + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity instanceof IslandSculkSensorBlockEntity) + return; + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + serverLevel.removeBlockEntity(sculkSensorBlockEntity.getBlockPos()); + + serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity)); + } + @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/vibration/IslandSculkSensorBlockEntity.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/vibration/IslandSculkSensorBlockEntity.java new file mode 100644 index 0000000000..fb5c5309c5 --- /dev/null +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/vibration/IslandSculkSensorBlockEntity.java @@ -0,0 +1,41 @@ +package com.bgsoftware.superiorskyblock.nms.v1_17.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.GameEventListener; + +import javax.annotation.Nullable; + +public class IslandSculkSensorBlockEntity extends SculkSensorBlockEntity { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + + public IslandSculkSensorBlockEntity(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + super(sculkSensorBlockEntity.getBlockPos(), sculkSensorBlockEntity.getBlockState()); + this.island = island; + } + + @Override + public boolean shouldListen(Level world, GameEventListener listener, BlockPos pos, GameEvent event, @Nullable Entity entity) { + if (!super.shouldListen(world, listener, pos, event, entity)) + return false; + + if (entity instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index 0e35556c62..d33fdc2bb7 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_18.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_18.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_18.vibration.IslandSculkSensorBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_18.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_18.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_18.world.WorldEditSessionImpl; @@ -35,6 +36,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; @@ -120,6 +122,18 @@ public void listenSpawner(Location location, IntFunction delayChangeCal blockEntityTickers.addAll(tickersToAdd); } + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity instanceof IslandSculkSensorBlockEntity) + return; + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + serverLevel.removeBlockEntity(sculkSensorBlockEntity.getBlockPos()); + + serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity)); + } + @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/vibration/IslandSculkSensorBlockEntity.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/vibration/IslandSculkSensorBlockEntity.java new file mode 100644 index 0000000000..bf0acfb43b --- /dev/null +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/vibration/IslandSculkSensorBlockEntity.java @@ -0,0 +1,41 @@ +package com.bgsoftware.superiorskyblock.nms.v1_18.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.GameEventListener; + +import javax.annotation.Nullable; + +public class IslandSculkSensorBlockEntity extends SculkSensorBlockEntity { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + + public IslandSculkSensorBlockEntity(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + super(sculkSensorBlockEntity.getBlockPos(), sculkSensorBlockEntity.getBlockState()); + this.island = island; + } + + @Override + public boolean shouldListen(Level world, GameEventListener listener, BlockPos pos, GameEvent event, @Nullable Entity entity) { + if (!super.shouldListen(world, listener, pos, event, entity)) + return false; + + if (entity instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index c9033be449..f1b92ef700 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_19.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_19.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_19.vibration.IslandSculkSensorBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_19.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_19.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_19.world.WorldEditSessionImpl; @@ -35,6 +36,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; @@ -69,8 +71,6 @@ public class NMSWorldImpl implements NMSWorld { - private static final byte[] EMPTY_LIGHTS = new byte[0]; - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, Object.class, "chunkPacketBlockController") @@ -122,6 +122,18 @@ public void listenSpawner(Location location, IntFunction delayChangeCal blockEntityTickers.addAll(tickersToAdd); } + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity instanceof IslandSculkSensorBlockEntity) + return; + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + serverLevel.removeBlockEntity(sculkSensorBlockEntity.getBlockPos()); + + serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity)); + } + @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/vibration/IslandSculkSensorBlockEntity.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/vibration/IslandSculkSensorBlockEntity.java new file mode 100644 index 0000000000..0fcb81340a --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/vibration/IslandSculkSensorBlockEntity.java @@ -0,0 +1,39 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.GameEventListener; + +import javax.annotation.Nullable; + +public class IslandSculkSensorBlockEntity extends SculkSensorBlockEntity { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + + public IslandSculkSensorBlockEntity(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + super(sculkSensorBlockEntity.getBlockPos(), sculkSensorBlockEntity.getBlockState()); + this.island = island; + } + + @Override + public boolean shouldListen(ServerLevel world, GameEventListener listener, BlockPos pos, GameEvent event, @Nullable GameEvent.Context context) { + if (!super.shouldListen(world, listener, pos, event, context)) + return false; + + if (context.sourceEntity() instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index 575d633558..8979e0d2b2 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.v1_20_3.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_20_3.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.WorldEditSessionImpl; @@ -34,11 +35,13 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; @@ -68,13 +71,11 @@ public class NMSWorldImpl implements NMSWorld { - private static final byte[] EMPTY_LIGHTS = new byte[0]; - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PUBLIC = new ReflectField<>( - Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( + SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private final SuperiorSkyblockPlugin plugin; @@ -127,6 +128,15 @@ public void listenSpawner(Location location, IntFunction delayChangeCal blockEntityTickers.addAll(tickersToAdd); } + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) + return; + + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } + @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/vibration/IslandVibrationUser.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/vibration/IslandVibrationUser.java new file mode 100644 index 0000000000..e10510d4cd --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/vibration/IslandVibrationUser.java @@ -0,0 +1,89 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.PositionSource; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; + +import javax.annotation.Nullable; + +public class IslandVibrationUser implements VibrationSystem.User { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final VibrationSystem.User original; + + public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + this.island = island; + this.original = sculkSensorBlockEntity.getVibrationUser(); + } + + @Override + public int getListenerRadius() { + return this.original.getListenerRadius(); + } + + @Override + public PositionSource getPositionSource() { + return this.original.getPositionSource(); + } + + @Override + public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, GameEvent gameEvent, GameEvent.Context context) { + if (!this.original.canReceiveVibration(serverLevel, blockPos, gameEvent, context)) + return false; + + if (context.sourceEntity() instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + + @Override + public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, GameEvent holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { + this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); + } + + @Override + public TagKey getListenableEvents() { + return this.original.getListenableEvents(); + } + + @Override + public boolean canTriggerAvoidVibration() { + return this.original.canTriggerAvoidVibration(); + } + + @Override + public boolean requiresAdjacentChunksToBeTicking() { + return this.original.requiresAdjacentChunksToBeTicking(); + } + + @Override + public int calculateTravelTimeInTicks(float distance) { + return this.original.calculateTravelTimeInTicks(distance); + } + + @Override + public boolean isValidVibration(GameEvent gameEvent, GameEvent.Context context) { + return this.original.isValidVibration(gameEvent, context); + } + + @Override + public void onDataChanged() { + this.original.onDataChanged(); + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index 5102cada6f..9d3e9ab9fe 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.v1_20_4.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_20_4.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.WorldEditSessionImpl; @@ -34,11 +35,13 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; @@ -73,8 +76,8 @@ public class NMSWorldImpl implements NMSWorld { private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PUBLIC = new ReflectField<>( - Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( + SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private final SuperiorSkyblockPlugin plugin; @@ -127,6 +130,15 @@ public void listenSpawner(Location location, IntFunction delayChangeCal blockEntityTickers.addAll(tickersToAdd); } + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) + return; + + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } + @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/vibration/IslandVibrationUser.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/vibration/IslandVibrationUser.java new file mode 100644 index 0000000000..00df0b5593 --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/vibration/IslandVibrationUser.java @@ -0,0 +1,90 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.PositionSource; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; + +import javax.annotation.Nullable; + +public class IslandVibrationUser implements VibrationSystem.User { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final VibrationSystem.User original; + + public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + this.island = island; + this.original = sculkSensorBlockEntity.getVibrationUser(); + } + + @Override + public int getListenerRadius() { + return this.original.getListenerRadius(); + } + + @Override + public PositionSource getPositionSource() { + return this.original.getPositionSource(); + } + + @Override + public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { + if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) + return false; + + if (context.sourceEntity() instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + + @Override + public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { + this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); + } + + @Override + public TagKey getListenableEvents() { + return this.original.getListenableEvents(); + } + + @Override + public boolean canTriggerAvoidVibration() { + return this.original.canTriggerAvoidVibration(); + } + + @Override + public boolean requiresAdjacentChunksToBeTicking() { + return this.original.requiresAdjacentChunksToBeTicking(); + } + + @Override + public int calculateTravelTimeInTicks(float distance) { + return this.original.calculateTravelTimeInTicks(distance); + } + + @Override + public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { + return this.original.isValidVibration(gameEvent, context); + } + + @Override + public void onDataChanged() { + this.original.onDataChanged(); + } + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index e1026bcbb7..9ef1f047af 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -19,6 +19,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_21.spawners.TickingSpawnerBlockEntityNotifier; import com.bgsoftware.superiorskyblock.nms.v1_21.trial.IslandPlayerDetector; +import com.bgsoftware.superiorskyblock.nms.v1_21.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_21.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_21.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_21.world.WorldEditSessionImpl; @@ -36,6 +37,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; @@ -46,6 +48,7 @@ import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; @@ -75,13 +78,11 @@ public class NMSWorldImpl implements NMSWorld { - private static final byte[] EMPTY_LIGHTS = new byte[0]; - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PUBLIC = new ReflectField<>( - Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( + SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private final SuperiorSkyblockPlugin plugin; @@ -178,6 +179,15 @@ public void replaceTrialBlockPlayerDetector(Island island, Location location) { } } + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) + return; + + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } + @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/vibration/IslandVibrationUser.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/vibration/IslandVibrationUser.java new file mode 100644 index 0000000000..72522ef28c --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/vibration/IslandVibrationUser.java @@ -0,0 +1,90 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.PositionSource; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; + +import javax.annotation.Nullable; + +public class IslandVibrationUser implements VibrationSystem.User { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final VibrationSystem.User original; + + public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + this.island = island; + this.original = sculkSensorBlockEntity.getVibrationUser(); + } + + @Override + public int getListenerRadius() { + return this.original.getListenerRadius(); + } + + @Override + public PositionSource getPositionSource() { + return this.original.getPositionSource(); + } + + @Override + public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { + if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) + return false; + + if (context.sourceEntity() instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + + @Override + public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { + this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); + } + + @Override + public TagKey getListenableEvents() { + return this.original.getListenableEvents(); + } + + @Override + public boolean canTriggerAvoidVibration() { + return this.original.canTriggerAvoidVibration(); + } + + @Override + public boolean requiresAdjacentChunksToBeTicking() { + return this.original.requiresAdjacentChunksToBeTicking(); + } + + @Override + public int calculateTravelTimeInTicks(float distance) { + return this.original.calculateTravelTimeInTicks(distance); + } + + @Override + public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { + return this.original.isValidVibration(gameEvent, context); + } + + @Override + public void onDataChanged() { + this.original.onDataChanged(); + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index 5481f814d9..e653696369 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -19,6 +19,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_3.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_21_3.spawners.TickingSpawnerBlockEntityNotifier; import com.bgsoftware.superiorskyblock.nms.v1_21_3.trial.IslandPlayerDetector; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.WorldEditSessionImpl; @@ -36,6 +37,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; @@ -46,6 +48,7 @@ import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; @@ -75,13 +78,11 @@ public class NMSWorldImpl implements NMSWorld { - private static final byte[] EMPTY_LIGHTS = new byte[0]; - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PUBLIC = new ReflectField<>( - Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( + SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private final SuperiorSkyblockPlugin plugin; @@ -178,6 +179,15 @@ public void replaceTrialBlockPlayerDetector(Island island, Location location) { } } + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) + return; + + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } + @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/vibration/IslandVibrationUser.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/vibration/IslandVibrationUser.java new file mode 100644 index 0000000000..590733e731 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/vibration/IslandVibrationUser.java @@ -0,0 +1,90 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.PositionSource; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; + +import javax.annotation.Nullable; + +public class IslandVibrationUser implements VibrationSystem.User { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final VibrationSystem.User original; + + public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + this.island = island; + this.original = sculkSensorBlockEntity.getVibrationUser(); + } + + @Override + public int getListenerRadius() { + return this.original.getListenerRadius(); + } + + @Override + public PositionSource getPositionSource() { + return this.original.getPositionSource(); + } + + @Override + public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { + if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) + return false; + + if (context.sourceEntity() instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + + @Override + public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { + this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); + } + + @Override + public TagKey getListenableEvents() { + return this.original.getListenableEvents(); + } + + @Override + public boolean canTriggerAvoidVibration() { + return this.original.canTriggerAvoidVibration(); + } + + @Override + public boolean requiresAdjacentChunksToBeTicking() { + return this.original.requiresAdjacentChunksToBeTicking(); + } + + @Override + public int calculateTravelTimeInTicks(float distance) { + return this.original.calculateTravelTimeInTicks(distance); + } + + @Override + public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { + return this.original.isValidVibration(gameEvent, context); + } + + @Override + public void onDataChanged() { + this.original.onDataChanged(); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index f941823291..5e0d4ec4f0 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -19,6 +19,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_4.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_21_4.spawners.TickingSpawnerBlockEntityNotifier; import com.bgsoftware.superiorskyblock.nms.v1_21_4.trial.IslandPlayerDetector; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.WorldEditSessionImpl; @@ -36,6 +37,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; @@ -46,6 +48,7 @@ import net.minecraft.world.level.block.entity.vault.VaultConfig; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; @@ -78,8 +81,8 @@ public class NMSWorldImpl implements NMSWorld { private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PUBLIC = new ReflectField<>( - Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( + SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); private final SuperiorSkyblockPlugin plugin; @@ -176,6 +179,15 @@ public void replaceTrialBlockPlayerDetector(Island island, Location location) { } } + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) + return; + + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } + @Override public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { if (!plugin.getSettings().isWorldBorders()) diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/vibration/IslandVibrationUser.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/vibration/IslandVibrationUser.java new file mode 100644 index 0000000000..bd30c3d19d --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/vibration/IslandVibrationUser.java @@ -0,0 +1,90 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.PositionSource; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; + +import javax.annotation.Nullable; + +public class IslandVibrationUser implements VibrationSystem.User { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final VibrationSystem.User original; + + public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + this.island = island; + this.original = sculkSensorBlockEntity.getVibrationUser(); + } + + @Override + public int getListenerRadius() { + return this.original.getListenerRadius(); + } + + @Override + public PositionSource getPositionSource() { + return this.original.getPositionSource(); + } + + @Override + public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { + if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) + return false; + + if (context.sourceEntity() instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + + @Override + public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { + this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); + } + + @Override + public TagKey getListenableEvents() { + return this.original.getListenableEvents(); + } + + @Override + public boolean canTriggerAvoidVibration() { + return this.original.canTriggerAvoidVibration(); + } + + @Override + public boolean requiresAdjacentChunksToBeTicking() { + return this.original.requiresAdjacentChunksToBeTicking(); + } + + @Override + public int calculateTravelTimeInTicks(float distance) { + return this.original.calculateTravelTimeInTicks(distance); + } + + @Override + public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { + return this.original.isValidVibration(gameEvent, context); + } + + @Override + public void onDataChanged() { + this.original.onDataChanged(); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index 6039127f43..f49e1cafd4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -65,6 +65,8 @@ public class IslandPrivileges { public static final IslandPrivilege PROMOTE_MEMBERS = register("PROMOTE_MEMBERS"); public static final IslandPrivilege RANKUP = register("RANKUP"); public static final IslandPrivilege RATINGS_SHOW = register("RATINGS_SHOW"); + @Nullable + public static final IslandPrivilege SCULK_SENSOR = register("SCULK_SENSOR", ServerVersion.isAtLeast(ServerVersion.v1_17)); public static final IslandPrivilege SET_BIOME = register("SET_BIOME"); public static final IslandPrivilege SET_DISCORD = register("SET_DISCORD"); public static final IslandPrivilege SET_HOME = register("SET_HOME"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java index 732b52151f..06c31c42af 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java @@ -50,9 +50,10 @@ public class FeaturesListener implements Listener { @Nullable private static final Material VAULT = EnumHelper.getEnum(Material.class, "VAULT"); - @Nullable private static final Material TRIAL_SPAWNER = EnumHelper.getEnum(Material.class, "TRIAL_SPAWNER"); + @Nullable + private static final Material SCULK_SENSOR = EnumHelper.getEnum(Material.class, "SCULK_SENSOR"); private final SuperiorSkyblockPlugin plugin; private final LazyReference protectionManager = new LazyReference() { @@ -66,6 +67,8 @@ public FeaturesListener(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; if (VAULT != null && TRIAL_SPAWNER != null) plugin.getServer().getPluginManager().registerEvents(new TrialsTracker(), plugin); + if (VAULT != null && TRIAL_SPAWNER != null) + plugin.getServer().getPluginManager().registerEvents(new SculkSensorTracker(), plugin); } /* EVENT COMMANDS */ @@ -196,6 +199,26 @@ public void onPlayerCommand(PlayerCommandPreprocessEvent e) { } } + /* BLOCKS TRACKING */ + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onChunkLoad(ChunkLoadEvent e) { + List chunkIslands = plugin.getGrid().getIslandsAt(e.getChunk()); + chunkIslands.forEach(island -> handleIslandChunkLoad(island, e.getChunk())); + } + + private void handleIslandChunkLoad(Island island, Chunk chunk) { + List blockEntities = plugin.getNMSChunks().getBlockEntities(chunk); + + if (blockEntities.isEmpty()) + return; + + blockEntities.forEach(blockEntity -> { + plugin.getNMSWorld().replaceSculkSensorListener(island, blockEntity); + plugin.getNMSWorld().replaceTrialBlockPlayerDetector(island, blockEntity); + }); + } + /* VAULTS & TRIAL SPAWNERS */ private class TrialsTracker implements Listener { @@ -219,20 +242,29 @@ private void onBlockPlace(BlockPlaceEvent e) { } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onChunkLoad(ChunkLoadEvent e) { - List chunkIslands = plugin.getGrid().getIslandsAt(e.getChunk()); - chunkIslands.forEach(island -> handleIslandChunkLoad(island, e.getChunk())); - } + } + + /* SCULK SENSORS */ - private void handleIslandChunkLoad(Island island, Chunk chunk) { - List blockEntities = plugin.getNMSChunks().getBlockEntities(chunk); + private class SculkSensorTracker implements Listener { + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onBlockPlace(BlockPlaceEvent e) { + Material blockType = e.getBlock().getType(); - if (blockEntities.isEmpty()) + if (blockType != SCULK_SENSOR) return; - blockEntities.forEach(blockEntity -> - plugin.getNMSWorld().replaceTrialBlockPlayerDetector(island, blockEntity)); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = e.getBlock().getLocation(wrapper.getHandle()); + + Island island = plugin.getGrid().getIslandAt(blockLocation); + + if (island == null) + return; + + plugin.getNMSWorld().replaceSculkSensorListener(island, blockLocation); + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 121576298f..79dc00d285 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -643,7 +643,7 @@ public void onPlayerItemPickup(PlayerAttemptPickupItemEvent e) { private class PlayerArrowPickup implements Listener { - @EventHandler + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onPlayerArrowPickup(PlayerPickupArrowEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); InteractionResult interactionResult = protectionManager.get().handlePlayerPickupItem(superiorPlayer, e.getItem()); @@ -655,7 +655,7 @@ public void onPlayerArrowPickup(PlayerPickupArrowEvent e) { private class PlayerTakeLecternBookListener implements Listener { - @EventHandler + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onPlayerTakeLecternBook(PlayerTakeLecternBookEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); InteractionResult interactionResult = protectionManager.get().handleBlockInteract(superiorPlayer, @@ -668,7 +668,7 @@ public void onPlayerTakeLecternBook(PlayerTakeLecternBookEvent e) { private class RaidTriggerListener implements Listener { - @EventHandler + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onRaidTrigger(RaidTriggerEvent e) { if (!plugin.getGrid().isIslandsWorld(e.getWorld())) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java index c17dc5089d..e3fc2de6ad 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java @@ -29,6 +29,10 @@ default void replaceTrialBlockPlayerDetector(Island island, Location location) { // Does not exist. } + default void replaceSculkSensorListener(Island island, Location location) { + // Does not exist. + } + void setWorldBorder(SuperiorPlayer superiorPlayer, Island island); Object getBlockData(Block block); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 78708dafb9..91927acc22 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -199,6 +199,7 @@ island-roles: - PICKUP_FISH - PICKUP_LECTERN_BOOK - SIGN_INTERACT + - SCULK_SENSOR - TURTLE_EGG_TRAMPING - USE - VILLAGER_TRADING diff --git a/src/main/resources/menus/permissions1_17.yml b/src/main/resources/menus/permissions1_17.yml index ff468993f6..f825a71df1 100644 --- a/src/main/resources/menus/permissions1_17.yml +++ b/src/main/resources/menus/permissions1_17.yml @@ -1726,6 +1726,39 @@ permissions: volume: 0.2 pitch: 0.2 + sculk_sensor: + display-menu: true + permission-enabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + ratings_show: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_20.yml b/src/main/resources/menus/permissions1_20.yml index b9e8f56032..0fed24c5f9 100644 --- a/src/main/resources/menus/permissions1_20.yml +++ b/src/main/resources/menus/permissions1_20.yml @@ -1759,6 +1759,39 @@ permissions: volume: 0.2 pitch: 0.2 + sculk_sensor: + display-menu: true + permission-enabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + ratings_show: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_21.yml b/src/main/resources/menus/permissions1_21.yml index f6864f9473..82b77410aa 100644 --- a/src/main/resources/menus/permissions1_21.yml +++ b/src/main/resources/menus/permissions1_21.yml @@ -1759,6 +1759,39 @@ permissions: volume: 0.2 pitch: 0.2 + sculk_sensor: + display-menu: true + permission-enabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + ratings_show: display-menu: true permission-enabled: From 8e87c8fc8e04443c6f467ae3baa2ceb4dbb11fc1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 17:44:34 +0200 Subject: [PATCH 077/600] Fixed the ability to trigger sculk shriekers on other islands (#2358) --- .../listener/FeaturesListener.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java index 06c31c42af..3253e115ac 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java @@ -22,6 +22,7 @@ import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Bukkit; @@ -32,6 +33,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerInteractEvent; @@ -54,6 +56,8 @@ public class FeaturesListener implements Listener { private static final Material TRIAL_SPAWNER = EnumHelper.getEnum(Material.class, "TRIAL_SPAWNER"); @Nullable private static final Material SCULK_SENSOR = EnumHelper.getEnum(Material.class, "SCULK_SENSOR"); + @Nullable + private static final Material SCULK_SHRIEKER = EnumHelper.getEnum(Material.class, "SCULK_SHRIEKER"); private final SuperiorSkyblockPlugin plugin; private final LazyReference protectionManager = new LazyReference() { @@ -249,7 +253,7 @@ private void onBlockPlace(BlockPlaceEvent e) { private class SculkSensorTracker implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onBlockPlace(BlockPlaceEvent e) { + private void onSculkSensorPlace(BlockPlaceEvent e) { Material blockType = e.getBlock().getType(); if (blockType != SCULK_SENSOR) @@ -267,6 +271,23 @@ private void onBlockPlace(BlockPlaceEvent e) { } } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onSculkShriekerInteract(PlayerInteractEvent e) { + if (e.getAction() != Action.PHYSICAL || !plugin.getGrid().isIslandsWorld(e.getClickedBlock().getWorld()) || + e.getClickedBlock().getType() != SCULK_SHRIEKER) + return; + + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + Location blockLocation = e.getClickedBlock().getLocation(wrapper.getHandle()); + interactionResult = protectionManager.get().handleCustomInteraction(superiorPlayer, + blockLocation, IslandPrivileges.SCULK_SENSOR); + } + if (ProtectionHelper.shouldPreventInteraction(interactionResult, null, false)) + e.setCancelled(true); + } + } /* INTERNAL */ From cd1f252b913aa6ff90094058942bf5e7b57b7404 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 17:48:38 +0200 Subject: [PATCH 078/600] Fixed the ability to fill up composters on other islands (#2358) --- src/main/resources/interactables.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index 4601f24a05..6616bb4928 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -78,6 +78,7 @@ interactables: - 'COMMAND_CHAIN' - 'COMMAND_REPEATING' - 'COMPARATOR' + - 'COMPOSTER' - 'COPPER_DOOR' - 'COPPER_TRAPDOOR' - 'CRAFTER' From 0bbbfa0d83ba2b2a4c2961d9b11e54c06b2579d9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 17:52:00 +0200 Subject: [PATCH 079/600] Fixed the ability to harvest glow berries on other islands (#2358) --- src/main/resources/interactables.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index 6616bb4928..798db570e6 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -59,6 +59,7 @@ interactables: - 'CANDLE' - 'CARTOGRAPHER_TABLE' - 'CAULDRON' + - 'CAVE_VINES' - 'CAVE_VINES_PLANT' - 'CHAIN_COMMAND_BLOCK' - 'CHERRY_BUTTON' From dbee4d86e8f156f88835e22f05e358e007acdfa3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 18:00:06 +0200 Subject: [PATCH 080/600] Fixed the ability to dye sheep on other islands (#2358) --- .../island/privilege/IslandPrivileges.java | 1 + .../region/RegionManagerServiceImpl.java | 3 ++ src/main/resources/config.yml | 1 + src/main/resources/menus/permissions.yml | 36 +++++++++++++++++++ src/main/resources/menus/permissions1_13.yml | 33 +++++++++++++++++ src/main/resources/menus/permissions1_16.yml | 33 +++++++++++++++++ src/main/resources/menus/permissions1_17.yml | 33 +++++++++++++++++ src/main/resources/menus/permissions1_20.yml | 33 +++++++++++++++++ src/main/resources/menus/permissions1_21.yml | 33 +++++++++++++++++ src/main/resources/menus/permissions1_9.yml | 36 +++++++++++++++++++ 10 files changed, 242 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index f49e1cafd4..3f0a09d804 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -30,6 +30,7 @@ public class IslandPrivileges { public static final IslandPrivilege DISBAND_ISLAND = register("DISBAND_ISLAND"); public static final IslandPrivilege DISCORD_SHOW = register("DISCORD_SHOW"); public static final IslandPrivilege DROP_ITEMS = register("DROP_ITEMS"); + public static final IslandPrivilege DYE_SHEEP = register("DYE_SHEEP"); public static final IslandPrivilege ENDER_PEARL = register("ENDER_PEARL"); public static final IslandPrivilege EXPEL_BYPASS = register("EXPEL_BYPASS"); public static final IslandPrivilege EXPEL_PLAYERS = register("EXPEL_PLAYERS"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index eb8403924f..3beea7835e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -54,6 +54,7 @@ import org.bukkit.entity.Mule; import org.bukkit.entity.Painting; import org.bukkit.entity.Player; +import org.bukkit.entity.Sheep; import org.bukkit.entity.Villager; import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.event.block.Action; @@ -270,6 +271,8 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent } else if (usedItem != null && entity instanceof PoweredMinecart && plugin.getNMSEntities().isMinecartFuel(usedItem, (PoweredMinecart) entity)) { islandPrivilege = IslandPrivileges.MINECART_OPEN; + } else if (usedItem != null && entity instanceof Sheep && Materials.isDye(usedItem.getType())) { + islandPrivilege = IslandPrivileges.DYE_SHEEP; } else { return InteractionResult.SUCCESS; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 91927acc22..e800db88be 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -178,6 +178,7 @@ island-roles: - CHORUS_FRUIT - CROPS_GROWTH - DROP_ITEMS + - DYE_SHEEP - ENDER_PEARL - EXPEL_BYPASS - FARM_TRAMPING diff --git a/src/main/resources/menus/permissions.yml b/src/main/resources/menus/permissions.yml index 34bd36925d..e6a3be8689 100644 --- a/src/main/resources/menus/permissions.yml +++ b/src/main/resources/menus/permissions.yml @@ -676,6 +676,42 @@ permissions: volume: 0.2 pitch: 0.2 + dye_sheep: + display-menu: true + permission-enabled: + type: MONSTER_EGG + entity: SHEEP + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: MONSTER_EGG + entity: SHEEP + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: MONSTER_EGG + entity: SHEEP + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + ender_pearl: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_13.yml b/src/main/resources/menus/permissions1_13.yml index 939b361caa..44a4c528f3 100644 --- a/src/main/resources/menus/permissions1_13.yml +++ b/src/main/resources/menus/permissions1_13.yml @@ -702,6 +702,39 @@ permissions: volume: 0.2 pitch: 0.2 + dye_sheep: + display-menu: true + permission-enabled: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + ender_pearl: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_16.yml b/src/main/resources/menus/permissions1_16.yml index f946539ecf..44ae26c094 100644 --- a/src/main/resources/menus/permissions1_16.yml +++ b/src/main/resources/menus/permissions1_16.yml @@ -702,6 +702,39 @@ permissions: volume: 0.2 pitch: 0.2 + dye_sheep: + display-menu: true + permission-enabled: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + ender_pearl: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_17.yml b/src/main/resources/menus/permissions1_17.yml index f825a71df1..3dbd9d3ff5 100644 --- a/src/main/resources/menus/permissions1_17.yml +++ b/src/main/resources/menus/permissions1_17.yml @@ -702,6 +702,39 @@ permissions: volume: 0.2 pitch: 0.2 + dye_sheep: + display-menu: true + permission-enabled: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + ender_pearl: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_20.yml b/src/main/resources/menus/permissions1_20.yml index 0fed24c5f9..cf1f499696 100644 --- a/src/main/resources/menus/permissions1_20.yml +++ b/src/main/resources/menus/permissions1_20.yml @@ -735,6 +735,39 @@ permissions: volume: 0.2 pitch: 0.2 + dye_sheep: + display-menu: true + permission-enabled: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + ender_pearl: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_21.yml b/src/main/resources/menus/permissions1_21.yml index 82b77410aa..173d7e77fe 100644 --- a/src/main/resources/menus/permissions1_21.yml +++ b/src/main/resources/menus/permissions1_21.yml @@ -735,6 +735,39 @@ permissions: volume: 0.2 pitch: 0.2 + dye_sheep: + display-menu: true + permission-enabled: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + ender_pearl: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_9.yml b/src/main/resources/menus/permissions1_9.yml index f4b958e3a6..0475713d25 100644 --- a/src/main/resources/menus/permissions1_9.yml +++ b/src/main/resources/menus/permissions1_9.yml @@ -709,6 +709,42 @@ permissions: volume: 0.2 pitch: 0.2 + dye_sheep: + display-menu: true + permission-enabled: + type: MONSTER_EGG + entity: SHEEP + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: MONSTER_EGG + entity: SHEEP + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: MONSTER_EGG + entity: SHEEP + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + ender_pearl: display-menu: true permission-enabled: From aa398f7688096d3b6d2cbb3428a68a0fad7befbe Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 18:05:19 +0200 Subject: [PATCH 081/600] Fixed the ability to open camel inventories on other islands (#2358) --- .../region/RegionManagerServiceImpl.java | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 3beea7835e..30aa08a6cf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -82,7 +82,10 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService @Nullable private static final Material OMINOUS_TRIAL_KEY = EnumHelper.getEnum(Material.class, "OMINOUS_TRIAL_KEY"); @Nullable - private static final EntityType AXOLOTL_TYPE = getSafeEntityType("AXOLOTL"); + private static final EntityType AXOLOTL_TYPE = EnumHelper.getEnum(EntityType.class, "AXOLOTL"); + @Nullable + private static final EntityType CAMEL_TYPE = EnumHelper.getEnum(EntityType.class, "CAMEL"); + private static final int MAX_PICKUP_DISTANCE = 1; private static EnumerateSet WORLD_PERMISSIONS_CACHE; private static KeySet INTERACTABLES_CACHE; @@ -255,7 +258,8 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent } else if (entity instanceof Villager) { islandPrivilege = IslandPrivileges.VILLAGER_TRADING; closeInventory = true; - } else if (entity instanceof Horse || (ServerVersion.isAtLeast(ServerVersion.v1_11) && (entity instanceof Mule || entity instanceof Donkey))) { + } else if (entity instanceof Horse || entity.getType() == CAMEL_TYPE || + (ServerVersion.isAtLeast(ServerVersion.v1_11) && (entity instanceof Mule || entity instanceof Donkey))) { islandPrivilege = IslandPrivileges.HORSE_INTERACT; closeInventory = true; } else if (usedItem != null && entity instanceof Creeper && usedItem.getType() == Material.FLINT_AND_STEEL) { @@ -753,13 +757,4 @@ private MoveResult handlePlayerLeaveIslandInternal(SuperiorPlayer superiorPlayer return MoveResult.SUCCESS; } - @Nullable - private static EntityType getSafeEntityType(String entityType) { - try { - return EntityType.valueOf(entityType); - } catch (IllegalArgumentException error) { - return null; - } - } - } From a3376af1269925c4eececbd28f05dbce83774bb6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 18:08:00 +0200 Subject: [PATCH 082/600] Optimize calls to Entity#getType and ItemStack#getType in RegionManagerServiceImpl#handleEntityInteract --- .../service/region/RegionManagerServiceImpl.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 30aa08a6cf..6d01499e3c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -247,24 +247,27 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent Location entityLocation = entity.getLocation(wrapper.getHandle()); Island island = plugin.getGrid().getIslandAt(entityLocation); + EntityType entityType = entity.getType(); + Material usedItemType = usedItem == null ? Material.AIR : usedItem.getType(); + IslandPrivilege islandPrivilege; if (entity instanceof ArmorStand) { islandPrivilege = IslandPrivileges.INTERACT; } else if (usedItem != null && entity instanceof Animals && plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) entity)) { islandPrivilege = IslandPrivileges.ANIMAL_BREED; - } else if (usedItem != null && usedItem.getType() == Material.NAME_TAG) { + } else if (usedItemType == Material.NAME_TAG) { islandPrivilege = IslandPrivileges.NAME_ENTITY; } else if (entity instanceof Villager) { islandPrivilege = IslandPrivileges.VILLAGER_TRADING; closeInventory = true; - } else if (entity instanceof Horse || entity.getType() == CAMEL_TYPE || + } else if (entity instanceof Horse || entityType == CAMEL_TYPE || (ServerVersion.isAtLeast(ServerVersion.v1_11) && (entity instanceof Mule || entity instanceof Donkey))) { islandPrivilege = IslandPrivileges.HORSE_INTERACT; closeInventory = true; - } else if (usedItem != null && entity instanceof Creeper && usedItem.getType() == Material.FLINT_AND_STEEL) { + } else if (usedItemType == Material.FLINT_AND_STEEL && entity instanceof Creeper) { islandPrivilege = IslandPrivileges.IGNITE_CREEPER; - } else if (usedItem != null && ServerVersion.isAtLeast(ServerVersion.v1_17) && usedItem.getType() == Material.WATER_BUCKET && entity.getType() == AXOLOTL_TYPE) { + } else if (usedItemType == Material.WATER_BUCKET && entityType == AXOLOTL_TYPE && ServerVersion.isAtLeast(ServerVersion.v1_17)) { islandPrivilege = IslandPrivileges.PICKUP_AXOLOTL; } else if (entity instanceof ItemFrame) { islandPrivilege = IslandPrivileges.ITEM_FRAME; @@ -275,7 +278,7 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent } else if (usedItem != null && entity instanceof PoweredMinecart && plugin.getNMSEntities().isMinecartFuel(usedItem, (PoweredMinecart) entity)) { islandPrivilege = IslandPrivileges.MINECART_OPEN; - } else if (usedItem != null && entity instanceof Sheep && Materials.isDye(usedItem.getType())) { + } else if (entity instanceof Sheep && Materials.isDye(usedItemType)) { islandPrivilege = IslandPrivileges.DYE_SHEEP; } else { return InteractionResult.SUCCESS; From f83197cd598ddf02faae87df7921413ff29faff6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 18:15:36 +0200 Subject: [PATCH 083/600] Fixed the ability to saddle entities on other islands (#2358) --- .../island/privilege/IslandPrivileges.java | 1 + .../region/RegionManagerServiceImpl.java | 2 + src/main/resources/config.yml | 1 + src/main/resources/menus/permissions.yml | 33 +++++++++ src/main/resources/menus/permissions1_13.yml | 33 +++++++++ src/main/resources/menus/permissions1_16.yml | 33 +++++++++ src/main/resources/menus/permissions1_17.yml | 73 ++++++++++++++----- src/main/resources/menus/permissions1_20.yml | 73 ++++++++++++++----- src/main/resources/menus/permissions1_21.yml | 73 ++++++++++++++----- src/main/resources/menus/permissions1_9.yml | 33 +++++++++ 10 files changed, 295 insertions(+), 60 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index 3f0a09d804..0ad05b8da6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -66,6 +66,7 @@ public class IslandPrivileges { public static final IslandPrivilege PROMOTE_MEMBERS = register("PROMOTE_MEMBERS"); public static final IslandPrivilege RANKUP = register("RANKUP"); public static final IslandPrivilege RATINGS_SHOW = register("RATINGS_SHOW"); + public static final IslandPrivilege SADDLE_ENTITY = register("SADDLE_ENTITY"); @Nullable public static final IslandPrivilege SCULK_SENSOR = register("SCULK_SENSOR", ServerVersion.isAtLeast(ServerVersion.v1_17)); public static final IslandPrivilege SET_BIOME = register("SET_BIOME"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 6d01499e3c..814c62a4de 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -258,6 +258,8 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent islandPrivilege = IslandPrivileges.ANIMAL_BREED; } else if (usedItemType == Material.NAME_TAG) { islandPrivilege = IslandPrivileges.NAME_ENTITY; + } else if (usedItemType == Material.SADDLE) { + islandPrivilege = IslandPrivileges.SADDLE_ENTITY; } else if (entity instanceof Villager) { islandPrivilege = IslandPrivileges.VILLAGER_TRADING; closeInventory = true; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index e800db88be..04e2e458dd 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -199,6 +199,7 @@ island-roles: - PICKUP_DROPS - PICKUP_FISH - PICKUP_LECTERN_BOOK + - SADDLE_ENTITY - SIGN_INTERACT - SCULK_SENSOR - TURTLE_EGG_TRAMPING diff --git a/src/main/resources/menus/permissions.yml b/src/main/resources/menus/permissions.yml index e6a3be8689..b30784dca3 100644 --- a/src/main/resources/menus/permissions.yml +++ b/src/main/resources/menus/permissions.yml @@ -1657,6 +1657,39 @@ permissions: volume: 0.2 pitch: 0.2 + saddle_entity: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + set_biome: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_13.yml b/src/main/resources/menus/permissions1_13.yml index 44a4c528f3..84c5327b1b 100644 --- a/src/main/resources/menus/permissions1_13.yml +++ b/src/main/resources/menus/permissions1_13.yml @@ -1726,6 +1726,39 @@ permissions: volume: 0.2 pitch: 0.2 + saddle_entity: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + set_biome: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_16.yml b/src/main/resources/menus/permissions1_16.yml index 44ae26c094..85104f7df0 100644 --- a/src/main/resources/menus/permissions1_16.yml +++ b/src/main/resources/menus/permissions1_16.yml @@ -1759,6 +1759,39 @@ permissions: volume: 0.2 pitch: 0.2 + saddle_entity: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + set_biome: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_17.yml b/src/main/resources/menus/permissions1_17.yml index 3dbd9d3ff5..cdeca13383 100644 --- a/src/main/resources/menus/permissions1_17.yml +++ b/src/main/resources/menus/permissions1_17.yml @@ -1759,25 +1759,25 @@ permissions: volume: 0.2 pitch: 0.2 - sculk_sensor: + ratings_show: display-menu: true permission-enabled: - type: SCULK_SENSOR - name: '&6Sculk Sensor' + type: NETHER_STAR + name: '&6Ratings Show' lore: - - '&7Access to trigger sculk sensors inside the island.' + - '&7Access to see all island''s ratings.' - '&7Currently &aENABLED&7.' permission-disabled: - type: SCULK_SENSOR - name: '&6Sculk Sensor' + type: NETHER_STAR + name: '&6Ratings Show' lore: - - '&7Access to trigger sculk sensors inside the island.' + - '&7Access to see all island''s ratings.' - '&7Currently &cDISABLED&7.' role-permission: - type: SCULK_SENSOR - name: '&6Sculk Sensor' + type: NETHER_STAR + name: '&6Ratings Show' lore: - - '&7Access to trigger sculk sensors inside the island.' + - '&7Access to see all island''s ratings.' - '&7Role: &e{}&7.' - '' - '{0}' @@ -1792,25 +1792,58 @@ permissions: volume: 0.2 pitch: 0.2 - ratings_show: + saddle_entity: display-menu: true permission-enabled: - type: NETHER_STAR - name: '&6Ratings Show' + type: SADDLE + name: '&6Saddle Entity' lore: - - '&7Access to see all island''s ratings.' + - '&7Access to add saddle to entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: - type: NETHER_STAR - name: '&6Ratings Show' + type: SADDLE + name: '&6Saddle Entity' lore: - - '&7Access to see all island''s ratings.' + - '&7Access to add saddle to entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: - type: NETHER_STAR - name: '&6Ratings Show' + type: SADDLE + name: '&6Saddle Entity' lore: - - '&7Access to see all island''s ratings.' + - '&7Access to add saddle to entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + sculk_sensor: + display-menu: true + permission-enabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' diff --git a/src/main/resources/menus/permissions1_20.yml b/src/main/resources/menus/permissions1_20.yml index cf1f499696..8f29987a92 100644 --- a/src/main/resources/menus/permissions1_20.yml +++ b/src/main/resources/menus/permissions1_20.yml @@ -1792,25 +1792,25 @@ permissions: volume: 0.2 pitch: 0.2 - sculk_sensor: + ratings_show: display-menu: true permission-enabled: - type: SCULK_SENSOR - name: '&6Sculk Sensor' + type: NETHER_STAR + name: '&6Ratings Show' lore: - - '&7Access to trigger sculk sensors inside the island.' + - '&7Access to see all island''s ratings.' - '&7Currently &aENABLED&7.' permission-disabled: - type: SCULK_SENSOR - name: '&6Sculk Sensor' + type: NETHER_STAR + name: '&6Ratings Show' lore: - - '&7Access to trigger sculk sensors inside the island.' + - '&7Access to see all island''s ratings.' - '&7Currently &cDISABLED&7.' role-permission: - type: SCULK_SENSOR - name: '&6Sculk Sensor' + type: NETHER_STAR + name: '&6Ratings Show' lore: - - '&7Access to trigger sculk sensors inside the island.' + - '&7Access to see all island''s ratings.' - '&7Role: &e{}&7.' - '' - '{0}' @@ -1825,25 +1825,58 @@ permissions: volume: 0.2 pitch: 0.2 - ratings_show: + saddle_entity: display-menu: true permission-enabled: - type: NETHER_STAR - name: '&6Ratings Show' + type: SADDLE + name: '&6Saddle Entity' lore: - - '&7Access to see all island''s ratings.' + - '&7Access to add saddle to entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: - type: NETHER_STAR - name: '&6Ratings Show' + type: SADDLE + name: '&6Saddle Entity' lore: - - '&7Access to see all island''s ratings.' + - '&7Access to add saddle to entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: - type: NETHER_STAR - name: '&6Ratings Show' + type: SADDLE + name: '&6Saddle Entity' lore: - - '&7Access to see all island''s ratings.' + - '&7Access to add saddle to entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + sculk_sensor: + display-menu: true + permission-enabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' diff --git a/src/main/resources/menus/permissions1_21.yml b/src/main/resources/menus/permissions1_21.yml index 173d7e77fe..b0b778b6cb 100644 --- a/src/main/resources/menus/permissions1_21.yml +++ b/src/main/resources/menus/permissions1_21.yml @@ -1792,25 +1792,25 @@ permissions: volume: 0.2 pitch: 0.2 - sculk_sensor: + ratings_show: display-menu: true permission-enabled: - type: SCULK_SENSOR - name: '&6Sculk Sensor' + type: NETHER_STAR + name: '&6Ratings Show' lore: - - '&7Access to trigger sculk sensors inside the island.' + - '&7Access to see all island''s ratings.' - '&7Currently &aENABLED&7.' permission-disabled: - type: SCULK_SENSOR - name: '&6Sculk Sensor' + type: NETHER_STAR + name: '&6Ratings Show' lore: - - '&7Access to trigger sculk sensors inside the island.' + - '&7Access to see all island''s ratings.' - '&7Currently &cDISABLED&7.' role-permission: - type: SCULK_SENSOR - name: '&6Sculk Sensor' + type: NETHER_STAR + name: '&6Ratings Show' lore: - - '&7Access to trigger sculk sensors inside the island.' + - '&7Access to see all island''s ratings.' - '&7Role: &e{}&7.' - '' - '{0}' @@ -1825,25 +1825,58 @@ permissions: volume: 0.2 pitch: 0.2 - ratings_show: + saddle_entity: display-menu: true permission-enabled: - type: NETHER_STAR - name: '&6Ratings Show' + type: SADDLE + name: '&6Saddle Entity' lore: - - '&7Access to see all island''s ratings.' + - '&7Access to add saddle to entities inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: - type: NETHER_STAR - name: '&6Ratings Show' + type: SADDLE + name: '&6Saddle Entity' lore: - - '&7Access to see all island''s ratings.' + - '&7Access to add saddle to entities inside the island.' - '&7Currently &cDISABLED&7.' role-permission: - type: NETHER_STAR - name: '&6Ratings Show' + type: SADDLE + name: '&6Saddle Entity' lore: - - '&7Access to see all island''s ratings.' + - '&7Access to add saddle to entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + sculk_sensor: + display-menu: true + permission-enabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' diff --git a/src/main/resources/menus/permissions1_9.yml b/src/main/resources/menus/permissions1_9.yml index 0475713d25..61e5d38b85 100644 --- a/src/main/resources/menus/permissions1_9.yml +++ b/src/main/resources/menus/permissions1_9.yml @@ -1690,6 +1690,39 @@ permissions: volume: 0.2 pitch: 0.2 + saddle_entity: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + set_biome: display-menu: true permission-enabled: From eddd39ea98ad0e392e5c9687cc6957b885bf5c1d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 18:23:11 +0200 Subject: [PATCH 084/600] Fixed the ability to add carpets to llamas on other islands (#2358) --- .../bgsoftware/superiorskyblock/core/Materials.java | 12 ++++++++++++ .../service/region/RegionManagerServiceImpl.java | 4 +++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java index f84e58742c..7d2be20b0d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java @@ -102,6 +102,10 @@ public static boolean isSpawnEgg(Material material) { return MATERIAL_TAGS.get(material) instanceof SpawnEggMaterialTag; } + public static boolean isCarpet(Material material) { + return MATERIAL_TAGS.get(material) instanceof CarpetMaterialTag; + } + public static Set getBlocksNonLegacy() { return Collections.unmodifiableSet(BLOCK_NON_LEGACY_MATERIALS); } @@ -152,6 +156,8 @@ else if (ServerVersion.isLegacy() ? material == Material.INK_SACK : materialName enumMap.put(material, DyeMaterialTag.INSTANCE); else if (ServerVersion.isLegacy() ? material == Material.MONSTER_EGG : materialName.contains("_SPAWN_EGG")) enumMap.put(material, SpawnEggMaterialTag.INSTANCE); + else if (materialName.contains("CARPET")) + enumMap.put(material, CarpetMaterialTag.INSTANCE); }); return enumMap; } @@ -236,4 +242,10 @@ private static class SpawnEggMaterialTag implements MaterialTag { } + private static class CarpetMaterialTag implements MaterialTag { + + private static final CarpetMaterialTag INSTANCE = new CarpetMaterialTag(); + + } + } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 814c62a4de..e391b7eb01 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -85,6 +85,8 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService private static final EntityType AXOLOTL_TYPE = EnumHelper.getEnum(EntityType.class, "AXOLOTL"); @Nullable private static final EntityType CAMEL_TYPE = EnumHelper.getEnum(EntityType.class, "CAMEL"); + @Nullable + private static final EntityType LLAMA_TYPE = EnumHelper.getEnum(EntityType.class, "LLAMA"); private static final int MAX_PICKUP_DISTANCE = 1; private static EnumerateSet WORLD_PERMISSIONS_CACHE; @@ -258,7 +260,7 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent islandPrivilege = IslandPrivileges.ANIMAL_BREED; } else if (usedItemType == Material.NAME_TAG) { islandPrivilege = IslandPrivileges.NAME_ENTITY; - } else if (usedItemType == Material.SADDLE) { + } else if (usedItemType == Material.SADDLE || (entityType == LLAMA_TYPE && Materials.isCarpet(usedItemType))) { islandPrivilege = IslandPrivileges.SADDLE_ENTITY; } else if (entity instanceof Villager) { islandPrivilege = IslandPrivileges.VILLAGER_TRADING; From 9dc8cf2cc5028b15381136efddc84f92ccc7fa38 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 18:30:43 +0200 Subject: [PATCH 085/600] Fixed the ability to harvest honey from nests on other islands (#2358) --- src/main/resources/interactables.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index 798db570e6..891e664808 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -32,6 +32,7 @@ interactables: - 'BARREL' - 'BEACON' - 'BED_BLOCK' + - 'BEE_NEST' - 'BIRCH_BUTTON' - 'BIRCH_DOOR' - 'BIRCH_FENCE' From 2624dd5be970781222a3b5c164bae7081762f4f5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 18:33:01 +0200 Subject: [PATCH 086/600] Fixed the ability to interact with chiseled bookshelves on other islands (#2358) --- src/main/resources/interactables.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index 891e664808..27dab488e5 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -75,6 +75,7 @@ interactables: - 'CHERRY_WALL_SIGN' - 'CHEST' - 'CHIPPED_ANVIL' + - 'CHISELED_BOOKSHELF' - 'COMMAND' - 'COMMAND_BLOCK' - 'COMMAND_CHAIN' From bab379eec805d764f6938e221e785ace3df84f47 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Feb 2025 18:35:58 +0200 Subject: [PATCH 087/600] Fixed a NPE when using /is rankup on an upgrade that is not in the menu (#2357) --- .../superiorskyblock/island/upgrade/SUpgradeLevel.java | 3 +++ .../module/upgrades/commands/CmdRankup.java | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java index 1c8a4eac61..9d21093f2a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.island.upgrade; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -66,6 +67,7 @@ protected PlaceholdersService create() { private final Value bankLimit; private final Int2IntMapView roleLimits; + @Nullable private ItemData itemData; public SUpgradeLevel(int level, UpgradeCost cost, List commands, String permission, Set requirements, @@ -371,6 +373,7 @@ public void setItemData(TemplateItem hasNextLevel, TemplateItem noNextLevel, this.itemData = new ItemData(hasNextLevel, noNextLevel, hasNextLevelSound, noNextLevelSound, hasNextLevelCommands, noNextLevelCommands); } + @Nullable public ItemData getItemData() { return itemData; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java index e768325379..b5c310feab 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java @@ -144,10 +144,11 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer } SUpgradeLevel.ItemData itemData = ((SUpgradeLevel) currentLevel).getItemData(); - GameSound sound = hasNextLevel ? itemData.hasNextLevelSound : itemData.noNextLevelSound; - - if (sound != null) - superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, sound)); + if (itemData != null) { + GameSound sound = hasNextLevel ? itemData.hasNextLevelSound : itemData.noNextLevelSound; + if (sound != null) + superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, sound)); + } } @Override From 7bb6df60cd1e8ff65482d99a665ea486ba6b49aa Mon Sep 17 00:00:00 2001 From: Ome_R Date: Fri, 21 Feb 2025 16:19:06 +0200 Subject: [PATCH 088/600] Custom event dispatcher (#2363) --- .../api/SuperiorSkyblock.java | 17 + .../api/platform/IEventsDispatcher.java | 27 + .../schematic/impl/WorldEditSchematic.java | 3 +- .../external/ProtocolLibHook.java | 3 +- .../chunks/CropsTickingTileEntity.java | 4 +- .../v1_16_R3/crops/CropsTickingMethod.java | 4 +- .../nms/v1_17/crops/CropsTickingMethod.java | 4 +- .../nms/v1_18/crops/CropsTickingMethod.java | 4 +- .../nms/v1_19/crops/CropsTickingMethod.java | 4 +- .../nms/v1_20_3/crops/CropsTickingMethod.java | 4 +- .../nms/v1_20_4/crops/CropsTickingMethod.java | 4 +- .../nms/v1_21/crops/CropsTickingMethod.java | 4 +- .../nms/v1_21_3/crops/CropsTickingMethod.java | 4 +- .../nms/v1_21_4/crops/CropsTickingMethod.java | 4 +- .../chunks/CropsTickingTileEntity.java | 4 +- .../SuperiorSkyblockPlugin.java | 46 +- .../commands/CommandsMap.java | 12 +- .../commands/admin/CmdAdminAdd.java | 3 +- .../commands/admin/CmdAdminAddBlockLimit.java | 21 +- .../commands/admin/CmdAdminAddBonus.java | 28 +- .../commands/admin/CmdAdminAddCoopLimit.java | 21 +- .../admin/CmdAdminAddEntityLimit.java | 21 +- .../commands/admin/CmdAdminAddSize.java | 21 +- .../commands/admin/CmdAdminAddTeamLimit.java | 21 +- .../commands/admin/CmdAdminAddWarpsLimit.java | 21 +- .../commands/admin/CmdAdminBypass.java | 3 +- .../commands/admin/CmdAdminClose.java | 3 +- .../commands/admin/CmdAdminDelWarp.java | 3 +- .../commands/admin/CmdAdminDemote.java | 5 +- .../commands/admin/CmdAdminDisband.java | 26 +- .../commands/admin/CmdAdminJoin.java | 3 +- .../commands/admin/CmdAdminName.java | 10 +- .../commands/admin/CmdAdminOpen.java | 3 +- .../commands/admin/CmdAdminPromote.java | 5 +- .../admin/CmdAdminRemoveBlockLimit.java | 11 +- .../commands/admin/CmdAdminRemoveRatings.java | 13 +- .../commands/admin/CmdAdminResetWorld.java | 11 +- .../commands/admin/CmdAdminSetBankLimit.java | 22 +- .../commands/admin/CmdAdminSetBlockLimit.java | 19 +- .../commands/admin/CmdAdminSetBonus.java | 28 +- .../commands/admin/CmdAdminSetCoopLimit.java | 21 +- .../admin/CmdAdminSetEntityLimit.java | 20 +- .../commands/admin/CmdAdminSetPermission.java | 16 +- .../commands/admin/CmdAdminSetRate.java | 5 +- .../commands/admin/CmdAdminSetRoleLimit.java | 24 +- .../commands/admin/CmdAdminSetSettings.java | 15 +- .../commands/admin/CmdAdminSetSize.java | 19 +- .../commands/admin/CmdAdminSetTeamLimit.java | 19 +- .../commands/admin/CmdAdminSetWarpsLimit.java | 19 +- .../commands/admin/CmdAdminSpy.java | 3 +- .../commands/admin/CmdAdminSyncBonus.java | 30 +- .../commands/admin/CmdAdminUnlockWorld.java | 14 +- .../commands/player/CmdAccept.java | 3 +- .../commands/player/CmdAdmin.java | 9 +- .../commands/player/CmdClose.java | 3 +- .../commands/player/CmdCoop.java | 3 +- .../commands/player/CmdDelWarp.java | 3 +- .../commands/player/CmdDemote.java | 3 +- .../commands/player/CmdDisband.java | 3 +- .../commands/player/CmdFly.java | 3 +- .../commands/player/CmdHelp.java | 9 +- .../commands/player/CmdInvite.java | 3 +- .../commands/player/CmdLeave.java | 3 +- .../commands/player/CmdName.java | 12 +- .../commands/player/CmdOpen.java | 3 +- .../commands/player/CmdPanel.java | 3 +- .../commands/player/CmdPardon.java | 3 +- .../commands/player/CmdPermissions.java | 5 +- .../commands/player/CmdPromote.java | 3 +- .../commands/player/CmdSetDiscord.java | 14 +- .../commands/player/CmdSetPaypal.java | 14 +- .../commands/player/CmdSetRole.java | 3 +- .../commands/player/CmdSetTeleport.java | 12 +- .../commands/player/CmdSetWarp.java | 5 +- .../commands/player/CmdTeamChat.java | 3 +- .../commands/player/CmdToggle.java | 5 +- .../commands/player/CmdUncoop.java | 3 +- .../config/SettingsManagerImpl.java | 4 +- .../superiorskyblock/core/Materials.java | 187 +-- .../core/database/DataManager.java | 3 +- .../core/events/CallbacksBus.java | 54 - .../core/events/EventCallback.java | 7 + .../core/events/EventResult.java | 30 - .../core/events/EventType.java | 22 + .../core/events/EventsBus.java | 943 ------------ .../core/events/EventsDispatcher.java | 88 ++ .../superiorskyblock/core/events/IEvent.java | 9 + .../core/events/args/IEventArgs.java | 4 + .../core/events/args/PluginEventArgs.java | 735 +++++++++ .../core/events/plugin/PluginEvent.java | 36 + .../events/plugin/PluginEventPriority.java | 7 + .../core/events/plugin/PluginEventType.java | 1189 +++++++++++++++ .../events/plugin/PluginEventsDispatcher.java | 92 ++ .../events/plugin/PluginEventsFactory.java | 1335 +++++++++++++++++ .../core/menu/button/impl/BiomeButton.java | 12 +- .../core/menu/button/impl/DisbandButton.java | 3 +- .../impl/IslandFlagPagedObjectButton.java | 5 +- .../IslandPrivilegePagedObjectButton.java | 5 +- .../core/menu/button/impl/LanguageButton.java | 3 +- .../core/menu/button/impl/LeaveButton.java | 3 +- .../menu/button/impl/RateIslandButton.java | 5 +- .../WarpCategoryIconEditConfirmButton.java | 13 +- .../impl/WarpCategoryManageIconButton.java | 14 +- .../impl/WarpCategoryManageRenameButton.java | 12 +- .../impl/WarpIconEditConfirmButton.java | 13 +- .../button/impl/WarpManageLocationButton.java | 16 +- .../button/impl/WarpManagePrivateButton.java | 5 +- .../button/impl/WarpManageRenameButton.java | 14 +- .../core/menu/view/AbstractMenuView.java | 16 +- .../core/messages/Message.java | 20 +- .../island/GridManagerImpl.java | 5 +- .../superiorskyblock/island/IslandUtils.java | 11 +- .../superiorskyblock/island/SIsland.java | 49 +- .../superiorskyblock/island/SpawnIsland.java | 7 +- .../DefaultIslandCreationAlgorithm.java | 9 +- .../island/bank/SIslandBank.java | 35 +- .../island/signs/IslandSigns.java | 24 +- .../listener/AbstractGameEventListener.java | 30 + .../listener/AdminPlayersListener.java | 29 +- .../listener/BlockChangesListener.java | 355 +++-- .../listener/BukkitEventsListener.java | 943 ++++++++++++ .../listener/BukkitListeners.java | 34 +- .../listener/ChunksListener.java | 41 +- .../listener/EntityTrackingListener.java | 98 +- .../listener/FeaturesListener.java | 309 ++-- .../listener/IslandFlagsListener.java | 218 ++- .../listener/IslandOutsideListener.java | 108 +- .../listener/IslandPreviewListener.java | 43 +- .../listener/IslandWorldEventsListener.java | 36 +- .../listener/MenusListener.java | 82 +- .../listener/PlayersListener.java | 355 ++--- .../listener/PortalsListener.java | 118 +- .../listener/ProtectionListener.java | 711 ++++----- .../listener/SignsListener.java | 134 +- .../listener/StackedBlocksListener.java | 248 +-- .../listener/WorldDestructionListener.java | 69 +- .../mission/MissionsManagerImpl.java | 11 +- .../commands/CmdAdminAddGenerator.java | 20 +- .../commands/CmdAdminClearGenerator.java | 9 +- .../commands/CmdAdminSetGenerator.java | 20 +- .../missions/commands/CmdAdminMission.java | 9 +- .../commands/CmdAdminAddCropGrowth.java | 21 +- .../upgrades/commands/CmdAdminAddEffect.java | 24 +- .../commands/CmdAdminAddMobDrops.java | 21 +- .../commands/CmdAdminAddSpawnerRates.java | 21 +- .../upgrades/commands/CmdAdminRankup.java | 11 +- .../commands/CmdAdminSetCropGrowth.java | 20 +- .../upgrades/commands/CmdAdminSetEffect.java | 24 +- .../commands/CmdAdminSetMobDrops.java | 20 +- .../commands/CmdAdminSetSpawnerRates.java | 20 +- .../upgrades/commands/CmdAdminSetUpgrade.java | 11 +- .../module/upgrades/commands/CmdRankup.java | 13 +- .../superiorskyblock/platform/IPlatform.java | 11 + .../platform/event/GameEvent.java | 36 + .../platform/event/GameEventCallback.java | 10 + .../platform/event/GameEventPriority.java | 12 + .../platform/event/GameEventType.java | 96 ++ .../platform/event/GameEventsDispatcher.java | 17 + .../platform/event/args/GameEventArgs.java | 445 ++++++ .../platform/event/args/IEventArgs.java | 4 + .../player/PlayersManagerImpl.java | 3 +- .../portals/PortalsManagerServiceImpl.java | 33 +- .../region/RegionManagerServiceImpl.java | 30 +- .../StackedBlocksInteractionServiceImpl.java | 7 +- .../superiorskyblock/world/BukkitItems.java | 14 +- .../world/EntityTeleports.java | 14 +- .../schematic/impl/SuperiorSchematic.java | 3 +- 167 files changed, 7487 insertions(+), 3340 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/platform/IEventsDispatcher.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/EventCallback.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/EventResult.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/EventType.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsBus.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/IEvent.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/args/IEventArgs.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEvent.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventPriority.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/listener/AbstractGameEventListener.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/platform/IPlatform.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEvent.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventCallback.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventPriority.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventsDispatcher.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/IEventArgs.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblock.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblock.java index d06b1ecde1..eb551fe25c 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblock.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblock.java @@ -16,6 +16,7 @@ import com.bgsoftware.superiorskyblock.api.handlers.SchematicManager; import com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager; import com.bgsoftware.superiorskyblock.api.handlers.UpgradesManager; +import com.bgsoftware.superiorskyblock.api.platform.IEventsDispatcher; import com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine; import org.bukkit.plugin.Plugin; @@ -109,4 +110,20 @@ public interface SuperiorSkyblock extends Plugin { */ void setScriptEngine(@Nullable IScriptEngine scriptEngine); + /** + * Get the events dispatcher of the plugin. + * + * @return The events dispatcher, or null if the default events dispatcher is used. + */ + @Nullable + IEventsDispatcher getEventsDispatcher(); + + /** + * Sets a custom events dispatcher for the plugin. + * + * @param eventsDispatcher The new events dispatcher to set. + * When null, the default events dispatcher will be used instead. + */ + void setEventsDispatcher(@Nullable IEventsDispatcher eventsDispatcher); + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/platform/IEventsDispatcher.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/platform/IEventsDispatcher.java new file mode 100644 index 0000000000..79748d37f6 --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/platform/IEventsDispatcher.java @@ -0,0 +1,27 @@ +package com.bgsoftware.superiorskyblock.api.platform; + +import org.bukkit.event.Event; +import org.bukkit.event.EventPriority; + +/** + * The events dispatcher is used to dispatch events to the plugin. + */ +public interface IEventsDispatcher { + + /** + * Notify about a new game-event. + * + * @param event The event that was fired. + * @param priority The priority of the event. + * @return Whether the event was successfully dispatched. + */ + boolean notifyEvent(Event event, EventPriority priority); + + /** + * Whether the default executor should be used if {@link #notifyEvent(Event, EventPriority)} fails. + */ + default boolean shouldFallbackToDefaultExecutorOnFailure() { + return true; + } + +} diff --git a/Hooks/FastAsyncWorldEdit/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/WorldEditSchematic.java b/Hooks/FastAsyncWorldEdit/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/WorldEditSchematic.java index 722444b673..091f3aaea8 100644 --- a/Hooks/FastAsyncWorldEdit/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/WorldEditSchematic.java +++ b/Hooks/FastAsyncWorldEdit/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/WorldEditSchematic.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -83,7 +84,7 @@ public void pasteSchematic(Island island, Location location, Runnable callback, try { island.handleBlocksPlace(cachedCounts); - plugin.getEventsBus().callIslandSchematicPasteEvent(island, name, location); + PluginEventsFactory.callIslandSchematicPasteEvent(island, null, name, location); callback.run(); } catch (Throwable ex) { diff --git a/Hooks/ProtocolLib/src/main/java/com/bgsoftware/superiorskyblock/external/ProtocolLibHook.java b/Hooks/ProtocolLib/src/main/java/com/bgsoftware/superiorskyblock/external/ProtocolLibHook.java index 78c34e9ffe..9339394143 100644 --- a/Hooks/ProtocolLib/src/main/java/com/bgsoftware/superiorskyblock/external/ProtocolLibHook.java +++ b/Hooks/ProtocolLib/src/main/java/com/bgsoftware/superiorskyblock/external/ProtocolLibHook.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolLibrary; @@ -46,7 +47,7 @@ public void onPacketReceiving(PacketEvent event) { SuperiorPlayer superiorPlayer = ProtocolLibHook.plugin.getPlayers().getPlayersContainer().getSuperiorPlayer(event.getPlayer().getUniqueId()); if (superiorPlayer != null && PlayerLocales.isValidLocale(newPlayerLocale) && !superiorPlayer.getUserLocale().equals(newPlayerLocale)) { - if (ProtocolLibHook.plugin.getEventsBus().callPlayerChangeLanguageEvent(superiorPlayer, newPlayerLocale)) + if (PluginEventsFactory.callPlayerChangeLanguageEvent(superiorPlayer, newPlayerLocale)) superiorPlayer.setUserLocale(newPlayerLocale); } } diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java index d3d02e95d8..f82386b2b8 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java @@ -6,7 +6,7 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.server.v1_12_R1.Block; @@ -33,7 +33,7 @@ public class CropsTickingTileEntity extends TileEntity implements ITickable { private static Set CROPS_TO_GROW_CACHE; static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingTileEntity::onSettingsUpdate); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingTileEntity::onSettingsUpdate); } private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java index 16b1a7f429..244e8157a3 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java @@ -3,7 +3,7 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.server.v1_16_R3.Block; @@ -30,7 +30,7 @@ public abstract class CropsTickingMethod { private static Set CROPS_TO_GROW_CACHE; static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); } private static final BlockPosition.MutableBlockPosition chunkTickMutablePosition = new BlockPosition.MutableBlockPosition(); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java index 1acaaaeaa5..b2bee8c987 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java @@ -3,7 +3,7 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; @@ -30,7 +30,7 @@ public abstract class CropsTickingMethod { private static Set CROPS_TO_GROW_CACHE; static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); } private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java index 0a5c4db0d0..4e91181ec9 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java @@ -3,7 +3,7 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; @@ -30,7 +30,7 @@ public abstract class CropsTickingMethod { private static Set CROPS_TO_GROW_CACHE; static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); } private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java index f5f1e95ad7..145c7c0bd2 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java @@ -3,7 +3,7 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; @@ -30,7 +30,7 @@ public abstract class CropsTickingMethod { private static Set CROPS_TO_GROW_CACHE; static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); } private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java index 02ca6bea8a..1fb93d680a 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java @@ -3,7 +3,7 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; @@ -30,7 +30,7 @@ public abstract class CropsTickingMethod { private static Set CROPS_TO_GROW_CACHE; static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); } private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java index 0944a3ca39..3b7231bc36 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java @@ -3,7 +3,7 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; @@ -30,7 +30,7 @@ public abstract class CropsTickingMethod { private static Set CROPS_TO_GROW_CACHE; static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); } private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java index dcaca12832..aa308d518b 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java @@ -2,7 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; @@ -28,7 +28,7 @@ public abstract class CropsTickingMethod { private static Set CROPS_TO_GROW_CACHE; static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); } private static final CropsTickingMethod INSTANCE = ((Supplier) () -> { diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java index d19ef091a2..f4afd4f8f0 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java @@ -3,7 +3,7 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; @@ -31,7 +31,7 @@ public abstract class CropsTickingMethod { private static Set CROPS_TO_GROW_CACHE; static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); } private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_SIMPLE_RANDOM.isValid() ? diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java index 66a1758608..eb6041c60c 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java @@ -3,7 +3,7 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.core.BlockPos; @@ -34,7 +34,7 @@ public abstract class CropsTickingMethod { private static Set CROPS_TO_GROW_CACHE; static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingMethod::onSettingsUpdate); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); } protected CropsTickingMethod() { diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java index f416c97604..0ef342b1ab 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java @@ -6,7 +6,7 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import net.minecraft.server.v1_8_R3.Block; @@ -33,7 +33,7 @@ public class CropsTickingTileEntity extends TileEntity implements IUpdatePlayerL private static Set CROPS_TO_GROW_CACHE; static { - plugin.getCallbacksBus().registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CropsTickingTileEntity::onSettingsUpdate); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingTileEntity::onSettingsUpdate); } private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index 9c4265eeb6..cf51cbf83d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.modules.ModuleLoadTime; +import com.bgsoftware.superiorskyblock.api.platform.IEventsDispatcher; import com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandsManagerImpl; @@ -25,8 +26,10 @@ import com.bgsoftware.superiorskyblock.core.engine.EnginesFactory; import com.bgsoftware.superiorskyblock.core.engine.NashornEngineDownloader; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; -import com.bgsoftware.superiorskyblock.core.events.EventsBus; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.factory.FactoriesManagerImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemSkulls; import com.bgsoftware.superiorskyblock.core.key.KeysManagerImpl; @@ -70,6 +73,7 @@ import com.bgsoftware.superiorskyblock.nms.NMSPlayers; import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.nms.NMSWorld; +import com.bgsoftware.superiorskyblock.platform.event.GameEventsDispatcher; import com.bgsoftware.superiorskyblock.player.PlayersManagerImpl; import com.bgsoftware.superiorskyblock.player.container.DefaultPlayersContainer; import com.bgsoftware.superiorskyblock.player.respawn.RespawnActions; @@ -114,10 +118,12 @@ public class SuperiorSkyblockPlugin extends JavaPlugin implements SuperiorSkyblo /* Global handlers */ private final Updater updater = new Updater(this, "superiorskyblock2"); - private final EventsBus eventsBus = new EventsBus(this); - private final CallbacksBus callbacksBus = new CallbacksBus(); private final BukkitListeners bukkitListeners = new BukkitListeners(this); + private final PluginEventsDispatcher pluginEventsDispatcher = new PluginEventsDispatcher(this); + private final GameEventsDispatcher gameEventsDispatcher = new GameEventsDispatcher(this); private IScriptEngine scriptEngine = EnginesFactory.createDefaultEngine(); + @Nullable + private IEventsDispatcher eventsDispatcher = null; /* NMS */ @Nullable @@ -139,7 +145,7 @@ public static SuperiorSkyblockPlugin getPlugin() { @Override public void onLoad() { plugin = this; - callbacksBus.registerDefaultCallbacks(); + pluginEventsDispatcher.registerDefaultListeners(); DependenciesManager.inject(this); @@ -230,9 +236,10 @@ public void onEnable() { modulesHandler.runModuleLifecycle(ModuleLoadTime.PLUGIN_INITIALIZE, false); - EventsBus.PluginInitializeResult eventResult = eventsBus.callPluginInitializeEvent(this); - this.playersHandler.setPlayersContainer(Optional.ofNullable(eventResult.getPlayersContainer()).orElse(new DefaultPlayersContainer())); - this.gridHandler.setIslandsContainer(Optional.ofNullable(eventResult.getIslandsContainer()).orElse(new DefaultIslandsContainer(this))); + PluginEvent event = PluginEventsFactory.callPluginInitializeEvent(); + + this.playersHandler.setPlayersContainer(Optional.ofNullable(event.getArgs().playersContainer).orElse(new DefaultPlayersContainer())); + this.gridHandler.setIslandsContainer(Optional.ofNullable(event.getArgs().islandsContainer).orElse(new DefaultIslandsContainer(this))); modulesHandler.runModuleLifecycle(ModuleLoadTime.BEFORE_WORLD_CREATION, false); @@ -314,11 +321,11 @@ public void onEnable() { } }, 1L); - eventsBus.callPluginInitializedEvent(this); + PluginEventsFactory.callPluginInitializedEvent(); loadingStage = PluginLoadingStage.ENABLED; - plugin.getCallbacksBus().notifyCallbacks(CallbacksBus.CallbackType.SETTINGS_UPDATE); + PluginEventsFactory.callSettingsUpdateEvent(); } catch (Throwable error) { Log.error(error, "An unexpected error occurred while enabling the plugin:"); Bukkit.shutdown(); @@ -590,12 +597,23 @@ public void setScriptEngine(@Nullable IScriptEngine scriptEngine) { this.scriptEngine = scriptEngine == null ? EnginesFactory.createDefaultEngine() : scriptEngine; } - public EventsBus getEventsBus() { - return eventsBus; + @Nullable + @Override + public IEventsDispatcher getEventsDispatcher() { + return this.eventsDispatcher; + } + + @Override + public void setEventsDispatcher(@Nullable IEventsDispatcher eventsDispatcher) { + this.eventsDispatcher = eventsDispatcher; + } + + public PluginEventsDispatcher getPluginEventsDispatcher() { + return pluginEventsDispatcher; } - public CallbacksBus getCallbacksBus() { - return callbacksBus; + public GameEventsDispatcher getGameEventsDispatcher() { + return gameEventsDispatcher; } public ServicesHandler getServices() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java index c70ae874d3..4b73fbeb01 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java @@ -4,7 +4,9 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.google.common.base.Preconditions; import java.util.Collections; @@ -32,8 +34,8 @@ private static void onSettingsUpdate() { }); } - public static void registerCallbacks(CallbacksBus bus) { - bus.registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CommandsMap::onSettingsUpdate); + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CommandsMap::onSettingsUpdate); } private final Map subCommands = new LinkedHashMap<>(); @@ -66,7 +68,7 @@ public void registerCommand(SuperiorCommand superiorCommand, boolean sort) { superiorCommands.forEach(s -> subCommands.put(s.getAliases().get(0), s)); } - plugin.getCallbacksBus().notifyCallbacks(CallbacksBus.CallbackType.COMMANDS_UPDATE); + PluginEventsFactory.callCommandsUpdateEvent(); } public void unregisterCommand(SuperiorCommand superiorCommand) { @@ -78,7 +80,7 @@ public void unregisterCommand(SuperiorCommand superiorCommand) { removeCommand(label); - plugin.getCallbacksBus().notifyCallbacks(CallbacksBus.CallbackType.COMMANDS_UPDATE); + PluginEventsFactory.callCommandsUpdateEvent(); } @Nullable diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java index 5e57451730..3e85542d6f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; @@ -73,7 +74,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; } - if (!plugin.getEventsBus().callIslandJoinEvent(targetPlayer, island, IslandJoinEvent.Cause.ADMIN)) + if (!PluginEventsFactory.callIslandJoinEvent(island, targetPlayer, IslandJoinEvent.Cause.ADMIN)) return; IslandUtils.sendMessage(island, Message.JOIN_ANNOUNCEMENT, Collections.emptyList(), targetPlayer.getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBlockLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBlockLimit.java index 3ac54da27d..138c1a02fa 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBlockLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBlockLimit.java @@ -9,7 +9,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -81,20 +83,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab int limit = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeBlockLimitEvent(sender, - island, key, island.getBlockLimit(key) + limit); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setBlockLimit(key, eventResult.getResult()); + PluginEvent event = + PluginEventsFactory.callIslandChangeBlockLimitEvent(island, sender, key, island.getBlockLimit(key) + limit); + if (!event.isCancelled()) { + island.setBlockLimit(key, event.getArgs().blockLimit); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_BLOCK_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey())); else if (targetPlayer == null) Message.CHANGED_BLOCK_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBonus.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBonus.java index 51b3a9638b..d35b49c1ec 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBonus.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBonus.java @@ -9,7 +9,9 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -72,27 +74,27 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (bonus == null) return; - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { if (isWorthBonus) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeWorthBonusEvent(sender, island, - IslandChangeWorthBonusEvent.Reason.COMMAND, island.getBonusWorth().add(bonus)); - if (!eventResult.isCancelled()) { - island.setBonusWorth(eventResult.getResult()); - anyIslandChanged = true; + PluginEvent event = PluginEventsFactory.callIslandChangeWorthBonusEvent( + island, sender, IslandChangeWorthBonusEvent.Reason.COMMAND, island.getBonusWorth().add(bonus)); + if (!event.isCancelled()) { + island.setBonusWorth(event.getArgs().worthBonus); + ++islandsChangedCount; } } else { - EventResult eventResult = plugin.getEventsBus().callIslandChangeLevelBonusEvent(sender, island, - IslandChangeLevelBonusEvent.Reason.COMMAND, island.getBonusLevel().add(bonus)); - if (!eventResult.isCancelled()) { - island.setBonusLevel(eventResult.getResult()); - anyIslandChanged = true; + PluginEvent event = PluginEventsFactory.callIslandChangeLevelBonusEvent( + island, sender, IslandChangeLevelBonusEvent.Reason.COMMAND, island.getBonusLevel().add(bonus)); + if (!event.isCancelled()) { + island.setBonusLevel(event.getArgs().levelBonus); + ++islandsChangedCount; } } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; Message.BONUS_SET_SUCCESS.send(sender, bonus.toString()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddCoopLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddCoopLimit.java index 2cfd75e1b7..1da9670559 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddCoopLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddCoopLimit.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -69,20 +71,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab int limit = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeCoopLimitEvent(sender, - island, island.getCoopLimit() + limit); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setCoopLimit(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeCoopLimitEvent( + island, sender, island.getCoopLimit() + limit); + if (!event.isCancelled()) { + island.setCoopLimit(event.getArgs().coopLimit); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_COOP_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_COOP_LIMIT_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddEntityLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddEntityLimit.java index 9c07103802..58de1a1382 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddEntityLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddEntityLimit.java @@ -9,7 +9,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -76,20 +78,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab int limit = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeEntityLimitEvent(sender, - island, entityKey, island.getEntityLimit(entityKey) + limit); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setEntityLimit(entityKey, eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeEntityLimitEvent( + island, sender, entityKey, island.getEntityLimit(entityKey) + limit); + if (!event.isCancelled()) { + island.setEntityLimit(entityKey, event.getArgs().entityLimit); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_ENTITY_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey())); else if (targetPlayer == null) Message.CHANGED_ENTITY_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey()), islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddSize.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddSize.java index b1609b71a7..3540c46d80 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddSize.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddSize.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -73,20 +75,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; } - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeBorderSizeEvent(sender, - island, island.getIslandSize() + size); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setIslandSize(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeBorderSizeEvent( + island, sender, island.getIslandSize() + size); + if (!event.isCancelled()) { + island.setIslandSize(event.getArgs().borderSize); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_ISLAND_SIZE_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_ISLAND_SIZE_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddTeamLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddTeamLimit.java index 768e204eba..1f2ce85ccc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddTeamLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddTeamLimit.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -69,20 +71,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab int limit = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeMembersLimitEvent(sender, - island, island.getTeamLimit() + limit); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setTeamLimit(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeMembersLimitEvent( + island, sender, island.getTeamLimit() + limit); + if (!event.isCancelled()) { + island.setTeamLimit(event.getArgs().membersLimit); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_TEAM_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_TEAM_LIMIT_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddWarpsLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddWarpsLimit.java index 45a2e492f4..8f4d1344a4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddWarpsLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddWarpsLimit.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -73,20 +75,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; } - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeWarpsLimitEvent(sender, - island, island.getWarpsLimit() + limit); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setWarpsLimit(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeWarpsLimitEvent( + island, sender, island.getWarpsLimit() + limit); + if (!event.isCancelled()) { + island.setWarpsLimit(event.getArgs().warpsLimit); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_WARPS_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_WARPS_LIMIT_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminBypass.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminBypass.java index c410b3ce54..2c7166272a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminBypass.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminBypass.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -50,7 +51,7 @@ public boolean canBeExecutedByConsole() { public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - if (!plugin.getEventsBus().callPlayerToggleBypassEvent(superiorPlayer)) + if (!PluginEventsFactory.callPlayerToggleBypassEvent(superiorPlayer)) return; if (superiorPlayer.hasBypassModeEnabled()) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java index e1bccb824b..74c699aa50 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -58,7 +59,7 @@ public boolean supportMultipleIslands() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { - if (plugin.getEventsBus().callIslandCloseEvent(island, sender)) { + if (PluginEventsFactory.callIslandCloseEvent(island, sender)) { island.setLocked(true); Message.ISLAND_CLOSED.send(sender); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java index 3db97acf73..156ef78a3b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.warp.SignWarp; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; @@ -70,7 +71,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (islandWarp == null) return; - if (!plugin.getEventsBus().callIslandDeleteWarpEvent(sender, islandWarp.getIsland(), islandWarp)) + if (!PluginEventsFactory.callIslandDeleteWarpEvent(islandWarp.getIsland(), sender, islandWarp)) return; island.deleteWarp(islandWarp.getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDemote.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDemote.java index ca5b3a55b2..c80bffc6b6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDemote.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDemote.java @@ -1,11 +1,12 @@ package com.bgsoftware.superiorskyblock.commands.admin; -import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; @@ -82,7 +83,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, Superio return; } - if (!plugin.getEventsBus().callPlayerChangeRoleEvent(targetPlayer, previousRole)) + if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, previousRole)) return; targetPlayer.setPlayerRole(previousRole); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDisband.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDisband.java index 5215674b7c..23dc5e24ba 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDisband.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDisband.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; @@ -61,22 +62,23 @@ public boolean supportMultipleIslands() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { - if (plugin.getEventsBus().callIslandDisbandEvent(targetPlayer, island)) { - IslandUtils.sendMessage(island, Message.DISBAND_ANNOUNCEMENT, Collections.emptyList(), sender.getName()); + if (!PluginEventsFactory.callIslandDisbandEvent(island, targetPlayer)) + return; - if (targetPlayer == null) - Message.DISBANDED_ISLAND_OTHER_NAME.send(sender, island.getName()); - else - Message.DISBANDED_ISLAND_OTHER.send(sender, targetPlayer.getName()); + IslandUtils.sendMessage(island, Message.DISBAND_ANNOUNCEMENT, Collections.emptyList(), sender.getName()); - if (BuiltinModules.BANK.disbandRefund > 0) { - Message.DISBAND_ISLAND_BALANCE_REFUND.send(island.getOwner(), - Formatters.NUMBER_FORMATTER.format(island.getIslandBank() - .getBalance().multiply(BigDecimal.valueOf(BuiltinModules.BANK.disbandRefund)))); - } + if (targetPlayer == null) + Message.DISBANDED_ISLAND_OTHER_NAME.send(sender, island.getName()); + else + Message.DISBANDED_ISLAND_OTHER.send(sender, targetPlayer.getName()); - island.disbandIsland(); + if (BuiltinModules.BANK.disbandRefund > 0) { + Message.DISBAND_ISLAND_BALANCE_REFUND.send(island.getOwner(), + Formatters.NUMBER_FORMATTER.format(island.getIslandBank() + .getBalance().multiply(BigDecimal.valueOf(BuiltinModules.BANK.disbandRefund)))); } + + island.disbandIsland(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java index c03083ef3d..600af66a93 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; @@ -67,7 +68,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; } - if (!plugin.getEventsBus().callIslandJoinEvent(superiorPlayer, island, IslandJoinEvent.Cause.ADMIN)) + if (!PluginEventsFactory.callIslandJoinEvent(island, superiorPlayer, IslandJoinEvent.Cause.ADMIN)) return; IslandUtils.sendMessage(island, Message.JOIN_ADMIN_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java index 7483bc9b21..2f78e72928 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java @@ -5,7 +5,9 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandNames; @@ -63,12 +65,12 @@ public boolean supportMultipleIslands() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { - EventResult eventResult = plugin.getEventsBus().callIslandRenameEvent(island, args[3]); + PluginEvent event = PluginEventsFactory.callIslandRenameEvent(island, sender, args[3]); - if (eventResult.isCancelled()) + if (event.isCancelled()) return; - String islandName = eventResult.getResult(); + String islandName = event.getArgs().islandName; if (!IslandNames.isValidName(sender, island, islandName)) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java index bf0927f60b..5516f0bd55 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -57,7 +58,7 @@ public boolean supportMultipleIslands() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { - if (plugin.getEventsBus().callIslandOpenEvent(island, sender)) { + if (PluginEventsFactory.callIslandOpenEvent(island, sender)) { island.setLocked(false); Message.ISLAND_OPENED.send(sender); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminPromote.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminPromote.java index e0923043c7..966a7b35e1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminPromote.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminPromote.java @@ -1,11 +1,12 @@ package com.bgsoftware.superiorskyblock.commands.admin; -import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Collections; @@ -89,7 +90,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, Superio return; } - if (!plugin.getEventsBus().callPlayerChangeRoleEvent(targetPlayer, nextRole)) + if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, nextRole)) return; targetPlayer.setPlayerRole(nextRole); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveBlockLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveBlockLimit.java index 0a5402eb96..3904625227 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveBlockLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveBlockLimit.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -66,19 +67,19 @@ public boolean supportMultipleIslands() { public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Key key = Keys.ofMaterialAndData(args[3]); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - if (plugin.getEventsBus().callIslandRemoveBlockLimitEvent(sender, island, key)) { - anyIslandChanged = true; + if (PluginEventsFactory.callIslandRemoveBlockLimitEvent(island, sender, key)) { + ++islandsChangedCount; island.removeBlockLimit(key); } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_BLOCK_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey())); else if (targetPlayer == null) Message.CHANGED_BLOCK_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveRatings.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveRatings.java index a06e03d15c..2c3aba29cc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveRatings.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveRatings.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -61,21 +62,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab boolean removingAllRatings = targetPlayer == null; Collection iterIslands = removingAllRatings ? islands : plugin.getGrid().getIslands(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : iterIslands) { if (removingAllRatings) { - if (plugin.getEventsBus().callIslandClearRatingsEvent(sender, island)) { - anyIslandChanged = true; + if (PluginEventsFactory.callIslandClearRatingsEvent(island, sender)) { + ++islandsChangedCount; island.removeRatings(); } - } else if (plugin.getEventsBus().callIslandRemoveRatingEvent(sender, targetPlayer, island)) { - anyIslandChanged = true; + } else if (PluginEventsFactory.callIslandRemoveRatingEvent(island, sender, targetPlayer)) { + ++islandsChangedCount; island.removeRating(targetPlayer); } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; if (!removingAllRatings) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java index 3675898026..87dddbe056 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.IslandWorlds; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.World; @@ -80,23 +81,23 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; } - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - if (!plugin.getEventsBus().callIslandWorldResetEvent(sender, island, dimension)) + if (!PluginEventsFactory.callIslandWorldResetEvent(island, sender, dimension)) continue; - anyIslandChanged = true; + ++islandsChangedCount; IslandWorlds.accessIslandWorldAsync(island, dimension, islandWorldResult -> { islandWorldResult.ifLeft(world -> resetChunksInternal(island, world, dimension)); }); } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.RESET_WORLD_SUCCEED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3])); else if (targetPlayer == null) Message.RESET_WORLD_SUCCEED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3]), islands.get(0). diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBankLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBankLimit.java index 61939624f8..9a24af2ae9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBankLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBankLimit.java @@ -6,7 +6,9 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -67,22 +69,20 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (limit == null) return; - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeBankLimitEvent(sender, island, limit); - - if (eventResult.isCancelled()) - continue; - - anyIslandChanged = true; - island.setBankLimit(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeBankLimitEvent(island, sender, limit); + if (!event.isCancelled()) { + island.setBankLimit(event.getArgs().bankLimit); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_BANK_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_BANK_LIMIT_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockLimit.java index a0c9d5deb2..0ea67b62b0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockLimit.java @@ -9,7 +9,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -76,19 +78,20 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab int limit = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeBlockLimitEvent(sender, island, key, limit); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setBlockLimit(key, eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeBlockLimitEvent(island, sender, key, limit); + if (!event.isCancelled()) { + island.setBlockLimit(key, event.getArgs().blockLimit); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_BLOCK_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey())); else if (targetPlayer == null) Message.CHANGED_BLOCK_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBonus.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBonus.java index f3d1d43e7a..f856daabfc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBonus.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBonus.java @@ -9,7 +9,9 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -73,27 +75,27 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (bonus == null) return; - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { if (isWorthBonus) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeWorthBonusEvent(sender, island, - IslandChangeWorthBonusEvent.Reason.COMMAND, bonus); - if (!eventResult.isCancelled()) { - island.setBonusWorth(eventResult.getResult()); - anyIslandChanged = true; + PluginEvent event = PluginEventsFactory.callIslandChangeWorthBonusEvent( + island, sender, IslandChangeWorthBonusEvent.Reason.COMMAND, bonus); + if (!event.isCancelled()) { + island.setBonusWorth(event.getArgs().worthBonus); + ++islandsChangedCount; } } else { - EventResult eventResult = plugin.getEventsBus().callIslandChangeLevelBonusEvent(sender, island, - IslandChangeLevelBonusEvent.Reason.COMMAND, bonus); - if (!eventResult.isCancelled()) { - island.setBonusLevel(eventResult.getResult()); - anyIslandChanged = true; + PluginEvent event = PluginEventsFactory.callIslandChangeLevelBonusEvent( + island, sender, IslandChangeLevelBonusEvent.Reason.COMMAND, bonus); + if (!event.isCancelled()) { + island.setBonusLevel(event.getArgs().levelBonus); + ++islandsChangedCount; } } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; Message.BONUS_SET_SUCCESS.send(sender, bonus.toString()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetCoopLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetCoopLimit.java index be8cb844e9..55e75e38ae 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetCoopLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetCoopLimit.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -69,20 +71,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab int limit = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeCoopLimitEvent(sender, - island, island.getCoopLimit() + limit); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setCoopLimit(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeCoopLimitEvent( + island, sender, island.getCoopLimit() + limit); + if (!event.isCancelled()) { + island.setCoopLimit(event.getArgs().coopLimit); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_COOP_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_COOP_LIMIT_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetEntityLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetEntityLimit.java index 65027de822..e541bddd25 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetEntityLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetEntityLimit.java @@ -9,7 +9,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -76,19 +78,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab int limit = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeEntityLimitEvent(sender, island, entityKey, limit); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setEntityLimit(entityKey, eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeEntityLimitEvent( + island, sender, entityKey, limit); + if (!event.isCancelled()) { + island.setEntityLimit(entityKey, event.getArgs().entityLimit); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_ENTITY_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey())); else if (targetPlayer == null) Message.CHANGED_ENTITY_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(entityKey.getGlobalKey()), islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java index 9515dfcc0f..58e3cf0db0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -76,20 +77,19 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (playerRole == null) return; - boolean anyPrivilegesChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - if (!plugin.getEventsBus().callIslandChangeRolePrivilegeEvent(island, playerRole)) - continue; - - anyPrivilegesChanged = true; - island.setPermission(playerRole, islandPrivilege); + if (PluginEventsFactory.callIslandChangeRolePrivilegeEvent(island, sender, playerRole)) { + island.setPermission(playerRole, islandPrivilege); + ++islandsChangedCount; + } } - if (!anyPrivilegesChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.PERMISSION_CHANGED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName())); else if (targetPlayer == null) Message.PERMISSION_CHANGED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName()), islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRate.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRate.java index 2024072302..e2f61df570 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRate.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRate.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -73,11 +74,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; if (rating == Rating.UNKNOWN) { - if (plugin.getEventsBus().callIslandRemoveRatingEvent(sender, superiorPlayer, island)) { + if (PluginEventsFactory.callIslandRemoveRatingEvent(island, sender, superiorPlayer)) { island.removeRating(targetPlayer); Message.RATE_REMOVE_ALL.send(sender, targetPlayer.getName()); } - } else if (plugin.getEventsBus().callIslandRateEvent(sender, superiorPlayer, island, rating)) { + } else if (PluginEventsFactory.callIslandRateEvent(island, sender, superiorPlayer, rating)) { island.setRating(targetPlayer, rating); Message.RATE_CHANGE_OTHER.send(sender, targetPlayer.getName(), Formatters.CAPITALIZED_FORMATTER.format(rating.name())); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java index 88c606348d..06d5605756 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java @@ -9,7 +9,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; @@ -84,26 +86,28 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab int limit = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { if (limit <= 0) { - if (plugin.getEventsBus().callIslandRemoveRoleLimitEvent(sender, island, playerRole)) { - anyIslandChanged = true; + if (PluginEventsFactory.callIslandRemoveRoleLimitEvent(island, sender, playerRole)) { + ++islandsChangedCount; island.removeRoleLimit(playerRole); } } else { - EventResult eventResult = plugin.getEventsBus().callIslandChangeRoleLimitEvent(sender, island, playerRole, limit); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setRoleLimit(playerRole, eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeRoleLimitEvent( + island, sender, playerRole, limit); + if (!event.isCancelled()) { + island.setRoleLimit(playerRole, event.getArgs().roleLimit); + ++islandsChangedCount; + } } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_ROLE_LIMIT_ALL.send(sender, playerRole); else if (targetPlayer == null) Message.CHANGED_ROLE_LIMIT_NAME.send(sender, playerRole, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSettings.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSettings.java index 7ca29db3a8..0b2f27cc90 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSettings.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSettings.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -71,26 +72,26 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab boolean value = args[4].equalsIgnoreCase("true"); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { if (island.hasSettingsEnabled(islandFlag) == value) { - anyIslandChanged = true; + ++islandsChangedCount; continue; } if (value) { - if (plugin.getEventsBus().callIslandEnableFlagEvent(sender, island, islandFlag)) { - anyIslandChanged = true; + if (PluginEventsFactory.callIslandEnableFlagEvent(island, sender, islandFlag)) { + ++islandsChangedCount; island.enableSettings(islandFlag); } - } else if (plugin.getEventsBus().callIslandDisableFlagEvent(sender, island, islandFlag)) { - anyIslandChanged = true; + } else if (PluginEventsFactory.callIslandDisableFlagEvent(island, sender, islandFlag)) { + ++islandsChangedCount; island.disableSettings(islandFlag); } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; if (islands.size() != 1) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSize.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSize.java index eb2b5efd71..e9fa2a6b3d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSize.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSize.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -74,19 +76,20 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; } - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeBorderSizeEvent(sender, island, size); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setIslandSize(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeBorderSizeEvent(island, sender, size); + if (!event.isCancelled()) { + island.setIslandSize(event.getArgs().borderSize); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_ISLAND_SIZE_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_ISLAND_SIZE_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetTeamLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetTeamLimit.java index c55a7ce326..c742d0ef5f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetTeamLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetTeamLimit.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -69,19 +71,20 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab int limit = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeMembersLimitEvent(sender, island, limit); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setTeamLimit(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeMembersLimitEvent(island, sender, limit); + if (!event.isCancelled()) { + island.setTeamLimit(event.getArgs().membersLimit); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_TEAM_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_TEAM_LIMIT_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetWarpsLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetWarpsLimit.java index a5893fa4d9..3ec04bbf7a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetWarpsLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetWarpsLimit.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -73,19 +75,20 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; } - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeWarpsLimitEvent(sender, island, limit); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setWarpsLimit(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeWarpsLimitEvent(island, sender, limit); + if (!event.isCancelled()) { + island.setWarpsLimit(event.getArgs().warpsLimit); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_WARPS_LIMIT_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_WARPS_LIMIT_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSpy.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSpy.java index 23fcb67d60..3be2fa5b0f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSpy.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSpy.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import org.bukkit.command.CommandSender; @@ -50,7 +51,7 @@ public boolean canBeExecutedByConsole() { public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - if (!plugin.getEventsBus().callPlayerToggleSpyEvent(superiorPlayer)) + if (!PluginEventsFactory.callPlayerToggleSpyEvent(superiorPlayer)) return; if (superiorPlayer.hasAdminSpyEnabled()) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSyncBonus.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSyncBonus.java index 28eb65f34d..7f2d9030d2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSyncBonus.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSyncBonus.java @@ -11,7 +11,9 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.world.Dimensions; import org.bukkit.command.CommandSender; @@ -73,34 +75,34 @@ public boolean supportMultipleIslands() { public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { boolean isWorthBonus = !args[3].equalsIgnoreCase("level"); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { BigDecimal currentBonus = isWorthBonus ? island.getBonusWorth() : island.getBonusLevel(); BigDecimal newBonus = calculateValue(island, isWorthBonus); if (!newBonus.equals(currentBonus)) { if (isWorthBonus) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeWorthBonusEvent(sender, island, - IslandChangeWorthBonusEvent.Reason.COMMAND, newBonus); - if (!eventResult.isCancelled()) { - island.setBonusWorth(eventResult.getResult()); - anyIslandChanged = true; + PluginEvent event = PluginEventsFactory.callIslandChangeWorthBonusEvent( + island, sender, IslandChangeWorthBonusEvent.Reason.COMMAND, newBonus); + if (!event.isCancelled()) { + island.setBonusWorth(event.getArgs().worthBonus); + ++islandsChangedCount; } } else { - EventResult eventResult = plugin.getEventsBus().callIslandChangeLevelBonusEvent(sender, island, - IslandChangeLevelBonusEvent.Reason.COMMAND, newBonus); - if (!eventResult.isCancelled()) { - island.setBonusLevel(eventResult.getResult()); - anyIslandChanged = true; + PluginEvent event = PluginEventsFactory.callIslandChangeLevelBonusEvent( + island, sender, IslandChangeLevelBonusEvent.Reason.COMMAND, newBonus); + if (!event.isCancelled()) { + island.setBonusLevel(event.getArgs().levelBonus); + ++islandsChangedCount; } } } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.BONUS_SYNC_ALL.send(sender); else if (targetPlayer == null) Message.BONUS_SYNC_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java index 51c21e0ec5..a63369787e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java @@ -8,16 +8,14 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; -import org.bukkit.World; import org.bukkit.command.CommandSender; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Locale; public class CmdAdminUnlockWorld implements IAdminIslandCommand { @@ -78,18 +76,18 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab boolean enable = Boolean.parseBoolean(args[4]); - boolean anyWorldsChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - if (enable ? !plugin.getEventsBus().callIslandUnlockWorldEvent(island, dimension) : - !plugin.getEventsBus().callIslandLockWorldEvent(island, dimension)) + if (enable ? !PluginEventsFactory.callIslandUnlockWorldEvent(island, sender, dimension) : + !PluginEventsFactory.callIslandLockWorldEvent(island, sender, dimension)) continue; - anyWorldsChanged = true; island.setDimensionEnabled(dimension, enable); + ++islandsChangedCount; } - if (anyWorldsChanged) + if (islandsChangedCount > 0) Message.UNLOCK_WORLD_ANNOUNCEMENT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3])); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java index b4c860529c..91adf0485c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; @@ -86,7 +87,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; } - if (!plugin.getEventsBus().callIslandJoinEvent(superiorPlayer, island, IslandJoinEvent.Cause.INVITE)) + if (!PluginEventsFactory.callIslandJoinEvent(island, superiorPlayer, IslandJoinEvent.Cause.INVITE)) return; IslandUtils.sendMessage(island, Message.JOIN_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java index 04a57b2096..420cde4054 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java @@ -7,7 +7,8 @@ import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -24,9 +25,9 @@ public class CmdAdmin implements ISuperiorCommand { private static final Int2ObjectMapView> commandsPerPageCache = CollectionsFactory.createInt2ObjectArrayMap(); - public static void registerCallbacks(CallbacksBus bus) { - bus.registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CmdAdmin::onCommandsRefresh); - bus.registerCallback(CallbacksBus.CallbackType.COMMANDS_UPDATE, CmdAdmin::onCommandsRefresh); + public static void registerCallbacks(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CmdAdmin::onCommandsRefresh); + dispatcher.registerCallback(PluginEventType.COMMANDS_UPDATE_EVENT, CmdAdmin::onCommandsRefresh); } private static void onCommandsRefresh() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdClose.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdClose.java index aa6ca1ec8d..4b38f98c03 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdClose.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdClose.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -60,7 +61,7 @@ public Message getPermissionLackMessage() { @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { - if (plugin.getEventsBus().callIslandCloseEvent(island, superiorPlayer)) { + if (PluginEventsFactory.callIslandCloseEvent(island, superiorPlayer)) { island.setLocked(true); Message.ISLAND_CLOSED.send(superiorPlayer); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCoop.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCoop.java index f1d0a3eb7f..19fd345ab3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCoop.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCoop.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -94,7 +95,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer return; } - if (!plugin.getEventsBus().callIslandCoopPlayerEvent(island, superiorPlayer, targetPlayer)) + if (!PluginEventsFactory.callIslandCoopPlayerEvent(island, superiorPlayer, targetPlayer)) return; island.addCoop(targetPlayer); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java index b7c3023d32..3390bf6c94 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.warp.SignWarp; @@ -74,7 +75,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer if (islandWarp == null) return; - if (!plugin.getEventsBus().callIslandDeleteWarpEvent(superiorPlayer, island, islandWarp)) + if (!PluginEventsFactory.callIslandDeleteWarpEvent(island, superiorPlayer, islandWarp)) return; island.deleteWarp(islandWarp.getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDemote.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDemote.java index cc1d0be3d2..a2ea7c180f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDemote.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDemote.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -91,7 +92,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer return; } - if (!plugin.getEventsBus().callPlayerChangeRoleEvent(targetPlayer, previousRole)) + if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, previousRole)) return; targetPlayer.setPlayerRole(previousRole); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java index a7ce76efcc..b827f2029c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -73,7 +74,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer if (plugin.getSettings().isDisbandConfirm()) { plugin.getMenus().openConfirmDisband(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); - } else if (plugin.getEventsBus().callIslandDisbandEvent(superiorPlayer, island)) { + } else if (PluginEventsFactory.callIslandDisbandEvent(island, superiorPlayer)) { IslandUtils.sendMessage(island, Message.DISBAND_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); Message.DISBANDED_ISLAND.send(superiorPlayer); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java index ae94b6fc94..33d405b932 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -55,7 +56,7 @@ public boolean canBeExecutedByConsole() { public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - if (!plugin.getEventsBus().callPlayerToggleFlyEvent(superiorPlayer)) + if (!PluginEventsFactory.callPlayerToggleFlyEvent(superiorPlayer)) return; Player player = (Player) sender; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java index e595f7f5fd..83aa3ead5c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java @@ -7,7 +7,8 @@ import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; @@ -20,9 +21,9 @@ public class CmdHelp implements ISuperiorCommand { private static final Int2ObjectMapView> commandsPerPageCache = CollectionsFactory.createInt2ObjectArrayMap(); - public static void registerCallbacks(CallbacksBus bus) { - bus.registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, CmdHelp::onCommandsRefresh); - bus.registerCallback(CallbacksBus.CallbackType.COMMANDS_UPDATE, CmdHelp::onCommandsRefresh); + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CmdHelp::onCommandsRefresh); + dispatcher.registerCallback(PluginEventType.COMMANDS_UPDATE_EVENT, CmdHelp::onCommandsRefresh); } private static void onCommandsRefresh() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdInvite.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdInvite.java index 2b86a2c5d4..fd88298e18 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdInvite.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdInvite.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -91,7 +92,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer return; } - if (!plugin.getEventsBus().callIslandInviteEvent(superiorPlayer, targetPlayer, island)) + if (!PluginEventsFactory.callIslandInviteEvent(island, superiorPlayer, targetPlayer)) return; island.inviteMember(targetPlayer); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdLeave.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdLeave.java index cf8d266de2..9b0b15e30b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdLeave.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdLeave.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; @@ -72,7 +73,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; } - if (!plugin.getEventsBus().callIslandQuitEvent(superiorPlayer, island)) + if (!PluginEventsFactory.callIslandQuitEvent(island, superiorPlayer)) return; island.kickMember(superiorPlayer); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java index 86af2e29f5..de56930d50 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java @@ -4,10 +4,12 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandNames; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.Bukkit; @@ -65,12 +67,12 @@ public Message getPermissionLackMessage() { @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { - EventResult eventResult = plugin.getEventsBus().callIslandRenameEvent(island, superiorPlayer, args[1]); + PluginEvent event = PluginEventsFactory.callIslandRenameEvent(island, superiorPlayer, args[1]); - if (eventResult.isCancelled()) + if (event.isCancelled()) return; - String islandName = eventResult.getResult(); + String islandName = event.getArgs().islandName; if (!IslandNames.isValidName(superiorPlayer, island, islandName)) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdOpen.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdOpen.java index d2efc40452..6562051bbc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdOpen.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdOpen.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -60,7 +61,7 @@ public Message getPermissionLackMessage() { @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { - if (plugin.getEventsBus().callIslandOpenEvent(island, superiorPlayer)) { + if (PluginEventsFactory.callIslandOpenEvent(island, superiorPlayer)) { island.setLocked(false); Message.ISLAND_OPENED.send(superiorPlayer); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPanel.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPanel.java index d4b66ed1bd..67925ad5b6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPanel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPanel.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -71,7 +72,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ plugin.getCommands().dispatchSubCommand(sender, "visitors"); return; } else if (args[1].equalsIgnoreCase("toggle")) { - if (!plugin.getEventsBus().callPlayerTogglePanelEvent(superiorPlayer)) + if (!PluginEventsFactory.callPlayerTogglePanelEvent(superiorPlayer)) return; if (superiorPlayer.hasToggledPanel()) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPardon.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPardon.java index 3605bb0aa3..841631201d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPardon.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPardon.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -74,7 +75,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer return; } - if (!plugin.getEventsBus().callIslandUnbanEvent(superiorPlayer, targetPlayer, island)) + if (!PluginEventsFactory.callIslandUnbanEvent(island, superiorPlayer, targetPlayer)) return; island.unbanMember(targetPlayer); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPermissions.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPermissions.java index 080df44995..367372b580 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPermissions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPermissions.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -97,12 +98,12 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer } } else { if (permissionHolder instanceof PlayerRole) { - if (plugin.getEventsBus().callIslandClearRolesPrivilegesEvent(island, superiorPlayer)) { + if (PluginEventsFactory.callIslandClearRolesPrivilegesEvent(island, superiorPlayer)) { island.resetPermissions(); Message.PERMISSIONS_RESET_ROLES.send(superiorPlayer); } } else { - if (plugin.getEventsBus().callIslandClearPlayerPrivilegesEvent(island, superiorPlayer, (SuperiorPlayer) permissionHolder)) { + if (PluginEventsFactory.callIslandClearPlayerPrivilegesEvent(island, superiorPlayer, (SuperiorPlayer) permissionHolder)) { island.resetPermissions((SuperiorPlayer) permissionHolder); Message.PERMISSIONS_RESET_PLAYER.send(superiorPlayer, ((SuperiorPlayer) permissionHolder).getName()); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPromote.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPromote.java index 199dc1ce3c..2deec8ce02 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPromote.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPromote.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -104,7 +105,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer return; } - if (!plugin.getEventsBus().callPlayerChangeRoleEvent(targetPlayer, nextRole)) + if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, nextRole)) return; targetPlayer.setPlayerRole(nextRole); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetDiscord.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetDiscord.java index 0aea386f9e..315242f837 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetDiscord.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetDiscord.java @@ -4,11 +4,13 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import com.bgsoftware.superiorskyblock.core.events.EventResult; import java.util.Collections; import java.util.List; @@ -64,13 +66,13 @@ public Message getPermissionLackMessage() { public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { String discord = CommandArguments.buildLongString(args, 1, false); - EventResult eventResult = plugin.getEventsBus().callIslandChangeDiscordEvent(superiorPlayer, island, discord); + PluginEvent event = PluginEventsFactory.callIslandChangeDiscordEvent(island, superiorPlayer, discord); - if (eventResult.isCancelled()) + if (event.isCancelled()) return; - island.setDiscord(eventResult.getResult()); - Message.CHANGED_DISCORD.send(superiorPlayer, eventResult.getResult()); + island.setDiscord(event.getArgs().discord); + Message.CHANGED_DISCORD.send(superiorPlayer, event.getArgs().discord); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetPaypal.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetPaypal.java index 9047b7603e..1076567fb9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetPaypal.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetPaypal.java @@ -1,13 +1,15 @@ package com.bgsoftware.superiorskyblock.commands.player; -import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import com.bgsoftware.superiorskyblock.core.events.EventResult; import java.util.Collections; import java.util.List; @@ -61,13 +63,13 @@ public Message getPermissionLackMessage() { @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { - EventResult eventResult = plugin.getEventsBus().callIslandChangePaypalEvent(superiorPlayer, island, args[1]); + PluginEvent event = PluginEventsFactory.callIslandChangePaypalEvent(island, superiorPlayer, args[1]); - if (eventResult.isCancelled()) + if (event.isCancelled()) return; - island.setPaypal(eventResult.getResult()); - Message.CHANGED_PAYPAL.send(superiorPlayer, eventResult.getResult()); + island.setPaypal(event.getArgs().paypal); + Message.CHANGED_PAYPAL.send(superiorPlayer, event.getArgs().paypal); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java index 6f5658f86b..e9ae24515e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; @@ -131,7 +132,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer PlayerRole currentRole = targetPlayer.getPlayerRole(); - if (!plugin.getEventsBus().callPlayerChangeRoleEvent(targetPlayer, playerRole)) + if (!PluginEventsFactory.callPlayerChangeRoleEvent(targetPlayer, playerRole)) return; targetPlayer.setPlayerRole(playerRole); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java index 63a9d9ba09..424306a661 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.Location; @@ -72,13 +74,13 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer return; } - EventResult eventResult = plugin.getEventsBus().callIslandSetHomeEvent(island, newLocation, - IslandSetHomeEvent.Reason.SET_HOME_COMMAND, superiorPlayer); + PluginEvent event = PluginEventsFactory.callIslandSetHomeEvent( + island, superiorPlayer, newLocation, IslandSetHomeEvent.Reason.SET_HOME_COMMAND); - if (eventResult.isCancelled()) + if (event.isCancelled()) return; - island.setIslandHome(eventResult.getResult()); + island.setIslandHome(event.getArgs().islandHome); } Message.CHANGED_TELEPORT_LOCATION.send(superiorPlayer); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java index 54ff9f5d02..2e16a8ce52 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; @@ -119,7 +120,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer } if (island.getWarpCategory(categoryName) == null && - !plugin.getEventsBus().callIslandCreateWarpCategoryEvent(superiorPlayer, island, categoryName)) + !PluginEventsFactory.callIslandCreateWarpCategoryEvent(island, superiorPlayer, categoryName)) return; } @@ -130,7 +131,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer Preconditions.checkState(warpLocation != null, "Null location for a warp."); - if (!plugin.getEventsBus().callIslandCreateWarpEvent(superiorPlayer, island, warpName, warpLocation, warpCategory)) + if (!PluginEventsFactory.callIslandCreateWarpEvent(island, superiorPlayer, warpName, warpLocation, warpCategory)) return; island.createWarp(warpName, warpLocation, warpCategory); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeamChat.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeamChat.java index 23c874ca1a..8d90917a6c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeamChat.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeamChat.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.Bukkit; @@ -65,7 +66,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); if (args.length == 1) { - if (!plugin.getEventsBus().callPlayerToggleTeamChatEvent(superiorPlayer)) + if (!PluginEventsFactory.callPlayerToggleTeamChatEvent(superiorPlayer)) return; if (superiorPlayer.hasTeamChatEnabled()) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java index 66b45e30ee..320bab178b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Location; import org.bukkit.command.CommandSender; @@ -60,7 +61,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; } - if (!plugin.getEventsBus().callPlayerToggleBorderEvent(superiorPlayer)) + if (!PluginEventsFactory.callPlayerToggleBorderEvent(superiorPlayer)) return; if (superiorPlayer.hasWorldBorderEnabled()) { @@ -79,7 +80,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; } - if (!plugin.getEventsBus().callPlayerToggleBlocksStackerEvent(superiorPlayer)) + if (!PluginEventsFactory.callPlayerToggleBlocksStackerEvent(superiorPlayer)) return; if (superiorPlayer.hasBlocksStackerEnabled()) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdUncoop.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdUncoop.java index ec2b827f83..2c7d6e2f28 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdUncoop.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdUncoop.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -75,7 +76,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer return; } - if (!plugin.getEventsBus().callIslandUncoopPlayerEvent(island, superiorPlayer, targetPlayer, IslandUncoopPlayerEvent.UncoopReason.PLAYER)) + if (!PluginEventsFactory.callIslandUncoopPlayerEvent(island, superiorPlayer, targetPlayer, IslandUncoopPlayerEvent.UncoopReason.PLAYER)) return; island.removeCoop(targetPlayer); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index e541162858..ac20c67c80 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -23,7 +23,7 @@ import com.bgsoftware.superiorskyblock.config.section.WorldsSection; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.Location; import org.bukkit.configuration.file.YamlConfiguration; @@ -83,7 +83,7 @@ public void loadData() throws ManagerLoadException { loadContainerFromConfig(cfg); - plugin.getCallbacksBus().notifyCallbacks(CallbacksBus.CallbackType.SETTINGS_UPDATE); + PluginEventsFactory.callSettingsUpdateEvent(); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java index 7d2be20b0d..ca1ae88170 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java @@ -25,7 +25,7 @@ public enum Materials { END_PORTAL_FRAME("ENDER_PORTAL_FRAME"); - private static final EnumMap MATERIAL_TAGS = setupMaterialTags(); + private static final EnumMap> MATERIAL_TAGS = setupMaterialTags(); private static final EnumSet BLOCK_NON_LEGACY_MATERIALS = allOf(material -> material.isBlock() && !isLegacy(material)); private static final EnumSet SOLID_MATERIALS = allOf(Material::isSolid); private static final Map PATCHED_MATERIAL_NAMES = setupPatchedMaterialNames(); @@ -58,52 +58,61 @@ public ItemStack toBukkitItem(int amount) { return ServerVersion.isLegacy() ? new ItemStack(toBukkitType(), amount, bukkitData) : new ItemStack(toBukkitType(), amount); } + public static boolean hasTag(Material material, Tag tag) { + EnumSet materialsTag = MATERIAL_TAGS.get(material); + return materialsTag != null && materialsTag.contains(tag); + } + public static boolean isSlab(Material material) { - return MATERIAL_TAGS.get(material) instanceof SlabMaterialTag; + return hasTag(material, Tag.SLAB); } public static boolean isWater(Material material) { - return MATERIAL_TAGS.get(material) instanceof WaterMaterialTag; + return hasTag(material, Tag.WATER); } public static boolean isLegacy(Material material) { - return MATERIAL_TAGS.get(material) instanceof LegacyMaterialTag; + return hasTag(material, Tag.LEGACY); } public static boolean isRail(Material material) { - return MATERIAL_TAGS.get(material) instanceof RailMaterialTag; + return hasTag(material, Tag.RAIL); } public static boolean isMinecart(Material material) { - return MATERIAL_TAGS.get(material) instanceof MinecartMaterialTag; + return hasTag(material, Tag.MINECART); } public static boolean isChest(Material material) { - return MATERIAL_TAGS.get(material) instanceof ChestMaterialTag; + return hasTag(material, Tag.CHEST); } public static boolean isBoat(Material material) { - return MATERIAL_TAGS.get(material) instanceof BoatMaterialTag; + return hasTag(material, Tag.BOAT); } public static boolean isLava(Material material) { - return MATERIAL_TAGS.get(material) instanceof LavaMaterialTag; + return hasTag(material, Tag.LAVA); } public static boolean isSign(Material material) { - return MATERIAL_TAGS.get(material) instanceof SignMaterialTag; + return hasTag(material, Tag.SIGN); } public static boolean isDye(Material material) { - return MATERIAL_TAGS.get(material) instanceof DyeMaterialTag; + return hasTag(material, Tag.DYE); } public static boolean isSpawnEgg(Material material) { - return MATERIAL_TAGS.get(material) instanceof SpawnEggMaterialTag; + return hasTag(material, Tag.SPAWN_EGG); } public static boolean isCarpet(Material material) { - return MATERIAL_TAGS.get(material) instanceof CarpetMaterialTag; + return hasTag(material, Tag.CARPET); + } + + public static boolean isBed(Material material) { + return hasTag(material, Tag.BED); } public static Set getBlocksNonLegacy() { @@ -128,36 +137,48 @@ private static EnumSet allOf(Predicate predicate) { return enumSet; } - private static EnumMap setupMaterialTags() { - EnumMap enumMap = new EnumMap<>(Material.class); - Arrays.stream(Material.values()).forEach(material -> { + private static EnumMap> setupMaterialTags() { + EnumMap> enumMap = new EnumMap<>(Material.class); + + for (Material material : Material.values()) { + EnumSet materialTags = EnumSet.noneOf(Tag.class); + String materialName = material.name(); if (materialName.startsWith("LEGACY_")) - enumMap.put(material, LegacyMaterialTag.INSTANCE); - else if (materialName.contains("SLAB")) - enumMap.put(material, SlabMaterialTag.INSTANCE); - else if (materialName.contains("WATER")) - enumMap.put(material, WaterMaterialTag.INSTANCE); - else if (materialName.contains("RAIL")) - enumMap.put(material, RailMaterialTag.INSTANCE); - else if (materialName.contains("MINECART")) - enumMap.put(material, MinecartMaterialTag.INSTANCE); - else if (material == Material.CHEST || material == Material.ENDER_CHEST || + materialTags.add(Tag.LEGACY); + if (materialName.contains("SLAB")) + materialTags.add(Tag.SLAB); + if (materialName.contains("WATER")) + materialTags.add(Tag.WATER); + if (materialName.contains("RAIL")) + materialTags.add(Tag.RAIL); + if (materialName.contains("MINECART")) + materialTags.add(Tag.MINECART); + if (material == Material.CHEST || material == Material.ENDER_CHEST || material == Material.TRAPPED_CHEST || materialName.contains("SHULKER_BOX") || materialName.equals("BARREL")) - enumMap.put(material, ChestMaterialTag.INSTANCE); - else if (materialName.contains("BOAT")) - enumMap.put(material, BoatMaterialTag.INSTANCE); - else if (materialName.contains("LAVA")) - enumMap.put(material, LavaMaterialTag.INSTANCE); - else if (materialName.contains("SIGN")) - enumMap.put(material, SignMaterialTag.INSTANCE); - else if (ServerVersion.isLegacy() ? material == Material.INK_SACK : materialName.contains("_DYE")) - enumMap.put(material, DyeMaterialTag.INSTANCE); - else if (ServerVersion.isLegacy() ? material == Material.MONSTER_EGG : materialName.contains("_SPAWN_EGG")) - enumMap.put(material, SpawnEggMaterialTag.INSTANCE); - else if (materialName.contains("CARPET")) - enumMap.put(material, CarpetMaterialTag.INSTANCE); + materialTags.add(Tag.CHEST); + if (materialName.contains("BOAT")) + materialTags.add(Tag.BOAT); + if (materialName.contains("LAVA")) + materialTags.add(Tag.LAVA); + if (materialName.contains("SIGN")) + materialTags.add(Tag.SIGN); + if (ServerVersion.isLegacy() ? material == Material.INK_SACK : materialName.contains("_DYE")) + materialTags.add(Tag.DYE); + if (ServerVersion.isLegacy() ? material == Material.MONSTER_EGG : materialName.contains("_SPAWN_EGG")) + materialTags.add(Tag.SPAWN_EGG); + if (materialName.contains("CARPET")) + materialTags.add(Tag.CARPET); + if (materialName.contains("BED")) + materialTags.add(Tag.BED); + + if (!materialTags.isEmpty()) + enumMap.put(material, materialTags); + } + + Arrays.stream(Material.values()).forEach(material -> { + }); return enumMap; } @@ -172,79 +193,21 @@ private static Map setupPatchedMaterialNames() { return map.isEmpty() ? Collections.emptyMap() : map; } - private interface MaterialTag { - - } - - private static class SlabMaterialTag implements MaterialTag { - - private static final SlabMaterialTag INSTANCE = new SlabMaterialTag(); - - } - - private static class WaterMaterialTag implements MaterialTag { - - private static final WaterMaterialTag INSTANCE = new WaterMaterialTag(); - - } - - private static class LegacyMaterialTag implements MaterialTag { - - private static final LegacyMaterialTag INSTANCE = new LegacyMaterialTag(); - - } - - private static class RailMaterialTag implements MaterialTag { - - private static final RailMaterialTag INSTANCE = new RailMaterialTag(); - - } - - private static class MinecartMaterialTag implements MaterialTag { - - private static final MinecartMaterialTag INSTANCE = new MinecartMaterialTag(); - - } - - private static class ChestMaterialTag implements MaterialTag { - - private static final ChestMaterialTag INSTANCE = new ChestMaterialTag(); - - } - - private static class BoatMaterialTag implements MaterialTag { - - private static final BoatMaterialTag INSTANCE = new BoatMaterialTag(); - - } - - private static class LavaMaterialTag implements MaterialTag { - - private static final LavaMaterialTag INSTANCE = new LavaMaterialTag(); - - } - - private static class SignMaterialTag implements MaterialTag { - - private static final SignMaterialTag INSTANCE = new SignMaterialTag(); - - } - - private static class DyeMaterialTag implements MaterialTag { - - private static final DyeMaterialTag INSTANCE = new DyeMaterialTag(); - - } - - private static class SpawnEggMaterialTag implements MaterialTag { - - private static final SpawnEggMaterialTag INSTANCE = new SpawnEggMaterialTag(); - - } - - private static class CarpetMaterialTag implements MaterialTag { - - private static final CarpetMaterialTag INSTANCE = new CarpetMaterialTag(); + public enum Tag { + + SLAB, + WATER, + LEGACY, + RAIL, + MINECART, + CHEST, + BOAT, + LAVA, + SIGN, + DYE, + SPAWN_EGG, + CARPET, + BED } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java index 5fba15e5fa..cedbf38472 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.core.database.serialization.IslandsDeserializer; import com.bgsoftware.superiorskyblock.core.database.serialization.PlayersDeserializer; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; @@ -54,7 +55,7 @@ public void loadData() throws ManagerLoadException { runState(DatabaseLoader.State.PRE_LOAD_DATA); - if (plugin.getEventsBus().callPluginLoadDataEvent(plugin)) { + if (PluginEventsFactory.callPluginLoadDataEvent()) { loadPlayers(); loadIslands(); loadGrid(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java deleted file mode 100644 index e2861b8868..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/CallbacksBus.java +++ /dev/null @@ -1,54 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.events; - -import com.bgsoftware.superiorskyblock.commands.CommandsMap; -import com.bgsoftware.superiorskyblock.commands.player.CmdAdmin; -import com.bgsoftware.superiorskyblock.commands.player.CmdHelp; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.island.SIsland; -import com.bgsoftware.superiorskyblock.island.SpawnIsland; -import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; - -import java.util.EnumMap; -import java.util.LinkedList; -import java.util.List; - -public class CallbacksBus { - - private final EnumMap> CALLBACKS = new EnumMap<>(CallbackType.class); - - public CallbacksBus() { - } - - public void registerDefaultCallbacks() { - SIsland.registerCallbacks(this); - CommandsMap.registerCallbacks(this); - SpawnIsland.registerCallbacks(this); - RegionManagerServiceImpl.registerCallbacks(this); - CmdHelp.registerCallbacks(this); - CmdAdmin.registerCallbacks(this); - } - - public void registerCallback(CallbackType callbackType, Runnable callback) { - CALLBACKS.computeIfAbsent(callbackType, c -> new LinkedList<>()).add(callback); - } - - public void notifyCallbacks(CallbackType callbackType) { - List callbacks = CALLBACKS.get(callbackType); - if (callbacks != null) - callbacks.forEach(callback -> { - try { - callback.run(); - } catch (Throwable error) { - Log.error(error, "An unexpected error occurred while running callback:"); - } - }); - } - - public enum CallbackType { - - SETTINGS_UPDATE, - COMMANDS_UPDATE - - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventCallback.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventCallback.java new file mode 100644 index 0000000000..ee19c3a18e --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventCallback.java @@ -0,0 +1,7 @@ +package com.bgsoftware.superiorskyblock.core.events; + +public interface EventCallback { + + void execute(E gameEvent); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventResult.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventResult.java deleted file mode 100644 index c69b34379e..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventResult.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.events; - -public class EventResult { - - private final boolean cancelled; - private final T result; - - private EventResult(boolean cancelled, T result) { - this.cancelled = cancelled; - this.result = result; - } - - static EventResult of(boolean cancelled) { - return new EventResult<>(cancelled, null); - } - - static EventResult of(boolean cancelled, T result) { - return new EventResult<>(cancelled, result); - } - - public boolean isCancelled() { - return cancelled; - } - - public T getResult() { - return result; - } - -} - diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventType.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventType.java new file mode 100644 index 0000000000..b37a743313 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventType.java @@ -0,0 +1,22 @@ +package com.bgsoftware.superiorskyblock.core.events; + +import com.bgsoftware.superiorskyblock.api.objects.Enumerable; + +public abstract class EventType implements Enumerable { + + private static int ordinalCounter = 0; + + private final int ordinal; + + protected EventType() { + this.ordinal = ordinalCounter++; + } + + @Override + public int ordinal() { + return this.ordinal; + } + + public abstract E createEvent(Args args); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsBus.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsBus.java deleted file mode 100644 index def3f57e14..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsBus.java +++ /dev/null @@ -1,943 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.events; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; -import com.bgsoftware.superiorskyblock.api.enums.BorderColor; -import com.bgsoftware.superiorskyblock.api.enums.Rating; -import com.bgsoftware.superiorskyblock.api.events.AttemptPlayerSendMessageEvent; -import com.bgsoftware.superiorskyblock.api.events.BlockStackEvent; -import com.bgsoftware.superiorskyblock.api.events.BlockUnstackEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandBanEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandBankDepositEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandBankWithdrawEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandBiomeChangeEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeBankLimitEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeBlockLimitEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeBorderSizeEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeCoopLimitEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeCropGrowthEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeDescriptionEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeDiscordEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeEffectLevelEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeEntityLimitEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeGeneratorRateEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeMembersLimitEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeMobDropsEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangePaypalEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangePlayerPrivilegeEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeRoleLimitEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeRolePrivilegeEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeSpawnerRatesEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpCategoryIconEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpCategorySlotEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpIconEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpLocationEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpsLimitEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChatEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChunkResetEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandClearGeneratorRatesEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandClearPlayerPrivilegesEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandClearRatingsEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandClearRolesPrivilegesEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandCloseEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandCloseWarpEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandCoopPlayerEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandCreateEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandCreateWarpCategoryEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandCreateWarpEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandDeleteWarpEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandDisableFlagEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandDisbandEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandEnableFlagEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandEnterPortalEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandEnterProtectedEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandInviteEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandKickEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandLeaveProtectedEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandLockWorldEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandOpenEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandOpenWarpEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandQuitEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandRateEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandRemoveBlockLimitEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandRemoveEffectEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandRemoveGeneratorRateEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandRemoveRatingEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandRemoveRoleLimitEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandRemoveVisitorHomeEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandRenameEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandRenameWarpCategoryEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandRenameWarpEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandSchematicPasteEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandSetVisitorHomeEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandTransferEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandUnbanEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandUnlockWorldEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandWorldResetEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandWorthCalculatedEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandWorthUpdateEvent; -import com.bgsoftware.superiorskyblock.api.events.MissionCompleteEvent; -import com.bgsoftware.superiorskyblock.api.events.MissionResetEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerChangeBorderColorEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerChangeLanguageEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerChangeNameEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerChangeRoleEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerCloseMenuEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerOpenMenuEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerReplaceEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerToggleBlocksStackerEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerToggleBorderEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerToggleBypassEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerToggleFlyEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerTogglePanelEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerToggleSpyEvent; -import com.bgsoftware.superiorskyblock.api.events.PlayerToggleTeamChatEvent; -import com.bgsoftware.superiorskyblock.api.events.PluginInitializeEvent; -import com.bgsoftware.superiorskyblock.api.events.PluginInitializedEvent; -import com.bgsoftware.superiorskyblock.api.events.PluginLoadDataEvent; -import com.bgsoftware.superiorskyblock.api.events.PostIslandCreateEvent; -import com.bgsoftware.superiorskyblock.api.events.PreIslandCreateEvent; -import com.bgsoftware.superiorskyblock.api.events.SendMessageEvent; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.island.IslandFlag; -import com.bgsoftware.superiorskyblock.api.island.PlayerRole; -import com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer; -import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; -import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; -import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; -import com.bgsoftware.superiorskyblock.api.missions.Mission; -import com.bgsoftware.superiorskyblock.api.player.container.PlayersContainer; -import com.bgsoftware.superiorskyblock.api.schematic.Schematic; -import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; -import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; -import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; -import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.logging.Debug; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.PortalType; -import org.bukkit.block.Biome; -import org.bukkit.block.Block; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; -import org.bukkit.event.Event; -import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionEffectType; - -import java.math.BigDecimal; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.function.Function; -import java.util.function.Supplier; - -public class EventsBus { - - private final SuperiorSkyblockPlugin plugin; - - public EventsBus(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - - - public boolean callAttemptPlayerSendMessageEvent(SuperiorPlayer receiver, String messageType, Object... args) { - return callEvent(() -> new AttemptPlayerSendMessageEvent(receiver, messageType, args), "attemptplayersendmessageevent"); - } - - public boolean callBlockStackEvent(Block block, Player player, int originalAmount, int newAmount) { - return callEvent(() -> new BlockStackEvent(block, player, originalAmount, newAmount), - "blockstackevent"); - } - - public boolean callBlockUnstackEvent(Block block, Player player, int originalAmount, int newAmount) { - return callEvent(() -> new BlockUnstackEvent(block, player, originalAmount, newAmount), - "blockunstackevent"); - } - - public boolean callIslandBanEvent(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, Island island) { - return callEvent(() -> new IslandBanEvent(superiorPlayer, targetPlayer, island), "islandbanevent"); - } - - public EventResult callIslandBankDepositEvent(SuperiorPlayer superiorPlayer, Island island, BigDecimal amount) { - return callEvent(() -> new IslandBankDepositEvent(superiorPlayer, island, amount), - "islandbankdepositevent", null, IslandBankDepositEvent::getFailureReason); - } - - public EventResult callIslandBankWithdrawEvent(SuperiorPlayer superiorPlayer, Island island, BigDecimal amount) { - return callEvent(() -> new IslandBankWithdrawEvent(superiorPlayer, island, amount), - "islandbankwithdrawevent", null, IslandBankWithdrawEvent::getFailureReason); - } - - public EventResult callIslandBiomeChangeEvent(SuperiorPlayer superiorPlayer, Island island, Biome biome) { - return callEvent(() -> new IslandBiomeChangeEvent(superiorPlayer, island, biome), - "islandbiomechangeevent", biome, IslandBiomeChangeEvent::getBiome); - } - - public EventResult callIslandChangeBankLimitEvent(CommandSender commandSender, Island island, BigDecimal bankLimit) { - return callEvent(() -> new IslandChangeBankLimitEvent(getSuperiorPlayer(commandSender), island, bankLimit), - "islandchangebanklimitevent", bankLimit, IslandChangeBankLimitEvent::getBankLimit); - } - - public EventResult callIslandChangeBlockLimitEvent(CommandSender commandSender, Island island, Key block, int blockLimit) { - return callEvent(() -> new IslandChangeBlockLimitEvent(getSuperiorPlayer(commandSender), island, block, blockLimit), - "islandchangeblocklimitevent", blockLimit, IslandChangeBlockLimitEvent::getBlockLimit); - } - - public EventResult callIslandChangeBorderSizeEvent(CommandSender commandSender, Island island, int borderSize) { - return callEvent(() -> new IslandChangeBorderSizeEvent(getSuperiorPlayer(commandSender), island, borderSize), - "islandchangebordersizeevent", borderSize, IslandChangeBorderSizeEvent::getBorderSize); - } - - public EventResult callIslandChangeCoopLimitEvent(CommandSender commandSender, Island island, int coopLimit) { - return callEvent(() -> new IslandChangeCoopLimitEvent(getSuperiorPlayer(commandSender), island, coopLimit), - "islandchangecooplimitevent", coopLimit, IslandChangeCoopLimitEvent::getCoopLimit); - } - - public EventResult callIslandChangeCropGrowthEvent(CommandSender commandSender, Island island, double cropGrowth) { - return callEvent(() -> new IslandChangeCropGrowthEvent(getSuperiorPlayer(commandSender), island, cropGrowth), - "islandchangecropgrowthevent", cropGrowth, IslandChangeCropGrowthEvent::getCropGrowth); - } - - public EventResult callIslandChangeDescriptionEvent(SuperiorPlayer superiorPlayer, Island island, String description) { - return callEvent(() -> new IslandChangeDescriptionEvent(island, superiorPlayer, description), - "islandchangedescriptionevent", description, IslandChangeDescriptionEvent::getDescription); - } - - public EventResult callIslandChangeDiscordEvent(SuperiorPlayer superiorPlayer, Island island, String discord) { - return callEvent(() -> new IslandChangeDiscordEvent(superiorPlayer, island, discord), - "islandchangediscordevent", discord, IslandChangeDiscordEvent::getDiscord); - } - - public EventResult callIslandChangeEffectLevelEvent(CommandSender commandSender, Island island, - PotionEffectType effectType, int effectLevel) { - return callEvent(() -> new IslandChangeEffectLevelEvent(getSuperiorPlayer(commandSender), island, effectType, effectLevel), - "islandchangeeffectlevelevent", effectLevel, IslandChangeEffectLevelEvent::getEffectLevel); - } - - public EventResult callIslandChangeEntityLimitEvent(CommandSender commandSender, Island island, Key entity, int entityLimit) { - return callEvent(() -> new IslandChangeEntityLimitEvent(getSuperiorPlayer(commandSender), island, entity, entityLimit), - "islandchangeentitylimitevent", entityLimit, IslandChangeEntityLimitEvent::getEntityLimit); - } - - public EventResult callIslandChangeGeneratorRateEvent(CommandSender commandSender, Island island, Key block, - Dimension dimension, int generatorRate) { - return callIslandChangeGeneratorRateEvent(getSuperiorPlayer(commandSender), island, block, dimension, generatorRate); - } - - public EventResult callIslandChangeGeneratorRateEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block, - Dimension dimension, int generatorRate) { - return callEvent(() -> new IslandChangeGeneratorRateEvent(superiorPlayer, island, block, dimension, generatorRate), - "islandchangegeneratorrateevent", generatorRate, IslandChangeGeneratorRateEvent::getGeneratorRate); - } - - public EventResult callIslandChangeLevelBonusEvent(CommandSender commandSender, Island island, - IslandChangeLevelBonusEvent.Reason reason, - BigDecimal levelBonus) { - return callEvent(() -> new IslandChangeLevelBonusEvent(getSuperiorPlayer(commandSender), island, reason, levelBonus), - "islandchangelevelbonusevent", levelBonus, IslandChangeLevelBonusEvent::getLevelBonus); - } - - public EventResult callIslandChangeMembersLimitEvent(CommandSender commandSender, Island island, int membersLimit) { - return callEvent(() -> new IslandChangeMembersLimitEvent(getSuperiorPlayer(commandSender), island, membersLimit), - "islandchangememberslimitevent", membersLimit, IslandChangeMembersLimitEvent::getMembersLimit); - } - - public EventResult callIslandChangeMobDropsEvent(CommandSender commandSender, Island island, double mobDrops) { - return callEvent(() -> new IslandChangeMobDropsEvent(getSuperiorPlayer(commandSender), island, mobDrops), - "islandchangemobdropsevent", mobDrops, IslandChangeMobDropsEvent::getMobDrops); - } - - public EventResult callIslandChangePaypalEvent(SuperiorPlayer superiorPlayer, Island island, String paypal) { - return callEvent(() -> new IslandChangePaypalEvent(superiorPlayer, island, paypal), - "islandchangepaypalevent", paypal, IslandChangePaypalEvent::getPaypal); - } - - public boolean callIslandChangePlayerPrivilegeEvent(Island island, SuperiorPlayer superiorPlayer, - SuperiorPlayer privilegedPlayer, boolean privilegeEnabled) { - return callEvent(() -> new IslandChangePlayerPrivilegeEvent(island, superiorPlayer, privilegedPlayer, privilegeEnabled), - "islandchangeplayerprivilegeevent"); - } - - public EventResult callIslandChangeRoleLimitEvent(CommandSender commandSender, Island island, PlayerRole playerRole, int roleLimit) { - return callEvent(() -> new IslandChangeRoleLimitEvent(getSuperiorPlayer(commandSender), island, playerRole, roleLimit), - "islandchangerolelimitevent", roleLimit, IslandChangeRoleLimitEvent::getRoleLimit); - } - - public boolean callIslandChangeRolePrivilegeEvent(Island island, PlayerRole playerRole) { - return callIslandChangeRolePrivilegeEvent(island, null, playerRole); - } - - public EventResult callIslandChangeSpawnerRatesEvent(CommandSender commandSender, Island island, double spawnerRates) { - return callEvent(() -> new IslandChangeSpawnerRatesEvent(getSuperiorPlayer(commandSender), island, spawnerRates), - "islandchangespawnerratesevent", spawnerRates, IslandChangeSpawnerRatesEvent::getSpawnerRates); - } - - public EventResult callIslandChangeWarpCategoryIconEvent(SuperiorPlayer superiorPlayer, Island island, - WarpCategory warpCategory, @Nullable ItemStack icon) { - return callEvent(() -> new IslandChangeWarpCategoryIconEvent(superiorPlayer, island, warpCategory, icon), - "islandchangewarpcategoryiconevent", icon, IslandChangeWarpCategoryIconEvent::getIcon); - } - - public EventResult callIslandChangeWarpCategorySlotEvent(SuperiorPlayer superiorPlayer, Island island, - WarpCategory warpCategory, int slot, int maxSlot) { - return callEvent(() -> new IslandChangeWarpCategorySlotEvent(superiorPlayer, island, warpCategory, slot, maxSlot), - "islandchangewarpcategoryslotevent", slot, IslandChangeWarpCategorySlotEvent::getSlot); - } - - public EventResult callIslandChangeWarpIconEvent(SuperiorPlayer superiorPlayer, Island island, - IslandWarp islandWarp, @Nullable ItemStack icon) { - return callEvent(() -> new IslandChangeWarpIconEvent(superiorPlayer, island, islandWarp, icon), - "islandchangewarpiconevent", icon, IslandChangeWarpIconEvent::getIcon); - } - - public EventResult callIslandChangeWarpLocationEvent(SuperiorPlayer superiorPlayer, Island island, - IslandWarp islandWarp, Location location) { - return callEvent(() -> new IslandChangeWarpLocationEvent(superiorPlayer, island, islandWarp, location), - "islandchangewarplocationevent", location, IslandChangeWarpLocationEvent::getLocation); - } - - public EventResult callIslandChangeWarpsLimitEvent(CommandSender commandSender, Island island, int warpsLimit) { - return callEvent(() -> new IslandChangeWarpsLimitEvent(getSuperiorPlayer(commandSender), island, warpsLimit), - "islandchangewarpslimitevent", warpsLimit, IslandChangeWarpsLimitEvent::getWarpsLimit); - } - - public EventResult callIslandChangeWorthBonusEvent(CommandSender commandSender, Island island, - IslandChangeWorthBonusEvent.Reason reason, - BigDecimal worthBonus) { - return callEvent(() -> new IslandChangeWorthBonusEvent(getSuperiorPlayer(commandSender), island, reason, worthBonus), - "islandchangeworthbonusevent", worthBonus, IslandChangeWorthBonusEvent::getWorthBonus); - } - - public boolean callIslandChangeRolePrivilegeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PlayerRole playerRole) { - return callEvent(() -> new IslandChangeRolePrivilegeEvent(island, superiorPlayer, playerRole), - "islandchangeroleprivilegeevent"); - } - - public EventResult callIslandChatEvent(Island island, SuperiorPlayer superiorPlayer, String message) { - return callEvent(() -> new IslandChatEvent(island, superiorPlayer, message), - "islandchatevent", message, IslandChatEvent::getMessage); - } - - public void callIslandChunkResetEvent(Island island, ChunkPosition chunkPosition) { - if (!plugin.getSettings().getDisabledEvents().contains("islandchunkresetevent")) { - callEvent(new IslandChunkResetEvent(island, chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ())); - } - } - - public boolean callIslandClearGeneratorRatesEvent(CommandSender commandSender, Island island, Dimension dimension) { - return callEvent(() -> new IslandClearGeneratorRatesEvent(getSuperiorPlayer(commandSender), island, dimension), - "islandcleargeneratorratesevent"); - } - - public boolean callIslandClearPlayerPrivilegesEvent(Island island, SuperiorPlayer superiorPlayer, - SuperiorPlayer privilegedPlayer) { - return callEvent(() -> new IslandClearPlayerPrivilegesEvent(island, superiorPlayer, privilegedPlayer), - "islandclearplayerprivilegesevent"); - } - - public boolean callIslandClearRatingsEvent(CommandSender sender, Island island) { - return callEvent(() -> new IslandClearRatingsEvent(getSuperiorPlayer(sender), island), "islandclearratingssevent"); - } - - public boolean callIslandClearRolesPrivilegesEvent(Island island, SuperiorPlayer superiorPlayer) { - return callEvent(() -> new IslandClearRolesPrivilegesEvent(island, superiorPlayer), - "islandclearrolesprivilegesevent"); - } - - public boolean callIslandCloseEvent(Island island, CommandSender commandSender) { - return callIslandCloseEvent(island, getSuperiorPlayer(commandSender)); - } - - public boolean callIslandCloseEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) { - return callEvent(() -> new IslandCloseEvent(superiorPlayer, island), "islandcloseevent"); - } - - public boolean callIslandCloseWarpEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { - return callEvent(() -> new IslandCloseWarpEvent(superiorPlayer, island, islandWarp), "islandclosewarpevent"); - } - - public boolean callIslandCoopPlayerEvent(Island island, SuperiorPlayer player, SuperiorPlayer target) { - return callEvent(() -> new IslandCoopPlayerEvent(island, player, target), "islandcoopplayerevent"); - } - - public EventResult callIslandCreateEvent(SuperiorPlayer superiorPlayer, Island island, String schemName) { - return callEvent(() -> new IslandCreateEvent(superiorPlayer, island, schemName), - "islandcreateevent", true, IslandCreateEvent::canTeleport); - } - - public boolean callIslandCreateWarpCategoryEvent(SuperiorPlayer superiorPlayer, Island island, String categoryName) { - return callEvent(() -> new IslandCreateWarpCategoryEvent(superiorPlayer, island, categoryName), - "islandcreatewarpcategoryevent"); - } - - public boolean callIslandCreateWarpEvent(SuperiorPlayer superiorPlayer, Island island, String warpName, - Location location, @Nullable WarpCategory warpCategory) { - return callIslandCreateWarpEvent(superiorPlayer, island, warpName, location, plugin.getSettings().isPublicWarps(), warpCategory); - } - - public boolean callIslandCreateWarpEvent(SuperiorPlayer superiorPlayer, Island island, String warpName, - Location location, boolean openToPublic, @Nullable WarpCategory warpCategory) { - return callEvent(() -> new IslandCreateWarpEvent(superiorPlayer, island, warpName, location, openToPublic, warpCategory), - "islandcreatewarpevent"); - } - - public boolean callIslandDeleteWarpEvent(CommandSender commandSender, Island island, IslandWarp islandWarp) { - return callIslandDeleteWarpEvent(getSuperiorPlayer(commandSender), island, islandWarp); - } - - public boolean callIslandDeleteWarpEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp) { - return callEvent(() -> new IslandDeleteWarpEvent(superiorPlayer, island, islandWarp), "islanddeletewarpevent"); - } - - public boolean callIslandDisableFlagEvent(CommandSender commandSender, Island island, IslandFlag islandFlag) { - return callIslandDisableFlagEvent(getSuperiorPlayer(commandSender), island, islandFlag); - } - - public boolean callIslandDisableFlagEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, IslandFlag islandFlag) { - return callEvent(() -> new IslandDisableFlagEvent(superiorPlayer, island, islandFlag), "islanddisableflagevent"); - } - - public boolean callIslandDisbandEvent(SuperiorPlayer superiorPlayer, Island island) { - return callEvent(() -> new IslandDisbandEvent(superiorPlayer, island), "islanddisbandevent"); - } - - public boolean callIslandEnableFlagEvent(CommandSender commandSender, Island island, IslandFlag islandFlag) { - return callIslandEnableFlagEvent(getSuperiorPlayer(commandSender), island, islandFlag); - } - - public boolean callIslandEnableFlagEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, IslandFlag islandFlag) { - return callEvent(() -> new IslandEnableFlagEvent(superiorPlayer, island, islandFlag), "islandenableflagevent"); - } - - public boolean callIslandEnterEvent(SuperiorPlayer superiorPlayer, Island island, IslandEnterEvent.EnterCause enterCause) { - if (plugin.getSettings().getDisabledEvents().contains("islandenterevent")) - return true; - - IslandEnterEvent islandEnterEvent = callEvent(new IslandEnterEvent(superiorPlayer, island, enterCause)); - - if (islandEnterEvent.isCancelled() && islandEnterEvent.getCancelTeleport() != null) - superiorPlayer.teleport(islandEnterEvent.getCancelTeleport()); - - return !islandEnterEvent.isCancelled(); - } - - public EventResult callIslandEnterPortalEvent(SuperiorPlayer superiorPlayer, Island island, - PortalType portalType, Dimension destination, - @Nullable Schematic schematic, boolean ignoreInvalidSchematic) { - return callEvent(() -> new IslandEnterPortalEvent(island, superiorPlayer, portalType, destination, schematic, ignoreInvalidSchematic), - "islandenterportalevent", new PortalEventResult(destination, schematic, ignoreInvalidSchematic), PortalEventResult::new); - } - - public boolean callIslandEnterProtectedEvent(SuperiorPlayer superiorPlayer, Island island, IslandEnterEvent.EnterCause enterCause) { - if (plugin.getSettings().getDisabledEvents().contains("islandenterprotectedevent")) - return true; - - IslandEnterProtectedEvent islandEnterProtectedEvent = callEvent(new IslandEnterProtectedEvent(superiorPlayer, island, enterCause)); - - if (islandEnterProtectedEvent.isCancelled() && islandEnterProtectedEvent.getCancelTeleport() != null) - superiorPlayer.teleport(islandEnterProtectedEvent.getCancelTeleport()); - - return !islandEnterProtectedEvent.isCancelled(); - } - - public EventResult callIslandGenerateBlockEvent(Island island, Location location, Key block) { - return callEvent(() -> new IslandGenerateBlockEvent(island, location, block), "islandgenerateblockevent", - new GenerateBlockResult(block, true), GenerateBlockResult::new); - } - - public boolean callIslandInviteEvent(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, Island island) { - return callEvent(() -> new IslandInviteEvent(superiorPlayer, targetPlayer, island), "islandinviteevent"); - } - - @SuppressWarnings("all") - public boolean callIslandJoinEvent(SuperiorPlayer superiorPlayer, Island island, IslandJoinEvent.Cause cause) { - return callEvent(() -> new IslandJoinEvent(superiorPlayer, island, cause), "islandjoinevent"); - } - - public boolean callIslandKickEvent(SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, Island island) { - return callEvent(() -> new IslandKickEvent(superiorPlayer, targetPlayer, island), "islandkickevent"); - } - - public boolean callIslandLeaveEvent(SuperiorPlayer superiorPlayer, Island island, - IslandLeaveEvent.LeaveCause leaveCause, Location location) { - return callEvent(() -> new IslandLeaveEvent(superiorPlayer, island, leaveCause, location), "islandleaveevent"); - } - - public boolean callIslandLeaveProtectedEvent(SuperiorPlayer superiorPlayer, Island island, - IslandLeaveEvent.LeaveCause leaveCause, Location location) { - return callEvent(() -> new IslandLeaveProtectedEvent(superiorPlayer, island, leaveCause, location), - "islandleaveprotectedevent"); - } - - public boolean callIslandLockWorldEvent(Island island, Dimension dimension) { - return callEvent(() -> new IslandLockWorldEvent(island, dimension), "islandlockworldevent"); - } - - public boolean callIslandOpenEvent(Island island, CommandSender commandSender) { - return callIslandOpenEvent(island, getSuperiorPlayer(commandSender)); - } - - public boolean callIslandOpenEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) { - return callEvent(() -> new IslandOpenEvent(superiorPlayer, island), "islandopenevent"); - } - - public boolean callIslandOpenWarpEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { - return callEvent(() -> new IslandOpenWarpEvent(superiorPlayer, island, islandWarp), "islandopenwarpevent"); - } - - public boolean callIslandQuitEvent(SuperiorPlayer superiorPlayer, Island island) { - return callEvent(() -> new IslandQuitEvent(superiorPlayer, island), "islandquitevent"); - } - - public boolean callIslandRateEvent(CommandSender commandSender, SuperiorPlayer ratingPlayer, Island island, Rating rating) { - return callIslandRateEvent(getSuperiorPlayer(commandSender), ratingPlayer, island, rating); - } - - public boolean callIslandRateEvent(@Nullable SuperiorPlayer superiorPlayer, SuperiorPlayer ratingPlayer, Island island, Rating rating) { - return callEvent(() -> new IslandRateEvent(superiorPlayer, ratingPlayer, island, rating), "islandrateevent"); - } - - public boolean callIslandRemoveBlockLimitEvent(CommandSender commandSender, Island island, Key block) { - return callEvent(() -> new IslandRemoveBlockLimitEvent(getSuperiorPlayer(commandSender), island, block), - "islandremoveblocklimitevent"); - } - - public boolean callIslandRemoveEffectEvent(CommandSender commandSender, Island island, PotionEffectType effectType) { - return callEvent(() -> new IslandRemoveEffectEvent(getSuperiorPlayer(commandSender), island, effectType), - "islandremoveeffectevent"); - } - - public boolean callIslandRemoveGeneratorRateEvent(CommandSender commandSender, Island island, Key block, - Dimension dimension) { - return callIslandRemoveGeneratorRateEvent(getSuperiorPlayer(commandSender), island, block, dimension); - } - - public boolean callIslandRemoveGeneratorRateEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key block, - Dimension dimension) { - return callEvent(() -> new IslandRemoveGeneratorRateEvent(superiorPlayer, island, block, dimension), - "islandremovegeneratorrateevent"); - } - - public boolean callIslandRemoveRatingEvent(CommandSender commandSender, SuperiorPlayer ratingPlayer, Island island) { - return callIslandRemoveRatingEvent(getSuperiorPlayer(commandSender), ratingPlayer, island); - } - - public boolean callIslandRemoveRatingEvent(@Nullable SuperiorPlayer superiorPlayer, SuperiorPlayer ratingPlayer, Island island) { - return callEvent(() -> new IslandRemoveRatingEvent(superiorPlayer, ratingPlayer, island), - "islandremoveratingevent"); - } - - public boolean callIslandRemoveRoleLimitEvent(CommandSender commandSender, Island island, PlayerRole playerRole) { - return callEvent(() -> new IslandRemoveRoleLimitEvent(getSuperiorPlayer(commandSender), island, playerRole), - "islandremoverolelimitevent"); - } - - public boolean callIslandRemoveVisitorHomeEvent(SuperiorPlayer superiorPlayer, Island island) { - return callEvent(() -> new IslandRemoveVisitorHomeEvent(superiorPlayer, island), "islandremovevisitorhomeevent"); - } - - public EventResult callIslandRenameEvent(Island island, String islandName) { - return callIslandRenameEvent(island, null, islandName); - } - - public EventResult callIslandRenameEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, String islandName) { - return callEvent(() -> new IslandRenameEvent(island, superiorPlayer, islandName), - "islandrenameevent", islandName, IslandRenameEvent::getIslandName); - } - - public EventResult callIslandRenameWarpCategoryEvent(Island island, SuperiorPlayer superiorPlayer, - WarpCategory warpCategory, String categoryName) { - return callEvent(() -> new IslandRenameWarpCategoryEvent(superiorPlayer, island, warpCategory, categoryName), - "islandrenamewarpcategoryevent", categoryName, IslandRenameWarpCategoryEvent::getCategoryName); - } - - public EventResult callIslandRenameWarpEvent(Island island, SuperiorPlayer superiorPlayer, - IslandWarp islandWarp, String warpName) { - return callEvent(() -> new IslandRenameWarpEvent(superiorPlayer, island, islandWarp, warpName), - "islandrenamewarpevent", warpName, IslandRenameWarpEvent::getWarpName); - } - - public void callIslandRestrictMoveEvent(SuperiorPlayer superiorPlayer, IslandRestrictMoveEvent.RestrictReason restrictReason) { - if (!plugin.getSettings().getDisabledEvents().contains("islandrestrictmoveevent")) { - callEvent(new IslandRestrictMoveEvent(superiorPlayer, restrictReason)); - } - } - - public void callIslandSchematicPasteEvent(Island island, String name, Location location) { - if (!plugin.getSettings().getDisabledEvents().contains("islandschematicpasteevent")) { - callEvent(new IslandSchematicPasteEvent(island, name, location)); - } - } - - public EventResult callIslandSetHomeEvent(Island island, Location islandHome, IslandSetHomeEvent.Reason reason, - @Nullable SuperiorPlayer superiorPlayer) { - return callEvent(() -> new IslandSetHomeEvent(island, islandHome, reason, superiorPlayer), - "islandsethomeevent", islandHome, IslandSetHomeEvent::getIslandHome); - } - - public EventResult callIslandSetVisitorHomeEvent(SuperiorPlayer superiorPlayer, Island island, - Location islandVisitorHome) { - return callEvent(() -> new IslandSetVisitorHomeEvent(superiorPlayer, island, islandVisitorHome), - "islandsetvisitorhomeevent", islandVisitorHome, IslandSetVisitorHomeEvent::getIslandVisitorHome); - } - - public boolean callIslandTransferEvent(Island island, SuperiorPlayer previousOwner, SuperiorPlayer superiorPlayer) { - return callEvent(() -> new IslandTransferEvent(island, previousOwner, superiorPlayer), "islandtransferevent"); - } - - public boolean callIslandUnbanEvent(SuperiorPlayer superiorPlayer, SuperiorPlayer unbannedPlayer, Island island) { - return callEvent(() -> new IslandUnbanEvent(superiorPlayer, unbannedPlayer, island), "islandunbanevent"); - } - - public boolean callIslandUncoopPlayerEvent(Island island, SuperiorPlayer player, SuperiorPlayer target, - IslandUncoopPlayerEvent.UncoopReason uncoopReason) { - return callEvent(() -> new IslandUncoopPlayerEvent(island, player, target, uncoopReason), "islanduncoopplayerevent"); - } - - public boolean callIslandUnlockWorldEvent(Island island, Dimension dimension) { - return callEvent(() -> new IslandUnlockWorldEvent(island, dimension), "islandunlockworldevent"); - } - - public EventResult callIslandUpgradeEvent(CommandSender commandSender, Island island, - Upgrade upgrade, UpgradeLevel nextUpdate, - IslandUpgradeEvent.Cause cause) { - return callIslandUpgradeEvent(getSuperiorPlayer(commandSender), island, upgrade, nextUpdate, - Collections.emptyList(), cause, null); - } - - public EventResult callIslandUpgradeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, - Upgrade upgrade, UpgradeLevel currentLevel, - UpgradeLevel nextLevel, IslandUpgradeEvent.Cause cause) { - return callIslandUpgradeEvent(superiorPlayer, island, upgrade, nextLevel, currentLevel.getCommands(), cause, currentLevel.getCost()); - } - - public EventResult callIslandUpgradeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, - Upgrade upgrade, UpgradeLevel nextLevel, - List commands, IslandUpgradeEvent.Cause cause, - @Nullable UpgradeCost upgradeCost) { - return callEvent(() -> new IslandUpgradeEvent(superiorPlayer, island, upgrade, nextLevel, commands, cause, upgradeCost), - "islandupgradeevent", new UpgradeResult(commands, upgradeCost), UpgradeResult::new); - } - - public boolean callIslandWorldResetEvent(CommandSender sender, Island island, Dimension dimension) { - return callEvent(() -> new IslandWorldResetEvent(getSuperiorPlayer(sender), island, dimension), - "islandworldresetevent"); - } - - public void callIslandWorthCalculatedEvent(Island island, SuperiorPlayer asker, BigDecimal islandLevel, BigDecimal islandWorth) { - if (!plugin.getSettings().getDisabledEvents().contains("islandworthcalculatedevent")) { - callEvent(new IslandWorthCalculatedEvent(island, asker, islandLevel, islandWorth)); - } - } - - public void callIslandWorthUpdateEvent(Island island, BigDecimal oldWorth, BigDecimal oldLevel, BigDecimal newWorth, BigDecimal newLevel) { - if (!plugin.getSettings().getDisabledEvents().contains("islandworthupdateevent")) { - callEvent(new IslandWorthUpdateEvent(island, oldWorth, oldLevel, newWorth, newLevel)); - } - } - - public EventResult callMissionCompleteEvent(SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder, - Mission mission, List itemRewards, - List commandRewards) { - return callEvent(() -> new MissionCompleteEvent(superiorPlayer, missionsHolder, mission, itemRewards, commandRewards), - "missioncompleteevent", new MissionRewards(itemRewards, commandRewards), MissionRewards::of); - } - - public boolean callMissionResetEvent(CommandSender commandSender, IMissionsHolder missionsHolder, Mission mission) { - return callMissionResetEvent(getSuperiorPlayer(commandSender), missionsHolder, mission); - } - - public boolean callMissionResetEvent(@Nullable SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder, Mission mission) { - return callEvent(() -> new MissionResetEvent(superiorPlayer, missionsHolder, mission), "missionresetevent"); - } - - public boolean callPlayerChangeBorderColorEvent(SuperiorPlayer superiorPlayer, BorderColor borderColor) { - return callEvent(() -> new PlayerChangeBorderColorEvent(superiorPlayer, borderColor), - "playerchangebordercolorevent"); - } - - public boolean callPlayerChangeLanguageEvent(SuperiorPlayer superiorPlayer, Locale language) { - return callEvent(() -> new PlayerChangeLanguageEvent(superiorPlayer, language), "playerchangelanguageevent"); - } - - public void callPlayerChangeNameEvent(SuperiorPlayer superiorPlayer, String newName) { - if (!plugin.getSettings().getDisabledEvents().contains("playerchangenameevent")) { - callEvent(new PlayerChangeNameEvent(superiorPlayer, newName)); - } - } - - public boolean callPlayerChangeRoleEvent(SuperiorPlayer superiorPlayer, PlayerRole newPlayer) { - return callEvent(() -> new PlayerChangeRoleEvent(superiorPlayer, newPlayer), "playerchangeroleevent"); - } - - public EventResult> callPlayerCloseMenuEvent(SuperiorPlayer superiorPlayer, MenuView menuView, - @Nullable MenuView newMenuView) { - return callEvent(() -> new PlayerCloseMenuEvent(superiorPlayer, menuView, newMenuView), - "playerclosemenuevent", newMenuView, PlayerCloseMenuEvent::getNewMenuView); - } - - public boolean callPlayerOpenMenuEvent(SuperiorPlayer superiorPlayer, MenuView menuView) { - return callEvent(() -> new PlayerOpenMenuEvent(superiorPlayer, menuView), "playeropenmenuevent"); - } - - public void callPlayerReplaceEvent(SuperiorPlayer oldPlayer, SuperiorPlayer newPlayer) { - if (!plugin.getSettings().getDisabledEvents().contains("playerreplaceevent")) { - callEvent(new PlayerReplaceEvent(oldPlayer, newPlayer)); - } - } - - public boolean callPlayerToggleBlocksStackerEvent(SuperiorPlayer superiorPlayer) { - return callEvent(() -> new PlayerToggleBlocksStackerEvent(superiorPlayer), "playertoggleblocksstackerevent"); - } - - public boolean callPlayerToggleBorderEvent(SuperiorPlayer superiorPlayer) { - return callEvent(() -> new PlayerToggleBorderEvent(superiorPlayer), "playertoggleborderevent"); - } - - public boolean callPlayerToggleBypassEvent(SuperiorPlayer superiorPlayer) { - return callEvent(() -> new PlayerToggleBypassEvent(superiorPlayer), "playertogglebypassevent"); - } - - public boolean callPlayerToggleFlyEvent(SuperiorPlayer superiorPlayer) { - return callEvent(() -> new PlayerToggleFlyEvent(superiorPlayer), "playertoggleflyevent"); - } - - public boolean callPlayerTogglePanelEvent(SuperiorPlayer superiorPlayer) { - return callEvent(() -> new PlayerTogglePanelEvent(superiorPlayer), "playertogglepanelevent"); - } - - public boolean callPlayerToggleSpyEvent(SuperiorPlayer superiorPlayer) { - return callEvent(() -> new PlayerToggleSpyEvent(superiorPlayer), "playertogglespyevent"); - } - - public boolean callPlayerToggleTeamChatEvent(SuperiorPlayer superiorPlayer) { - return callEvent(() -> new PlayerToggleTeamChatEvent(superiorPlayer), "playertoggleteamchatevent"); - } - - public void callPluginInitializedEvent(SuperiorSkyblock plugin) { - callEvent(new PluginInitializedEvent(plugin)); - } - - public PluginInitializeResult callPluginInitializeEvent(SuperiorSkyblock plugin) { - return new PluginInitializeResult(callEvent(new PluginInitializeEvent(plugin))); - } - - public boolean callPluginLoadDataEvent(SuperiorSkyblock plugin) { - return !callEvent(new PluginLoadDataEvent(plugin)).isCancelled(); - } - - public void callPostIslandCreateEvent(SuperiorPlayer superiorPlayer, Island island) { - if (!plugin.getSettings().getDisabledEvents().contains("postislandcreateevent")) { - callEvent(new PostIslandCreateEvent(superiorPlayer, island)); - } - } - - public boolean callPreIslandCreateEvent(SuperiorPlayer superiorPlayer, String islandName) { - return callEvent(() -> new PreIslandCreateEvent(superiorPlayer, islandName), "preislandcreateevent"); - } - - public EventResult callSendMessageEvent(CommandSender receiver, String messageType, IMessageComponent messageComponent, Object... args) { - return callEvent(() -> new SendMessageEvent(receiver, messageType, messageComponent, args), - "sendmessageevent", messageComponent, SendMessageEvent::getMessageComponent); - } - - private EventResult callEvent(Supplier eventSupplier, String eventName, - @Nullable T def, Function getResultFunction) { - if (plugin.getSettings().getDisabledEvents().contains(eventName)) - return EventResult.of(false, def); - - Log.debug(Debug.FIRE_EVENT, eventName); - - E event = eventSupplier.get(); - - Bukkit.getPluginManager().callEvent(event); - - boolean cancelled = event.isCancelled(); - T result = getResultFunction.apply(event); - - Log.debugResult(Debug.FIRE_EVENT, "Cancelled:", cancelled); - Log.debugResult(Debug.FIRE_EVENT, "Result:", result); - - return EventResult.of(cancelled, result); - } - - private boolean callEvent(Supplier eventSupplier, String eventName) { - if (plugin.getSettings().getDisabledEvents().contains(eventName)) - return true; - - Log.debug(Debug.FIRE_EVENT, eventName); - - E event = eventSupplier.get(); - - Bukkit.getPluginManager().callEvent(event); - - Log.debugResult(Debug.FIRE_EVENT, "Cancelled:", event.isCancelled()); - - return !event.isCancelled(); - } - - private static T callEvent(T event) { - Log.debug(Debug.FIRE_EVENT, event.getEventName()); - Bukkit.getPluginManager().callEvent(event); - return event; - } - - @Nullable - private SuperiorPlayer getSuperiorPlayer(CommandSender commandSender) { - return commandSender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(commandSender) : null; - } - - public static class MissionRewards { - - private static final MissionRewards EMPTY = new MissionRewards(Collections.emptyList(), Collections.emptyList()); - - private final List itemRewards; - private final List commandRewards; - - private static MissionRewards of(MissionCompleteEvent missionCompleteEvent) { - return missionCompleteEvent.getItemRewards().isEmpty() && missionCompleteEvent.getCommandRewards().isEmpty() - ? EMPTY : new MissionRewards(missionCompleteEvent.getItemRewards(), missionCompleteEvent.getCommandRewards()); - } - - private MissionRewards(List itemRewards, List commandRewards) { - this.itemRewards = itemRewards; - this.commandRewards = commandRewards; - } - - public List getItemRewards() { - return itemRewards; - } - - public List getCommandRewards() { - return commandRewards; - } - - } - - public static class UpgradeResult { - - private final List commands; - private final UpgradeCost upgradeCost; - - public UpgradeResult(IslandUpgradeEvent islandUpgradeEvent) { - this(islandUpgradeEvent.getCommands(), islandUpgradeEvent.getUpgradeCost()); - } - - public UpgradeResult(List commands, UpgradeCost upgradeCost) { - this.commands = commands; - this.upgradeCost = upgradeCost; - } - - public List getCommands() { - return commands; - } - - public UpgradeCost getUpgradeCost() { - return upgradeCost; - } - - } - - public static class GenerateBlockResult { - - private final Key block; - private final boolean placeBlock; - - public GenerateBlockResult(IslandGenerateBlockEvent event) { - this(event.getBlock(), event.isPlaceBlock()); - } - - public GenerateBlockResult(Key block, boolean placeBlock) { - this.block = block; - this.placeBlock = placeBlock; - } - - public Key getBlock() { - return block; - } - - public boolean isPlaceBlock() { - return placeBlock; - } - - } - - public static class PluginInitializeResult { - - @Nullable - private final IslandsContainer islandsContainer; - @Nullable - private final PlayersContainer playersContainer; - - public PluginInitializeResult(PluginInitializeEvent event) { - this(event.getIslandsContainer(), event.getPlayersContainer()); - } - - public PluginInitializeResult(@Nullable IslandsContainer islandsContainer, @Nullable PlayersContainer playersContainer) { - this.islandsContainer = islandsContainer; - this.playersContainer = playersContainer; - } - - @Nullable - public IslandsContainer getIslandsContainer() { - return islandsContainer; - } - - @Nullable - public PlayersContainer getPlayersContainer() { - return playersContainer; - } - - } - - public static class PortalEventResult { - - private final Dimension destination; - @Nullable - private final Schematic schematic; - private final boolean isIgnoreInvalidSchematic; - - public PortalEventResult(IslandEnterPortalEvent event) { - this(event.getDestinationDimension(), event.getSchematic(), event.isIgnoreInvalidSchematic()); - } - - public PortalEventResult(Dimension destination, @Nullable Schematic schematic, boolean isIgnoreInvalidSchematic) { - this.destination = destination; - this.schematic = schematic; - this.isIgnoreInvalidSchematic = isIgnoreInvalidSchematic; - } - - public Dimension getDestination() { - return destination; - } - - @Nullable - public Schematic getSchematic() { - return schematic; - } - - public boolean isIgnoreInvalidSchematic() { - return isIgnoreInvalidSchematic; - } - - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java new file mode 100644 index 0000000000..1199110158 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java @@ -0,0 +1,88 @@ +package com.bgsoftware.superiorskyblock.core.events; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; +import com.bgsoftware.superiorskyblock.core.logging.Log; + +import java.util.Collection; +import java.util.Collections; +import java.util.EnumMap; +import java.util.IdentityHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class EventsDispatcher, P extends Enum

, E extends IEvent> { + + protected final EnumerateMap>> callbacks; + + protected final SuperiorSkyblockPlugin plugin; + protected final Class

priorityClass; + + protected EventsDispatcher(SuperiorSkyblockPlugin plugin, Class

priorityClass, Collection allTypes) { + this.plugin = plugin; + this.priorityClass = priorityClass; + this.callbacks = new EnumerateMap<>(allTypes); + } + + public void registerCallback(L listener, T type, P priority, boolean ignoreCancelled, EventCallback callback) { + callbacks.computeIfAbsent(type, t -> new EnumMap<>(this.priorityClass)) + .computeIfAbsent(priority, p -> new LinkedList<>()) + .add(new RegisteredListener(listener, ignoreCancelled, callback)); + } + + public void onGameEvent(E event, P priority) { + if (event.isCancelled()) + return; + + EnumMap> gameEventCallbacks = callbacks.get(event.getType()); + if (gameEventCallbacks != null) { + List priorityCallbacks = gameEventCallbacks.get(priority); + if (priorityCallbacks != null) { + for (RegisteredListener listener : priorityCallbacks) { + if (listener.ignoreCancelled && event.isCancelled()) { + continue; + } + + try { + listener.callback.execute(event); + } catch (Throwable error) { + Log.error(error, "Could not pass listener: " + listener.listener); + } + } + } + } + } + + public Map> getCallbacks(T eventType) { + Map> priorityListeners = callbacks.get(eventType); + + if (priorityListeners == null || priorityListeners.isEmpty()) + return Collections.emptyMap(); + + Map> priorityCallbacks = new EnumMap<>(this.priorityClass); + + priorityListeners.forEach((eventPriority, listeners) -> { + List callbacks = new LinkedList<>(); + listeners.forEach(listener -> callbacks.add(listener.callback)); + priorityCallbacks.put(eventPriority, callbacks); + }); + + return priorityCallbacks; + } + + protected class RegisteredListener { + + public final L listener; + public final boolean ignoreCancelled; + public final EventCallback callback; + + RegisteredListener(L listener, boolean ignoreCancelled, EventCallback callback) { + this.listener = listener; + this.ignoreCancelled = ignoreCancelled; + this.callback = callback; + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/IEvent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/IEvent.java new file mode 100644 index 0000000000..7786199091 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/IEvent.java @@ -0,0 +1,9 @@ +package com.bgsoftware.superiorskyblock.core.events; + +public interface IEvent { + + T getType(); + + boolean isCancelled(); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/IEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/IEventArgs.java new file mode 100644 index 0000000000..eea15ee08b --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/IEventArgs.java @@ -0,0 +1,4 @@ +package com.bgsoftware.superiorskyblock.core.events.args; + +public interface IEventArgs { +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java new file mode 100644 index 0000000000..51024cb61c --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java @@ -0,0 +1,735 @@ +package com.bgsoftware.superiorskyblock.core.events.args; + +import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; +import com.bgsoftware.superiorskyblock.api.enums.BorderColor; +import com.bgsoftware.superiorskyblock.api.enums.Rating; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandFlag; +import com.bgsoftware.superiorskyblock.api.island.PlayerRole; +import com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer; +import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; +import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; +import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; +import com.bgsoftware.superiorskyblock.api.missions.Mission; +import com.bgsoftware.superiorskyblock.api.player.container.PlayersContainer; +import com.bgsoftware.superiorskyblock.api.schematic.Schematic; +import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; +import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; +import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; +import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import org.bukkit.Location; +import org.bukkit.PortalType; +import org.bukkit.block.Biome; +import org.bukkit.block.Block; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffectType; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Locale; + +public class PluginEventArgs { + + private PluginEventArgs() { + + } + + public static class Empty extends PluginEventArgs { + + public static final Empty INSTANCE = new Empty(); + + private Empty() { + + } + + } + + public static class AttemptPlayerSendMessage extends PluginEventArgs { + + public SuperiorPlayer receiver; + public String messageType; + public Object[] args; + + } + + public static class BlockStack extends StackedBlockChangeCountArgs { + + } + + public static class BlockUnstack extends StackedBlockChangeCountArgs { + + } + + public static class IslandBan extends IslandDoActionArgs { + + public SuperiorPlayer targetPlayer; + + } + + public static class IslandBankDeposit extends IslandBankTransactionArgs { + + } + + public static class IslandBankWithdraw extends IslandBankTransactionArgs { + + } + + public static class IslandBiomeChange extends IslandDoActionArgs { + + public Biome biome; + + } + + public static class IslandChangeBankLimit extends IslandDoActionArgs { + + public BigDecimal bankLimit; + + } + + public static class IslandChangeBlockLimit extends IslandDoActionArgs { + + public Key block; + public int blockLimit; + + } + + public static class IslandChangeBorderSize extends IslandDoActionArgs { + + public int borderSize; + + } + + public static class IslandChangeCoopLimit extends IslandDoActionArgs { + + public int coopLimit; + + } + + public static class IslandChangeCropGrowth extends IslandDoActionArgs { + + public double cropGrowth; + + } + + public static class IslandChangeDescription extends IslandDoActionArgs { + + public String description; + + } + + public static class IslandChangeDiscord extends IslandDoActionArgs { + + public String discord; + + } + + public static class IslandChangeEffectLevel extends IslandDoActionArgs { + + public PotionEffectType effectType; + public int effectLevel; + + } + + public static class IslandChangeEntityLimit extends IslandDoActionArgs { + + public Key entity; + public int entityLimit; + + } + + public static class IslandChangeGeneratorRate extends IslandDoActionArgs { + + public Key block; + public Dimension dimension; + public int generatorRate; + + } + + public static class IslandChangeLevelBonus extends IslandDoActionArgs { + + public IslandChangeLevelBonusEvent.Reason reason; + public BigDecimal levelBonus; + + } + + public static class IslandChangeMembersLimit extends IslandDoActionArgs { + + public int membersLimit; + + } + + public static class IslandChangeMobDrops extends IslandDoActionArgs { + + public double mobDrops; + + } + + public static class IslandChangePaypal extends IslandDoActionArgs { + + public String paypal; + + } + + public static class IslandChangePlayerPrivilege extends IslandDoActionArgs { + + public SuperiorPlayer privilegedPlayer; + public boolean privilegeEnabled; + + } + + public static class IslandChangeRoleLimit extends IslandDoActionArgs { + + public PlayerRole playerRole; + public int roleLimit; + + } + + public static class IslandChangeSpawnerRates extends IslandDoActionArgs { + + public double spawnerRates; + + } + + public static class IslandChangeWarpCategoryIcon extends WarpCategoryDoActionArgs { + + public ItemStack icon; + + } + + public static class IslandChangeWarpCategorySlot extends WarpCategoryDoActionArgs { + + public int slot; + public int maxSlot; + + } + + public static class IslandChangeWarpIcon extends IslandWarpDoActionArgs { + + public ItemStack icon; + + } + + public static class IslandChangeWarpLocation extends IslandWarpDoActionArgs { + + public Location location; + + } + + public static class IslandChangeWarpsLimit extends IslandDoActionArgs { + + public int warpsLimit; + + } + + public static class IslandChangeWorthBonus extends IslandDoActionArgs { + + public IslandChangeWorthBonusEvent.Reason reason; + public BigDecimal worthBonus; + + } + + public static class IslandChangeRolePrivilege extends IslandDoActionArgs { + + public PlayerRole playerRole; + + } + + public static class IslandChat extends IslandDoActionArgs { + + public String message; + + } + + public static class IslandChunkReset extends PluginEventArgs { + + public Island island; + public ChunkPosition chunkPosition; + + } + + public static class IslandClearGeneratorRates extends IslandDoActionArgs { + + public Dimension dimension; + + } + + public static class IslandClearPlayerPrivileges extends IslandDoActionArgs { + + public SuperiorPlayer privilegedPlayer; + + } + + public static class IslandClearRatings extends IslandDoActionArgs { + + } + + public static class IslandClearRolesPrivileges extends IslandDoActionArgs { + + } + + public static class IslandClose extends IslandDoActionArgs { + + } + + public static class IslandCloseWarp extends IslandWarpDoActionArgs { + + } + + public static class IslandCoopPlayer extends IslandDoActionArgs { + + public SuperiorPlayer targetPlayer; + + } + + public static class IslandCreate extends IslandDoActionArgs { + + public String schematicName; + public boolean canTeleport = true; + + } + + public static class IslandCreateWarpCategory extends IslandDoActionArgs { + + public String categoryName; + + } + + public static class IslandCreateWarp extends IslandDoActionArgs { + + public String warpName; + public boolean openToPublic; + public Location location; + public WarpCategory warpCategory; + + } + + public static class IslandDeleteWarp extends IslandWarpDoActionArgs { + + } + + public static class IslandDisableFlag extends IslandDoActionArgs { + + public IslandFlag islandFlag; + + } + + public static class IslandDisband extends IslandDoActionArgs { + + } + + public static class IslandEnableFlag extends IslandDoActionArgs { + + public IslandFlag islandFlag; + + } + + public static class IslandEnter extends IslandDoActionArgs { + + public IslandEnterEvent.EnterCause enterCause; + + } + + public static class IslandEnterPortal extends IslandDoActionArgs { + + public PortalType portalType; + public Dimension destination; + public Schematic schematic; + public boolean ignoreInvalidSchematic; + + } + + public static class IslandEnterProtected extends IslandEnter { + + } + + public static class IslandGenerateBlock extends PluginEventArgs { + + public Island island; + public Location location; + public Key block; + public boolean placeBlock = true; + + } + + public static class IslandInvite extends IslandDoActionArgs { + + public SuperiorPlayer targetPlayer; + + } + + public static class IslandJoin extends IslandDoActionArgs { + + public IslandJoinEvent.Cause joinCause; + + } + + public static class IslandKick extends IslandDoActionArgs { + + public SuperiorPlayer targetPlayer; + + } + + public static class IslandLeave extends IslandDoActionArgs { + + public IslandLeaveEvent.LeaveCause leaveCause; + public Location location; + + } + + public static class IslandLeaveProtected extends IslandLeave { + + } + + public static class IslandLockWorld extends IslandDoActionArgs { + + public Dimension dimension; + + } + + public static class IslandOpen extends IslandDoActionArgs { + + } + + public static class IslandOpenWarp extends IslandWarpDoActionArgs { + + } + + public static class IslandQuit extends IslandDoActionArgs { + + } + + public static class IslandRate extends IslandDoActionArgs { + + public SuperiorPlayer ratingPlayer; + public Rating rating; + + } + + public static class IslandRemoveBlockLimit extends IslandDoActionArgs { + + public Key block; + + } + + public static class IslandRemoveEffect extends IslandDoActionArgs { + + public PotionEffectType effectType; + + } + + public static class IslandRemoveGeneratorRate extends IslandDoActionArgs { + + public Key block; + public Dimension dimension; + + } + + public static class IslandRemoveRating extends IslandDoActionArgs { + + public SuperiorPlayer ratingPlayer; + + } + + public static class IslandRemoveRoleLimit extends IslandDoActionArgs { + + public PlayerRole playerRole; + + } + + public static class IslandRemoveVisitorHome extends IslandDoActionArgs { + + } + + public static class IslandRename extends IslandDoActionArgs { + + public String islandName; + + } + + public static class IslandRenameWarpCategory extends WarpCategoryDoActionArgs { + + public String categoryName; + + } + + public static class IslandRenameWarp extends IslandWarpDoActionArgs { + + public String warpName; + + } + + public static class IslandRestrictMove extends IslandDoActionArgs { + + public IslandRestrictMoveEvent.RestrictReason restrictReason; + + } + + public static class IslandSchematicPaste extends IslandDoActionArgs { + + public String schematicName; + public Location location; + + } + + public static class IslandSetHome extends IslandDoActionArgs { + + public Location islandHome; + public IslandSetHomeEvent.Reason reason; + + } + + public static class IslandSetVisitorHome extends IslandDoActionArgs { + + public Location islandVisitorHome; + + } + + public static class IslandTransfer extends IslandDoActionArgs { + + public SuperiorPlayer previousOwner; + + } + + public static class IslandUnban extends IslandDoActionArgs { + + public SuperiorPlayer unbannedPlayer; + + } + + public static class IslandUncoopPlayer extends IslandDoActionArgs { + + public SuperiorPlayer targetPlayer; + public IslandUncoopPlayerEvent.UncoopReason uncoopReason; + + } + + public static class IslandUnlockWorld extends IslandDoActionArgs { + + public Dimension dimension; + + } + + public static class IslandUpgrade extends IslandDoActionArgs { + + public Upgrade upgrade; + public UpgradeLevel nextLevel; + public List commands; + public IslandUpgradeEvent.Cause upgradeCause; + public UpgradeCost upgradeCost; + + } + + public static class IslandWorldReset extends IslandDoActionArgs { + + public Dimension dimension; + + } + + public static class IslandWorthCalculated extends IslandDoActionArgs { + + public BigDecimal islandLevel; + public BigDecimal islandWorth; + + } + + public static class IslandWorthUpdate extends PluginEventArgs { + + public Island island; + public BigDecimal oldWorth; + public BigDecimal oldLevel; + public BigDecimal newWorth; + public BigDecimal newLevel; + + } + + public static class MissionComplete extends MissionArgs { + + public List itemRewards; + public List commandRewards; + + } + + public static class MissionReset extends MissionArgs { + + } + + public static class PlayerChangeBorderColor extends PlayerDoActionArgs { + + public BorderColor borderColor; + + } + + public static class PlayerChangeLanguage extends PlayerDoActionArgs { + + public Locale language; + + } + + public static class PlayerChangeName extends PlayerDoActionArgs { + + public String newName; + + } + + public static class PlayerChangeRole extends PlayerDoActionArgs { + + public PlayerRole newRole; + + } + + public static class PlayerCloseMenu extends PlayerDoActionArgs { + + public MenuView menuView; + public MenuView newMenuView; + + } + + public static class PlayerOpenMenu extends PlayerDoActionArgs { + + public MenuView menuView; + + } + + public static class PlayerReplace extends PlayerDoActionArgs { + + public SuperiorPlayer newPlayer; + + } + + public static class PlayerToggleBlocksStacker extends PlayerDoActionArgs { + + } + + public static class PlayerToggleBorder extends PlayerDoActionArgs { + + } + + public static class PlayerToggleBypass extends PlayerDoActionArgs { + + } + + public static class PlayerToggleFly extends PlayerDoActionArgs { + + } + + public static class PlayerTogglePanel extends PlayerDoActionArgs { + + } + + public static class PlayerToggleSpy extends PlayerDoActionArgs { + + } + + public static class PlayerToggleTeamChat extends PlayerDoActionArgs { + + } + + public static class PluginInitialized extends PluginDoActionArgs { + + } + + public static class PluginInitialize extends PluginDoActionArgs { + + public IslandsContainer islandsContainer; + public PlayersContainer playersContainer; + + } + + public static class PluginLoadData extends PluginDoActionArgs { + + } + + public static class PostIslandCreate extends IslandDoActionArgs { + + } + + public static class PreIslandCreate extends PluginEventArgs { + + public SuperiorPlayer superiorPlayer; + public String islandName; + + } + + public static class SendMessage extends PluginEventArgs { + + public CommandSender receiver; + public String messageType; + public IMessageComponent messageComponent; + public Object[] args; + + } + + private static class StackedBlockChangeCountArgs extends PluginEventArgs { + + public Block block; + public Player player; + public int originalCount; + public int newCount; + + } + + private static class IslandBankTransactionArgs extends PluginEventArgs { + + public Island island; + public SuperiorPlayer superiorPlayer; + public BigDecimal amount; + public String failureReason; + + } + + private static class IslandDoActionArgs extends PluginEventArgs { + + public Island island; + public SuperiorPlayer superiorPlayer; + + } + + private static class WarpCategoryDoActionArgs extends IslandDoActionArgs { + + public WarpCategory warpCategory; + + } + + private static class IslandWarpDoActionArgs extends IslandDoActionArgs { + + public IslandWarp islandWarp; + + } + + private static class MissionArgs extends PluginEventArgs { + + public SuperiorPlayer superiorPlayer; + public IMissionsHolder missionsHolder; + public Mission mission; + + } + + private static class PlayerDoActionArgs extends PluginEventArgs { + + public SuperiorPlayer superiorPlayer; + + } + + private static class PluginDoActionArgs extends PluginEventArgs { + + public SuperiorSkyblock plugin; + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEvent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEvent.java new file mode 100644 index 0000000000..a76f5eae79 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEvent.java @@ -0,0 +1,36 @@ +package com.bgsoftware.superiorskyblock.core.events.plugin; + +import com.bgsoftware.superiorskyblock.core.events.IEvent; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; + +public class PluginEvent implements IEvent> { + + private final PluginEventType type; + private final Args args; + + private boolean cancelled = false; + + public PluginEvent(PluginEventType type, Args args) { + this.type = type; + this.args = args; + } + + @Override + public PluginEventType getType() { + return type; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + public Args getArgs() { + return args; + } + + public void setCancelled() { + this.cancelled = true; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventPriority.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventPriority.java new file mode 100644 index 0000000000..9fad018b96 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventPriority.java @@ -0,0 +1,7 @@ +package com.bgsoftware.superiorskyblock.core.events.plugin; + +public enum PluginEventPriority { + + NORMAL + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java new file mode 100644 index 0000000000..c253798897 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java @@ -0,0 +1,1189 @@ +package com.bgsoftware.superiorskyblock.core.events.plugin; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.events.AttemptPlayerSendMessageEvent; +import com.bgsoftware.superiorskyblock.api.events.BlockStackEvent; +import com.bgsoftware.superiorskyblock.api.events.BlockUnstackEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandBanEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandBankDepositEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandBankWithdrawEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandBiomeChangeEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeBankLimitEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeBlockLimitEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeBorderSizeEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeCoopLimitEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeCropGrowthEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeDescriptionEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeDiscordEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeEffectLevelEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeEntityLimitEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeGeneratorRateEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeMembersLimitEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeMobDropsEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangePaypalEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangePlayerPrivilegeEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeRoleLimitEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeRolePrivilegeEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeSpawnerRatesEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpCategoryIconEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpCategorySlotEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpIconEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpLocationEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeWarpsLimitEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChatEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChunkResetEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandClearGeneratorRatesEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandClearPlayerPrivilegesEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandClearRatingsEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandClearRolesPrivilegesEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandCloseEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandCloseWarpEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandCoopPlayerEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandCreateEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandCreateWarpCategoryEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandCreateWarpEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandDeleteWarpEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandDisableFlagEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandDisbandEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandEnableFlagEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandEnterPortalEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandEnterProtectedEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandInviteEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandKickEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandLeaveProtectedEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandLockWorldEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandOpenEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandOpenWarpEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandQuitEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRateEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRemoveBlockLimitEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRemoveEffectEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRemoveGeneratorRateEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRemoveRatingEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRemoveRoleLimitEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRemoveVisitorHomeEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRenameEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRenameWarpCategoryEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRenameWarpEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandSchematicPasteEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandSetVisitorHomeEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandTransferEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandUnbanEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandUnlockWorldEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandWorldResetEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandWorthCalculatedEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandWorthUpdateEvent; +import com.bgsoftware.superiorskyblock.api.events.MissionCompleteEvent; +import com.bgsoftware.superiorskyblock.api.events.MissionResetEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerChangeBorderColorEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerChangeLanguageEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerChangeNameEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerChangeRoleEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerCloseMenuEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerOpenMenuEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerReplaceEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerToggleBlocksStackerEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerToggleBorderEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerToggleBypassEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerToggleFlyEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerTogglePanelEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerToggleSpyEvent; +import com.bgsoftware.superiorskyblock.api.events.PlayerToggleTeamChatEvent; +import com.bgsoftware.superiorskyblock.api.events.PluginInitializeEvent; +import com.bgsoftware.superiorskyblock.api.events.PluginInitializedEvent; +import com.bgsoftware.superiorskyblock.api.events.PluginLoadDataEvent; +import com.bgsoftware.superiorskyblock.api.events.PostIslandCreateEvent; +import com.bgsoftware.superiorskyblock.api.events.PreIslandCreateEvent; +import com.bgsoftware.superiorskyblock.api.events.SendMessageEvent; +import com.bgsoftware.superiorskyblock.core.events.EventType; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; + +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.AttemptPlayerSendMessage; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.BlockStack; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.BlockUnstack; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.Empty; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBan; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBankDeposit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBankWithdraw; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBiomeChange; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBankLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBlockLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBorderSize; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeCoopLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeCropGrowth; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeDescription; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeDiscord; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeEffectLevel; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeEntityLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeGeneratorRate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeLevelBonus; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeMembersLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeMobDrops; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangePaypal; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangePlayerPrivilege; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeRoleLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeRolePrivilege; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeSpawnerRates; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpCategoryIcon; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpCategorySlot; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpIcon; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpLocation; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpsLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWorthBonus; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChat; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChunkReset; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearGeneratorRates; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearPlayerPrivileges; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearRatings; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearRolesPrivileges; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClose; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCloseWarp; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCoopPlayer; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreateWarp; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreateWarpCategory; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDeleteWarp; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDisableFlag; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDisband; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnableFlag; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnter; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnterPortal; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnterProtected; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandGenerateBlock; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandInvite; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandJoin; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandKick; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLeave; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLeaveProtected; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLockWorld; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandOpen; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandOpenWarp; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandQuit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveBlockLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveEffect; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveGeneratorRate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveRating; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveRoleLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveVisitorHome; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRename; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRenameWarp; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRenameWarpCategory; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRestrictMove; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSchematicPaste; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSetHome; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSetVisitorHome; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandTransfer; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUnban; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUncoopPlayer; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUnlockWorld; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUpgrade; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorldReset; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthCalculated; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthUpdate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.MissionComplete; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.MissionReset; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeBorderColor; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeLanguage; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeName; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeRole; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerCloseMenu; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerOpenMenu; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerReplace; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBlocksStacker; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBorder; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBypass; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleFly; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerTogglePanel; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleSpy; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleTeamChat; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginInitialize; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginInitialized; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginLoadData; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PostIslandCreate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PreIslandCreate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.SendMessage; + +; + +public abstract class PluginEventType extends EventType> { + + private static final List> ALL_TYPES = new LinkedList<>(); + + public static final PluginEventType SETTINGS_UPDATE_EVENT = new PluginEventType(null) { + @Override + public Event createBukkitEvent(Empty args) { + return null; + } + }; + public static final PluginEventType COMMANDS_UPDATE_EVENT = new PluginEventType(null) { + @Override + public Event createBukkitEvent(Empty args) { + return null; + } + }; + + public static final PluginEventType ATTEMPT_PLAYER_SEND_MESSAGE_EVENT = new PluginEventType(AttemptPlayerSendMessageEvent.class) { + @Override + public Event createBukkitEvent(AttemptPlayerSendMessage args) { + return new AttemptPlayerSendMessageEvent(args.receiver, args.messageType, args.args); + } + }; + public static final PluginEventType BLOCK_STACK_EVENT = new PluginEventType(BlockStackEvent.class) { + @Override + public Event createBukkitEvent(BlockStack args) { + return new BlockStackEvent(args.block, args.player, args.originalCount, args.newCount); + } + }; + public static final PluginEventType BLOCK_UNSTACK_EVENT = new PluginEventType(BlockUnstackEvent.class) { + @Override + public Event createBukkitEvent(BlockUnstack args) { + return new BlockUnstackEvent(args.block, args.player, args.originalCount, args.newCount); + } + }; + public static final PluginEventType ISLAND_BAN_EVENT = new PluginEventType(IslandBanEvent.class) { + @Override + public Event createBukkitEvent(IslandBan args) { + return new IslandBanEvent(args.superiorPlayer, args.targetPlayer, args.island); + } + }; + public static final PluginEventType ISLAND_BANK_DEPOSIT_EVENT = new PluginEventType(IslandBankDepositEvent.class) { + @Override + public Event createBukkitEvent(IslandBankDeposit args) { + return new IslandBankDepositEvent(args.superiorPlayer, args.island, args.amount); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().failureReason = ((IslandBankDepositEvent) bukkitEvent).getFailureReason(); + } + }; + public static final PluginEventType ISLAND_BANK_WITHDRAW_EVENT = new PluginEventType(IslandBankWithdrawEvent.class) { + @Override + public Event createBukkitEvent(IslandBankWithdraw args) { + return new IslandBankWithdrawEvent(args.superiorPlayer, args.island, args.amount); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().failureReason = ((IslandBankWithdrawEvent) bukkitEvent).getFailureReason(); + } + }; + public static final PluginEventType ISLAND_BIOME_CHANGE_EVENT = new PluginEventType(IslandBiomeChangeEvent.class) { + @Override + public Event createBukkitEvent(IslandBiomeChange args) { + return new IslandBiomeChangeEvent(args.superiorPlayer, args.island, args.biome); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().biome = ((IslandBiomeChangeEvent) bukkitEvent).getBiome(); + } + }; + public static final PluginEventType ISLAND_CHANGE_BANK_LIMIT_EVENT = new PluginEventType(IslandChangeBankLimitEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeBankLimit args) { + return new IslandChangeBankLimitEvent(args.superiorPlayer, args.island, args.bankLimit); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().bankLimit = ((IslandChangeBankLimitEvent) bukkitEvent).getBankLimit(); + } + }; + public static final PluginEventType ISLAND_CHANGE_BLOCK_LIMIT_EVENT = new PluginEventType(IslandChangeBlockLimitEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeBlockLimit args) { + return new IslandChangeBlockLimitEvent(args.superiorPlayer, args.island, args.block, args.blockLimit); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().blockLimit = ((IslandChangeBlockLimitEvent) bukkitEvent).getBlockLimit(); + } + }; + public static final PluginEventType ISLAND_CHANGE_BORDER_SIZE_EVENT = new PluginEventType(IslandChangeBorderSizeEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeBorderSize args) { + return new IslandChangeBorderSizeEvent(args.superiorPlayer, args.island, args.borderSize); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().borderSize = ((IslandChangeBorderSizeEvent) bukkitEvent).getBorderSize(); + } + }; + public static final PluginEventType ISLAND_CHANGE_COOP_LIMIT_EVENT = new PluginEventType(IslandChangeCoopLimitEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeCoopLimit args) { + return new IslandChangeCoopLimitEvent(args.superiorPlayer, args.island, args.coopLimit); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().coopLimit = ((IslandChangeCoopLimitEvent) bukkitEvent).getCoopLimit(); + } + }; + public static final PluginEventType ISLAND_CHANGE_CROP_GROWTH_EVENT = new PluginEventType(IslandChangeCropGrowthEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeCropGrowth args) { + return new IslandChangeCropGrowthEvent(args.superiorPlayer, args.island, args.cropGrowth); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().cropGrowth = ((IslandChangeCropGrowthEvent) bukkitEvent).getCropGrowth(); + } + }; + public static final PluginEventType ISLAND_CHANGE_DESCRIPTION_EVENT = new PluginEventType(IslandChangeDescriptionEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeDescription args) { + return new IslandChangeDescriptionEvent(args.island, args.superiorPlayer, args.description); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().description = ((IslandChangeDescriptionEvent) bukkitEvent).getDescription(); + } + }; + public static final PluginEventType ISLAND_CHANGE_DISCORD_EVENT = new PluginEventType(IslandChangeDiscordEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeDiscord args) { + return new IslandChangeDiscordEvent(args.superiorPlayer, args.island, args.discord); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().discord = ((IslandChangeDiscordEvent) bukkitEvent).getDiscord(); + } + }; + public static final PluginEventType ISLAND_CHANGE_EFFECT_LEVEL_EVENT = new PluginEventType(IslandChangeEffectLevelEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeEffectLevel args) { + return new IslandChangeEffectLevelEvent(args.superiorPlayer, args.island, args.effectType, args.effectLevel); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().effectLevel = ((IslandChangeEffectLevelEvent) bukkitEvent).getEffectLevel(); + } + }; + public static final PluginEventType ISLAND_CHANGE_ENTITY_LIMIT_EVENT = new PluginEventType(IslandChangeEntityLimitEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeEntityLimit args) { + return new IslandChangeEntityLimitEvent(args.superiorPlayer, args.island, args.entity, args.entityLimit); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().entityLimit = ((IslandChangeEntityLimitEvent) bukkitEvent).getEntityLimit(); + } + }; + public static final PluginEventType ISLAND_CHANGE_GENERATOR_RATE_EVENT = new PluginEventType(IslandChangeGeneratorRateEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeGeneratorRate args) { + return new IslandChangeGeneratorRateEvent(args.superiorPlayer, args.island, args.block, args.dimension, args.generatorRate); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().generatorRate = ((IslandChangeGeneratorRateEvent) bukkitEvent).getGeneratorRate(); + } + }; + public static final PluginEventType ISLAND_CHANGE_LEVEL_BONUS_EVENT = new PluginEventType(IslandChangeLevelBonusEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeLevelBonus args) { + return new IslandChangeLevelBonusEvent(args.superiorPlayer, args.island, args.reason, args.levelBonus); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().levelBonus = ((IslandChangeLevelBonusEvent) bukkitEvent).getLevelBonus(); + } + }; + public static final PluginEventType ISLAND_CHANGE_MEMBERS_LIMIT_EVENT = new PluginEventType(IslandChangeMembersLimitEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeMembersLimit args) { + return new IslandChangeMembersLimitEvent(args.superiorPlayer, args.island, args.membersLimit); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().membersLimit = ((IslandChangeMembersLimitEvent) bukkitEvent).getMembersLimit(); + } + }; + public static final PluginEventType ISLAND_CHANGE_MOB_DROPS_EVENT = new PluginEventType(IslandChangeMobDropsEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeMobDrops args) { + return new IslandChangeMobDropsEvent(args.superiorPlayer, args.island, args.mobDrops); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().mobDrops = ((IslandChangeMobDropsEvent) bukkitEvent).getMobDrops(); + } + }; + public static final PluginEventType ISLAND_CHANGE_PAYPAL_EVENT = new PluginEventType(IslandChangePaypalEvent.class) { + @Override + public Event createBukkitEvent(IslandChangePaypal args) { + return new IslandChangePaypalEvent(args.superiorPlayer, args.island, args.paypal); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().paypal = ((IslandChangePaypalEvent) bukkitEvent).getPaypal(); + } + }; + public static final PluginEventType ISLAND_CHANGE_PLAYER_PRIVILEGE_EVENT = new PluginEventType(IslandChangePlayerPrivilegeEvent.class) { + @Override + public Event createBukkitEvent(IslandChangePlayerPrivilege args) { + return new IslandChangePlayerPrivilegeEvent(args.island, args.superiorPlayer, args.privilegedPlayer, args.privilegeEnabled); + } + }; + public static final PluginEventType ISLAND_CHANGE_ROLE_LIMIT_EVENT = new PluginEventType(IslandChangeRoleLimitEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeRoleLimit args) { + return new IslandChangeRoleLimitEvent(args.superiorPlayer, args.island, args.playerRole, args.roleLimit); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().roleLimit = ((IslandChangeRoleLimitEvent) bukkitEvent).getRoleLimit(); + } + }; + public static final PluginEventType ISLAND_CHANGE_SPAWNER_RATES_EVENT = new PluginEventType(IslandChangeSpawnerRatesEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeSpawnerRates args) { + return new IslandChangeSpawnerRatesEvent(args.superiorPlayer, args.island, args.spawnerRates); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().spawnerRates = ((IslandChangeSpawnerRatesEvent) bukkitEvent).getSpawnerRates(); + } + }; + public static final PluginEventType ISLAND_CHANGE_WARP_CATEGORY_ICON_EVENT = new PluginEventType(IslandChangeWarpIconEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeWarpCategoryIcon args) { + return new IslandChangeWarpCategoryIconEvent(args.superiorPlayer, args.island, args.warpCategory, args.icon); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().icon = ((IslandChangeWarpCategoryIconEvent) bukkitEvent).getIcon(); + } + }; + public static final PluginEventType ISLAND_CHANGE_WARP_CATEGORY_SLOT_EVENT = new PluginEventType(IslandChangeWarpCategorySlotEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeWarpCategorySlot args) { + return new IslandChangeWarpCategorySlotEvent(args.superiorPlayer, args.island, args.warpCategory, args.slot, args.maxSlot); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().slot = ((IslandChangeWarpCategorySlotEvent) bukkitEvent).getSlot(); + } + }; + public static final PluginEventType ISLAND_CHANGE_WARP_ICON_EVENT = new PluginEventType(IslandChangeWarpIconEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeWarpIcon args) { + return new IslandChangeWarpIconEvent(args.superiorPlayer, args.island, args.islandWarp, args.icon); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().icon = ((IslandChangeWarpIconEvent) bukkitEvent).getIcon(); + } + }; + public static final PluginEventType ISLAND_CHANGE_WARP_LOCATION_EVENT = new PluginEventType(IslandChangeWarpLocationEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeWarpLocation args) { + return new IslandChangeWarpLocationEvent(args.superiorPlayer, args.island, args.islandWarp, args.location); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().location = ((IslandChangeWarpLocationEvent) bukkitEvent).getLocation(); + } + }; + public static final PluginEventType ISLAND_CHANGE_WARPS_LIMIT_EVENT = new PluginEventType(IslandChangeWarpsLimitEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeWarpsLimit args) { + return new IslandChangeWarpsLimitEvent(args.superiorPlayer, args.island, args.warpsLimit); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().warpsLimit = ((IslandChangeWarpsLimitEvent) bukkitEvent).getWarpsLimit(); + } + }; + public static final PluginEventType ISLAND_CHANGE_WORTH_BONUS_EVENT = new PluginEventType(IslandChangeWorthBonusEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeWorthBonus args) { + return new IslandChangeWorthBonusEvent(args.superiorPlayer, args.island, args.reason, args.worthBonus); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().worthBonus = ((IslandChangeWorthBonusEvent) bukkitEvent).getWorthBonus(); + } + }; + public static final PluginEventType ISLAND_CHANGE_ROLE_PRIVILEGE_EVENT = new PluginEventType(IslandChangeRolePrivilegeEvent.class) { + @Override + public Event createBukkitEvent(IslandChangeRolePrivilege args) { + return new IslandChangeRolePrivilegeEvent(args.island, args.superiorPlayer, args.playerRole); + } + }; + public static final PluginEventType ISLAND_CHAT_EVENT = new PluginEventType(IslandChatEvent.class) { + @Override + public Event createBukkitEvent(IslandChat args) { + return new IslandChatEvent(args.island, args.superiorPlayer, args.message); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().message = ((IslandChatEvent) bukkitEvent).getMessage(); + } + }; + public static final PluginEventType ISLAND_CHUNK_RESET_EVENT = new PluginEventType(IslandChunkResetEvent.class) { + @Override + public Event createBukkitEvent(IslandChunkReset args) { + return new IslandChunkResetEvent(args.island, args.chunkPosition.getWorld(), args.chunkPosition.getX(), + args.chunkPosition.getZ()); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + // Do nothing + } + }; + public static final PluginEventType ISLAND_CLEAR_GENERATOR_RATES_EVENT = new PluginEventType(IslandClearGeneratorRatesEvent.class) { + @Override + public Event createBukkitEvent(IslandClearGeneratorRates args) { + return new IslandClearGeneratorRatesEvent(args.superiorPlayer, args.island, args.dimension); + } + }; + public static final PluginEventType ISLAND_CLEAR_PLAYER_PRIVILEGES_EVENT = new PluginEventType(IslandClearPlayerPrivilegesEvent.class) { + @Override + public Event createBukkitEvent(IslandClearPlayerPrivileges args) { + return new IslandClearPlayerPrivilegesEvent(args.island, args.superiorPlayer, args.privilegedPlayer); + } + }; + public static final PluginEventType ISLAND_CLEAR_RATINGS_EVENT = new PluginEventType(IslandClearRatingsEvent.class) { + @Override + public Event createBukkitEvent(IslandClearRatings args) { + return new IslandClearRatingsEvent(args.superiorPlayer, args.island); + } + }; + public static final PluginEventType ISLAND_CLEAR_ROLES_PRIVILEGES_EVENT = new PluginEventType(IslandClearRolesPrivilegesEvent.class) { + @Override + public Event createBukkitEvent(IslandClearRolesPrivileges args) { + return new IslandClearRolesPrivilegesEvent(args.island, args.superiorPlayer); + } + }; + public static final PluginEventType ISLAND_CLOSE_EVENT = new PluginEventType(IslandCloseEvent.class) { + @Override + public Event createBukkitEvent(IslandClose args) { + return new IslandCloseEvent(args.superiorPlayer, args.island); + } + }; + public static final PluginEventType ISLAND_CLOSE_WARP_EVENT = new PluginEventType(IslandCloseWarpEvent.class) { + @Override + public Event createBukkitEvent(IslandCloseWarp args) { + return new IslandCloseWarpEvent(args.superiorPlayer, args.island, args.islandWarp); + } + }; + public static final PluginEventType ISLAND_COOP_PLAYER_EVENT = new PluginEventType(IslandCoopPlayerEvent.class) { + @Override + public Event createBukkitEvent(IslandCoopPlayer args) { + return new IslandCoopPlayerEvent(args.island, args.superiorPlayer, args.targetPlayer); + } + }; + public static final PluginEventType ISLAND_CREATE_EVENT = new PluginEventType(IslandCreateEvent.class) { + @Override + public Event createBukkitEvent(IslandCreate args) { + return new IslandCreateEvent(args.superiorPlayer, args.island, args.schematicName); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().canTeleport = ((IslandCreateEvent) bukkitEvent).canTeleport(); + } + }; + public static final PluginEventType ISLAND_CREATE_WARP_CATEGORY_EVENT = new PluginEventType(IslandCreateWarpCategoryEvent.class) { + @Override + public Event createBukkitEvent(IslandCreateWarpCategory args) { + return new IslandCreateWarpCategoryEvent(args.superiorPlayer, args.island, args.categoryName); + } + }; + public static final PluginEventType ISLAND_CREATE_WARP_EVENT = new PluginEventType(IslandCreateWarpEvent.class) { + @Override + public Event createBukkitEvent(IslandCreateWarp args) { + return new IslandCreateWarpEvent(args.superiorPlayer, args.island, args.warpName, args.location, args.openToPublic, args.warpCategory); + } + }; + public static final PluginEventType ISLAND_DELETE_WARP_EVENT = new PluginEventType(IslandDeleteWarpEvent.class) { + @Override + public Event createBukkitEvent(IslandDeleteWarp args) { + return new IslandDeleteWarpEvent(args.superiorPlayer, args.island, args.islandWarp); + } + }; + public static final PluginEventType ISLAND_DISABLE_FLAG_EVENT = new PluginEventType(IslandDisableFlagEvent.class) { + @Override + public Event createBukkitEvent(IslandDisableFlag args) { + return new IslandDisableFlagEvent(args.superiorPlayer, args.island, args.islandFlag); + } + }; + public static final PluginEventType ISLAND_DISBAND_EVENT = new PluginEventType(IslandDisbandEvent.class) { + @Override + public Event createBukkitEvent(IslandDisband args) { + return new IslandDisbandEvent(args.superiorPlayer, args.island); + } + }; + public static final PluginEventType ISLAND_ENABLE_FLAG_EVENT = new PluginEventType(IslandEnableFlagEvent.class) { + @Override + public Event createBukkitEvent(IslandEnableFlag args) { + return new IslandEnableFlagEvent(args.superiorPlayer, args.island, args.islandFlag); + } + }; + public static final PluginEventType ISLAND_ENTER_EVENT = new PluginEventType(IslandEnterEvent.class) { + @Override + public Event createBukkitEvent(IslandEnter args) { + return new IslandEnterEvent(args.superiorPlayer, args.island, args.enterCause); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + + IslandEnterEvent islandEnterEvent = (IslandEnterEvent) bukkitEvent; + + if (islandEnterEvent.isCancelled() && islandEnterEvent.getCancelTeleport() != null) + pluginEvent.getArgs().superiorPlayer.teleport(islandEnterEvent.getCancelTeleport()); + } + }; + public static final PluginEventType ISLAND_ENTER_PORTAL_EVENT = new PluginEventType(IslandEnterPortalEvent.class) { + @Override + public Event createBukkitEvent(IslandEnterPortal args) { + return new IslandEnterPortalEvent(args.island, args.superiorPlayer, args.portalType, args.destination, + args.schematic, args.ignoreInvalidSchematic); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().destination = ((IslandEnterPortalEvent) bukkitEvent).getDestinationDimension(); + pluginEvent.getArgs().schematic = ((IslandEnterPortalEvent) bukkitEvent).getSchematic(); + pluginEvent.getArgs().ignoreInvalidSchematic = ((IslandEnterPortalEvent) bukkitEvent).isIgnoreInvalidSchematic(); + } + }; + public static final PluginEventType ISLAND_ENTER_PROTECTED_EVENT = new PluginEventType(IslandEnterProtectedEvent.class) { + @Override + public Event createBukkitEvent(IslandEnterProtected args) { + return new IslandEnterProtectedEvent(args.superiorPlayer, args.island, args.enterCause); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + + IslandEnterProtectedEvent islandEnterProtectedEvent = (IslandEnterProtectedEvent) bukkitEvent; + + if (islandEnterProtectedEvent.isCancelled() && islandEnterProtectedEvent.getCancelTeleport() != null) + pluginEvent.getArgs().superiorPlayer.teleport(islandEnterProtectedEvent.getCancelTeleport()); + } + }; + public static final PluginEventType ISLAND_GENERATE_BLOCK_EVENT = new PluginEventType(IslandGenerateBlockEvent.class) { + @Override + public Event createBukkitEvent(IslandGenerateBlock args) { + return new IslandGenerateBlockEvent(args.island, args.location, args.block); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().block = ((IslandGenerateBlockEvent) bukkitEvent).getBlock(); + pluginEvent.getArgs().placeBlock = ((IslandGenerateBlockEvent) bukkitEvent).isPlaceBlock(); + } + }; + public static final PluginEventType ISLAND_INVITE_EVENT = new PluginEventType(IslandInviteEvent.class) { + @Override + public Event createBukkitEvent(IslandInvite args) { + return new IslandInviteEvent(args.superiorPlayer, args.targetPlayer, args.island); + } + }; + public static final PluginEventType ISLAND_JOIN_EVENT = new PluginEventType(IslandJoinEvent.class) { + @Override + public Event createBukkitEvent(IslandJoin args) { + return new IslandJoinEvent(args.superiorPlayer, args.island, args.joinCause); + } + }; + public static final PluginEventType ISLAND_KICK_EVENT = new PluginEventType(IslandKickEvent.class) { + @Override + public Event createBukkitEvent(IslandKick args) { + return new IslandKickEvent(args.superiorPlayer, args.targetPlayer, args.island); + } + }; + public static final PluginEventType ISLAND_LEAVE_EVENT = new PluginEventType(IslandLeaveEvent.class) { + @Override + public Event createBukkitEvent(IslandLeave args) { + return new IslandLeaveEvent(args.superiorPlayer, args.island, args.leaveCause, args.location); + } + }; + public static final PluginEventType ISLAND_LEAVE_PROTECTED_EVENT = new PluginEventType(IslandLeaveProtectedEvent.class) { + @Override + public Event createBukkitEvent(IslandLeaveProtected args) { + return new IslandLeaveEvent(args.superiorPlayer, args.island, args.leaveCause, args.location); + } + }; + public static final PluginEventType ISLAND_LOCK_WORLD_EVENT = new PluginEventType(IslandLockWorldEvent.class) { + @Override + public Event createBukkitEvent(IslandLockWorld args) { + return new IslandLockWorldEvent(args.island, args.dimension); + } + }; + public static final PluginEventType ISLAND_OPEN_EVENT = new PluginEventType(IslandOpenEvent.class) { + @Override + public Event createBukkitEvent(IslandOpen args) { + return new IslandOpenEvent(args.superiorPlayer, args.island); + } + }; + public static final PluginEventType ISLAND_OPEN_WARP_EVENT = new PluginEventType(IslandOpenWarpEvent.class) { + @Override + public Event createBukkitEvent(IslandOpenWarp args) { + return new IslandOpenWarpEvent(args.superiorPlayer, args.island, args.islandWarp); + } + }; + public static final PluginEventType ISLAND_QUIT_EVENT = new PluginEventType(IslandQuitEvent.class) { + @Override + public Event createBukkitEvent(IslandQuit args) { + return new IslandQuitEvent(args.superiorPlayer, args.island); + } + }; + public static final PluginEventType ISLAND_RATE_EVENT = new PluginEventType(IslandRateEvent.class) { + @Override + public Event createBukkitEvent(IslandRate args) { + return new IslandRateEvent(args.superiorPlayer, args.ratingPlayer, args.island, args.rating); + } + }; + public static final PluginEventType ISLAND_REMOVE_BLOCK_LIMIT_EVENT = new PluginEventType(IslandRemoveBlockLimitEvent.class) { + @Override + public Event createBukkitEvent(IslandRemoveBlockLimit args) { + return new IslandRemoveBlockLimitEvent(args.superiorPlayer, args.island, args.block); + } + }; + public static final PluginEventType ISLAND_REMOVE_EFFECT_EVENT = new PluginEventType(IslandRemoveEffectEvent.class) { + @Override + public Event createBukkitEvent(IslandRemoveEffect args) { + return new IslandRemoveEffectEvent(args.superiorPlayer, args.island, args.effectType); + } + }; + public static final PluginEventType ISLAND_REMOVE_GENERATOR_RATE_EVENT = new PluginEventType(IslandRemoveGeneratorRateEvent.class) { + @Override + public Event createBukkitEvent(IslandRemoveGeneratorRate args) { + return new IslandRemoveGeneratorRateEvent(args.superiorPlayer, args.island, args.block, args.dimension); + } + }; + public static final PluginEventType ISLAND_REMOVE_RATING_EVENT = new PluginEventType(IslandRemoveRatingEvent.class) { + @Override + public Event createBukkitEvent(IslandRemoveRating args) { + return new IslandRemoveRatingEvent(args.superiorPlayer, args.ratingPlayer, args.island); + } + }; + public static final PluginEventType ISLAND_REMOVE_ROLE_LIMIT_EVENT = new PluginEventType(IslandRemoveRoleLimitEvent.class) { + @Override + public Event createBukkitEvent(IslandRemoveRoleLimit args) { + return new IslandRemoveRoleLimitEvent(args.superiorPlayer, args.island, args.playerRole); + } + }; + public static final PluginEventType ISLAND_REMOVE_VISITOR_HOME_EVENT = new PluginEventType(IslandRemoveVisitorHomeEvent.class) { + @Override + public Event createBukkitEvent(IslandRemoveVisitorHome args) { + return new IslandRemoveVisitorHomeEvent(args.superiorPlayer, args.island); + } + }; + public static final PluginEventType ISLAND_RENAME_EVENT = new PluginEventType(IslandRenameEvent.class) { + @Override + public Event createBukkitEvent(IslandRename args) { + return new IslandRenameEvent(args.island, args.superiorPlayer, args.islandName); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().islandName = ((IslandRenameEvent) bukkitEvent).getIslandName(); + } + }; + public static final PluginEventType ISLAND_RENAME_WARP_CATEGORY_EVENT = new PluginEventType(IslandRenameWarpCategoryEvent.class) { + @Override + public Event createBukkitEvent(IslandRenameWarpCategory args) { + return new IslandRenameWarpCategoryEvent(args.superiorPlayer, args.island, args.warpCategory, args.categoryName); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().categoryName = ((IslandRenameWarpCategoryEvent) bukkitEvent).getCategoryName(); + } + }; + public static final PluginEventType ISLAND_RENAME_WARP_EVENT = new PluginEventType(IslandRenameWarpEvent.class) { + @Override + public Event createBukkitEvent(IslandRenameWarp args) { + return new IslandRenameWarpEvent(args.superiorPlayer, args.island, args.islandWarp, args.warpName); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().warpName = ((IslandRenameWarpEvent) bukkitEvent).getWarpName(); + } + }; + public static final PluginEventType ISLAND_RESTRICT_MOVE_EVENT = new PluginEventType(IslandRestrictMoveEvent.class) { + @Override + public Event createBukkitEvent(IslandRestrictMove args) { + return new IslandRestrictMoveEvent(args.superiorPlayer, args.restrictReason); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + // Do nothing + } + }; + public static final PluginEventType ISLAND_SCHEMATIC_PASTE_EVENT = new PluginEventType(IslandSchematicPasteEvent.class) { + @Override + public Event createBukkitEvent(IslandSchematicPaste args) { + return new IslandSchematicPasteEvent(args.island, args.schematicName, args.location); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + // Do nothing + } + }; + public static final PluginEventType ISLAND_SET_HOME_EVENT = new PluginEventType(IslandSetHomeEvent.class) { + @Override + public Event createBukkitEvent(IslandSetHome args) { + return new IslandSetHomeEvent(args.island, args.islandHome, args.reason, args.superiorPlayer); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().islandHome = ((IslandSetHomeEvent) bukkitEvent).getIslandHome(); + } + }; + public static final PluginEventType ISLAND_SET_VISITOR_HOME_EVENT = new PluginEventType(IslandSetVisitorHomeEvent.class) { + @Override + public Event createBukkitEvent(IslandSetVisitorHome args) { + return new IslandSetVisitorHomeEvent(args.superiorPlayer, args.island, args.islandVisitorHome); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().islandVisitorHome = ((IslandSetVisitorHomeEvent) bukkitEvent).getIslandVisitorHome(); + } + }; + public static final PluginEventType ISLAND_TRANSFER_EVENT = new PluginEventType(IslandTransferEvent.class) { + @Override + public Event createBukkitEvent(IslandTransfer args) { + return new IslandTransferEvent(args.island, args.previousOwner, args.superiorPlayer); + } + }; + public static final PluginEventType ISLAND_UNBAN_EVENT = new PluginEventType(IslandUnbanEvent.class) { + @Override + public Event createBukkitEvent(IslandUnban args) { + return new IslandUnbanEvent(args.superiorPlayer, args.unbannedPlayer, args.island); + } + }; + public static final PluginEventType ISLAND_UNCOOP_PLAYER_EVENT = new PluginEventType(IslandUncoopPlayerEvent.class) { + @Override + public Event createBukkitEvent(IslandUncoopPlayer args) { + return new IslandUncoopPlayerEvent(args.island, args.superiorPlayer, args.targetPlayer, args.uncoopReason); + } + }; + public static final PluginEventType ISLAND_UNLOCK_WORLD_EVENT = new PluginEventType(IslandUnlockWorldEvent.class) { + @Override + public Event createBukkitEvent(IslandUnlockWorld args) { + return new IslandUnlockWorldEvent(args.island, args.dimension); + } + }; + public static final PluginEventType ISLAND_UPGRADE_EVENT = new PluginEventType(IslandUpgradeEvent.class) { + @Override + public Event createBukkitEvent(IslandUpgrade args) { + return new IslandUpgradeEvent(args.superiorPlayer, args.island, args.upgrade, args.nextLevel, args.commands, + args.upgradeCause, args.upgradeCost); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().commands = ((IslandUpgradeEvent) bukkitEvent).getCommands(); + pluginEvent.getArgs().upgradeCost = ((IslandUpgradeEvent) bukkitEvent).getUpgradeCost(); + } + }; + public static final PluginEventType ISLAND_WORLD_RESET_EVENT = new PluginEventType(IslandWorldResetEvent.class) { + @Override + public Event createBukkitEvent(IslandWorldReset args) { + return new IslandWorldResetEvent(args.superiorPlayer, args.island, args.dimension); + } + }; + public static final PluginEventType ISLAND_WORTH_CALCULATED_EVENT = new PluginEventType(IslandWorthCalculatedEvent.class) { + @Override + public Event createBukkitEvent(IslandWorthCalculated args) { + return new IslandWorthCalculatedEvent(args.island, args.superiorPlayer, args.islandLevel, args.islandWorth); + } + }; + public static final PluginEventType ISLAND_WORTH_UPDATE_EVENT = new PluginEventType(IslandWorthUpdateEvent.class) { + @Override + public Event createBukkitEvent(IslandWorthUpdate args) { + return new IslandWorthUpdateEvent(args.island, args.oldWorth, args.oldLevel, args.newWorth, args.newLevel); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + // Do nothing + } + }; + public static final PluginEventType MISSION_COMPLETE_EVENT = new PluginEventType(MissionCompleteEvent.class) { + @Override + public Event createBukkitEvent(MissionComplete args) { + return new MissionCompleteEvent(args.superiorPlayer, args.missionsHolder, args.mission, args.itemRewards, args.commandRewards); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().itemRewards = ((MissionCompleteEvent) bukkitEvent).getItemRewards(); + pluginEvent.getArgs().commandRewards = ((MissionCompleteEvent) bukkitEvent).getCommandRewards(); + } + }; + public static final PluginEventType MISSION_RESET_EVENT = new PluginEventType(MissionResetEvent.class) { + @Override + public Event createBukkitEvent(MissionReset args) { + return new MissionResetEvent(args.superiorPlayer, args.missionsHolder, args.mission); + } + }; + public static final PluginEventType PLAYER_CHANGE_BORDER_COLOR_EVENT = new PluginEventType(PlayerChangeBorderColorEvent.class) { + @Override + public Event createBukkitEvent(PlayerChangeBorderColor args) { + return new PlayerChangeBorderColorEvent(args.superiorPlayer, args.borderColor); + } + }; + public static final PluginEventType PLAYER_CHANGE_LANGUAGE_EVENT = new PluginEventType(PlayerChangeLanguageEvent.class) { + @Override + public Event createBukkitEvent(PlayerChangeLanguage args) { + return new PlayerChangeLanguageEvent(args.superiorPlayer, args.language); + } + }; + public static final PluginEventType PLAYER_CHANGE_NAME_EVENT = new PluginEventType(PlayerChangeNameEvent.class) { + @Override + public Event createBukkitEvent(PlayerChangeName args) { + return new PlayerChangeNameEvent(args.superiorPlayer, args.newName); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + // Do nothing + } + }; + public static final PluginEventType PLAYER_CHANGE_ROLE_EVENT = new PluginEventType(PlayerChangeRoleEvent.class) { + @Override + public Event createBukkitEvent(PlayerChangeRole args) { + return new PlayerChangeRoleEvent(args.superiorPlayer, args.newRole); + } + }; + public static final PluginEventType PLAYER_CLOSE_MENU_EVENT = new PluginEventType(PlayerCloseMenuEvent.class) { + @Override + public Event createBukkitEvent(PlayerCloseMenu args) { + return new PlayerCloseMenuEvent(args.superiorPlayer, args.menuView, args.newMenuView); + } + }; + public static final PluginEventType PLAYER_OPEN_MENU_EVENT = new PluginEventType(PlayerOpenMenuEvent.class) { + @Override + public Event createBukkitEvent(PlayerOpenMenu args) { + return new PlayerOpenMenuEvent(args.superiorPlayer, args.menuView); + } + }; + public static final PluginEventType PLAYER_REPLACE_EVENT = new PluginEventType(PlayerReplaceEvent.class) { + @Override + public Event createBukkitEvent(PlayerReplace args) { + return new PlayerReplaceEvent(args.superiorPlayer, args.newPlayer); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + // Do nothing + } + }; + public static final PluginEventType PLAYER_TOGGLE_BLOCKS_STACKER_EVENT = new PluginEventType(PlayerToggleBlocksStackerEvent.class) { + @Override + public Event createBukkitEvent(PlayerToggleBlocksStacker args) { + return new PlayerToggleBlocksStackerEvent(args.superiorPlayer); + } + }; + public static final PluginEventType PLAYER_TOGGLE_BORDER_EVENT = new PluginEventType(PlayerToggleBorderEvent.class) { + @Override + public Event createBukkitEvent(PlayerToggleBorder args) { + return new PlayerToggleBorderEvent(args.superiorPlayer); + } + }; + public static final PluginEventType PLAYER_TOGGLE_BYPASS_EVENT = new PluginEventType(PlayerToggleBypassEvent.class) { + @Override + public Event createBukkitEvent(PlayerToggleBypass args) { + return new PlayerToggleBypassEvent(args.superiorPlayer); + } + }; + public static final PluginEventType PLAYER_TOGGLE_FLY_EVENT = new PluginEventType(PlayerToggleFlyEvent.class) { + @Override + public Event createBukkitEvent(PlayerToggleFly args) { + return new PlayerToggleFlyEvent(args.superiorPlayer); + } + }; + public static final PluginEventType PLAYER_TOGGLE_PANEL_EVENT = new PluginEventType(PlayerTogglePanelEvent.class) { + @Override + public Event createBukkitEvent(PlayerTogglePanel args) { + return new PlayerTogglePanelEvent(args.superiorPlayer); + } + }; + public static final PluginEventType PLAYER_TOGGLE_SPY_EVENT = new PluginEventType(PlayerToggleSpyEvent.class) { + @Override + public Event createBukkitEvent(PlayerToggleSpy args) { + return new PlayerToggleSpyEvent(args.superiorPlayer); + } + }; + public static final PluginEventType PLAYER_TOGGLE_TEAM_CHAT_EVENT = new PluginEventType(PlayerToggleTeamChatEvent.class) { + @Override + public Event createBukkitEvent(PlayerToggleTeamChat args) { + return new PlayerToggleTeamChatEvent(args.superiorPlayer); + } + }; + public static final PluginEventType PLUGIN_INITIALIZED_EVENT = new PluginEventType(PluginInitializedEvent.class) { + @Override + public Event createBukkitEvent(PluginInitialized args) { + return new PluginInitializedEvent(args.plugin); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + // Do nothing + } + }; + public static final PluginEventType PLUGIN_INITIALIZE_EVENT = new PluginEventType(PluginInitializeEvent.class) { + @Override + public Event createBukkitEvent(PluginInitialize args) { + return new PluginInitializeEvent(args.plugin); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + pluginEvent.getArgs().islandsContainer = ((PluginInitializeEvent) bukkitEvent).getIslandsContainer(); + pluginEvent.getArgs().playersContainer = ((PluginInitializeEvent) bukkitEvent).getPlayersContainer(); + } + }; + public static final PluginEventType PLUGIN_LOAD_DATA_EVENT = new PluginEventType(null) { + @Override + public Event createBukkitEvent(PluginLoadData args) { + return new PluginLoadDataEvent(args.plugin); + } + }; + public static final PluginEventType POST_ISLAND_CREATE_EVENT = new PluginEventType(PostIslandCreateEvent.class) { + @Override + public Event createBukkitEvent(PostIslandCreate args) { + return new PostIslandCreateEvent(args.superiorPlayer, args.island); + } + }; + public static final PluginEventType PRE_ISLAND_CREATE_EVENT = new PluginEventType(PreIslandCreateEvent.class) { + @Override + public Event createBukkitEvent(PreIslandCreate args) { + return new PreIslandCreateEvent(args.superiorPlayer, args.islandName); + } + }; + public static final PluginEventType SEND_MESSAGE_EVENT = new PluginEventType(SendMessageEvent.class) { + @Override + public Event createBukkitEvent(SendMessage args) { + return new SendMessageEvent(args.receiver, args.messageType, args.messageComponent, args.args); + } + + @Override + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + super.applyBukkitToPluginEvent(bukkitEvent, pluginEvent); + pluginEvent.getArgs().messageComponent = ((SendMessageEvent) bukkitEvent).getMessageComponent(); + } + }; + + private final String bukkitEventName; + + private PluginEventType(@Nullable Class bukkitEventClass) { + this.bukkitEventName = bukkitEventClass == null ? null : bukkitEventClass.getSimpleName().toLowerCase(Locale.ENGLISH); + ALL_TYPES.add(this); + } + + @Override + public PluginEvent createEvent(Args args) { + return new PluginEvent<>(this, args); + } + + @Nullable + public String getBukkitEventName() { + return bukkitEventName; + } + + @Nullable + public abstract Event createBukkitEvent(Args args); + + public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent pluginEvent) { + if (bukkitEvent instanceof Cancellable && ((Cancellable) bukkitEvent).isCancelled()) + pluginEvent.setCancelled(); + } + + public static Collection> values() { + return Collections.unmodifiableList(ALL_TYPES); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java new file mode 100644 index 0000000000..cd3b5d228e --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java @@ -0,0 +1,92 @@ +package com.bgsoftware.superiorskyblock.core.events.plugin; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.commands.CommandsMap; +import com.bgsoftware.superiorskyblock.commands.player.CmdAdmin; +import com.bgsoftware.superiorskyblock.commands.player.CmdHelp; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.events.EventCallback; +import com.bgsoftware.superiorskyblock.core.events.EventsDispatcher; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.logging.Debug; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.island.SIsland; +import com.bgsoftware.superiorskyblock.island.SpawnIsland; +import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; +import org.bukkit.Bukkit; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; + +import java.util.EnumMap; +import java.util.List; + +public class PluginEventsDispatcher extends EventsDispatcher< + Void, + PluginEventType, + PluginEventPriority, + PluginEvent> { + + public PluginEventsDispatcher(SuperiorSkyblockPlugin plugin) { + super(plugin, PluginEventPriority.class, PluginEventType.values()); + } + + public void registerDefaultListeners() { + SIsland.registerListeners(this); + CommandsMap.registerListeners(this); + SpawnIsland.registerListeners(this); + RegionManagerServiceImpl.registerCallbacks(this); + CmdHelp.registerListeners(this); + CmdAdmin.registerCallbacks(this); + } + + public void registerCallback(PluginEventType type, Runnable callback) { + registerCallback(type, unused -> callback.run()); + } + + public void registerCallback(PluginEventType type, EventCallback> callback) { + registerCallback(null, type, PluginEventPriority.NORMAL, true, callback); + } + + public PluginEvent fireEvent(PluginEventType type, Args args) { + PluginEvent event = type.createEvent(args); + + EnumMap> gameEventCallbacks = callbacks.get(type); + if (gameEventCallbacks != null) { + gameEventCallbacks.forEach((priority, priorityCallbacks) -> { + for (RegisteredListener listener : priorityCallbacks) { + if (listener.ignoreCancelled && event.isCancelled()) { + continue; + } + + try { + listener.callback.execute(event); + } catch (Throwable error) { + Log.error(error, "Could not pass listener: " + listener.listener); + } + } + }); + } + + String bukkitEventName = type.getBukkitEventName(); + boolean fireEventDebug = !Text.isBlank(bukkitEventName); + if (!fireEventDebug || !plugin.getSettings().getDisabledEvents().contains(bukkitEventName)) { + if (fireEventDebug) + Log.debug(Debug.FIRE_EVENT, bukkitEventName); + + Event bukkitEvent = type.createBukkitEvent(event.getArgs()); + if (bukkitEvent != null) { + Bukkit.getPluginManager().callEvent(bukkitEvent); + + if (fireEventDebug && bukkitEvent instanceof Cancellable) { + Log.debugResult(Debug.FIRE_EVENT, "Cancelled:", ((Cancellable) bukkitEvent).isCancelled()); + } + + type.applyBukkitToPluginEvent(bukkitEvent, event); + } + } + + + return event; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java new file mode 100644 index 0000000000..f95d708446 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java @@ -0,0 +1,1335 @@ +package com.bgsoftware.superiorskyblock.core.events.plugin; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.enums.BorderColor; +import com.bgsoftware.superiorskyblock.api.enums.Rating; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandSetHomeEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandFlag; +import com.bgsoftware.superiorskyblock.api.island.PlayerRole; +import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; +import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; +import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; +import com.bgsoftware.superiorskyblock.api.missions.Mission; +import com.bgsoftware.superiorskyblock.api.schematic.Schematic; +import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; +import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; +import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; +import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import org.bukkit.Location; +import org.bukkit.PortalType; +import org.bukkit.block.Biome; +import org.bukkit.block.Block; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffectType; + +import java.math.BigDecimal; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.AttemptPlayerSendMessage; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.BlockStack; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.BlockUnstack; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.Empty; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBan; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBankDeposit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBankWithdraw; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBiomeChange; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBankLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBlockLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBorderSize; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeCoopLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeCropGrowth; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeDescription; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeDiscord; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeEffectLevel; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeEntityLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeGeneratorRate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeLevelBonus; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeMembersLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeMobDrops; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangePaypal; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangePlayerPrivilege; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeRoleLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeRolePrivilege; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeSpawnerRates; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpCategoryIcon; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpCategorySlot; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpIcon; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpLocation; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpsLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWorthBonus; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChat; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChunkReset; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearGeneratorRates; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearPlayerPrivileges; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearRatings; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearRolesPrivileges; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClose; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCloseWarp; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCoopPlayer; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreateWarp; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreateWarpCategory; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDeleteWarp; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDisableFlag; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDisband; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnableFlag; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnter; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnterPortal; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnterProtected; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandGenerateBlock; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandInvite; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandJoin; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandKick; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLeave; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLeaveProtected; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLockWorld; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandOpen; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandOpenWarp; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandQuit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveBlockLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveEffect; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveGeneratorRate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveRating; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveRoleLimit; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveVisitorHome; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRename; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRenameWarp; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRenameWarpCategory; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRestrictMove; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSchematicPaste; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSetHome; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSetVisitorHome; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandTransfer; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUnban; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUncoopPlayer; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUnlockWorld; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUpgrade; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorldReset; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthCalculated; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthUpdate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.MissionComplete; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.MissionReset; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeBorderColor; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeLanguage; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeName; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeRole; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerCloseMenu; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerOpenMenu; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerReplace; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBlocksStacker; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBorder; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBypass; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleFly; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerTogglePanel; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleSpy; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleTeamChat; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginInitialize; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginInitialized; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginLoadData; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PostIslandCreate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PreIslandCreate; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.SendMessage; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ATTEMPT_PLAYER_SEND_MESSAGE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.BLOCK_STACK_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.BLOCK_UNSTACK_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.COMMANDS_UPDATE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_BANK_DEPOSIT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_BANK_WITHDRAW_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_BAN_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_BIOME_CHANGE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_BANK_LIMIT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_BLOCK_LIMIT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_BORDER_SIZE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_COOP_LIMIT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_CROP_GROWTH_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_DESCRIPTION_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_DISCORD_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_EFFECT_LEVEL_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_ENTITY_LIMIT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_GENERATOR_RATE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_LEVEL_BONUS_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_MEMBERS_LIMIT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_MOB_DROPS_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_PAYPAL_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_PLAYER_PRIVILEGE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_ROLE_LIMIT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_ROLE_PRIVILEGE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_SPAWNER_RATES_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WARPS_LIMIT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WARP_CATEGORY_ICON_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WARP_CATEGORY_SLOT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WARP_ICON_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WARP_LOCATION_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WORTH_BONUS_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHAT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHUNK_RESET_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_GENERATOR_RATES_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_PLAYER_PRIVILEGES_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_RATINGS_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_ROLES_PRIVILEGES_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLOSE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLOSE_WARP_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_COOP_PLAYER_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CREATE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CREATE_WARP_CATEGORY_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CREATE_WARP_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_DELETE_WARP_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_DISABLE_FLAG_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_DISBAND_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_ENABLE_FLAG_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_ENTER_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_ENTER_PORTAL_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_ENTER_PROTECTED_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_GENERATE_BLOCK_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_INVITE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_JOIN_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_KICK_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_LEAVE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_LEAVE_PROTECTED_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_LOCK_WORLD_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_OPEN_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_OPEN_WARP_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_QUIT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_RATE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_REMOVE_BLOCK_LIMIT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_REMOVE_EFFECT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_REMOVE_GENERATOR_RATE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_REMOVE_RATING_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_REMOVE_ROLE_LIMIT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_REMOVE_VISITOR_HOME_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_RENAME_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_RENAME_WARP_CATEGORY_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_RENAME_WARP_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_RESTRICT_MOVE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_SCHEMATIC_PASTE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_SET_HOME_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_SET_VISITOR_HOME_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_TRANSFER_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_UNBAN_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_UNCOOP_PLAYER_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_UNLOCK_WORLD_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_UPGRADE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_WORLD_RESET_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_WORTH_CALCULATED_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_WORTH_UPDATE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.MISSION_COMPLETE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.MISSION_RESET_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_CHANGE_BORDER_COLOR_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_CHANGE_LANGUAGE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_CHANGE_NAME_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_CHANGE_ROLE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_CLOSE_MENU_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_OPEN_MENU_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_REPLACE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_BLOCKS_STACKER_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_BORDER_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_BYPASS_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_FLY_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_PANEL_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_SPY_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_TEAM_CHAT_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLUGIN_INITIALIZED_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLUGIN_INITIALIZE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLUGIN_LOAD_DATA_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.POST_ISLAND_CREATE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PRE_ISLAND_CREATE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.SEND_MESSAGE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.SETTINGS_UPDATE_EVENT; + +public class PluginEventsFactory { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + public static void callSettingsUpdateEvent() { + fireEvent(SETTINGS_UPDATE_EVENT, Empty.INSTANCE); + } + + public static void callCommandsUpdateEvent() { + fireEvent(COMMANDS_UPDATE_EVENT, Empty.INSTANCE); + } + + public static boolean callAttemptPlayerSendMessageEvent(SuperiorPlayer receiver, String messageType, Object... args) { + AttemptPlayerSendMessage attemptPlayerSendMessage = new AttemptPlayerSendMessage(); + attemptPlayerSendMessage.receiver = receiver; + attemptPlayerSendMessage.messageType = messageType; + attemptPlayerSendMessage.args = args; + return !fireEvent(ATTEMPT_PLAYER_SEND_MESSAGE_EVENT, attemptPlayerSendMessage).isCancelled(); + } + + public static boolean callBlockStackEvent(Block block, Player player, int originalCount, int newCount) { + BlockStack blockStack = new BlockStack(); + blockStack.block = block; + blockStack.player = player; + blockStack.originalCount = originalCount; + blockStack.newCount = newCount; + return !fireEvent(BLOCK_STACK_EVENT, blockStack).isCancelled(); + } + + public static boolean callBlockUnstackEvent(Block block, Player player, int originalCount, int newCount) { + BlockUnstack blockUnstack = new BlockUnstack(); + blockUnstack.block = block; + blockUnstack.player = player; + blockUnstack.originalCount = originalCount; + blockUnstack.newCount = newCount; + return !fireEvent(BLOCK_UNSTACK_EVENT, blockUnstack).isCancelled(); + } + + public static boolean callIslandBanEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) { + IslandBan islandBan = new IslandBan(); + islandBan.island = island; + islandBan.superiorPlayer = superiorPlayer; + islandBan.targetPlayer = targetPlayer; + return !fireEvent(ISLAND_BAN_EVENT, islandBan).isCancelled(); + } + + public static PluginEvent callIslandBankDepositEvent(Island island, CommandSender commandSender, BigDecimal amount) { + return callIslandBankDepositEvent(island, commandSenderToSuperiorPlayer(commandSender), amount); + } + + public static PluginEvent callIslandBankDepositEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, BigDecimal amount) { + IslandBankDeposit islandBankDeposit = new IslandBankDeposit(); + islandBankDeposit.island = island; + islandBankDeposit.superiorPlayer = superiorPlayer; + islandBankDeposit.amount = amount; + return fireEvent(ISLAND_BANK_DEPOSIT_EVENT, islandBankDeposit); + } + + public static PluginEvent callIslandBankWithdrawEvent(Island island, CommandSender commandSender, BigDecimal amount) { + return callIslandBankWithdrawEvent(island, commandSenderToSuperiorPlayer(commandSender), amount); + } + + public static PluginEvent callIslandBankWithdrawEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, BigDecimal amount) { + IslandBankWithdraw islandBankWithdraw = new IslandBankWithdraw(); + islandBankWithdraw.island = island; + islandBankWithdraw.superiorPlayer = superiorPlayer; + islandBankWithdraw.amount = amount; + return fireEvent(ISLAND_BANK_WITHDRAW_EVENT, islandBankWithdraw); + } + + public static PluginEvent callIslandBiomeChangeEvent(Island island, SuperiorPlayer superiorPlayer, Biome biome) { + IslandBiomeChange islandBiomeChange = new IslandBiomeChange(); + islandBiomeChange.island = island; + islandBiomeChange.superiorPlayer = superiorPlayer; + islandBiomeChange.biome = biome; + return fireEvent(ISLAND_BIOME_CHANGE_EVENT, islandBiomeChange); + } + + public static PluginEvent callIslandChangeBankLimitEvent(Island island, CommandSender commandSender, BigDecimal bankLimit) { + return callIslandChangeBankLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), bankLimit); + } + + public static PluginEvent callIslandChangeBankLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, BigDecimal bankLimit) { + IslandChangeBankLimit islandChangeBankLimit = new IslandChangeBankLimit(); + islandChangeBankLimit.island = island; + islandChangeBankLimit.superiorPlayer = superiorPlayer; + islandChangeBankLimit.bankLimit = bankLimit; + return fireEvent(ISLAND_CHANGE_BANK_LIMIT_EVENT, islandChangeBankLimit); + } + + public static PluginEvent callIslandChangeBlockLimitEvent(Island island, CommandSender commandSender, Key block, int blockLimit) { + return callIslandChangeBlockLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), block, blockLimit); + } + + public static PluginEvent callIslandChangeBlockLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key block, int blockLimit) { + IslandChangeBlockLimit islandChangeBlockLimit = new IslandChangeBlockLimit(); + islandChangeBlockLimit.island = island; + islandChangeBlockLimit.superiorPlayer = superiorPlayer; + islandChangeBlockLimit.block = block; + islandChangeBlockLimit.blockLimit = blockLimit; + return fireEvent(ISLAND_CHANGE_BLOCK_LIMIT_EVENT, islandChangeBlockLimit); + } + + public static PluginEvent callIslandChangeBorderSizeEvent(Island island, CommandSender commandSender, int borderSize) { + return callIslandChangeBorderSizeEvent(island, commandSenderToSuperiorPlayer(commandSender), borderSize); + } + + public static PluginEvent callIslandChangeBorderSizeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, int borderSize) { + IslandChangeBorderSize islandChangeBorderSize = new IslandChangeBorderSize(); + islandChangeBorderSize.island = island; + islandChangeBorderSize.superiorPlayer = superiorPlayer; + islandChangeBorderSize.borderSize = borderSize; + return fireEvent(ISLAND_CHANGE_BORDER_SIZE_EVENT, islandChangeBorderSize); + } + + public static PluginEvent callIslandChangeCoopLimitEvent(Island island, CommandSender commandSender, int coopLimit) { + return callIslandChangeCoopLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), coopLimit); + } + + public static PluginEvent callIslandChangeCoopLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, int coopLimit) { + IslandChangeCoopLimit islandChangeCoopLimit = new IslandChangeCoopLimit(); + islandChangeCoopLimit.island = island; + islandChangeCoopLimit.superiorPlayer = superiorPlayer; + islandChangeCoopLimit.coopLimit = coopLimit; + return fireEvent(ISLAND_CHANGE_COOP_LIMIT_EVENT, islandChangeCoopLimit); + } + + public static PluginEvent callIslandChangeCropGrowthEvent(Island island, CommandSender commandSender, double cropGrowth) { + return callIslandChangeCropGrowthEvent(island, commandSenderToSuperiorPlayer(commandSender), cropGrowth); + } + + public static PluginEvent callIslandChangeCropGrowthEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, double cropGrowth) { + IslandChangeCropGrowth islandChangeCropGrowth = new IslandChangeCropGrowth(); + islandChangeCropGrowth.island = island; + islandChangeCropGrowth.superiorPlayer = superiorPlayer; + islandChangeCropGrowth.cropGrowth = cropGrowth; + return fireEvent(ISLAND_CHANGE_CROP_GROWTH_EVENT, islandChangeCropGrowth); + } + + public static PluginEvent callIslandChangeDescriptionEvent(Island island, SuperiorPlayer superiorPlayer, String description) { + IslandChangeDescription islandChangeDescription = new IslandChangeDescription(); + islandChangeDescription.island = island; + islandChangeDescription.superiorPlayer = superiorPlayer; + islandChangeDescription.description = description; + return fireEvent(ISLAND_CHANGE_DESCRIPTION_EVENT, islandChangeDescription); + } + + public static PluginEvent callIslandChangeDiscordEvent(Island island, SuperiorPlayer superiorPlayer, String discord) { + IslandChangeDiscord islandChangeDiscord = new IslandChangeDiscord(); + islandChangeDiscord.island = island; + islandChangeDiscord.superiorPlayer = superiorPlayer; + islandChangeDiscord.discord = discord; + return fireEvent(ISLAND_CHANGE_DISCORD_EVENT, islandChangeDiscord); + } + + public static PluginEvent callIslandChangeEffectLevelEvent(Island island, CommandSender commandSender, + PotionEffectType effectType, int effectLevel) { + return callIslandChangeEffectLevelEvent(island, commandSenderToSuperiorPlayer(commandSender), effectType, effectLevel); + } + + public static PluginEvent callIslandChangeEffectLevelEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, + PotionEffectType effectType, int effectLevel) { + IslandChangeEffectLevel islandChangeEffectLevel = new IslandChangeEffectLevel(); + islandChangeEffectLevel.island = island; + islandChangeEffectLevel.superiorPlayer = superiorPlayer; + islandChangeEffectLevel.effectType = effectType; + islandChangeEffectLevel.effectLevel = effectLevel; + return fireEvent(ISLAND_CHANGE_EFFECT_LEVEL_EVENT, islandChangeEffectLevel); + } + + public static PluginEvent callIslandChangeEntityLimitEvent(Island island, CommandSender commandSender, + Key entity, int entityLimit) { + return callIslandChangeEntityLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), entity, entityLimit); + } + + public static PluginEvent callIslandChangeEntityLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, + Key entity, int entityLimit) { + IslandChangeEntityLimit islandChangeEntityLimit = new IslandChangeEntityLimit(); + islandChangeEntityLimit.island = island; + islandChangeEntityLimit.superiorPlayer = superiorPlayer; + islandChangeEntityLimit.entity = entity; + islandChangeEntityLimit.entityLimit = entityLimit; + return fireEvent(ISLAND_CHANGE_ENTITY_LIMIT_EVENT, islandChangeEntityLimit); + } + + public static PluginEvent callIslandChangeGeneratorRateEvent(Island island, CommandSender commandSender, + Key block, Dimension dimension, int generatorRate) { + return callIslandChangeGeneratorRateEvent(island, commandSenderToSuperiorPlayer(commandSender), block, dimension, generatorRate); + } + + public static PluginEvent callIslandChangeGeneratorRateEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, + Key block, Dimension dimension, int generatorRate) { + IslandChangeGeneratorRate islandChangeGeneratorRate = new IslandChangeGeneratorRate(); + islandChangeGeneratorRate.island = island; + islandChangeGeneratorRate.superiorPlayer = superiorPlayer; + islandChangeGeneratorRate.block = block; + islandChangeGeneratorRate.dimension = dimension; + islandChangeGeneratorRate.generatorRate = generatorRate; + return fireEvent(ISLAND_CHANGE_GENERATOR_RATE_EVENT, islandChangeGeneratorRate); + } + + public static PluginEvent callIslandChangeLevelBonusEvent(Island island, CommandSender commandSender, + IslandChangeLevelBonusEvent.Reason reason, BigDecimal levelBonus) { + return callIslandChangeLevelBonusEvent(island, commandSenderToSuperiorPlayer(commandSender), reason, levelBonus); + } + + public static PluginEvent callIslandChangeLevelBonusEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, + IslandChangeLevelBonusEvent.Reason reason, BigDecimal levelBonus) { + IslandChangeLevelBonus islandChangeLevelBonus = new IslandChangeLevelBonus(); + islandChangeLevelBonus.island = island; + islandChangeLevelBonus.superiorPlayer = superiorPlayer; + islandChangeLevelBonus.reason = reason; + islandChangeLevelBonus.levelBonus = levelBonus; + return fireEvent(ISLAND_CHANGE_LEVEL_BONUS_EVENT, islandChangeLevelBonus); + } + + public static PluginEvent callIslandChangeMembersLimitEvent(Island island, CommandSender commandSender, int membersLimit) { + return callIslandChangeMembersLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), membersLimit); + } + + public static PluginEvent callIslandChangeMembersLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, int membersLimit) { + IslandChangeMembersLimit islandChangeMembersLimit = new IslandChangeMembersLimit(); + islandChangeMembersLimit.island = island; + islandChangeMembersLimit.superiorPlayer = superiorPlayer; + islandChangeMembersLimit.membersLimit = membersLimit; + return fireEvent(ISLAND_CHANGE_MEMBERS_LIMIT_EVENT, islandChangeMembersLimit); + } + + public static PluginEvent callIslandChangeMobDropsEvent(Island island, CommandSender commandSender, double mobDrops) { + return callIslandChangeMobDropsEvent(island, commandSenderToSuperiorPlayer(commandSender), mobDrops); + } + + public static PluginEvent callIslandChangeMobDropsEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, double mobDrops) { + IslandChangeMobDrops islandChangeMobDrops = new IslandChangeMobDrops(); + islandChangeMobDrops.island = island; + islandChangeMobDrops.superiorPlayer = superiorPlayer; + islandChangeMobDrops.mobDrops = mobDrops; + return fireEvent(ISLAND_CHANGE_MOB_DROPS_EVENT, islandChangeMobDrops); + } + + public static PluginEvent callIslandChangePaypalEvent(Island island, SuperiorPlayer superiorPlayer, String paypal) { + IslandChangePaypal islandChangePaypal = new IslandChangePaypal(); + islandChangePaypal.island = island; + islandChangePaypal.superiorPlayer = superiorPlayer; + islandChangePaypal.paypal = paypal; + return fireEvent(ISLAND_CHANGE_PAYPAL_EVENT, islandChangePaypal); + } + + public static boolean callIslandChangePlayerPrivilegeEvent(Island island, SuperiorPlayer superiorPlayer, + SuperiorPlayer privilegedPlayer, boolean privilegeEnabled) { + IslandChangePlayerPrivilege islandChangePlayerPrivilege = new IslandChangePlayerPrivilege(); + islandChangePlayerPrivilege.island = island; + islandChangePlayerPrivilege.superiorPlayer = superiorPlayer; + islandChangePlayerPrivilege.privilegedPlayer = privilegedPlayer; + islandChangePlayerPrivilege.privilegeEnabled = privilegeEnabled; + return !fireEvent(ISLAND_CHANGE_PLAYER_PRIVILEGE_EVENT, islandChangePlayerPrivilege).isCancelled(); + } + + public static PluginEvent callIslandChangeRoleLimitEvent(Island island, CommandSender commandSender, + PlayerRole playerRole, int roleLimit) { + return callIslandChangeRoleLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), playerRole, roleLimit); + } + + public static PluginEvent callIslandChangeRoleLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, + PlayerRole playerRole, int roleLimit) { + IslandChangeRoleLimit islandChangeRoleLimit = new IslandChangeRoleLimit(); + islandChangeRoleLimit.island = island; + islandChangeRoleLimit.superiorPlayer = superiorPlayer; + islandChangeRoleLimit.playerRole = playerRole; + islandChangeRoleLimit.roleLimit = roleLimit; + return fireEvent(ISLAND_CHANGE_ROLE_LIMIT_EVENT, islandChangeRoleLimit); + } + + public static PluginEvent callIslandChangeSpawnerRatesEvent(Island island, CommandSender commandSender, double spawnerRates) { + return callIslandChangeSpawnerRatesEvent(island, commandSenderToSuperiorPlayer(commandSender), spawnerRates); + } + + public static PluginEvent callIslandChangeSpawnerRatesEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, double spawnerRates) { + IslandChangeSpawnerRates islandChangeSpawnerRates = new IslandChangeSpawnerRates(); + islandChangeSpawnerRates.island = island; + islandChangeSpawnerRates.superiorPlayer = superiorPlayer; + islandChangeSpawnerRates.spawnerRates = spawnerRates; + return fireEvent(ISLAND_CHANGE_SPAWNER_RATES_EVENT, islandChangeSpawnerRates); + } + + public static PluginEvent callIslandChangeWarpCategoryIconEvent(Island island, SuperiorPlayer superiorPlayer, + WarpCategory warpCategory, @Nullable ItemStack icon) { + IslandChangeWarpCategoryIcon islandChangeWarpCategoryIcon = new IslandChangeWarpCategoryIcon(); + islandChangeWarpCategoryIcon.island = island; + islandChangeWarpCategoryIcon.superiorPlayer = superiorPlayer; + islandChangeWarpCategoryIcon.warpCategory = warpCategory; + islandChangeWarpCategoryIcon.icon = icon; + return fireEvent(ISLAND_CHANGE_WARP_CATEGORY_ICON_EVENT, islandChangeWarpCategoryIcon); + } + + public static PluginEvent callIslandChangeWarpCategorySlotEvent(Island island, SuperiorPlayer superiorPlayer, + WarpCategory warpCategory, int slot, int maxSlot) { + IslandChangeWarpCategorySlot islandChangeWarpCategorySlot = new IslandChangeWarpCategorySlot(); + islandChangeWarpCategorySlot.island = island; + islandChangeWarpCategorySlot.superiorPlayer = superiorPlayer; + islandChangeWarpCategorySlot.warpCategory = warpCategory; + islandChangeWarpCategorySlot.slot = slot; + islandChangeWarpCategorySlot.maxSlot = maxSlot; + return fireEvent(ISLAND_CHANGE_WARP_CATEGORY_SLOT_EVENT, islandChangeWarpCategorySlot); + } + + public static PluginEvent callIslandChangeWarpIconEvent(Island island, SuperiorPlayer superiorPlayer, + IslandWarp islandWarp, @Nullable ItemStack icon) { + IslandChangeWarpIcon islandChangeWarpIcon = new IslandChangeWarpIcon(); + islandChangeWarpIcon.island = island; + islandChangeWarpIcon.superiorPlayer = superiorPlayer; + islandChangeWarpIcon.islandWarp = islandWarp; + islandChangeWarpIcon.icon = icon; + return fireEvent(ISLAND_CHANGE_WARP_ICON_EVENT, islandChangeWarpIcon); + } + + public static PluginEvent callIslandChangeWarpLocationEvent(Island island, Player player, + IslandWarp islandWarp, Location location) { + return callIslandChangeWarpLocationEvent(island, commandSenderToSuperiorPlayer(player), islandWarp, location); + } + + public static PluginEvent callIslandChangeWarpLocationEvent(Island island, SuperiorPlayer superiorPlayer, + IslandWarp islandWarp, Location location) { + IslandChangeWarpLocation islandChangeWarpLocation = new IslandChangeWarpLocation(); + islandChangeWarpLocation.island = island; + islandChangeWarpLocation.superiorPlayer = superiorPlayer; + islandChangeWarpLocation.islandWarp = islandWarp; + islandChangeWarpLocation.location = location; + return fireEvent(ISLAND_CHANGE_WARP_LOCATION_EVENT, islandChangeWarpLocation); + } + + public static PluginEvent callIslandChangeWarpsLimitEvent(Island island, CommandSender commandSender, int warpsLimit) { + return callIslandChangeWarpsLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), warpsLimit); + } + + public static PluginEvent callIslandChangeWarpsLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, int warpsLimit) { + IslandChangeWarpsLimit islandChangeWarpsLimit = new IslandChangeWarpsLimit(); + islandChangeWarpsLimit.island = island; + islandChangeWarpsLimit.superiorPlayer = superiorPlayer; + islandChangeWarpsLimit.warpsLimit = warpsLimit; + return fireEvent(ISLAND_CHANGE_WARPS_LIMIT_EVENT, islandChangeWarpsLimit); + } + + public static PluginEvent callIslandChangeWorthBonusEvent(Island island, CommandSender commandSender, + IslandChangeWorthBonusEvent.Reason reason, BigDecimal worthBonus) { + return callIslandChangeWorthBonusEvent(island, commandSenderToSuperiorPlayer(commandSender), reason, worthBonus); + } + + public static PluginEvent callIslandChangeWorthBonusEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, + IslandChangeWorthBonusEvent.Reason reason, BigDecimal worthBonus) { + IslandChangeWorthBonus islandChangeWorthBonus = new IslandChangeWorthBonus(); + islandChangeWorthBonus.island = island; + islandChangeWorthBonus.superiorPlayer = superiorPlayer; + islandChangeWorthBonus.reason = reason; + islandChangeWorthBonus.worthBonus = worthBonus; + return fireEvent(ISLAND_CHANGE_WORTH_BONUS_EVENT, islandChangeWorthBonus); + } + + public static boolean callIslandChangeRolePrivilegeEvent(Island island, CommandSender commandSender, PlayerRole playerRole) { + return callIslandChangeRolePrivilegeEvent(island, commandSenderToSuperiorPlayer(commandSender), playerRole); + } + + public static boolean callIslandChangeRolePrivilegeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PlayerRole playerRole) { + IslandChangeRolePrivilege islandChangeRolePrivilege = new IslandChangeRolePrivilege(); + islandChangeRolePrivilege.island = island; + islandChangeRolePrivilege.superiorPlayer = superiorPlayer; + islandChangeRolePrivilege.playerRole = playerRole; + return !fireEvent(ISLAND_CHANGE_ROLE_PRIVILEGE_EVENT, islandChangeRolePrivilege).isCancelled(); + } + + public static PluginEvent callIslandChatEvent(Island island, SuperiorPlayer superiorPlayer, String message) { + IslandChat islandChat = new IslandChat(); + islandChat.island = island; + islandChat.superiorPlayer = superiorPlayer; + islandChat.message = message; + return fireEvent(ISLAND_CHAT_EVENT, islandChat); + } + + public static void callIslandChunkResetEvent(Island island, ChunkPosition chunkPosition) { + IslandChunkReset islandChunkReset = new IslandChunkReset(); + islandChunkReset.island = island; + islandChunkReset.chunkPosition = chunkPosition; + fireEvent(ISLAND_CHUNK_RESET_EVENT, islandChunkReset); + } + + public static boolean callIslandClearGeneratorRatesEvent(Island island, CommandSender commandSender, Dimension dimension) { + return callIslandClearGeneratorRatesEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension); + } + + public static boolean callIslandClearGeneratorRatesEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Dimension dimension) { + IslandClearGeneratorRates islandClearGeneratorRates = new IslandClearGeneratorRates(); + islandClearGeneratorRates.island = island; + islandClearGeneratorRates.superiorPlayer = superiorPlayer; + islandClearGeneratorRates.dimension = dimension; + return !fireEvent(ISLAND_CLEAR_GENERATOR_RATES_EVENT, islandClearGeneratorRates).isCancelled(); + } + + public static boolean callIslandClearPlayerPrivilegesEvent(Island island, SuperiorPlayer superiorPlayer, + SuperiorPlayer privilegedPlayer) { + IslandClearPlayerPrivileges islandClearPlayerPrivileges = new IslandClearPlayerPrivileges(); + islandClearPlayerPrivileges.island = island; + islandClearPlayerPrivileges.superiorPlayer = superiorPlayer; + islandClearPlayerPrivileges.privilegedPlayer = privilegedPlayer; + return !fireEvent(ISLAND_CLEAR_PLAYER_PRIVILEGES_EVENT, islandClearPlayerPrivileges).isCancelled(); + } + + public static boolean callIslandClearRatingsEvent(Island island, CommandSender commandSender) { + return callIslandClearRatingsEvent(island, commandSenderToSuperiorPlayer(commandSender)); + } + + public static boolean callIslandClearRatingsEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) { + IslandClearRatings islandClearRatings = new IslandClearRatings(); + islandClearRatings.island = island; + islandClearRatings.superiorPlayer = superiorPlayer; + return !fireEvent(ISLAND_CLEAR_RATINGS_EVENT, islandClearRatings).isCancelled(); + } + + public static boolean callIslandClearRolesPrivilegesEvent(Island island, SuperiorPlayer superiorPlayer) { + IslandClearRolesPrivileges islandClearRolesPrivileges = new IslandClearRolesPrivileges(); + islandClearRolesPrivileges.island = island; + islandClearRolesPrivileges.superiorPlayer = superiorPlayer; + return !fireEvent(ISLAND_CLEAR_ROLES_PRIVILEGES_EVENT, islandClearRolesPrivileges).isCancelled(); + } + + public static boolean callIslandCloseEvent(Island island, CommandSender commandSender) { + return callIslandCloseEvent(island, commandSenderToSuperiorPlayer(commandSender)); + } + + public static boolean callIslandCloseEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) { + IslandClose islandClose = new IslandClose(); + islandClose.island = island; + islandClose.superiorPlayer = superiorPlayer; + return !fireEvent(ISLAND_CLOSE_EVENT, islandClose).isCancelled(); + } + + public static boolean callIslandCloseWarpEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { + IslandCloseWarp islandCloseWarp = new IslandCloseWarp(); + islandCloseWarp.island = island; + islandCloseWarp.superiorPlayer = superiorPlayer; + islandCloseWarp.islandWarp = islandWarp; + return !fireEvent(ISLAND_CLOSE_WARP_EVENT, islandCloseWarp).isCancelled(); + } + + public static boolean callIslandCoopPlayerEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) { + IslandCoopPlayer islandCoopPlayer = new IslandCoopPlayer(); + islandCoopPlayer.island = island; + islandCoopPlayer.superiorPlayer = superiorPlayer; + islandCoopPlayer.targetPlayer = targetPlayer; + return !fireEvent(ISLAND_COOP_PLAYER_EVENT, islandCoopPlayer).isCancelled(); + } + + public static PluginEvent callIslandCreateEvent(Island island, SuperiorPlayer superiorPlayer, String schematicName) { + IslandCreate islandCreate = new IslandCreate(); + islandCreate.island = island; + islandCreate.superiorPlayer = superiorPlayer; + islandCreate.schematicName = schematicName; + return fireEvent(ISLAND_CREATE_EVENT, islandCreate); + } + + public static boolean callIslandCreateWarpCategoryEvent(Island island, SuperiorPlayer superiorPlayer, String categoryName) { + IslandCreateWarpCategory islandCreateWarpCategory = new IslandCreateWarpCategory(); + islandCreateWarpCategory.island = island; + islandCreateWarpCategory.superiorPlayer = superiorPlayer; + islandCreateWarpCategory.categoryName = categoryName; + return !fireEvent(ISLAND_CREATE_WARP_CATEGORY_EVENT, islandCreateWarpCategory).isCancelled(); + } + + public static boolean callIslandCreateWarpEvent(Island island, SuperiorPlayer superiorPlayer, String warpName, + Location location, @Nullable WarpCategory warpCategory) { + return callIslandCreateWarpEvent(island, superiorPlayer, warpName, location, plugin.getSettings().isPublicWarps(), warpCategory); + } + + public static boolean callIslandCreateWarpEvent(Island island, SuperiorPlayer superiorPlayer, String warpName, + Location location, boolean openToPublic, @Nullable WarpCategory warpCategory) { + IslandCreateWarp islandCreateWarp = new IslandCreateWarp(); + islandCreateWarp.island = island; + islandCreateWarp.superiorPlayer = superiorPlayer; + islandCreateWarp.warpName = warpName; + islandCreateWarp.location = location; + islandCreateWarp.openToPublic = openToPublic; + islandCreateWarp.warpCategory = warpCategory; + return !fireEvent(ISLAND_CREATE_WARP_EVENT, islandCreateWarp).isCancelled(); + } + + public static boolean callIslandDeleteWarpEvent(Island island, CommandSender commandSender, IslandWarp islandWarp) { + return callIslandDeleteWarpEvent(island, commandSenderToSuperiorPlayer(commandSender), islandWarp); + } + + public static boolean callIslandDeleteWarpEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { + IslandDeleteWarp islandDeleteWarp = new IslandDeleteWarp(); + islandDeleteWarp.island = island; + islandDeleteWarp.superiorPlayer = superiorPlayer; + islandDeleteWarp.islandWarp = islandWarp; + return !fireEvent(ISLAND_DELETE_WARP_EVENT, islandDeleteWarp).isCancelled(); + } + + public static boolean callIslandDisableFlagEvent(Island island, CommandSender commandSender, IslandFlag islandFlag) { + return callIslandDisableFlagEvent(island, commandSenderToSuperiorPlayer(commandSender), islandFlag); + } + + public static boolean callIslandDisableFlagEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, IslandFlag islandFlag) { + IslandDisableFlag islandDisableFlag = new IslandDisableFlag(); + islandDisableFlag.island = island; + islandDisableFlag.superiorPlayer = superiorPlayer; + islandDisableFlag.islandFlag = islandFlag; + return !fireEvent(ISLAND_DISABLE_FLAG_EVENT, islandDisableFlag).isCancelled(); + } + + public static boolean callIslandDisbandEvent(Island island, SuperiorPlayer superiorPlayer) { + IslandDisband islandDisband = new IslandDisband(); + islandDisband.island = island; + islandDisband.superiorPlayer = superiorPlayer; + return !fireEvent(ISLAND_DISBAND_EVENT, islandDisband).isCancelled(); + } + + public static boolean callIslandEnableFlagEvent(Island island, CommandSender commandSender, IslandFlag islandFlag) { + return callIslandEnableFlagEvent(island, commandSenderToSuperiorPlayer(commandSender), islandFlag); + } + + public static boolean callIslandEnableFlagEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, IslandFlag islandFlag) { + IslandEnableFlag islandEnableFlag = new IslandEnableFlag(); + islandEnableFlag.island = island; + islandEnableFlag.superiorPlayer = superiorPlayer; + islandEnableFlag.islandFlag = islandFlag; + return !fireEvent(ISLAND_ENABLE_FLAG_EVENT, islandEnableFlag).isCancelled(); + } + + public static boolean callIslandEnterEvent(Island island, SuperiorPlayer superiorPlayer, IslandEnterEvent.EnterCause enterCause) { + IslandEnter islandEnter = new IslandEnter(); + islandEnter.island = island; + islandEnter.superiorPlayer = superiorPlayer; + islandEnter.enterCause = enterCause; + return !fireEvent(ISLAND_ENTER_EVENT, islandEnter).isCancelled(); + } + + public static PluginEvent callIslandEnterPortalEvent(Island island, SuperiorPlayer superiorPlayer, + PortalType portalType, Dimension destination, + @Nullable Schematic schematic, boolean ignoreInvalidSchematic) { + IslandEnterPortal islandEnterPortal = new IslandEnterPortal(); + islandEnterPortal.island = island; + islandEnterPortal.superiorPlayer = superiorPlayer; + islandEnterPortal.portalType = portalType; + islandEnterPortal.destination = destination; + islandEnterPortal.schematic = schematic; + islandEnterPortal.ignoreInvalidSchematic = ignoreInvalidSchematic; + return fireEvent(ISLAND_ENTER_PORTAL_EVENT, islandEnterPortal); + } + + public static boolean callIslandEnterProtectedEvent(Island island, SuperiorPlayer superiorPlayer, IslandEnterEvent.EnterCause enterCause) { + IslandEnterProtected islandEnterProtected = new IslandEnterProtected(); + islandEnterProtected.island = island; + islandEnterProtected.superiorPlayer = superiorPlayer; + islandEnterProtected.enterCause = enterCause; + return !fireEvent(ISLAND_ENTER_PROTECTED_EVENT, islandEnterProtected).isCancelled(); + } + + public static PluginEvent callIslandGenerateBlockEvent(Island island, Location location, Key block) { + IslandGenerateBlock islandGenerateBlock = new IslandGenerateBlock(); + islandGenerateBlock.island = island; + islandGenerateBlock.location = location; + islandGenerateBlock.block = block; + return fireEvent(ISLAND_GENERATE_BLOCK_EVENT, islandGenerateBlock); + } + + public static boolean callIslandInviteEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) { + IslandInvite islandInvite = new IslandInvite(); + islandInvite.island = island; + islandInvite.superiorPlayer = superiorPlayer; + islandInvite.targetPlayer = targetPlayer; + return !fireEvent(ISLAND_INVITE_EVENT, islandInvite).isCancelled(); + } + + public static boolean callIslandJoinEvent(Island island, SuperiorPlayer superiorPlayer, IslandJoinEvent.Cause joinCause) { + IslandJoin islandJoin = new IslandJoin(); + islandJoin.island = island; + islandJoin.superiorPlayer = superiorPlayer; + islandJoin.joinCause = joinCause; + return !fireEvent(ISLAND_JOIN_EVENT, islandJoin).isCancelled(); + } + + public static boolean callIslandKickEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) { + IslandKick islandKick = new IslandKick(); + islandKick.island = island; + islandKick.superiorPlayer = superiorPlayer; + islandKick.targetPlayer = targetPlayer; + return !fireEvent(ISLAND_KICK_EVENT, islandKick).isCancelled(); + } + + public static boolean callIslandLeaveEvent(Island island, SuperiorPlayer superiorPlayer, + IslandLeaveEvent.LeaveCause leaveCause, Location location) { + IslandLeave islandLeave = new IslandLeave(); + islandLeave.island = island; + islandLeave.superiorPlayer = superiorPlayer; + islandLeave.leaveCause = leaveCause; + islandLeave.location = location; + return !fireEvent(ISLAND_LEAVE_EVENT, islandLeave).isCancelled(); + } + + public static boolean callIslandLeaveProtectedEvent(Island island, SuperiorPlayer superiorPlayer, + IslandLeaveEvent.LeaveCause leaveCause, Location location) { + IslandLeaveProtected islandLeaveProtected = new IslandLeaveProtected(); + islandLeaveProtected.island = island; + islandLeaveProtected.superiorPlayer = superiorPlayer; + islandLeaveProtected.leaveCause = leaveCause; + islandLeaveProtected.location = location; + return !fireEvent(ISLAND_LEAVE_PROTECTED_EVENT, islandLeaveProtected).isCancelled(); + } + + public static boolean callIslandLockWorldEvent(Island island, CommandSender commandSender, Dimension dimension) { + return callIslandLockWorldEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension); + } + + public static boolean callIslandLockWorldEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Dimension dimension) { + IslandLockWorld islandLockWorld = new IslandLockWorld(); + islandLockWorld.island = island; + islandLockWorld.superiorPlayer = superiorPlayer; + islandLockWorld.dimension = dimension; + return !fireEvent(ISLAND_LOCK_WORLD_EVENT, islandLockWorld).isCancelled(); + } + + public static boolean callIslandOpenEvent(Island island, CommandSender commandSender) { + return callIslandOpenEvent(island, commandSenderToSuperiorPlayer(commandSender)); + } + + public static boolean callIslandOpenEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) { + IslandOpen islandOpen = new IslandOpen(); + islandOpen.island = island; + islandOpen.superiorPlayer = superiorPlayer; + return !fireEvent(ISLAND_OPEN_EVENT, islandOpen).isCancelled(); + } + + public static boolean callIslandOpenWarpEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { + IslandOpenWarp islandOpenWarp = new IslandOpenWarp(); + islandOpenWarp.island = island; + islandOpenWarp.superiorPlayer = superiorPlayer; + islandOpenWarp.islandWarp = islandWarp; + return !fireEvent(ISLAND_OPEN_WARP_EVENT, islandOpenWarp).isCancelled(); + } + + public static boolean callIslandQuitEvent(Island island, SuperiorPlayer superiorPlayer) { + IslandQuit islandQuit = new IslandQuit(); + islandQuit.island = island; + islandQuit.superiorPlayer = superiorPlayer; + return !fireEvent(ISLAND_QUIT_EVENT, islandQuit).isCancelled(); + } + + public static boolean callIslandRateEvent(Island island, CommandSender commandSender, SuperiorPlayer ratingPlayer, Rating rating) { + return callIslandRateEvent(island, commandSenderToSuperiorPlayer(commandSender), ratingPlayer, rating); + } + + public static boolean callIslandRateEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, SuperiorPlayer ratingPlayer, Rating rating) { + IslandRate islandRate = new IslandRate(); + islandRate.island = island; + islandRate.superiorPlayer = superiorPlayer; + islandRate.ratingPlayer = ratingPlayer; + islandRate.rating = rating; + return !fireEvent(ISLAND_RATE_EVENT, islandRate).isCancelled(); + } + + public static boolean callIslandRemoveBlockLimitEvent(Island island, CommandSender commandSender, Key block) { + return callIslandRemoveBlockLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), block); + } + + public static boolean callIslandRemoveBlockLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key block) { + IslandRemoveBlockLimit islandRemoveBlockLimit = new IslandRemoveBlockLimit(); + islandRemoveBlockLimit.island = island; + islandRemoveBlockLimit.superiorPlayer = superiorPlayer; + islandRemoveBlockLimit.block = block; + return !fireEvent(ISLAND_REMOVE_BLOCK_LIMIT_EVENT, islandRemoveBlockLimit).isCancelled(); + } + + public static boolean callIslandRemoveEffectEvent(Island island, CommandSender commandSender, PotionEffectType effectType) { + return callIslandRemoveEffectEvent(island, commandSenderToSuperiorPlayer(commandSender), effectType); + } + + public static boolean callIslandRemoveEffectEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PotionEffectType effectType) { + IslandRemoveEffect islandRemoveEffect = new IslandRemoveEffect(); + islandRemoveEffect.island = island; + islandRemoveEffect.superiorPlayer = superiorPlayer; + islandRemoveEffect.effectType = effectType; + return !fireEvent(ISLAND_REMOVE_EFFECT_EVENT, islandRemoveEffect).isCancelled(); + } + + public static boolean callIslandRemoveGeneratorRateEvent(Island island, CommandSender commandSender, Key block, Dimension dimension) { + return callIslandRemoveGeneratorRateEvent(island, commandSenderToSuperiorPlayer(commandSender), block, dimension); + } + + public static boolean callIslandRemoveGeneratorRateEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key block, Dimension dimension) { + IslandRemoveGeneratorRate islandRemoveGeneratorRate = new IslandRemoveGeneratorRate(); + islandRemoveGeneratorRate.island = island; + islandRemoveGeneratorRate.superiorPlayer = superiorPlayer; + islandRemoveGeneratorRate.block = block; + islandRemoveGeneratorRate.dimension = dimension; + return !fireEvent(ISLAND_REMOVE_GENERATOR_RATE_EVENT, islandRemoveGeneratorRate).isCancelled(); + } + + public static boolean callIslandRemoveRatingEvent(Island island, CommandSender commandSender, SuperiorPlayer ratingPlayer) { + return callIslandRemoveRatingEvent(island, commandSenderToSuperiorPlayer(commandSender), ratingPlayer); + } + + public static boolean callIslandRemoveRatingEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, SuperiorPlayer ratingPlayer) { + IslandRemoveRating islandRemoveRating = new IslandRemoveRating(); + islandRemoveRating.island = island; + islandRemoveRating.superiorPlayer = superiorPlayer; + islandRemoveRating.ratingPlayer = ratingPlayer; + return !fireEvent(ISLAND_REMOVE_RATING_EVENT, islandRemoveRating).isCancelled(); + } + + public static boolean callIslandRemoveRoleLimitEvent(Island island, CommandSender commandSender, PlayerRole playerRole) { + return callIslandRemoveRoleLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), playerRole); + } + + public static boolean callIslandRemoveRoleLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, PlayerRole playerRole) { + IslandRemoveRoleLimit islandRemoveRoleLimit = new IslandRemoveRoleLimit(); + islandRemoveRoleLimit.island = island; + islandRemoveRoleLimit.superiorPlayer = superiorPlayer; + islandRemoveRoleLimit.playerRole = playerRole; + return !fireEvent(ISLAND_REMOVE_ROLE_LIMIT_EVENT, islandRemoveRoleLimit).isCancelled(); + } + + public static boolean callIslandRemoveVisitorHomeEvent(Island island, SuperiorPlayer superiorPlayer) { + IslandRemoveVisitorHome islandRemoveVisitorHome = new IslandRemoveVisitorHome(); + islandRemoveVisitorHome.island = island; + islandRemoveVisitorHome.superiorPlayer = superiorPlayer; + return !fireEvent(ISLAND_REMOVE_VISITOR_HOME_EVENT, islandRemoveVisitorHome).isCancelled(); + } + + public static PluginEvent callIslandRenameEvent(Island island, CommandSender commandSender, String islandName) { + return callIslandRenameEvent(island, commandSenderToSuperiorPlayer(commandSender), islandName); + } + + public static PluginEvent callIslandRenameEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, String islandName) { + IslandRename islandRename = new IslandRename(); + islandRename.island = island; + islandRename.superiorPlayer = superiorPlayer; + islandRename.islandName = islandName; + return fireEvent(ISLAND_RENAME_EVENT, islandRename); + } + + public static PluginEvent callIslandRenameWarpCategoryEvent(Island island, SuperiorPlayer superiorPlayer, + WarpCategory warpCategory, String categoryName) { + IslandRenameWarpCategory islandRenameWarpCategory = new IslandRenameWarpCategory(); + islandRenameWarpCategory.island = island; + islandRenameWarpCategory.superiorPlayer = superiorPlayer; + islandRenameWarpCategory.warpCategory = warpCategory; + islandRenameWarpCategory.categoryName = categoryName; + return fireEvent(ISLAND_RENAME_WARP_CATEGORY_EVENT, islandRenameWarpCategory); + } + + public static PluginEvent callIslandRenameWarpEvent(Island island, Player player, + IslandWarp islandWarp, String warpName) { + return callIslandRenameWarpEvent(island, commandSenderToSuperiorPlayer(player), islandWarp, warpName); + } + + public static PluginEvent callIslandRenameWarpEvent(Island island, SuperiorPlayer superiorPlayer, + IslandWarp islandWarp, String warpName) { + IslandRenameWarp islandRenameWarp = new IslandRenameWarp(); + islandRenameWarp.island = island; + islandRenameWarp.superiorPlayer = superiorPlayer; + islandRenameWarp.islandWarp = islandWarp; + islandRenameWarp.warpName = warpName; + return fireEvent(ISLAND_RENAME_WARP_EVENT, islandRenameWarp); + } + + public static void callIslandRestrictMoveEvent(Island island, SuperiorPlayer superiorPlayer, IslandRestrictMoveEvent.RestrictReason restrictReason) { + IslandRestrictMove islandRestrictMove = new IslandRestrictMove(); + islandRestrictMove.island = island; + islandRestrictMove.superiorPlayer = superiorPlayer; + islandRestrictMove.restrictReason = restrictReason; + fireEvent(ISLAND_RESTRICT_MOVE_EVENT, islandRestrictMove); + } + + public static void callIslandSchematicPasteEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, String schematicName, Location location) { + IslandSchematicPaste islandSchematicPaste = new IslandSchematicPaste(); + islandSchematicPaste.island = island; + islandSchematicPaste.superiorPlayer = superiorPlayer; + islandSchematicPaste.schematicName = schematicName; + islandSchematicPaste.location = location; + fireEvent(ISLAND_SCHEMATIC_PASTE_EVENT, islandSchematicPaste); + } + + public static PluginEvent callIslandSetHomeEvent(Island island, CommandSender commandSender, + Location islandHome, IslandSetHomeEvent.Reason reason) { + return callIslandSetHomeEvent(island, commandSenderToSuperiorPlayer(commandSender), islandHome, reason); + } + + public static PluginEvent callIslandSetHomeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, + Location islandHome, IslandSetHomeEvent.Reason reason) { + IslandSetHome islandRenameWarp = new IslandSetHome(); + islandRenameWarp.island = island; + islandRenameWarp.superiorPlayer = superiorPlayer; + islandRenameWarp.islandHome = islandHome; + islandRenameWarp.reason = reason; + return fireEvent(ISLAND_SET_HOME_EVENT, islandRenameWarp); + } + + public static PluginEvent callIslandSetVisitorHomeEvent(Island island, SuperiorPlayer superiorPlayer, + Location islandVisitorHome) { + IslandSetVisitorHome islandSetVisitorHome = new IslandSetVisitorHome(); + islandSetVisitorHome.island = island; + islandSetVisitorHome.superiorPlayer = superiorPlayer; + islandSetVisitorHome.islandVisitorHome = islandVisitorHome; + return fireEvent(ISLAND_SET_VISITOR_HOME_EVENT, islandSetVisitorHome); + } + + public static boolean callIslandTransferEvent(Island island, SuperiorPlayer previousOwner, SuperiorPlayer superiorPlayer) { + IslandTransfer islandTransfer = new IslandTransfer(); + islandTransfer.island = island; + islandTransfer.superiorPlayer = superiorPlayer; + islandTransfer.previousOwner = previousOwner; + return !fireEvent(ISLAND_TRANSFER_EVENT, islandTransfer).isCancelled(); + } + + public static boolean callIslandUnbanEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer unbannedPlayer) { + IslandUnban islandUnban = new IslandUnban(); + islandUnban.island = island; + islandUnban.superiorPlayer = superiorPlayer; + islandUnban.unbannedPlayer = unbannedPlayer; + return !fireEvent(ISLAND_UNBAN_EVENT, islandUnban).isCancelled(); + } + + public static boolean callIslandUncoopPlayerEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer, + IslandUncoopPlayerEvent.UncoopReason uncoopReason) { + IslandUncoopPlayer islandUncoopPlayer = new IslandUncoopPlayer(); + islandUncoopPlayer.island = island; + islandUncoopPlayer.superiorPlayer = superiorPlayer; + islandUncoopPlayer.targetPlayer = targetPlayer; + islandUncoopPlayer.uncoopReason = uncoopReason; + return !fireEvent(ISLAND_UNCOOP_PLAYER_EVENT, islandUncoopPlayer).isCancelled(); + } + + public static boolean callIslandUnlockWorldEvent(Island island, CommandSender commandSender, Dimension dimension) { + return callIslandUnlockWorldEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension); + } + + public static boolean callIslandUnlockWorldEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Dimension dimension) { + IslandUnlockWorld islandUncoopPlayer = new IslandUnlockWorld(); + islandUncoopPlayer.island = island; + islandUncoopPlayer.superiorPlayer = superiorPlayer; + islandUncoopPlayer.dimension = dimension; + return !fireEvent(ISLAND_UNLOCK_WORLD_EVENT, islandUncoopPlayer).isCancelled(); + } + + public static PluginEvent callIslandUpgradeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, + Upgrade upgrade, UpgradeLevel currentLevel, + UpgradeLevel nextLevel, IslandUpgradeEvent.Cause upgradeCause) { + return callIslandUpgradeEvent(island, superiorPlayer, upgrade, nextLevel, currentLevel.getCommands(), + upgradeCause, currentLevel.getCost()); + } + + public static PluginEvent callIslandUpgradeEvent(Island island, CommandSender commandSender, + Upgrade upgrade, UpgradeLevel nextLevel, + IslandUpgradeEvent.Cause upgradeCause) { + return callIslandUpgradeEvent(island, commandSenderToSuperiorPlayer(commandSender), upgrade, nextLevel, + Collections.emptyList(), upgradeCause, null); + } + + public static PluginEvent callIslandUpgradeEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, + Upgrade upgrade, UpgradeLevel nextLevel, + List commands, IslandUpgradeEvent.Cause upgradeCause, + @Nullable UpgradeCost upgradeCost) { + IslandUpgrade islandUpgrade = new IslandUpgrade(); + islandUpgrade.island = island; + islandUpgrade.superiorPlayer = superiorPlayer; + islandUpgrade.upgrade = upgrade; + islandUpgrade.nextLevel = nextLevel; + islandUpgrade.commands = commands; + islandUpgrade.upgradeCause = upgradeCause; + islandUpgrade.upgradeCost = upgradeCost; + return fireEvent(ISLAND_UPGRADE_EVENT, islandUpgrade); + } + + public static boolean callIslandWorldResetEvent(Island island, CommandSender commandSender, Dimension dimension) { + return callIslandWorldResetEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension); + } + + public static boolean callIslandWorldResetEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Dimension dimension) { + IslandWorldReset islandWorldReset = new IslandWorldReset(); + islandWorldReset.island = island; + islandWorldReset.superiorPlayer = superiorPlayer; + islandWorldReset.dimension = dimension; + return !fireEvent(ISLAND_WORLD_RESET_EVENT, islandWorldReset).isCancelled(); + } + + public static void callIslandWorthCalculatedEvent(Island island, SuperiorPlayer asker, BigDecimal islandLevel, BigDecimal islandWorth) { + IslandWorthCalculated islandWorthCalculated = new IslandWorthCalculated(); + islandWorthCalculated.island = island; + islandWorthCalculated.superiorPlayer = asker; + islandWorthCalculated.islandLevel = islandLevel; + islandWorthCalculated.islandWorth = islandWorth; + fireEvent(ISLAND_WORTH_CALCULATED_EVENT, islandWorthCalculated); + } + + public static void callIslandWorthUpdateEvent(Island island, BigDecimal oldWorth, BigDecimal oldLevel, BigDecimal newWorth, BigDecimal newLevel) { + IslandWorthUpdate islandWorthUpdate = new IslandWorthUpdate(); + islandWorthUpdate.island = island; + islandWorthUpdate.oldWorth = oldWorth; + islandWorthUpdate.oldLevel = oldLevel; + islandWorthUpdate.newWorth = newWorth; + islandWorthUpdate.newLevel = newLevel; + fireEvent(ISLAND_WORTH_UPDATE_EVENT, islandWorthUpdate); + } + + public static PluginEvent callMissionCompleteEvent(SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder, + Mission mission, List itemRewards, + List commandRewards) { + MissionComplete missionComplete = new MissionComplete(); + missionComplete.superiorPlayer = superiorPlayer; + missionComplete.missionsHolder = missionsHolder; + missionComplete.mission = mission; + missionComplete.itemRewards = itemRewards; + missionComplete.commandRewards = commandRewards; + return fireEvent(MISSION_COMPLETE_EVENT, missionComplete); + } + + public static boolean callMissionResetEvent(CommandSender commandSender, IMissionsHolder missionsHolder, Mission mission) { + return callMissionResetEvent(commandSenderToSuperiorPlayer(commandSender), missionsHolder, mission); + } + + public static boolean callMissionResetEvent(@Nullable SuperiorPlayer superiorPlayer, IMissionsHolder missionsHolder, Mission mission) { + MissionReset missionReset = new MissionReset(); + missionReset.superiorPlayer = superiorPlayer; + missionReset.missionsHolder = missionsHolder; + missionReset.mission = mission; + return !fireEvent(MISSION_RESET_EVENT, missionReset).isCancelled(); + } + + public static boolean callPlayerChangeBorderColorEvent(SuperiorPlayer superiorPlayer, BorderColor borderColor) { + PlayerChangeBorderColor playerChangeBorderColor = new PlayerChangeBorderColor(); + playerChangeBorderColor.superiorPlayer = superiorPlayer; + playerChangeBorderColor.borderColor = borderColor; + return !fireEvent(PLAYER_CHANGE_BORDER_COLOR_EVENT, playerChangeBorderColor).isCancelled(); + } + + public static boolean callPlayerChangeLanguageEvent(SuperiorPlayer superiorPlayer, Locale language) { + PlayerChangeLanguage playerChangeLanguage = new PlayerChangeLanguage(); + playerChangeLanguage.superiorPlayer = superiorPlayer; + playerChangeLanguage.language = language; + return !fireEvent(PLAYER_CHANGE_LANGUAGE_EVENT, playerChangeLanguage).isCancelled(); + } + + public static void callPlayerChangeNameEvent(SuperiorPlayer superiorPlayer, String newName) { + PlayerChangeName missionComplete = new PlayerChangeName(); + missionComplete.superiorPlayer = superiorPlayer; + missionComplete.newName = newName; + fireEvent(PLAYER_CHANGE_NAME_EVENT, missionComplete); + } + + public static boolean callPlayerChangeRoleEvent(SuperiorPlayer superiorPlayer, PlayerRole newRole) { + PlayerChangeRole playerChangeRole = new PlayerChangeRole(); + playerChangeRole.superiorPlayer = superiorPlayer; + playerChangeRole.newRole = newRole; + return !fireEvent(PLAYER_CHANGE_ROLE_EVENT, playerChangeRole).isCancelled(); + } + + public static PluginEvent callPlayerCloseMenuEvent(SuperiorPlayer superiorPlayer, MenuView menuView, + @Nullable MenuView newMenuView) { + PlayerCloseMenu playerCloseMenu = new PlayerCloseMenu(); + playerCloseMenu.superiorPlayer = superiorPlayer; + playerCloseMenu.menuView = menuView; + playerCloseMenu.newMenuView = newMenuView; + return fireEvent(PLAYER_CLOSE_MENU_EVENT, playerCloseMenu); + } + + public static boolean callPlayerOpenMenuEvent(SuperiorPlayer superiorPlayer, MenuView menuView) { + PlayerOpenMenu playerOpenMenu = new PlayerOpenMenu(); + playerOpenMenu.superiorPlayer = superiorPlayer; + playerOpenMenu.menuView = menuView; + return !fireEvent(PLAYER_OPEN_MENU_EVENT, playerOpenMenu).isCancelled(); + } + + public static void callPlayerReplaceEvent(SuperiorPlayer oldPlayer, SuperiorPlayer newPlayer) { + PlayerReplace playerReplace = new PlayerReplace(); + playerReplace.superiorPlayer = oldPlayer; + playerReplace.newPlayer = newPlayer; + fireEvent(PLAYER_REPLACE_EVENT, playerReplace); + } + + public static boolean callPlayerToggleBlocksStackerEvent(SuperiorPlayer superiorPlayer) { + PlayerToggleBlocksStacker playerToggleBlocksStacker = new PlayerToggleBlocksStacker(); + playerToggleBlocksStacker.superiorPlayer = superiorPlayer; + return !fireEvent(PLAYER_TOGGLE_BLOCKS_STACKER_EVENT, playerToggleBlocksStacker).isCancelled(); + } + + public static boolean callPlayerToggleBorderEvent(SuperiorPlayer superiorPlayer) { + PlayerToggleBorder playerToggleBorder = new PlayerToggleBorder(); + playerToggleBorder.superiorPlayer = superiorPlayer; + return !fireEvent(PLAYER_TOGGLE_BORDER_EVENT, playerToggleBorder).isCancelled(); + } + + public static boolean callPlayerToggleBypassEvent(SuperiorPlayer superiorPlayer) { + PlayerToggleBypass playerToggleBypass = new PlayerToggleBypass(); + playerToggleBypass.superiorPlayer = superiorPlayer; + return !fireEvent(PLAYER_TOGGLE_BYPASS_EVENT, playerToggleBypass).isCancelled(); + } + + public static boolean callPlayerToggleFlyEvent(SuperiorPlayer superiorPlayer) { + PlayerToggleFly playerToggleFly = new PlayerToggleFly(); + playerToggleFly.superiorPlayer = superiorPlayer; + return !fireEvent(PLAYER_TOGGLE_FLY_EVENT, playerToggleFly).isCancelled(); + } + + public static boolean callPlayerTogglePanelEvent(SuperiorPlayer superiorPlayer) { + PlayerTogglePanel playerTogglePanel = new PlayerTogglePanel(); + playerTogglePanel.superiorPlayer = superiorPlayer; + return !fireEvent(PLAYER_TOGGLE_PANEL_EVENT, playerTogglePanel).isCancelled(); + } + + public static boolean callPlayerToggleSpyEvent(SuperiorPlayer superiorPlayer) { + PlayerToggleSpy playerToggleSpy = new PlayerToggleSpy(); + playerToggleSpy.superiorPlayer = superiorPlayer; + return !fireEvent(PLAYER_TOGGLE_SPY_EVENT, playerToggleSpy).isCancelled(); + } + + public static boolean callPlayerToggleTeamChatEvent(SuperiorPlayer superiorPlayer) { + PlayerToggleTeamChat playerToggleTeamChat = new PlayerToggleTeamChat(); + playerToggleTeamChat.superiorPlayer = superiorPlayer; + return !fireEvent(PLAYER_TOGGLE_TEAM_CHAT_EVENT, playerToggleTeamChat).isCancelled(); + } + + public static void callPluginInitializedEvent() { + PluginInitialized pluginInitialized = new PluginInitialized(); + pluginInitialized.plugin = plugin; + fireEvent(PLUGIN_INITIALIZED_EVENT, pluginInitialized); + } + + public static PluginEvent callPluginInitializeEvent() { + PluginInitialize pluginInitialize = new PluginInitialize(); + pluginInitialize.plugin = plugin; + return fireEvent(PLUGIN_INITIALIZE_EVENT, pluginInitialize); + } + + public static boolean callPluginLoadDataEvent() { + PluginLoadData pluginLoadData = new PluginLoadData(); + pluginLoadData.plugin = plugin; + return !fireEvent(PLUGIN_LOAD_DATA_EVENT, pluginLoadData).isCancelled(); + } + + public static void callPostIslandCreateEvent(Island island, SuperiorPlayer superiorPlayer) { + PostIslandCreate postIslandCreate = new PostIslandCreate(); + postIslandCreate.island = island; + postIslandCreate.superiorPlayer = superiorPlayer; + fireEvent(POST_ISLAND_CREATE_EVENT, postIslandCreate); + } + + public static boolean callPreIslandCreateEvent(SuperiorPlayer superiorPlayer, String islandName) { + PreIslandCreate preIslandCreate = new PreIslandCreate(); + preIslandCreate.superiorPlayer = superiorPlayer; + preIslandCreate.islandName = islandName; + return !fireEvent(PRE_ISLAND_CREATE_EVENT, preIslandCreate).isCancelled(); + } + + public static PluginEvent callSendMessageEvent(CommandSender receiver, String messageType, + IMessageComponent messageComponent, Object... args) { + SendMessage pluginInitialize = new SendMessage(); + pluginInitialize.receiver = receiver; + pluginInitialize.messageType = messageType; + pluginInitialize.messageComponent = messageComponent; + pluginInitialize.args = args; + return fireEvent(SEND_MESSAGE_EVENT, pluginInitialize); + } + + private static PluginEvent fireEvent(PluginEventType type, Args args) { + return plugin.getPluginEventsDispatcher().fireEvent(type, args); + } + + @Nullable + private static SuperiorPlayer commandSenderToSuperiorPlayer(@Nullable CommandSender commandSender) { + return commandSender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(commandSender) : null; + } + + private PluginEventsFactory() { + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java index 745143a2ea..9185bc7220 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java @@ -6,7 +6,9 @@ import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; @@ -71,8 +73,8 @@ public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Player player = inventoryViewer.asPlayer(); - EventResult event = plugin.getEventsBus().callIslandBiomeChangeEvent(inventoryViewer, - menuView.getIsland(), getTemplate().biome); + PluginEvent event = PluginEventsFactory.callIslandBiomeChangeEvent( + menuView.getIsland(), inventoryViewer, getTemplate().biome); if (event.isCancelled()) { GameSoundImpl.playSound(player, getTemplate().getLackPermissionSound()); @@ -84,8 +86,8 @@ public void onButtonClick(InventoryClickEvent clickEvent) { getTemplate().accessCommands.forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command.replace("%player%", inventoryViewer.getName()))); - menuView.getIsland().setBiome(event.getResult()); - Message.CHANGED_BIOME.send(inventoryViewer, event.getResult().name().toLowerCase(Locale.ENGLISH)); + menuView.getIsland().setBiome(event.getArgs().biome); + Message.CHANGED_BIOME.send(inventoryViewer, event.getArgs().biome.name().toLowerCase(Locale.ENGLISH)); BukkitExecutor.sync(menuView::closeView, 1L); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java index a2579510fa..286b57d7a5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; @@ -37,7 +38,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Island targetIsland = menuView.getIsland(); - if (getTemplate().disbandIsland && plugin.getEventsBus().callIslandDisbandEvent(inventoryViewer, targetIsland)) { + if (getTemplate().disbandIsland && PluginEventsFactory.callIslandDisbandEvent(targetIsland, inventoryViewer)) { IslandUtils.sendMessage(targetIsland, Message.DISBAND_ANNOUNCEMENT, Collections.emptyList(), inventoryViewer.getName()); Message.DISBANDED_ISLAND.send(inventoryViewer); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandFlagPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandFlagPagedObjectButton.java index a09dd831a8..da87eb80b7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandFlagPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandFlagPagedObjectButton.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; @@ -32,12 +33,12 @@ public void onButtonClick(InventoryClickEvent clickEvent) { return; if (island.hasSettingsEnabled(islandFlag)) { - if (!plugin.getEventsBus().callIslandDisableFlagEvent(inventoryViewer, island, islandFlag)) + if (!PluginEventsFactory.callIslandDisableFlagEvent(island, inventoryViewer, islandFlag)) return; island.disableSettings(islandFlag); } else { - if (!plugin.getEventsBus().callIslandEnableFlagEvent(inventoryViewer, island, islandFlag)) + if (!PluginEventsFactory.callIslandEnableFlagEvent(island, inventoryViewer, islandFlag)) return; island.enableSettings(islandFlag); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandPrivilegePagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandPrivilegePagedObjectButton.java index 8921ab6cb7..c4b8a923d6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandPrivilegePagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandPrivilegePagedObjectButton.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; @@ -107,7 +108,7 @@ private void onRoleButtonClick(Island island, SuperiorPlayer clickedPlayer, Inve newRole = SPlayerRole.guestRole(); } - if (plugin.getEventsBus().callIslandChangeRolePrivilegeEvent(island, clickedPlayer, newRole)) { + if (PluginEventsFactory.callIslandChangeRolePrivilegeEvent(island, clickedPlayer, newRole)) { island.setPermission(newRole, islandPrivilege); onSuccessfulPermissionChange(clickedPlayer, Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName())); } @@ -125,7 +126,7 @@ private void onPlayerButtonClick(Island island, SuperiorPlayer clickedPlayer, Su boolean currentValue = permissionNode.hasPermission(islandPrivilege); - if (!plugin.getEventsBus().callIslandChangePlayerPrivilegeEvent(island, clickedPlayer, permissionHolder, !currentValue)) + if (!PluginEventsFactory.callIslandChangePlayerPrivilegeEvent(island, clickedPlayer, permissionHolder, !currentValue)) return; island.setPermission(permissionHolder, islandPrivilege, !currentValue); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LanguageButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LanguageButton.java index 0bda8f100d..b64e96dac6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LanguageButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LanguageButton.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; @@ -34,7 +35,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { Locale language = getTemplate().language; - if (!plugin.getEventsBus().callPlayerChangeLanguageEvent(inventoryViewer, language)) + if (!PluginEventsFactory.callPlayerChangeLanguageEvent(inventoryViewer, language)) return; inventoryViewer.setUserLocale(language); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LeaveButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LeaveButton.java index e8ffeb964d..44159bf81b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LeaveButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LeaveButton.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; @@ -34,7 +35,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Island island = inventoryViewer.getIsland(); - if (getTemplate().leaveIsland && island != null && plugin.getEventsBus().callIslandQuitEvent(inventoryViewer, island)) { + if (getTemplate().leaveIsland && island != null && PluginEventsFactory.callIslandQuitEvent(island, inventoryViewer)) { island.kickMember(inventoryViewer); IslandUtils.sendMessage(island, Message.LEAVE_ANNOUNCEMENT, Collections.emptyList(), inventoryViewer.getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/RateIslandButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/RateIslandButton.java index fbd3db822b..d2efa79dd1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/RateIslandButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/RateIslandButton.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; @@ -38,12 +39,12 @@ public void onButtonClick(InventoryClickEvent clickEvent) { Rating rating = getTemplate().rating; if (rating == Rating.UNKNOWN) { - if (!plugin.getEventsBus().callIslandRemoveRatingEvent(inventoryViewer, inventoryViewer, island)) + if (!PluginEventsFactory.callIslandRemoveRatingEvent(island, inventoryViewer, inventoryViewer)) return; island.removeRating(inventoryViewer); } else { - if (!plugin.getEventsBus().callIslandRateEvent(inventoryViewer, inventoryViewer, island, rating)) + if (!PluginEventsFactory.callIslandRateEvent(island, inventoryViewer, inventoryViewer, rating)) return; island.setRating(inventoryViewer, rating); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryIconEditConfirmButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryIconEditConfirmButton.java index 4ec54adc5f..962cc311ad 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryIconEditConfirmButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryIconEditConfirmButton.java @@ -3,14 +3,15 @@ import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.inventory.ItemStack; public class WarpCategoryIconEditConfirmButton extends AbstractMenuViewButton> { @@ -25,17 +26,17 @@ public void onButtonClick(InventoryClickEvent clickEvent) { WarpCategory warpCategory = menuView.getIconProvider(); - EventResult eventResult = plugin.getEventsBus().callIslandChangeWarpCategoryIconEvent(superiorPlayer, - warpCategory.getIsland(), warpCategory, menuView.getIconTemplate().build()); + PluginEvent event = PluginEventsFactory.callIslandChangeWarpCategoryIconEvent( + warpCategory.getIsland(), superiorPlayer, warpCategory, menuView.getIconTemplate().build()); - if (eventResult.isCancelled()) + if (event.isCancelled()) return; clickEvent.getWhoClicked().closeInventory(); Message.WARP_CATEGORY_ICON_UPDATED.send(superiorPlayer); - warpCategory.setIcon(eventResult.getResult()); + warpCategory.setIcon(event.getArgs().icon); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder> { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageIconButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageIconButton.java index 86b8d22c11..834675b470 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageIconButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageIconButton.java @@ -4,7 +4,9 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; @@ -81,13 +83,13 @@ public void onButtonClick(InventoryClickEvent clickEvent) { return true; } - EventResult eventResult = plugin.getEventsBus().callIslandChangeWarpCategorySlotEvent( - inventoryViewer, warpCategory.getIsland(), warpCategory, slot, rowsSize * 9); + PluginEvent event = PluginEventsFactory.callIslandChangeWarpCategorySlotEvent( + warpCategory.getIsland(), inventoryViewer, warpCategory, slot, rowsSize * 9); - if (!eventResult.isCancelled()) { - warpCategory.setSlot(eventResult.getResult()); + if (!event.isCancelled()) { + warpCategory.setSlot(event.getArgs().slot); - Message.WARP_CATEGORY_SLOT_SUCCESS.send(player, eventResult.getResult()); + Message.WARP_CATEGORY_SLOT_SUCCESS.send(player, event.getArgs().slot); GameSoundImpl.playSound(player, Menus.MENU_WARP_CATEGORY_MANAGE.getSuccessUpdateSound()); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageRenameButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageRenameButton.java index 3400b8e01b..d5789ac692 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageRenameButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageRenameButton.java @@ -3,7 +3,9 @@ import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; @@ -44,13 +46,13 @@ public void onButtonClick(InventoryClickEvent clickEvent) { return true; } - EventResult eventResult = plugin.getEventsBus().callIslandRenameWarpCategoryEvent( + PluginEvent event = PluginEventsFactory.callIslandRenameWarpCategoryEvent( warpCategory.getIsland(), plugin.getPlayers().getSuperiorPlayer(player), warpCategory, newName); - if (!eventResult.isCancelled()) { - warpCategory.getIsland().renameCategory(warpCategory, eventResult.getResult()); + if (!event.isCancelled()) { + warpCategory.getIsland().renameCategory(warpCategory, event.getArgs().categoryName); - Message.WARP_CATEGORY_RENAME_SUCCESS.send(player, eventResult.getResult()); + Message.WARP_CATEGORY_RENAME_SUCCESS.send(player, event.getArgs().categoryName); GameSoundImpl.playSound(player, Menus.MENU_WARP_CATEGORY_MANAGE.getSuccessUpdateSound()); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpIconEditConfirmButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpIconEditConfirmButton.java index a75db96809..713542c00f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpIconEditConfirmButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpIconEditConfirmButton.java @@ -3,14 +3,15 @@ import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractIconProviderMenu; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.inventory.ItemStack; public class WarpIconEditConfirmButton extends AbstractMenuViewButton> { @@ -25,17 +26,17 @@ public void onButtonClick(InventoryClickEvent clickEvent) { IslandWarp islandWarp = menuView.getIconProvider(); - EventResult eventResult = plugin.getEventsBus().callIslandChangeWarpIconEvent(inventoryViewer, - islandWarp.getIsland(), islandWarp, menuView.getIconTemplate().build()); + PluginEvent event = PluginEventsFactory.callIslandChangeWarpIconEvent( + islandWarp.getIsland(), inventoryViewer, islandWarp, menuView.getIconTemplate().build()); - if (eventResult.isCancelled()) + if (event.isCancelled()) return; clickEvent.getWhoClicked().closeInventory(); Message.WARP_ICON_UPDATED.send(inventoryViewer); - islandWarp.setIcon(eventResult.getResult()); + islandWarp.setIcon(event.getArgs().icon); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder> { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java index 47e142759d..44e1f44612 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java @@ -5,7 +5,9 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; @@ -30,7 +32,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { Player player = (Player) clickEvent.getWhoClicked(); IslandWarp islandWarp = menuView.getIslandWarp(); - EventResult eventResult; + PluginEvent event; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location playerLocation = player.getLocation(wrapper.getHandle()); @@ -39,11 +41,11 @@ public void onButtonClick(InventoryClickEvent clickEvent) { return; } - eventResult = plugin.getEventsBus().callIslandChangeWarpLocationEvent( - plugin.getPlayers().getSuperiorPlayer(player), islandWarp.getIsland(), islandWarp, playerLocation); + event = PluginEventsFactory.callIslandChangeWarpLocationEvent( + islandWarp.getIsland(), player, islandWarp, playerLocation); } - if (eventResult.isCancelled()) + if (event.isCancelled()) return; @@ -52,14 +54,14 @@ public void onButtonClick(InventoryClickEvent clickEvent) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location warpLocation = islandWarp.getLocation(wrapper.getHandle()); - if (!warpLocation.equals(eventResult.getResult())) { + if (!warpLocation.equals(event.getArgs().location)) { ChunksProvider.loadChunk(ChunkPosition.of(warpLocation), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { SignWarp.trySignWarpBreak(islandWarp, player); }); } } - islandWarp.setLocation(eventResult.getResult()); + islandWarp.setLocation(event.getArgs().location); GameSoundImpl.playSound(player, Menus.MENU_WARP_MANAGE.getSuccessUpdateSound()); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManagePrivateButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManagePrivateButton.java index 3e8a6dfec4..b87b4ee6dd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManagePrivateButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManagePrivateButton.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; @@ -24,8 +25,8 @@ public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); - if (openToPublic ? !plugin.getEventsBus().callIslandOpenWarpEvent(islandWarp.getIsland(), superiorPlayer, islandWarp) : - !plugin.getEventsBus().callIslandCloseWarpEvent(islandWarp.getIsland(), superiorPlayer, islandWarp)) + if (openToPublic ? !PluginEventsFactory.callIslandOpenWarpEvent(islandWarp.getIsland(), superiorPlayer, islandWarp) : + !PluginEventsFactory.callIslandCloseWarpEvent(islandWarp.getIsland(), superiorPlayer, islandWarp)) return; islandWarp.setPrivateFlag(!openToPublic); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageRenameButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageRenameButton.java index 902fa002bf..747e6e6f17 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageRenameButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageRenameButton.java @@ -3,7 +3,9 @@ import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; @@ -43,13 +45,13 @@ public void onButtonClick(InventoryClickEvent clickEvent) { return true; } - EventResult eventResult = plugin.getEventsBus().callIslandRenameWarpEvent( - islandWarp.getIsland(), plugin.getPlayers().getSuperiorPlayer(player), islandWarp, newName); + PluginEvent event = PluginEventsFactory.callIslandRenameWarpEvent( + islandWarp.getIsland(), player, islandWarp, newName); - if (!eventResult.isCancelled()) { - islandWarp.getIsland().renameWarp(islandWarp, eventResult.getResult()); + if (!event.isCancelled()) { + islandWarp.getIsland().renameWarp(islandWarp, event.getArgs().warpName); - Message.WARP_RENAME_SUCCESS.send(player, eventResult.getResult()); + Message.WARP_RENAME_SUCCESS.send(player, event.getArgs().warpName); GameSoundImpl.playSound(player, Menus.MENU_WARP_MANAGE.getSuccessUpdateSound()); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractMenuView.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractMenuView.java index 3c7256c0d6..e655564f2e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractMenuView.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractMenuView.java @@ -8,7 +8,9 @@ import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; @@ -102,7 +104,7 @@ private void openView() { AbstractMenu menu = (AbstractMenu) getMenu(); - if (!plugin.getEventsBus().callPlayerOpenMenuEvent(inventoryViewer, this)) + if (!PluginEventsFactory.callPlayerOpenMenuEvent(inventoryViewer, this)) return; Log.debug(Debug.OPEN_MENU, inventoryViewer.getName()); @@ -147,17 +149,17 @@ public void onClose() { if (!nextMove && !closeButton && plugin.getSettings().isOnlyBackButton()) { BukkitExecutor.sync(this::openView); } else if (this.previousMenuView != null && this.menu.isPreviousMoveAllowed()) { - EventResult> eventResult = plugin.getEventsBus().callPlayerCloseMenuEvent(this.inventoryViewer, - this, previousMove ? this.previousMenuView : null); + PluginEvent event = PluginEventsFactory.callPlayerCloseMenuEvent( + this.inventoryViewer, this, previousMove ? this.previousMenuView : null); if (previousMove) { - if (!eventResult.isCancelled()) { - MenuView newMenu = eventResult.getResult(); + if (!event.isCancelled()) { + MenuView newMenu = event.getArgs().newMenuView; if (newMenu != null) BukkitExecutor.sync(newMenu::refreshView); } - } else if (eventResult.isCancelled()) { + } else if (event.isCancelled()) { BukkitExecutor.sync(this::openView); } else { previousMove = true; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 569700406b..e3df90a0c3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -12,7 +12,9 @@ import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.io.Files; import com.bgsoftware.superiorskyblock.core.logging.Debug; @@ -393,9 +395,9 @@ public void send(CommandSender sender, Locale locale, Object... args) { IMessageComponent messageComponent = ComplexMessageComponent.of(baseComponents); if (messageComponent != null) { - EventResult eventResult = plugin.getEventsBus().callSendMessageEvent(sender, name(), messageComponent, args); - if (!eventResult.isCancelled()) - eventResult.getResult().sendMessage(sender, args); + PluginEvent event = PluginEventsFactory.callSendMessageEvent(sender, name(), messageComponent, args); + if (!event.isCancelled()) + event.getArgs().messageComponent.sendMessage(sender, args); } } } @@ -946,14 +948,14 @@ public String getMessage(Locale locale, Object... args) { } public final void send(SuperiorPlayer superiorPlayer, Object... args) { - if (plugin.getEventsBus().callAttemptPlayerSendMessageEvent(superiorPlayer, name(), args)) + if (PluginEventsFactory.callAttemptPlayerSendMessageEvent(superiorPlayer, name(), args)) superiorPlayer.runIfOnline(player -> send(player, superiorPlayer.getUserLocale(), args)); } public final void send(CommandSender sender, Object... args) { if (sender instanceof Player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - if (!plugin.getEventsBus().callAttemptPlayerSendMessageEvent(superiorPlayer, name(), args)) + if (!PluginEventsFactory.callAttemptPlayerSendMessageEvent(superiorPlayer, name(), args)) return; } @@ -971,9 +973,9 @@ public void send(CommandSender sender, Locale locale, Object... objects) { return; } - EventResult eventResult = plugin.getEventsBus().callSendMessageEvent(sender, name(), messageComponent, objects); - if (!eventResult.isCancelled()) { - eventResult.getResult().sendMessage(sender, objects); + PluginEvent event = PluginEventsFactory.callSendMessageEvent(sender, name(), messageComponent, objects); + if (!event.isCancelled()) { + event.getArgs().messageComponent.sendMessage(sender, objects); if (!(sender instanceof Player) && Log.isDebugged(Debug.SHOW_STACKTRACE)) { Thread.dumpStack(); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index ab16cc447e..3ba4db55e2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -31,6 +31,7 @@ import com.bgsoftware.superiorskyblock.core.database.bridge.GridDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -255,7 +256,7 @@ private void createIslandInternalAsync(IslandBuilderImpl builder, Biome biome, b // Removing any active previews for the player. boolean updateGamemode = this.islandPreviews.endIslandPreview(builder.owner) != null; - if (!plugin.getEventsBus().callPreIslandCreateEvent(builder.owner, builder.islandName)) + if (!PluginEventsFactory.callPreIslandCreateEvent(builder.owner, builder.islandName)) return; builder.setUniqueId(generateIslandUUID()); @@ -385,7 +386,7 @@ private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Bi this.dragonBattleService.get().resetEnderDragonBattle(island, defaultDimension); } - plugin.getEventsBus().callPostIslandCreateEvent(builder.owner, island); + PluginEventsFactory.callPostIslandCreateEvent(island, builder.owner); if (onTeleportCallback != null) onTeleportCallback.run(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java index 27ab8a3a89..cb0a249ac6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java @@ -16,6 +16,7 @@ import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -204,7 +205,7 @@ public static void handleKickPlayer(SuperiorPlayer caller, Island island, Superi } public static void handleKickPlayer(SuperiorPlayer caller, String callerName, Island island, SuperiorPlayer target) { - if (!plugin.getEventsBus().callIslandKickEvent(caller, target, island)) + if (!PluginEventsFactory.callIslandKickEvent(island, caller, target)) return; island.kickMember(target); @@ -231,7 +232,7 @@ public static boolean checkBanRestrictions(SuperiorPlayer superiorPlayer, Island } public static void handleBanPlayer(SuperiorPlayer caller, Island island, SuperiorPlayer target) { - if (!plugin.getEventsBus().callIslandBanEvent(caller, target, island)) + if (!PluginEventsFactory.callIslandBanEvent(island, caller, target)) return; island.banMember(target, caller); @@ -245,7 +246,7 @@ public static void deleteChunks(Island island, List chunkPosition plugin.getNMSChunks().deleteChunks(island, chunkPositions, onFinish); chunkPositions.forEach(chunkPosition -> { plugin.getStackedBlocks().removeStackedBlocks(chunkPosition); - plugin.getEventsBus().callIslandChunkResetEvent(island, chunkPosition); + PluginEventsFactory.callIslandChunkResetEvent(island, chunkPosition); }); } @@ -263,13 +264,13 @@ public static int getMaxWarpNameLength() { public static boolean handleBorderColorUpdate(SuperiorPlayer superiorPlayer, BorderColor borderColor) { if (!superiorPlayer.hasWorldBorderEnabled()) { - if (!plugin.getEventsBus().callPlayerToggleBorderEvent(superiorPlayer)) + if (!PluginEventsFactory.callPlayerToggleBorderEvent(superiorPlayer)) return false; superiorPlayer.toggleWorldBorder(); } - if (!plugin.getEventsBus().callPlayerChangeBorderColorEvent(superiorPlayer, borderColor)) + if (!PluginEventsFactory.callPlayerChangeBorderColorEvent(superiorPlayer, borderColor)) return false; superiorPlayer.setBorderColor(borderColor); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 8fa25ed120..a074a990bb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -53,9 +53,11 @@ import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; -import com.bgsoftware.superiorskyblock.core.events.EventResult; -import com.bgsoftware.superiorskyblock.core.events.EventsBus; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; @@ -547,7 +549,7 @@ public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) { superiorPlayer.setIsland(this); - if (plugin.getEventsBus().callPlayerChangeRoleEvent(superiorPlayer, playerRole)) { + if (PluginEventsFactory.callPlayerChangeRoleEvent(superiorPlayer, playerRole)) { superiorPlayer.setPlayerRole(playerRole); } else { superiorPlayer.setPlayerRole(SPlayerRole.defaultRole()); @@ -1772,7 +1774,7 @@ public boolean transferIsland(SuperiorPlayer superiorPlayer) { SuperiorPlayer previousOwner = getOwner(); - if (!plugin.getEventsBus().callIslandTransferEvent(this, previousOwner, superiorPlayer)) + if (!PluginEventsFactory.callIslandTransferEvent(this, previousOwner, superiorPlayer)) return false; Log.debug(Debug.TRANSFER_ISLAND, owner.getName(), superiorPlayer.getName()); @@ -3902,8 +3904,7 @@ public boolean setGeneratorPercentage(Key key, int percentage, Dimension dimensi Preconditions.checkArgument(percentage >= 0 && percentage <= 100, "Percentage must be between 0 and 100 - got " + percentage + "."); if (percentage == 0) { - if (callEvent && !plugin.getEventsBus().callIslandRemoveGeneratorRateEvent( - caller, this, key, dimension)) + if (callEvent && !PluginEventsFactory.callIslandRemoveGeneratorRateEvent(this, caller, key, dimension)) return false; removeGeneratorAmount(key, dimension); @@ -3915,14 +3916,14 @@ public boolean setGeneratorPercentage(Key key, int percentage, Dimension dimensi int generatorRate = 1; if (callEvent) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeGeneratorRateEvent( - caller, this, key, dimension, generatorRate); - if (eventResult.isCancelled()) { + PluginEvent event = + PluginEventsFactory.callIslandChangeGeneratorRateEvent(this, caller, key, dimension, generatorRate); + if (event.isCancelled()) { // Restore the original values worldGeneratorRates.putAll(cobbleGeneratorValuesOriginal); return false; } - generatorRate = eventResult.getResult(); + generatorRate = event.getArgs().generatorRate; } setGeneratorAmount(key, generatorRate, dimension); @@ -3945,13 +3946,13 @@ public boolean setGeneratorPercentage(Key key, int percentage, Dimension dimensi amount *= 10; } - EventResult eventResult = plugin.getEventsBus().callIslandChangeGeneratorRateEvent(caller, - this, key, dimension, (int) Math.round(amount)); + PluginEvent event = + PluginEventsFactory.callIslandChangeGeneratorRateEvent(this, caller, key, dimension, (int) Math.round(amount)); - if (eventResult.isCancelled()) + if (event.isCancelled()) return false; - setGeneratorAmount(key, eventResult.getResult(), dimension); + setGeneratorAmount(key, event.getArgs().generatorRate, dimension); } return true; @@ -4202,15 +4203,15 @@ public Key generateBlock(Location location, Dimension dimension, boolean optimiz } } - EventResult eventResult = plugin.getEventsBus().callIslandGenerateBlockEvent( - this, location, newStateKey); + PluginEvent event = + PluginEventsFactory.callIslandGenerateBlockEvent(this, location, newStateKey); - if (eventResult.isCancelled()) { + if (event.isCancelled()) { Log.debugResult(Debug.GENERATE_BLOCK, "Return Event Cancelled", "null"); return null; } - Key generatedBlock = eventResult.getResult().getBlock(); + Key generatedBlock = event.getArgs().block; if (optimizeDefaultBlock && generatedBlock.equals(defaultBlockKey)) { Log.debugResult(Debug.GENERATE_BLOCK, "Return Default Block", generatedBlock); @@ -4221,7 +4222,7 @@ public Key generateBlock(Location location, Dimension dimension, boolean optimiz handleBlockPlace(generatedBlock, 1); // Checking whether the plugin should set the block in the world. - if (eventResult.getResult().isPlaceBlock()) { + if (event.getArgs().placeBlock) { int combinedId; try { @@ -4536,7 +4537,7 @@ private void saveBlockCounts(BigInteger currentTotalBlocksCount, BigDecimal oldW BigDecimal newLevel = getIslandLevel(); if (oldLevel.compareTo(newLevel) != 0 || oldWorth.compareTo(newWorth) != 0) { - BukkitExecutor.async(() -> plugin.getEventsBus().callIslandWorthUpdateEvent(this, oldWorth, oldLevel, newWorth, newLevel), 0L); + BukkitExecutor.async(() -> PluginEventsFactory.callIslandWorthUpdateEvent(this, oldWorth, oldLevel, newWorth, newLevel), 0L); } BigInteger deltaBlockCounts = this.lastSavedBlockCounts.subtract(currentTotalBlocksCount); @@ -5064,7 +5065,7 @@ private void updateIslandChests() { } private void finishCalcIsland(SuperiorPlayer asker, Runnable callback, BigDecimal islandLevel, BigDecimal islandWorth) { - plugin.getEventsBus().callIslandWorthCalculatedEvent(this, asker, islandLevel, islandWorth); + PluginEventsFactory.callIslandWorthCalculatedEvent(this, asker, islandLevel, islandWorth); if (asker != null) Message.ISLAND_WORTH_RESULT.send(asker, islandWorth, islandLevel); @@ -5090,8 +5091,8 @@ private void notifyCropGrowthChange(double newCropGrowth) { .values().forEach(chunkPositions -> plugin.getNMSChunks().updateCropsTicker(chunkPositions, newCropGrowthMultiplier)); } - public static void registerCallbacks(CallbacksBus bus) { - bus.registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, SIsland::onSettingsUpdate); + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SIsland::onSettingsUpdate); } private static void onSettingsUpdate() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 51c55994e7..cfe9bdf6cd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -41,7 +41,8 @@ import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.database.bridge.EmptyDatabaseBridge; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.persistence.EmptyPersistentDataContainer; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; @@ -97,8 +98,8 @@ protected SSuperiorPlayer create() { private static EnumerateSet DEFAULT_SPAWN_FLAGS_CACHE; private static EnumerateSet DEFAULT_SPAWN_PRIVILEGES_CACHE; - public static void registerCallbacks(CallbacksBus bus) { - bus.registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, SpawnIsland::onSettingsUpdate); + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SpawnIsland::onSettingsUpdate); } private static void onSettingsUpdate() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java index b90bffbcbc..5e5738310e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java @@ -7,9 +7,10 @@ import com.bgsoftware.superiorskyblock.api.world.algorithm.IslandCreationAlgorithm; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.profiler.ProfileType; @@ -91,7 +92,7 @@ public CompletableFuture createIsland(Island.Builder build island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.IDLE); - EventResult event = plugin.getEventsBus().callIslandCreateEvent(builder.owner, island, builder.islandType); + PluginEvent event = PluginEventsFactory.callIslandCreateEvent(island, builder.owner, builder.islandType); if (event.isCancelled()) { Log.debugResult(Debug.CREATE_ISLAND, "Creation Failed", "Event was cancelled for creating the island '" + builder.islandName + "'."); @@ -106,7 +107,7 @@ public CompletableFuture createIsland(Island.Builder build schematic.pasteSchematic(island, location, () -> { plugin.getProviders().getWorldsProvider().finishIslandCreation(islandLocation, builder.owner.getUniqueId(), builder.uuid); - completableFuture.complete(new IslandCreationResult(IslandCreationResult.Status.SUCCESS, island, islandLocation, event.getResult())); + completableFuture.complete(new IslandCreationResult(IslandCreationResult.Status.SUCCESS, island, islandLocation, event.getArgs().canTeleport)); island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); Profiler.end(profiler); }, error -> { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java index 5ea2339880..c175261865 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java @@ -10,7 +10,9 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -83,10 +85,10 @@ public BankTransaction depositMoney(SuperiorPlayer superiorPlayer, BigDecimal am } else { BigDecimal playerBalance = plugin.getProviders().getBankEconomyProvider().getBalance(superiorPlayer); - EventResult eventResult = plugin.getEventsBus().callIslandBankDepositEvent(superiorPlayer, island, amount); + PluginEvent event = PluginEventsFactory.callIslandBankDepositEvent(island, superiorPlayer, amount); - if (eventResult.isCancelled()) { - failureReason = eventResult.getResult(); + if (event.isCancelled()) { + failureReason = event.getArgs().failureReason; } else if (playerBalance.compareTo(amount) < 0) { failureReason = "Not enough money"; } else if (!canDepositMoney(amount)) { @@ -130,15 +132,14 @@ public BankTransaction depositAdminMoney(CommandSender commandSender, BigDecimal Log.debug(Debug.DEPOSIT_MONEY, island.getOwner().getName(), commandSender.getName(), amount); - EventResult eventResult = plugin.getEventsBus().callIslandBankDepositEvent(commandSender instanceof Player ? - plugin.getPlayers().getSuperiorPlayer(commandSender) : null, island, amount); + PluginEvent event = PluginEventsFactory.callIslandBankDepositEvent(island, commandSender, amount); UUID senderUUID = commandSender instanceof Player ? ((Player) commandSender).getUniqueId() : null; int position = this.bankLogs.getLastTransactionPosition() + 1; BankAction bankAction; - if (eventResult.isCancelled()) { + if (event.isCancelled()) { bankAction = BankAction.DEPOSIT_FAILED; Log.debugResult(Debug.DEPOSIT_MONEY, "Return Failure", "Event Cancelled"); } else { @@ -147,11 +148,11 @@ public BankTransaction depositAdminMoney(CommandSender commandSender, BigDecimal } BankTransaction bankTransaction = new SBankTransaction(senderUUID, bankAction, position, - System.currentTimeMillis(), eventResult.getResult(), amount); + System.currentTimeMillis(), event.getArgs().failureReason, amount); addTransaction(bankTransaction, true); - if (!eventResult.isCancelled()) + if (!event.isCancelled()) increaseBalance(amount); plugin.getMenus().refreshBankLogs(island); @@ -186,10 +187,10 @@ public BankTransaction withdrawMoney(SuperiorPlayer superiorPlayer, BigDecimal a } else if (amount.compareTo(BigDecimal.ZERO) <= 0) { failureReason = "Invalid amount"; } else { - EventResult eventResult = plugin.getEventsBus().callIslandBankWithdrawEvent(superiorPlayer, island, withdrawAmount); + PluginEvent event = PluginEventsFactory.callIslandBankWithdrawEvent(island, superiorPlayer, withdrawAmount); - if (eventResult.isCancelled()) { - failureReason = eventResult.getResult(); + if (event.isCancelled()) { + failureReason = event.getArgs().failureReason; } else if (commandsToExecute == null || commandsToExecute.isEmpty()) { EconomyProvider.EconomyResult result = plugin.getProviders().depositMoneyForBanks(superiorPlayer, withdrawAmount); failureReason = result.getErrorMessage(); @@ -237,11 +238,11 @@ public BankTransaction withdrawAdminMoney(CommandSender commandSender, BigDecima int position = this.bankLogs.getLastTransactionPosition() + 1; - EventResult eventResult = plugin.getEventsBus().callIslandBankWithdrawEvent(commandSender instanceof Player ? - plugin.getPlayers().getSuperiorPlayer(commandSender) : null, island, amount); + PluginEvent event = PluginEventsFactory.callIslandBankWithdrawEvent( + island, commandSender, amount); BankAction bankAction; - if (eventResult.isCancelled()) { + if (event.isCancelled()) { bankAction = BankAction.DEPOSIT_FAILED; Log.debugResult(Debug.WITHDRAW_MONEY, "Return Failure", "Event Cancelled"); } else { @@ -249,9 +250,9 @@ public BankTransaction withdrawAdminMoney(CommandSender commandSender, BigDecima Log.debugResult(Debug.WITHDRAW_MONEY, "Return Success", amount); } BankTransaction bankTransaction = new SBankTransaction(senderUUID, bankAction, position, - System.currentTimeMillis(), eventResult.getResult(), amount); + System.currentTimeMillis(), event.getArgs().failureReason, amount); - if (!eventResult.isCancelled()) + if (!event.isCancelled()) decreaseBalance(amount); addTransaction(bankTransaction, true); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java b/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java index d03ed3f481..f65239b573 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; @@ -59,13 +61,13 @@ public static Result handleSignBreak(SuperiorPlayer superiorPlayer, Sign sign) { IslandWarp islandWarp = island.getWarp(signLocation); if (islandWarp != null) { - if (!plugin.getEventsBus().callIslandDeleteWarpEvent(superiorPlayer, island, islandWarp)) + if (!PluginEventsFactory.callIslandDeleteWarpEvent(island, superiorPlayer, islandWarp)) return new Result(Reason.EVENT_CANCELLED, true); island.deleteWarp(superiorPlayer, signLocation); } else { if (sign.getLine(0).equalsIgnoreCase(plugin.getSettings().getVisitorsSign().getActive())) { - if (!plugin.getEventsBus().callIslandRemoveVisitorHomeEvent(superiorPlayer, island)) + if (!PluginEventsFactory.callIslandRemoveVisitorHomeEvent(island, superiorPlayer)) return new Result(Reason.EVENT_CANCELLED, true); island.setVisitorsLocation(null); @@ -104,7 +106,7 @@ private static Reason handleWarpSignPlace(SuperiorPlayer superiorPlayer, Island result = Reason.NAME_TOO_LONG; } - if (!plugin.getEventsBus().callIslandCreateWarpEvent(superiorPlayer, island, warpName, warpLocation, !privateFlag, null)) + if (!PluginEventsFactory.callIslandCreateWarpEvent(island, superiorPlayer, warpName, warpLocation, !privateFlag, null)) result = Reason.EVENT_CANCELLED; if (result != Reason.SUCCESS) @@ -132,9 +134,10 @@ private static Result handleVisitorsSignPlace(SuperiorPlayer superiorPlayer, Isl return new Result(Reason.LIMIT_REACHED, true); } - EventResult eventResult = plugin.getEventsBus().callIslandSetVisitorHomeEvent(superiorPlayer, island, visitorsLocation); + PluginEvent setVisitorHomeEvent = + PluginEventsFactory.callIslandSetVisitorHomeEvent(island, superiorPlayer, visitorsLocation); - if (eventResult.isCancelled()) + if (setVisitorHomeEvent.isCancelled()) return new Result(Reason.EVENT_CANCELLED, false); StringBuilder descriptionBuilder = new StringBuilder(); @@ -161,12 +164,13 @@ private static Result handleVisitorsSignPlace(SuperiorPlayer superiorPlayer, Isl oldWelcomeSign.update(); } - island.setVisitorsLocation(eventResult.getResult()); + island.setVisitorsLocation(setVisitorHomeEvent.getArgs().islandVisitorHome); - EventResult descriptionEventResult = plugin.getEventsBus().callIslandChangeDescriptionEvent(superiorPlayer, island, description); + PluginEvent changeDescriptionEvent = + PluginEventsFactory.callIslandChangeDescriptionEvent(island, superiorPlayer, description); - if (!descriptionEventResult.isCancelled()) - island.setDescription(descriptionEventResult.getResult()); + if (!changeDescriptionEvent.isCancelled()) + island.setDescription(changeDescriptionEvent.getArgs().description); if (sendMessage) Message.SET_WARP.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(visitorsLocation)); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/AbstractGameEventListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/AbstractGameEventListener.java new file mode 100644 index 0000000000..6c84968930 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/AbstractGameEventListener.java @@ -0,0 +1,30 @@ +package com.bgsoftware.superiorskyblock.listener; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEventCallback; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs; + +public abstract class AbstractGameEventListener { + + + protected final SuperiorSkyblockPlugin plugin; + + protected AbstractGameEventListener(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + } + + protected void registerCallback(GameEventType type, GameEventPriority priority, + GameEventCallback callback) { + registerCallback(type, priority, true, callback); + } + + protected void registerCallback(GameEventType type, GameEventPriority priority, + boolean ignoreCancelled, + GameEventCallback callback) { + plugin.getGameEventsDispatcher().registerCallback(this, type, priority, ignoreCancelled, callback); + } + + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/AdminPlayersListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/AdminPlayersListener.java index 9a008426bf..dabef9231c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/AdminPlayersListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/AdminPlayersListener.java @@ -2,42 +2,45 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.entity.Player; import java.util.UUID; -public class AdminPlayersListener implements Listener { +public class AdminPlayersListener extends AbstractGameEventListener { private static final UUID DEVELOPER_UUID = UUID.fromString("45713654-41bf-45a1-aa6f-00fe6598703b"); - private final SuperiorSkyblockPlugin plugin; private final String buildName; public AdminPlayersListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); String fileName = plugin.getFileName().split("\\.")[0]; String buildName = fileName.contains("-") ? fileName.substring(fileName.indexOf('-') + 1) : ""; this.buildName = buildName.isEmpty() ? "" : " (Build: " + buildName + ")"; + + registerCallback(GameEventType.PLAYER_JOIN_EVENT, GameEventPriority.MONITOR, this::onPlayerJoin); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerJoin(PlayerJoinEvent e) { + private void onPlayerJoin(GameEvent e) { + Player player = e.getArgs().player; + // Notifies me when a server uses one of my plugins. - if (e.getPlayer().getUniqueId().equals(DEVELOPER_UUID)) { - Bukkit.getScheduler().runTaskLater(plugin, () -> Message.CUSTOM.send(e.getPlayer(), + if (player.getUniqueId().equals(DEVELOPER_UUID)) { + Bukkit.getScheduler().runTaskLater(plugin, () -> Message.CUSTOM.send(player, "&8[&fSuperiorSeries&8] &7This server is using SuperiorSkyblock2 v" + plugin.getDescription().getVersion() + buildName, true), 5L); } // Notifies operators about new updates - if (e.getPlayer().isOp() && plugin.getUpdater().isOutdated()) { + if (player.isOp() && plugin.getUpdater().isOutdated()) { Bukkit.getScheduler().runTaskLater(plugin, () -> - e.getPlayer().sendMessage(ChatColor.BLUE + "" + ChatColor.BOLD + "SuperiorSkyblock2" + ChatColor.GRAY + + player.sendMessage(ChatColor.BLUE + "" + ChatColor.BOLD + "SuperiorSkyblock2" + ChatColor.GRAY + " A new version is available (v" + plugin.getUpdater().getLatestVersion() + ")!"), 20L); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index 43408bca6b..abda77d4f1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; @@ -12,7 +11,6 @@ import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; -import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; @@ -20,9 +18,11 @@ import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.world.BukkitEntities; -import com.bgsoftware.superiorskyblock.world.BukkitItems; -import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; @@ -31,41 +31,19 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.Item; import org.bukkit.entity.Minecart; +import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; import org.bukkit.event.block.Action; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.BlockFormEvent; -import org.bukkit.event.block.BlockFromToEvent; -import org.bukkit.event.block.BlockGrowEvent; -import org.bukkit.event.block.BlockPistonExtendEvent; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.block.BlockSpreadEvent; -import org.bukkit.event.block.LeavesDecayEvent; -import org.bukkit.event.entity.EntityChangeBlockEvent; -import org.bukkit.event.entity.EntityDeathEvent; -import org.bukkit.event.entity.EntityExplodeEvent; -import org.bukkit.event.entity.ItemSpawnEvent; -import org.bukkit.event.entity.ProjectileHitEvent; -import org.bukkit.event.player.PlayerBucketEmptyEvent; -import org.bukkit.event.player.PlayerBucketFillEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.vehicle.VehicleCreateEvent; -import org.bukkit.event.vehicle.VehicleDestroyEvent; -import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.metadata.FixedMetadataValue; import java.util.Collection; import java.util.concurrent.TimeUnit; -public class BlockChangesListener implements Listener { +public class BlockChangesListener extends AbstractGameEventListener { - private static final ReflectMethod PROJECTILE_HIT_EVENT_TARGET_BLOCK = new ReflectMethod<>( - ProjectileHitEvent.class, "getHitBlock"); @Nullable private static final Material CHORUS_FLOWER = EnumHelper.getEnum(Material.class, "CHORUS_FLOWER"); @Nullable @@ -80,49 +58,52 @@ public class BlockChangesListener implements Listener { @WorldRecordFlags private static final int ALL_RECORD_FLAGS = REGULAR_RECORD_FLAGS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS; + private final Collection alreadySpongeAbosrbCalled = AutoRemovalCollection.newArrayList(5L * 50, TimeUnit.MILLISECONDS); + private final LazyReference worldRecordService = new LazyReference() { @Override protected WorldRecordService create() { return plugin.getServices().getService(WorldRecordService.class); } }; - private final SuperiorSkyblockPlugin plugin; public BlockChangesListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - this.registerSpongeListener(); - this.registerBlockDestroyListener(); + super(plugin); + this.registerListeners(); } /* BLOCK PLACES */ - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onBlockPlace(BlockPlaceEvent e) { - boolean shouldAvoidReplacedState = e.getBlockReplacedState().equals(e.getBlock().getState()); + private void onBlockPlace(GameEvent e) { + Block block = e.getArgs().block; + BlockState replacedState = e.getArgs().replacedState; + + boolean shouldAvoidReplacedState = replacedState.equals(block.getState()); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockPlace(Keys.of(e.getBlock()), - e.getBlock().getLocation(wrapper.getHandle()), - plugin.getNMSWorld().getDefaultAmount(e.getBlock()), - shouldAvoidReplacedState ? null : e.getBlockReplacedState(), + this.worldRecordService.get().recordBlockPlace(Keys.of(block), + block.getLocation(wrapper.getHandle()), + plugin.getNMSWorld().getDefaultAmount(block), + shouldAvoidReplacedState ? null : replacedState, REGULAR_RECORD_FLAGS); } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onBucketEmpty(PlayerBucketEmptyEvent e) { - Key blockKey = Keys.ofMaterialAndData(e.getBucket().name().replace("_BUCKET", "")); + private void onBucketEmpty(GameEvent e) { + Material bucket = e.getArgs().bucket; + + Key blockKey = Keys.ofMaterialAndData(bucket.name().replace("_BUCKET", "")); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Block clickedBlock = e.getArgs().clickedBlock; this.worldRecordService.get().recordBlockPlace(blockKey, - e.getBlockClicked().getLocation(wrapper.getHandle()), 1, + clickedBlock.getLocation(wrapper.getHandle()), 1, null, REGULAR_RECORD_FLAGS); } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onStructureGrow(StructureGrowEvent e) { + private void onStructureGrow(GameEvent e) { KeyMap placedBlockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); KeyMap brokenBlockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); - e.getBlocks().forEach(blockState -> { + e.getArgs().blocks.forEach(blockState -> { Key placedBlockKey = Keys.of(blockState); Key brokenBlockKey = Keys.of(blockState.getBlock()); if (!placedBlockKey.equals(brokenBlockKey)) { @@ -132,60 +113,68 @@ private void onStructureGrow(StructureGrowEvent e) { brokenBlockCounts.put(brokenBlockKey, brokenBlockCounts.getOrDefault(brokenBlockKey, 0) + 1); } }); - this.worldRecordService.get().recordMultiBlocksPlace(placedBlockCounts, e.getLocation(), WorldRecordFlags.DIRTY_CHUNKS); - this.worldRecordService.get().recordMultiBlocksBreak(brokenBlockCounts, e.getLocation(), WorldRecordFlags.DIRTY_CHUNKS); + Location growLocation = e.getArgs().location; + this.worldRecordService.get().recordMultiBlocksPlace(placedBlockCounts, growLocation, WorldRecordFlags.DIRTY_CHUNKS); + this.worldRecordService.get().recordMultiBlocksBreak(brokenBlockCounts, growLocation, WorldRecordFlags.DIRTY_CHUNKS); } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onBlockGrow(BlockGrowEvent e) { + private void onBlockGrow(GameEvent e) { + Block block = e.getArgs().block; + BlockState newState = e.getArgs().newState; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockPlace(Keys.of(e.getNewState()), - e.getBlock().getLocation(wrapper.getHandle()), - 1, e.getBlock().getState(), REGULAR_RECORD_FLAGS); + this.worldRecordService.get().recordBlockPlace(Keys.of(newState), + block.getLocation(wrapper.getHandle()), + 1, block.getState(), REGULAR_RECORD_FLAGS); } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onBlockFrom(BlockFormEvent e) { + private void onBlockForm(GameEvent e) { + Block block = e.getArgs().block; + BlockState newState = e.getArgs().newState; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = e.getNewState().getLocation(wrapper.getHandle()); + Location location = newState.getLocation(wrapper.getHandle()); // Do not save block counts - this.worldRecordService.get().recordBlockBreak(Keys.of(e.getBlock()), location, 1, WorldRecordFlags.DIRTY_CHUNKS); + this.worldRecordService.get().recordBlockBreak(Keys.of(block), location, 1, WorldRecordFlags.DIRTY_CHUNKS); } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockSpread(BlockSpreadEvent e) { + private void onBlockSpread(GameEvent e) { + Block block = e.getArgs().block; + BlockState newState = e.getArgs().newState; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockPlace(Keys.of(e.getNewState()), - e.getBlock().getLocation(wrapper.getHandle()), - 1, e.getBlock().getState(), REGULAR_RECORD_FLAGS); + this.worldRecordService.get().recordBlockPlace(Keys.of(newState), + block.getLocation(wrapper.getHandle()), + 1, block.getState(), REGULAR_RECORD_FLAGS); } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onMinecartPlace(VehicleCreateEvent e) { - if (e.getVehicle().isDead() || !(e.getVehicle() instanceof Minecart)) + private void onMinecartPlace(GameEvent e) { + Entity vehicle = e.getArgs().entity; + + if (!(vehicle instanceof Minecart)) return; - Key minecartBlockKey = getMinecartBlockKey(e.getVehicle().getType()); + Key minecartBlockKey = getMinecartBlockKey(vehicle.getType()); if (minecartBlockKey != null) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.worldRecordService.get().recordBlockPlace(minecartBlockKey, - e.getVehicle().getLocation(wrapper.getHandle()), + vehicle.getLocation(wrapper.getHandle()), 1, null, REGULAR_RECORD_FLAGS); } } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onSpawnerChange(PlayerInteractEvent e) { - if (e.getAction() != Action.RIGHT_CLICK_BLOCK || - e.getClickedBlock().getType() != Materials.SPAWNER.toBukkitType()) + private void onSpawnerChange(GameEvent e) { + Action action = e.getArgs().action; + Block clickedBlock = e.getArgs().clickedBlock; + + if (action != Action.RIGHT_CLICK_BLOCK || clickedBlock.getType() != Materials.SPAWNER.toBukkitType()) return; - PlayerHand playerHand = BukkitItems.getHand(e); - ItemStack handItem = BukkitItems.getHandItem(e.getPlayer(), playerHand); + ItemStack handItem = e.getArgs().usedItem; if (handItem == null) return; @@ -194,78 +183,78 @@ private void onSpawnerChange(PlayerInteractEvent e) { if (!Materials.isSpawnEgg(handItemType)) return; - Block block = e.getClickedBlock(); - Chunk chunk = block.getChunk(); - BlockState oldBlockState = block.getState(); + Chunk chunk = clickedBlock.getChunk(); + BlockState oldBlockState = clickedBlock.getState(); Key oldSpawnerKey = Keys.of(oldBlockState); BukkitExecutor.sync(() -> { if (!chunk.isLoaded()) return; - Key newSpawnerKey = Keys.of(block); + Key newSpawnerKey = Keys.of(clickedBlock); if (!oldSpawnerKey.equals(newSpawnerKey)) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockPlace(newSpawnerKey, block.getLocation(wrapper.getHandle()), + this.worldRecordService.get().recordBlockPlace(newSpawnerKey, clickedBlock.getLocation(wrapper.getHandle()), 1, oldBlockState, REGULAR_RECORD_FLAGS); } } }, 1L); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onEntityChangeBlock(EntityChangeBlockEvent e) { - Key blockKey; - - if (ServerVersion.isLegacy()) { - // noinspection deprecated - blockKey = Keys.of(e.getTo(), e.getData()); - } else { - blockKey = Keys.of(e.getTo(), (byte) 0); - } + private void onEntityChangeBlock(GameEvent e) { + Key blockKey = e.getArgs().newType; + Block block = e.getArgs().block; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockPlace(blockKey, e.getBlock().getLocation(wrapper.getHandle()), 1, - e.getBlock().getState(), WorldRecordFlags.SAVE_BLOCK_COUNT); + this.worldRecordService.get().recordBlockPlace(blockKey, block.getLocation(wrapper.getHandle()), 1, + block.getState(), WorldRecordFlags.SAVE_BLOCK_COUNT); } } /* BLOCK BREAKS */ - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onBlockBreak(BlockBreakEvent e) { - this.worldRecordService.get().recordBlockBreak(e.getBlock(), ALL_RECORD_FLAGS); + private void onBlockBreak(GameEvent e) { + this.worldRecordService.get().recordBlockBreak(e.getArgs().block, ALL_RECORD_FLAGS); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onEntityBlockDeath(EntityDeathEvent e) { - if (e.getEntity() instanceof FallingBlock) { - Key blockKey = plugin.getNMSAlgorithms().getFallingBlockType((FallingBlock) e.getEntity()); + private void onBlockDestroy(GameEvent e) { + this.worldRecordService.get().recordBlockBreak(e.getArgs().block, WorldRecordFlags.DIRTY_CHUNKS); + } + + private void onEntityBlockDeath(GameEvent e) { + Entity entity = e.getArgs().entity; + if (entity instanceof FallingBlock) { + Key blockKey = plugin.getNMSAlgorithms().getFallingBlockType((FallingBlock) entity); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockBreak(blockKey, e.getEntity().getLocation(wrapper.getHandle()), + this.worldRecordService.get().recordBlockBreak(blockKey, entity.getLocation(wrapper.getHandle()), 1, REGULAR_RECORD_FLAGS); } } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onBucketFill(PlayerBucketFillEvent e) { - boolean isWaterLogged = plugin.getNMSWorld().isWaterLogged(e.getBlockClicked()); - if (isWaterLogged || e.getBlockClicked().isLiquid()) { - Key blockKey = isWaterLogged ? ConstantKeys.WATER : Keys.of(e.getBlockClicked()); + private void onBucketFill(GameEvent e) { + Block clickedBlock = e.getArgs().clickedBlock; + + boolean isWaterLogged = plugin.getNMSWorld().isWaterLogged(clickedBlock); + if (isWaterLogged || clickedBlock.isLiquid()) { + Key blockKey = isWaterLogged ? ConstantKeys.WATER : Keys.of(clickedBlock); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.worldRecordService.get().recordBlockBreak(blockKey, - e.getBlockClicked().getLocation(wrapper.getHandle()), + clickedBlock.getLocation(wrapper.getHandle()), 1, REGULAR_RECORD_FLAGS); } } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onDragonEggDrop(ItemSpawnEvent e) { - if (e.getEntity().getItemStack().getType() == Material.DRAGON_EGG) { + private void onDragonEggDrop(GameEvent e) { + if (!(e.getArgs().entity instanceof Item)) + return; + + Item item = (Item) e.getArgs().entity; + + if (item.getItemStack().getType() == Material.DRAGON_EGG) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - for (Entity nearby : e.getEntity().getNearbyEntities(2, 2, 2)) { + for (Entity nearby : item.getNearbyEntities(2, 2, 2)) { if (nearby instanceof FallingBlock) { Key blockKey = plugin.getNMSAlgorithms().getFallingBlockType((FallingBlock) nearby); this.worldRecordService.get().recordBlockBreak(blockKey, nearby.getLocation(wrapper.getHandle()), @@ -277,39 +266,40 @@ private void onDragonEggDrop(ItemSpawnEvent e) { } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPistonExtend(BlockPistonExtendEvent e) { - for (Block block : e.getBlocks()) { + private void onPistonExtend(GameEvent e) { + for (Block block : e.getArgs().blocks) { if (plugin.getNMSWorld().getPistonReaction(block) == PistonPushReaction.DESTROY) { this.worldRecordService.get().recordBlockBreak(block, 1, REGULAR_RECORD_FLAGS); } } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onLeavesDecay(LeavesDecayEvent e) { - this.worldRecordService.get().recordBlockBreak(e.getBlock(), 1, REGULAR_RECORD_FLAGS); + private void onLeavesDecay(GameEvent e) { + this.worldRecordService.get().recordBlockBreak(e.getArgs().block, 1, REGULAR_RECORD_FLAGS); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onBlockFromTo(BlockFromToEvent e) { - if (e.getToBlock().getType() != Material.AIR) { + private void onBlockFromTo(GameEvent e) { + Block toBlock = e.getArgs().toBlock; + + if (toBlock.getType() != Material.AIR) { // Do not save block counts - this.worldRecordService.get().recordBlockBreak(e.getToBlock(), 1, WorldRecordFlags.DIRTY_CHUNKS); + this.worldRecordService.get().recordBlockBreak(toBlock, 1, WorldRecordFlags.DIRTY_CHUNKS); } else { BukkitExecutor.sync(() -> { // Do not save block counts - this.worldRecordService.get().recordBlockPlace(e.getToBlock(), 1, null, WorldRecordFlags.DIRTY_CHUNKS); + this.worldRecordService.get().recordBlockPlace(toBlock, 1, null, WorldRecordFlags.DIRTY_CHUNKS); }); } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onEntityExplode(EntityExplodeEvent e) { - boolean isWindCharge = e.getEntityType() == WIND_CHARGE || e.getEntityType() == BREEZE_WIND_CHARGE; + private void onEntityExplode(GameEvent e) { + Entity entity = e.getArgs().entity; + EntityType entityType = entity.getType(); + + boolean isWindCharge = entityType == WIND_CHARGE || entityType == BREEZE_WIND_CHARGE; KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); - e.blockList().forEach(block -> { + e.getArgs().blocks.forEach(block -> { Material blockType = block.getType(); // Wind charges only break chorus flowers and pointed drip-stones if (isWindCharge && blockType != CHORUS_FLOWER && blockType != POINTED_DRIPSTONE) @@ -319,52 +309,76 @@ private void onEntityExplode(EntityExplodeEvent e) { blockCounts.put(blockKey, blockCounts.getOrDefault(blockKey, 0) + 1); }); - if (e.getEntity() instanceof TNTPrimed) + if (entity instanceof TNTPrimed) blockCounts.put(ConstantKeys.TNT, blockCounts.getOrDefault(ConstantKeys.TNT, 0) + 1); - this.worldRecordService.get().recordMultiBlocksBreak(blockCounts, e.getLocation(), REGULAR_RECORD_FLAGS); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordMultiBlocksBreak(blockCounts, + entity.getLocation(wrapper.getHandle()), REGULAR_RECORD_FLAGS); + } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onMinecartBreak(VehicleDestroyEvent e) { - if (e.getVehicle() instanceof Minecart) { - Key blockKey = plugin.getNMSAlgorithms().getMinecartBlock((Minecart) e.getVehicle()); + private void onMinecartBreak(GameEvent e) { + Entity vehicle = e.getArgs().entity; + + if (vehicle instanceof Minecart) { + Key blockKey = plugin.getNMSAlgorithms().getMinecartBlock((Minecart) vehicle); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockBreak(blockKey, e.getVehicle().getLocation(wrapper.getHandle()), + this.worldRecordService.get().recordBlockBreak(blockKey, vehicle.getLocation(wrapper.getHandle()), 1, REGULAR_RECORD_FLAGS); } - e.getVehicle().setMetadata("SSB-VehicleDestory", new FixedMetadataValue(plugin, true)); + vehicle.setMetadata("SSB-VehicleDestory", new FixedMetadataValue(plugin, true)); } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onChorusHit(ProjectileHitEvent e) { - if (ServerVersion.isLessThan(ServerVersion.v1_18) && PROJECTILE_HIT_EVENT_TARGET_BLOCK.isValid()) { - BukkitEntities.getPlayerSource(e.getEntity()).ifPresent(shooter -> { - Block hitBlock = PROJECTILE_HIT_EVENT_TARGET_BLOCK.invoke(e); - if (hitBlock != null && hitBlock.getType() == CHORUS_FLOWER) { - this.worldRecordService.get().recordBlockBreak(hitBlock, 1, REGULAR_RECORD_FLAGS); - } - }); - } + private void onChorusHit(GameEvent e) { + BukkitEntities.getPlayerSource(e.getArgs().entity).ifPresent(shooter -> { + Block hitBlock = e.getArgs().hitBlock; + if (hitBlock != null && hitBlock.getType() == CHORUS_FLOWER) { + this.worldRecordService.get().recordBlockBreak(hitBlock, 1, REGULAR_RECORD_FLAGS); + } + }); } - /* INTERNAL */ + private void onSpongeAbsorb(GameEvent e) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Block block = e.getArgs().block; + Location location = block.getLocation(wrapper.getHandle()); + + if (alreadySpongeAbosrbCalled.contains(location)) + return; - private void registerSpongeListener() { - try { - Class.forName("org.bukkit.event.block.SpongeAbsorbEvent"); - Bukkit.getPluginManager().registerEvents(new SpongeAbsorbListener(), plugin); - } catch (Throwable ignored) { + worldRecordService.get().recordBlockPlace(ConstantKeys.WET_SPONGE, location, 1, + block.getState(), WorldRecordFlags.SAVE_BLOCK_COUNT); + + alreadySpongeAbosrbCalled.add(location.clone()); } } - private void registerBlockDestroyListener() { - try { - Class.forName("com.destroystokyo.paper.event.block.BlockDestroyEvent"); - Bukkit.getPluginManager().registerEvents(new BlockDestoryListener(), plugin); - } catch (Throwable ignored) { - } + /* INTERNAL */ + + private void registerListeners() { + registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.MONITOR, this::onBlockPlace); + registerCallback(GameEventType.PLAYER_EMPTY_BUCKET_EVENT, GameEventPriority.MONITOR, this::onBucketEmpty); + registerCallback(GameEventType.STRUCTURE_GROW_EVENT, GameEventPriority.MONITOR, this::onStructureGrow); + registerCallback(GameEventType.BLOCK_GROW_EVENT, GameEventPriority.MONITOR, this::onBlockGrow); + registerCallback(GameEventType.BLOCK_FORM_EVENT, GameEventPriority.MONITOR, this::onBlockForm); + registerCallback(GameEventType.BLOCK_SPREAD_EVENT, GameEventPriority.MONITOR, this::onBlockSpread); + registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.MONITOR, this::onMinecartPlace); + registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.MONITOR, this::onSpawnerChange); + registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.MONITOR, this::onEntityChangeBlock); + registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.MONITOR, this::onBlockBreak); + registerCallback(GameEventType.BLOCK_DESTROY_EVENT, GameEventPriority.MONITOR, this::onBlockDestroy); + registerCallback(GameEventType.ENTITY_DEATH_EVENT, GameEventPriority.MONITOR, this::onEntityBlockDeath); + registerCallback(GameEventType.PLAYER_FILL_BUCKET_EVENT, GameEventPriority.MONITOR, this::onBucketFill); + registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.MONITOR, this::onDragonEggDrop); + registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.MONITOR, this::onPistonExtend); + registerCallback(GameEventType.LEAVES_DECAY_EVENT, GameEventPriority.MONITOR, this::onLeavesDecay); + registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.MONITOR, this::onBlockFromTo); + registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.MONITOR, this::onEntityExplode); + registerCallback(GameEventType.ENTITY_DEATH_EVENT, GameEventPriority.MONITOR, this::onMinecartBreak); + registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.MONITOR, this::onChorusHit); + registerCallback(GameEventType.SPONGE_ABSORB_EVENT, GameEventPriority.MONITOR, this::onSpongeAbsorb); } @Nullable @@ -387,37 +401,4 @@ private static Key getMinecartBlockKey(EntityType minecartType) { return null; } - private class SpongeAbsorbListener implements Listener { - - private final Collection alreadySpongeAbosrbCalled = AutoRemovalCollection.newArrayList(5L * 50, TimeUnit.MILLISECONDS); - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onSpongeAbsorb(org.bukkit.event.block.SpongeAbsorbEvent e) { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = e.getBlock().getLocation(wrapper.getHandle()); - - if (alreadySpongeAbosrbCalled.contains(location)) - return; - - worldRecordService.get().recordBlockPlace(ConstantKeys.WET_SPONGE, location, 1, - e.getBlock().getState(), WorldRecordFlags.SAVE_BLOCK_COUNT); - - alreadySpongeAbosrbCalled.add(location.clone()); - } - } - - } - - private class BlockDestoryListener implements Listener { - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockDestroy(com.destroystokyo.paper.event.block.BlockDestroyEvent e) { - if (e.getNewState().getMaterial() != Material.AIR) - return; - - worldRecordService.get().recordBlockBreak(e.getBlock(), WorldRecordFlags.DIRTY_CHUNKS); - } - - } - } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java new file mode 100644 index 0000000000..151b156f5d --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -0,0 +1,943 @@ +package com.bgsoftware.superiorskyblock.listener; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.platform.IEventsDispatcher; +import com.bgsoftware.superiorskyblock.core.ServerVersion; +import com.bgsoftware.superiorskyblock.core.events.EventCallback; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs; +import com.bgsoftware.superiorskyblock.world.BukkitItems; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Entity; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockBurnEvent; +import org.bukkit.event.block.BlockDispenseEvent; +import org.bukkit.event.block.BlockFormEvent; +import org.bukkit.event.block.BlockFromToEvent; +import org.bukkit.event.block.BlockGrowEvent; +import org.bukkit.event.block.BlockIgniteEvent; +import org.bukkit.event.block.BlockPhysicsEvent; +import org.bukkit.event.block.BlockPistonExtendEvent; +import org.bukkit.event.block.BlockPistonRetractEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.BlockRedstoneEvent; +import org.bukkit.event.block.BlockSpreadEvent; +import org.bukkit.event.block.EntityBlockFormEvent; +import org.bukkit.event.block.LeavesDecayEvent; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.EntityChangeBlockEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.EntityPortalEnterEvent; +import org.bukkit.event.entity.EntityPortalEvent; +import org.bukkit.event.entity.EntityTargetEvent; +import org.bukkit.event.entity.EntityTeleportEvent; +import org.bukkit.event.entity.ItemSpawnEvent; +import org.bukkit.event.entity.PlayerLeashEntityEvent; +import org.bukkit.event.entity.ProjectileHitEvent; +import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.event.hanging.HangingBreakByEntityEvent; +import org.bukkit.event.hanging.HangingPlaceEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.PlayerBucketEmptyEvent; +import org.bukkit.event.player.PlayerBucketFillEvent; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerDropItemEvent; +import org.bukkit.event.player.PlayerGameModeChangeEvent; +import org.bukkit.event.player.PlayerInteractAtEntityEvent; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerLoginEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.event.player.PlayerRespawnEvent; +import org.bukkit.event.player.PlayerShearEntityEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.event.player.PlayerUnleashEntityEvent; +import org.bukkit.event.vehicle.VehicleCreateEvent; +import org.bukkit.event.vehicle.VehicleDamageEvent; +import org.bukkit.event.vehicle.VehicleDestroyEvent; +import org.bukkit.event.vehicle.VehicleEnterEvent; +import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; +import org.bukkit.event.vehicle.VehicleMoveEvent; +import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.event.world.ChunkUnloadEvent; +import org.bukkit.event.world.StructureGrowEvent; +import org.bukkit.event.world.WorldUnloadEvent; + +import java.util.List; +import java.util.Map; + +public class BukkitEventsListener implements Listener { + + private static final ReflectMethod PROJECTILE_HIT_TARGET_ENTITY = new ReflectMethod<>( + ProjectileHitEvent.class, "getHitEntity"); + private static final ReflectMethod PROJECTILE_HIT_EVENT_TARGET_BLOCK = new ReflectMethod<>( + ProjectileHitEvent.class, "getHitBlock"); + + private final SuperiorSkyblockPlugin plugin; + + private boolean shouldFireAttemptEntitySpawnEvent = false; + + public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + + createEventListener(GameEventType.PLAYER_JOIN_EVENT, PlayerJoinEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_QUIT_EVENT, PlayerQuitEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_PLACE_EVENT, BlockPlaceEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_EMPTY_BUCKET_EVENT, PlayerBucketEmptyEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_FILL_BUCKET_EVENT, PlayerBucketFillEvent.class, this::createGameEvent); + createEventListener(GameEventType.STRUCTURE_GROW_EVENT, StructureGrowEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_GROW_EVENT, BlockGrowEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_FORM_EVENT, BlockFormEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_SPREAD_EVENT, BlockSpreadEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_SPAWN_EVENT, VehicleCreateEvent.class, this::createGameEvent, this::cancelVehicleCreateEvent); + createEventListener(GameEventType.ENTITY_SPAWN_EVENT, HangingPlaceEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_SPAWN_EVENT, CreatureSpawnEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, EntityChangeBlockEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_BREAK_EVENT, BlockBreakEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_DEATH_EVENT, EntityDeathEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_SPAWN_EVENT, ItemSpawnEvent.class, this::createGameEvent); + createEventListener(GameEventType.PISTON_EXTEND_EVENT, BlockPistonExtendEvent.class, this::createGameEvent); + createEventListener(GameEventType.PISTON_RETRACT_EVENT, BlockPistonRetractEvent.class, this::createGameEvent); + createEventListener(GameEventType.LEAVES_DECAY_EVENT, LeavesDecayEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_FROM_TO_EVENT, BlockFromToEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_EXPLODE_EVENT, EntityExplodeEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_DEATH_EVENT, VehicleDestroyEvent.class, this::createGameEvent); + createEventListener(GameEventType.CHUNK_LOAD_EVENT, ChunkLoadEvent.class, this::createGameEvent); + createEventListener(GameEventType.CHUNK_UNLOAD_EVENT, ChunkUnloadEvent.class, this::createGameEvent); + createEventListener(GameEventType.WORLD_UNLOAD_EVENT, WorldUnloadEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_COMMAND_EVENT, PlayerCommandPreprocessEvent.class, this::createGameEvent); + createEventListener(GameEventType.HANGING_BREAK_EVENT, HangingBreakByEntityEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, EntityDamageByEntityEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_BURN_EVENT, BlockBurnEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_IGNITE_EVENT, BlockIgniteEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractAtEntityEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractEntityEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_RIDE_EVENT, VehicleEnterEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_MOVE_EVENT, VehicleMoveEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_MOVE_EVENT, PlayerMoveEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_TELEPORT_EVENT, EntityTeleportEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_TELEPORT_EVENT, PlayerTeleportEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_REDSTONE_EVENT, BlockRedstoneEvent.class, this::createGameEvent, this::cancelBlockRedstoneEvent); + createEventListener(GameEventType.INVENTORY_CLICK_EVENT, InventoryClickEvent.class, this::createGameEvent); + createEventListener(GameEventType.INVENTORY_CLOSE_EVENT, InventoryCloseEvent.class, this::createGameEvent); + createEventListener(GameEventType.INVENTORY_OPEN_EVENT, InventoryOpenEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_LOGIN_EVENT, PlayerLoginEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_GAMEMODE_CHANGE, PlayerGameModeChangeEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_CHANGED_WORLD_EVENT, PlayerChangedWorldEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_RESPAWN_EVENT, PlayerRespawnEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_PORTAL_EVENT, EntityPortalEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_ENTER_PORTAL_EVENT, EntityPortalEnterEvent.class, this::createGameEvent); + createEventListener(GameEventType.PROJECTILE_LAUNCH_EVENT, ProjectileLaunchEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_BLOCK_FORM_EVENT, EntityBlockFormEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_DISPENSE_EVENT, BlockDispenseEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_ITEM_CONSUME_EVENT, PlayerItemConsumeEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_SHEAR_ENTITY_EVENT, PlayerShearEntityEvent.class, this::createGameEvent); + createEventListener(GameEventType.HANGING_PLACE_EVENT, HangingPlaceEvent.class, this::createGameEvent2); + createEventListener(GameEventType.ENTITY_TARGET_EVENT, EntityTargetEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_LEASH_ENTITY_EVENT, PlayerLeashEntityEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_UNLEASH_ENTITY_EVENT, PlayerUnleashEntityEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, VehicleDamageEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_COLLISION_EVENT, VehicleEntityCollisionEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_DROP_ITEM_EVENT, PlayerDropItemEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_PICKUP_ITEM_EVENT, PlayerPickupItemEvent.class, this::createGameEvent); + createEventListener(GameEventType.PROJECTILE_HIT_EVENT, ProjectileHitEvent.class, this::createGameEvent); + createEventListener(GameEventType.SIGN_CHANGE_EVENT, SignChangeEvent.class, this::createGameEvent); + + try { + Class.forName("org.bukkit.event.block.SpongeAbsorbEvent"); + createEventListener(GameEventType.SPONGE_ABSORB_EVENT, org.bukkit.event.block.SpongeAbsorbEvent.class, new SpongeAbsorbEventFunction()); + } catch (ClassNotFoundException ignored) { + } + + try { + Class.forName("com.destroystokyo.paper.event.block.BlockDestroyEvent"); + createEventListener(GameEventType.BLOCK_DESTROY_EVENT, com.destroystokyo.paper.event.block.BlockDestroyEvent.class, new BlockDestroyEventFunction()); + } catch (ClassNotFoundException ignored) { + } + + try { + Class.forName("com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent"); + createEventListener(GameEventType.ENTITY_DEATH_EVENT, com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent.class, new EntityRemoveFromWorldEventFunction()); + } catch (ClassNotFoundException ignored) { + } + + try { + Class.forName("com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent"); + createEventListener(GameEventType.ATTEMPT_ENTITY_SPAWN_EVENT, com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent.class, new AttemptEntitySpawnEventFunction()); + } catch (ClassNotFoundException ignored) { + shouldFireAttemptEntitySpawnEvent = true; + } + + boolean registeredChatListener = false; + if (plugin.getSettings().getChatSigningSupport()) { + try { + Class.forName("io.papermc.paper.event.player.AsyncChatEvent"); + createEventListener(GameEventType.PLAYER_CHAT_EVENT, io.papermc.paper.event.player.AsyncChatEvent.class, new AsyncChatEventFunctions(), new AsyncChatEventFunctions()); + registeredChatListener = true; + } catch (Exception ignored) { + } + } + + if (!registeredChatListener) + createEventListener(GameEventType.PLAYER_CHAT_EVENT, AsyncPlayerChatEvent.class, this::createGameEvent); + + try { + Class.forName("org.bukkit.event.player.PlayerPickupArrowEvent"); + createEventListener(GameEventType.PLAYER_PICKUP_ARROW_EVENT, org.bukkit.event.player.PlayerPickupArrowEvent.class, new PlayerPickupArrowEventFunctions()); + } catch (Exception ignored) { + } + + try { + Class.forName("org.bukkit.event.player.PlayerAttemptPickupItemEvent"); + createEventListener(GameEventType.PLAYER_PICKUP_ITEM_EVENT, org.bukkit.event.player.PlayerAttemptPickupItemEvent.class, new PlayerPickupItemEventFunctions()); + } catch (Exception ignored) { + } + + try { + Class.forName("org.bukkit.event.raid.RaidTriggerEvent"); + createEventListener(GameEventType.RAID_TRIGGER_EVENT, org.bukkit.event.raid.RaidTriggerEvent.class, new RaidTriggerEventFunctions()); + } catch (Exception ignored) { + } + + if (plugin.getSettings().isPhysicsListener()) + createEventListener(GameEventType.BLOCK_PHYSICS_EVENT, BlockPhysicsEvent.class, this::createGameEvent); + + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerJoinEvent e) { + GameEventArgs.PlayerJoinEvent playerJoinEvent = new GameEventArgs.PlayerJoinEvent(); + playerJoinEvent.player = e.getPlayer(); + return eventType.createEvent(playerJoinEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerQuitEvent e) { + GameEventArgs.PlayerQuitEvent playerQuitEvent = new GameEventArgs.PlayerQuitEvent(); + playerQuitEvent.player = e.getPlayer(); + return eventType.createEvent(playerQuitEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPlaceEvent e) { + GameEventArgs.BlockPlaceEvent blockPlaceEvent = new GameEventArgs.BlockPlaceEvent(); + blockPlaceEvent.block = e.getBlock(); + blockPlaceEvent.player = e.getPlayer(); + blockPlaceEvent.againstBlock = e.getBlockAgainst(); + blockPlaceEvent.replacedState = e.getBlockReplacedState(); + blockPlaceEvent.usedHand = BukkitItems.getHand(e); + blockPlaceEvent.usedItem = BukkitItems.getHandItem(e.getPlayer(), blockPlaceEvent.usedHand); + return eventType.createEvent(blockPlaceEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerBucketEmptyEvent e) { + GameEventArgs.PlayerEmptyBucketEvent playerEmptyBucketEvent = new GameEventArgs.PlayerEmptyBucketEvent(); + playerEmptyBucketEvent.player = e.getPlayer(); + playerEmptyBucketEvent.bucket = e.getBucket(); + playerEmptyBucketEvent.clickedBlock = e.getBlockClicked(); + return eventType.createEvent(playerEmptyBucketEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerBucketFillEvent e) { + GameEventArgs.PlayerFillBucketEvent playerFillBucketEvent = new GameEventArgs.PlayerFillBucketEvent(); + playerFillBucketEvent.player = e.getPlayer(); + playerFillBucketEvent.bucket = e.getBucket(); + playerFillBucketEvent.clickedBlock = e.getBlockClicked(); + return eventType.createEvent(playerFillBucketEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, StructureGrowEvent e) { + GameEventArgs.StructureGrowEvent structureGrowEvent = new GameEventArgs.StructureGrowEvent(); + structureGrowEvent.world = e.getWorld(); + structureGrowEvent.location = e.getLocation(); + structureGrowEvent.blocks = e.getBlocks(); + return eventType.createEvent(structureGrowEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockGrowEvent e) { + GameEventArgs.BlockGrowEvent blockGrowEvent = new GameEventArgs.BlockGrowEvent(); + blockGrowEvent.block = e.getBlock(); + blockGrowEvent.newState = e.getNewState(); + return eventType.createEvent(blockGrowEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockFormEvent e) { + GameEventArgs.BlockFormEvent blockFormEvent = new GameEventArgs.BlockFormEvent(); + blockFormEvent.block = e.getBlock(); + blockFormEvent.newState = e.getNewState(); + return eventType.createEvent(blockFormEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockSpreadEvent e) { + GameEventArgs.BlockSpreadEvent blockSpreadEvent = new GameEventArgs.BlockSpreadEvent(); + blockSpreadEvent.block = e.getBlock(); + blockSpreadEvent.newState = e.getNewState(); + blockSpreadEvent.source = e.getSource(); + return eventType.createEvent(blockSpreadEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleCreateEvent e) { + GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); + entitySpawnEvent.entity = e.getVehicle(); + entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT; + return eventType.createEvent(entitySpawnEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, HangingPlaceEvent e) { + GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); + entitySpawnEvent.entity = e.getEntity(); + entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT; + return eventType.createEvent(entitySpawnEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, CreatureSpawnEvent e) { + if (this.shouldFireAttemptEntitySpawnEvent) { + GameEventArgs.AttemptEntitySpawnEvent attemptEntitySpawnEvent = new GameEventArgs.AttemptEntitySpawnEvent(); + attemptEntitySpawnEvent.entityType = e.getEntityType(); + attemptEntitySpawnEvent.spawnLocation = e.getLocation(); + attemptEntitySpawnEvent.spawnReason = e.getSpawnReason(); + GameEvent gameEvent = GameEventType.ATTEMPT_ENTITY_SPAWN_EVENT + .createEvent(attemptEntitySpawnEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, priority); + if (gameEvent.isCancelled()) { + e.getEntity().remove(); + return null; + } + } + + GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); + entitySpawnEvent.entity = e.getEntity(); + entitySpawnEvent.spawnReason = e.getSpawnReason(); + return eventType.createEvent(entitySpawnEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ItemSpawnEvent e) { + GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); + entitySpawnEvent.entity = e.getEntity(); + entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT; + return eventType.createEvent(entitySpawnEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerInteractEvent e) { + GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent(); + playerInteractEvent.player = e.getPlayer(); + playerInteractEvent.action = e.getAction(); + playerInteractEvent.usedHand = BukkitItems.getHand(e); + playerInteractEvent.usedItem = BukkitItems.getHandItem(e.getPlayer(), playerInteractEvent.usedHand); + playerInteractEvent.clickedBlock = e.getClickedBlock(); + return eventType.createEvent(playerInteractEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityChangeBlockEvent e) { + GameEventArgs.EntityChangeBlockEvent entityChangeBlockEvent = new GameEventArgs.EntityChangeBlockEvent(); + + entityChangeBlockEvent.entity = e.getEntity(); + entityChangeBlockEvent.block = e.getBlock(); + if (ServerVersion.isLegacy()) { + // noinspection deprecated + entityChangeBlockEvent.newType = Keys.of(e.getTo(), e.getData()); + } else { + entityChangeBlockEvent.newType = Keys.of(e.getTo(), (byte) 0); + } + + return eventType.createEvent(entityChangeBlockEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockBreakEvent e) { + GameEventArgs.BlockBreakEvent blockBreakEvent = new GameEventArgs.BlockBreakEvent(); + blockBreakEvent.block = e.getBlock(); + blockBreakEvent.player = e.getPlayer(); + return eventType.createEvent(blockBreakEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityDeathEvent e) { + GameEventArgs.EntityDeathEvent entityDeathEvent = new GameEventArgs.EntityDeathEvent(); + entityDeathEvent.entity = e.getEntity(); + return eventType.createEvent(entityDeathEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleDestroyEvent e) { + GameEventArgs.EntityDeathEvent entityDeathEvent = new GameEventArgs.EntityDeathEvent(); + entityDeathEvent.entity = e.getVehicle(); + return eventType.createEvent(entityDeathEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPistonExtendEvent e) { + GameEventArgs.PistonExtendEvent pistonExtendEvent = new GameEventArgs.PistonExtendEvent(); + pistonExtendEvent.block = e.getBlock(); + pistonExtendEvent.blocks = e.getBlocks(); + pistonExtendEvent.direction = e.getDirection(); + return eventType.createEvent(pistonExtendEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPistonRetractEvent e) { + GameEventArgs.PistonRetractEvent pistonRetractEvent = new GameEventArgs.PistonRetractEvent(); + pistonRetractEvent.block = e.getBlock(); + pistonRetractEvent.blocks = e.getBlocks(); + pistonRetractEvent.direction = e.getDirection(); + return eventType.createEvent(pistonRetractEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, LeavesDecayEvent e) { + GameEventArgs.LeavesDecayEvent leavesDecayEvent = new GameEventArgs.LeavesDecayEvent(); + leavesDecayEvent.block = e.getBlock(); + return eventType.createEvent(leavesDecayEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockFromToEvent e) { + GameEventArgs.BlockFromToEvent blockFromToEvent = new GameEventArgs.BlockFromToEvent(); + blockFromToEvent.block = e.getBlock(); + blockFromToEvent.toBlock = e.getToBlock(); + return eventType.createEvent(blockFromToEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityExplodeEvent e) { + GameEventArgs.EntityExplodeEvent entityExplodeEvent = new GameEventArgs.EntityExplodeEvent(); + entityExplodeEvent.entity = e.getEntity(); + entityExplodeEvent.blocks = e.blockList(); + return eventType.createEvent(entityExplodeEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ProjectileHitEvent e) { + GameEventArgs.ProjectileHitEvent projectileHitEvent = new GameEventArgs.ProjectileHitEvent(); + projectileHitEvent.entity = e.getEntity(); + if (PROJECTILE_HIT_TARGET_ENTITY.isValid()) + projectileHitEvent.hitEntity = PROJECTILE_HIT_TARGET_ENTITY.invoke(e); + if (PROJECTILE_HIT_EVENT_TARGET_BLOCK.isValid()) + projectileHitEvent.hitBlock = PROJECTILE_HIT_EVENT_TARGET_BLOCK.invoke(e); + return eventType.createEvent(projectileHitEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, SignChangeEvent e) { + GameEventArgs.SignChangeEvent signChangeEvent = new GameEventArgs.SignChangeEvent(); + signChangeEvent.block = e.getBlock(); + signChangeEvent.player = e.getPlayer(); + signChangeEvent.lines = e.getLines(); + return eventType.createEvent(signChangeEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ChunkLoadEvent e) { + GameEventArgs.ChunkLoadEvent chunkLoadEvent = new GameEventArgs.ChunkLoadEvent(); + chunkLoadEvent.chunk = e.getChunk(); + chunkLoadEvent.isNewChunk = e.isNewChunk(); + return eventType.createEvent(chunkLoadEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ChunkUnloadEvent e) { + GameEventArgs.ChunkUnloadEvent chunkUnloadEvent = new GameEventArgs.ChunkUnloadEvent(); + chunkUnloadEvent.chunk = e.getChunk(); + return eventType.createEvent(chunkUnloadEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, WorldUnloadEvent e) { + GameEventArgs.WorldUnloadEvent worldUnloadEvent = new GameEventArgs.WorldUnloadEvent(); + worldUnloadEvent.world = e.getWorld(); + return eventType.createEvent(worldUnloadEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerCommandPreprocessEvent e) { + GameEventArgs.PlayerCommandEvent playerCommandEvent = new GameEventArgs.PlayerCommandEvent(); + playerCommandEvent.player = e.getPlayer(); + playerCommandEvent.command = e.getMessage(); + return eventType.createEvent(playerCommandEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, HangingBreakByEntityEvent e) { + GameEventArgs.HangingBreakEvent hangingBreakEvent = new GameEventArgs.HangingBreakEvent(); + hangingBreakEvent.entity = e.getEntity(); + hangingBreakEvent.remover = e.getRemover(); + hangingBreakEvent.removeCause = e.getCause(); + return eventType.createEvent(hangingBreakEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityDamageByEntityEvent e) { + GameEventArgs.EntityDamageEvent entityDamageEvent = new GameEventArgs.EntityDamageEvent(); + entityDamageEvent.entity = e.getEntity(); + entityDamageEvent.damageCause = e.getCause(); + entityDamageEvent.damager = e.getDamager(); + return eventType.createEvent(entityDamageEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockBurnEvent e) { + GameEventArgs.BlockBurnEvent blockBurnEvent = new GameEventArgs.BlockBurnEvent(); + blockBurnEvent.block = e.getBlock(); + return eventType.createEvent(blockBurnEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockIgniteEvent e) { + GameEventArgs.BlockIgniteEvent blockIgniteEvent = new GameEventArgs.BlockIgniteEvent(); + blockIgniteEvent.block = e.getBlock(); + blockIgniteEvent.igniteCause = e.getCause(); + return eventType.createEvent(blockIgniteEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerInteractAtEntityEvent e) { + GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent(); + playerInteractEvent.player = e.getPlayer(); + playerInteractEvent.action = Action.RIGHT_CLICK_AIR; + playerInteractEvent.usedHand = BukkitItems.getHand(e); + playerInteractEvent.usedItem = BukkitItems.getHandItem(e.getPlayer(), playerInteractEvent.usedHand); + playerInteractEvent.clickedEntity = e.getRightClicked(); + return eventType.createEvent(playerInteractEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerInteractEntityEvent e) { + GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent(); + playerInteractEvent.player = e.getPlayer(); + playerInteractEvent.action = Action.RIGHT_CLICK_AIR; + playerInteractEvent.usedHand = BukkitItems.getHand(e); + playerInteractEvent.usedItem = BukkitItems.getHandItem(e.getPlayer(), playerInteractEvent.usedHand); + playerInteractEvent.clickedEntity = e.getRightClicked(); + return eventType.createEvent(playerInteractEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleEnterEvent e) { + GameEventArgs.EntityRideEvent entityRideEvent = new GameEventArgs.EntityRideEvent(); + entityRideEvent.entity = e.getEntered(); + entityRideEvent.vehicle = e.getVehicle(); + return eventType.createEvent(entityRideEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleMoveEvent e) { + Location from = e.getFrom(); + Location to = e.getTo(); + + if (from.getBlockX() == to.getBlockX() && from.getBlockZ() == to.getBlockZ() && from.getBlockY() == to.getBlockY()) + return null; + + GameEventArgs.EntityMoveEvent entityMoveEvent = new GameEventArgs.EntityMoveEvent(); + entityMoveEvent.entity = e.getVehicle(); + entityMoveEvent.from = e.getFrom(); + entityMoveEvent.to = e.getTo(); + return eventType.createEvent(entityMoveEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerMoveEvent e) { + Location from = e.getFrom(); + Location to = e.getTo(); + + if (from.getBlockX() == to.getBlockX() && from.getBlockZ() == to.getBlockZ() && from.getBlockY() == to.getBlockY()) + return null; + + GameEventArgs.EntityMoveEvent entityMoveEvent = new GameEventArgs.EntityMoveEvent(); + entityMoveEvent.entity = e.getPlayer(); + entityMoveEvent.from = e.getFrom(); + entityMoveEvent.to = e.getTo(); + return eventType.createEvent(entityMoveEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityTeleportEvent e) { + GameEventArgs.EntityTeleportEvent entityTeleportEvent = new GameEventArgs.EntityTeleportEvent(); + entityTeleportEvent.entity = e.getEntity(); + entityTeleportEvent.from = e.getFrom(); + entityTeleportEvent.to = e.getTo(); + entityTeleportEvent.cause = PlayerTeleportEvent.TeleportCause.UNKNOWN; + return eventType.createEvent(entityTeleportEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerTeleportEvent e) { + GameEventArgs.EntityTeleportEvent entityTeleportEvent = new GameEventArgs.EntityTeleportEvent(); + entityTeleportEvent.entity = e.getPlayer(); + entityTeleportEvent.from = e.getFrom(); + entityTeleportEvent.to = e.getTo(); + entityTeleportEvent.cause = e.getCause(); + return eventType.createEvent(entityTeleportEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockRedstoneEvent e) { + GameEventArgs.BlockRedstoneEvent blockRedstoneEvent = new GameEventArgs.BlockRedstoneEvent(); + blockRedstoneEvent.block = e.getBlock(); + return eventType.createEvent(blockRedstoneEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, InventoryClickEvent e) { + GameEventArgs.InventoryClickEvent inventoryClickEvent = new GameEventArgs.InventoryClickEvent(); + inventoryClickEvent.bukkitEvent = e; + return eventType.createEvent(inventoryClickEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, InventoryCloseEvent e) { + GameEventArgs.InventoryCloseEvent inventoryCloseEvent = new GameEventArgs.InventoryCloseEvent(); + inventoryCloseEvent.bukkitEvent = e; + return eventType.createEvent(inventoryCloseEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, InventoryOpenEvent e) { + GameEventArgs.InventoryOpenEvent inventoryOpenEvent = new GameEventArgs.InventoryOpenEvent(); + inventoryOpenEvent.bukkitEvent = e; + return eventType.createEvent(inventoryOpenEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerLoginEvent e) { + GameEventArgs.PlayerLoginEvent playerLoginEvent = new GameEventArgs.PlayerLoginEvent(); + playerLoginEvent.player = e.getPlayer(); + return eventType.createEvent(playerLoginEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerGameModeChangeEvent e) { + GameEventArgs.PlayerGamemodeChangeEvent playerGamemodeChangeEvent = new GameEventArgs.PlayerGamemodeChangeEvent(); + playerGamemodeChangeEvent.player = e.getPlayer(); + playerGamemodeChangeEvent.newGamemode = e.getNewGameMode(); + return eventType.createEvent(playerGamemodeChangeEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerChangedWorldEvent e) { + GameEventArgs.PlayerChangedWorldEvent playerChangedWorldEvent = new GameEventArgs.PlayerChangedWorldEvent(); + playerChangedWorldEvent.player = e.getPlayer(); + playerChangedWorldEvent.from = e.getFrom(); + return eventType.createEvent(playerChangedWorldEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerRespawnEvent e) { + GameEventArgs.PlayerRespawnEvent playerRespawnEvent = new GameEventArgs.PlayerRespawnEvent(); + playerRespawnEvent.player = e.getPlayer(); + playerRespawnEvent.bukkitEvent = e; + return eventType.createEvent(playerRespawnEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityPortalEnterEvent e) { + GameEventArgs.EntityEnterPortalEvent entityEnterPortalEvent = new GameEventArgs.EntityEnterPortalEvent(); + entityEnterPortalEvent.entity = e.getEntity(); + entityEnterPortalEvent.portalLocation = e.getLocation(); + return eventType.createEvent(entityEnterPortalEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ProjectileLaunchEvent e) { + GameEventArgs.ProjectileLaunchEvent projectileLaunchEvent = new GameEventArgs.ProjectileLaunchEvent(); + projectileLaunchEvent.entity = e.getEntity(); + return eventType.createEvent(projectileLaunchEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityBlockFormEvent e) { + GameEventArgs.EntityBlockFormEvent entityBlockFormEvent = new GameEventArgs.EntityBlockFormEvent(); + entityBlockFormEvent.block = e.getBlock(); + entityBlockFormEvent.newState = e.getNewState(); + entityBlockFormEvent.entity = e.getEntity(); + return eventType.createEvent(entityBlockFormEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockDispenseEvent e) { + GameEventArgs.BlockDispenseEvent blockDispenseEvent = new GameEventArgs.BlockDispenseEvent(); + blockDispenseEvent.block = e.getBlock(); + blockDispenseEvent.dispensedItem = e.getItem(); + blockDispenseEvent.velocity = e.getVelocity(); + return eventType.createEvent(blockDispenseEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerItemConsumeEvent e) { + GameEventArgs.PlayerItemConsumeEvent playerItemConsumeEvent = new GameEventArgs.PlayerItemConsumeEvent(); + playerItemConsumeEvent.player = e.getPlayer(); + playerItemConsumeEvent.consumedItem = e.getItem(); + return eventType.createEvent(playerItemConsumeEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerShearEntityEvent e) { + GameEventArgs.PlayerShearEntityEvent playerShearEntityEvent = new GameEventArgs.PlayerShearEntityEvent(); + playerShearEntityEvent.player = e.getPlayer(); + playerShearEntityEvent.entity = e.getEntity(); + return eventType.createEvent(playerShearEntityEvent); + } + + private GameEvent createGameEvent2(GameEventType eventType, GameEventPriority priority, HangingPlaceEvent e) { + GameEventArgs.HangingPlaceEvent hangingPlaceEvent = new GameEventArgs.HangingPlaceEvent(); + hangingPlaceEvent.entity = e.getEntity(); + hangingPlaceEvent.player = e.getPlayer(); + return eventType.createEvent(hangingPlaceEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityTargetEvent e) { + GameEventArgs.EntityTargetEvent entityTargetEvent = new GameEventArgs.EntityTargetEvent(); + entityTargetEvent.entity = e.getEntity(); + entityTargetEvent.target = e.getTarget(); + return eventType.createEvent(entityTargetEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerLeashEntityEvent e) { + GameEventArgs.PlayerLeashEntityEvent playerLeashEntityEvent = new GameEventArgs.PlayerLeashEntityEvent(); + playerLeashEntityEvent.player = e.getPlayer(); + playerLeashEntityEvent.entity = e.getEntity(); + return eventType.createEvent(playerLeashEntityEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerUnleashEntityEvent e) { + GameEventArgs.PlayerUnleashEntityEvent playerUnleashEntityEvent = new GameEventArgs.PlayerUnleashEntityEvent(); + playerUnleashEntityEvent.player = e.getPlayer(); + playerUnleashEntityEvent.entity = e.getEntity(); + return eventType.createEvent(playerUnleashEntityEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleDamageEvent e) { + GameEventArgs.EntityDamageEvent entityDamageEvent = new GameEventArgs.EntityDamageEvent(); + entityDamageEvent.entity = e.getVehicle(); + entityDamageEvent.damager = e.getAttacker(); + entityDamageEvent.damageCause = EntityDamageEvent.DamageCause.ENTITY_ATTACK; + return eventType.createEvent(entityDamageEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleEntityCollisionEvent e) { + GameEventArgs.EntityCollisionEvent entityCollisionEvent = new GameEventArgs.EntityCollisionEvent(); + entityCollisionEvent.entity = e.getEntity(); + entityCollisionEvent.target = e.getVehicle(); + return eventType.createEvent(entityCollisionEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerDropItemEvent e) { + GameEventArgs.PlayerDropItemEvent playerDropItemEvent = new GameEventArgs.PlayerDropItemEvent(); + playerDropItemEvent.player = e.getPlayer(); + playerDropItemEvent.droppedItem = e.getItemDrop(); + return eventType.createEvent(playerDropItemEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerPickupItemEvent e) { + GameEventArgs.PlayerPickupItemEvent playerPickupItemEvent = new GameEventArgs.PlayerPickupItemEvent(); + playerPickupItemEvent.player = e.getPlayer(); + playerPickupItemEvent.pickedUpItem = e.getItem(); + return eventType.createEvent(playerPickupItemEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityPortalEvent e) { + GameEventArgs.EntityPortalEvent entityPortalEvent = new GameEventArgs.EntityPortalEvent(); + entityPortalEvent.entity = e.getEntity(); + entityPortalEvent.cause = e.getTo().getWorld().getEnvironment() == World.Environment.THE_END || + e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ? + PlayerTeleportEvent.TeleportCause.NETHER_PORTAL : PlayerTeleportEvent.TeleportCause.END_PORTAL; + entityPortalEvent.from = e.getFrom(); + entityPortalEvent.to = e.getTo(); + return eventType.createEvent(entityPortalEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, AsyncPlayerChatEvent e) { + GameEventArgs.PlayerChatEvent playerChatEvent = new GameEventArgs.PlayerChatEvent(); + playerChatEvent.player = e.getPlayer(); + playerChatEvent.message = e.getMessage(); + playerChatEvent.format = e.getFormat(); + return eventType.createEvent(playerChatEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPhysicsEvent e) { + GameEventArgs.BlockPhysicsEvent blockPhysicsEvent = new GameEventArgs.BlockPhysicsEvent(); + blockPhysicsEvent.block = e.getBlock(); + return eventType.createEvent(blockPhysicsEvent); + } + + private void cancelVehicleCreateEvent(VehicleCreateEvent bukkitEvent, GameEvent gameEvent) { + if (gameEvent.isCancelled()) + bukkitEvent.getVehicle().remove(); + } + + private void cancelBlockRedstoneEvent(BlockRedstoneEvent bukkitEvent, GameEvent gameEvent) { + if (gameEvent.isCancelled()) + bukkitEvent.setNewCurrent(0); + } + + private void createEventListener(GameEventType eventType, + Class bukkitEventClass, + GameEventCreator function) { + createEventListener(eventType, bukkitEventClass, function, null); + } + + private void createEventListener(GameEventType eventType, + Class bukkitEventClass, + GameEventCreator function, + @Nullable ApplyBukkitEventFunction applyBukkitEventFunction) { + Map> callbacks = plugin.getGameEventsDispatcher().getCallbacks(eventType); + if (!callbacks.isEmpty()) { + callbacks.keySet().forEach(priority -> + createEventListenerForPriority(eventType, bukkitEventClass, priority, function, applyBukkitEventFunction)); + } + } + + private void createEventListenerForPriority(GameEventType eventType, + Class bukkitEventClass, + GameEventPriority gameEventPriority, + GameEventCreator function, + @Nullable ApplyBukkitEventFunction applyBukkitEventFunction) { + EventPriority bukkitEventPriority = EventPriority.valueOf(gameEventPriority.name()); + plugin.getServer().getPluginManager().registerEvent(bukkitEventClass, this, bukkitEventPriority, (listener, event) -> { + if (!bukkitEventClass.isAssignableFrom(event.getClass())) + return; + + IEventsDispatcher customEventsDispatcher = plugin.getEventsDispatcher(); + if (customEventsDispatcher != null) { + if (customEventsDispatcher.notifyEvent(event, bukkitEventPriority)) + return; + if (!customEventsDispatcher.shouldFallbackToDefaultExecutorOnFailure()) + return; + } + + GameEvent gameEvent = function.execute(eventType, gameEventPriority, (E) event); + if (gameEvent == null) + return; + + if (event instanceof Cancellable && ((Cancellable) event).isCancelled()) + gameEvent.setCancelled(); + + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, gameEventPriority); + if (gameEvent.isCancelled()) { + if (event instanceof Cancellable) + ((Cancellable) event).setCancelled(true); + } + if (applyBukkitEventFunction != null) + applyBukkitEventFunction.apply((E) event, gameEvent); + }, plugin, false); + } + + private interface GameEventCreator { + + @Nullable + GameEvent execute(GameEventType eventType, GameEventPriority priority, E e); + + } + + private interface ApplyBukkitEventFunction { + + void apply(E bukkitEvent, GameEvent event); + + } + + private static class SpongeAbsorbEventFunction implements GameEventCreator { + + @Override + public GameEvent execute(GameEventType eventType, GameEventPriority priority, org.bukkit.event.block.SpongeAbsorbEvent e) { + GameEventArgs.SpongeAbsorbEvent spongeAbsorbEvent = new GameEventArgs.SpongeAbsorbEvent(); + spongeAbsorbEvent.block = e.getBlock(); + spongeAbsorbEvent.blocks = e.getBlocks(); + return eventType.createEvent(spongeAbsorbEvent); + } + } + + private static class BlockDestroyEventFunction implements GameEventCreator { + + @Override + public GameEvent execute(GameEventType eventType, GameEventPriority priority, com.destroystokyo.paper.event.block.BlockDestroyEvent e) { + if (e.getNewState().getMaterial() != Material.AIR) + return null; + + GameEventArgs.BlockDestroyEvent blockDestroyEvent = new GameEventArgs.BlockDestroyEvent(); + blockDestroyEvent.block = e.getBlock(); + return eventType.createEvent(blockDestroyEvent); + } + } + + private class EntityRemoveFromWorldEventFunction implements GameEventCreator { + + @Override + public GameEvent execute(GameEventType eventType, GameEventPriority priority, com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent e) { + Location entityLocation = e.getEntity().getLocation(); + + BukkitExecutor.sync(() -> { + if (e.getEntity().isValid() && !e.getEntity().isDead()) + return; + + World world = entityLocation.getWorld(); + int chunkX = entityLocation.getBlockX() >> 4; + int chunkZ = entityLocation.getBlockZ() >> 4; + // We don't want call this event if + if (world.isChunkLoaded(chunkX, chunkZ)) { + GameEventArgs.EntityDeathEvent entityDeathEvent = new GameEventArgs.EntityDeathEvent(); + entityDeathEvent.entity = e.getEntity(); + GameEvent gameEvent = eventType.createEvent(entityDeathEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, priority); + } + }, 1L); + + return null; + } + } + + private static class AttemptEntitySpawnEventFunction implements GameEventCreator { + + @Override + public GameEvent execute(GameEventType eventType, GameEventPriority priority, com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent e) { + GameEventArgs.AttemptEntitySpawnEvent attemptEntitySpawnEvent = new GameEventArgs.AttemptEntitySpawnEvent(); + attemptEntitySpawnEvent.entityType = e.getType(); + attemptEntitySpawnEvent.spawnLocation = e.getSpawnLocation(); + attemptEntitySpawnEvent.spawnReason = e.getReason(); + return eventType.createEvent(attemptEntitySpawnEvent); + } + + } + + private class AsyncChatEventFunctions implements + GameEventCreator, + ApplyBukkitEventFunction { + + @Override + public GameEvent execute(GameEventType eventType, GameEventPriority priority, io.papermc.paper.event.player.AsyncChatEvent e) { + GameEventArgs.PlayerChatEvent playerChatEvent = new GameEventArgs.PlayerChatEvent(); + playerChatEvent.player = e.getPlayer(); + playerChatEvent.message = LegacyComponentSerializer.legacyAmpersand().serialize(e.message()); + return eventType.createEvent(playerChatEvent); + } + + @Override + public void apply(io.papermc.paper.event.player.AsyncChatEvent bukkitEvent, GameEvent event) { + plugin.getNMSAlgorithms().handlePaperChatRenderer(bukkitEvent); + } + + } + + private static class PlayerPickupArrowEventFunctions implements GameEventCreator { + + @Override + public GameEvent execute(GameEventType eventType, GameEventPriority priority, org.bukkit.event.player.PlayerPickupArrowEvent e) { + GameEventArgs.PlayerPickupArrowEvent playerPickupArrowEvent = new GameEventArgs.PlayerPickupArrowEvent(); + playerPickupArrowEvent.player = e.getPlayer(); + playerPickupArrowEvent.pickedUpItem = e.getItem(); + return eventType.createEvent(playerPickupArrowEvent); + } + + } + + private static class PlayerPickupItemEventFunctions implements GameEventCreator { + + @Override + public GameEvent execute(GameEventType eventType, GameEventPriority priority, org.bukkit.event.player.PlayerAttemptPickupItemEvent e) { + GameEventArgs.PlayerPickupItemEvent playerPickupItemEvent = new GameEventArgs.PlayerPickupItemEvent(); + playerPickupItemEvent.player = e.getPlayer(); + playerPickupItemEvent.pickedUpItem = e.getItem(); + return eventType.createEvent(playerPickupItemEvent); + } + + } + + private static class RaidTriggerEventFunctions implements GameEventCreator { + + @Override + public GameEvent execute(GameEventType eventType, GameEventPriority priority, org.bukkit.event.raid.RaidTriggerEvent e) { + GameEventArgs.RaidTriggerEvent raidTriggerEvent = new GameEventArgs.RaidTriggerEvent(); + raidTriggerEvent.world = e.getWorld(); + raidTriggerEvent.player = e.getPlayer(); + raidTriggerEvent.raidLocation = e.getRaid().getLocation(); + return eventType.createEvent(raidTriggerEvent); + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java index e148e86f99..d5550cd3d0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java @@ -20,22 +20,24 @@ public BukkitListeners(SuperiorSkyblockPlugin plugin) { } public void registerListeners() { - safeEventsRegister(new AdminPlayersListener(this.plugin)); - safeEventsRegister(new BlockChangesListener(this.plugin)); - safeEventsRegister(new ChunksListener(this.plugin)); - safeEventsRegister(new EntityTrackingListener(this.plugin)); - safeEventsRegister(new FeaturesListener(this.plugin)); - safeEventsRegister(new IslandFlagsListener(this.plugin)); - safeEventsRegister(new IslandOutsideListener(this.plugin)); - safeEventsRegister(new IslandPreviewListener(this.plugin)); - safeEventsRegister(new IslandWorldEventsListener(this.plugin)); - safeEventsRegister(new MenusListener()); - safeEventsRegister(new PlayersListener(this.plugin)); - safeEventsRegister(new PortalsListener(this.plugin)); - safeEventsRegister(new ProtectionListener(this.plugin)); - safeEventsRegister(new SignsListener(this.plugin)); - safeEventsRegister(new StackedBlocksListener(this.plugin)); - safeEventsRegister(new WorldDestructionListener(this.plugin)); + new AdminPlayersListener(this.plugin); + new BlockChangesListener(this.plugin); + new ChunksListener(this.plugin); + new EntityTrackingListener(this.plugin); + new FeaturesListener(this.plugin); + new IslandFlagsListener(this.plugin); + new IslandOutsideListener(this.plugin); + new IslandPreviewListener(this.plugin); + new IslandWorldEventsListener(this.plugin); + new MenusListener(this.plugin); + new PlayersListener(this.plugin); + new PortalsListener(this.plugin); + new ProtectionListener(this.plugin); + new SignsListener(this.plugin); + new StackedBlocksListener(this.plugin); + new WorldDestructionListener(this.plugin); + + safeEventsRegister(new BukkitEventsListener(this.plugin)); } public void registerListenerFailureFilter() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java index 3250ca8a3c..c6d9609d8b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java @@ -18,6 +18,10 @@ import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; @@ -26,12 +30,6 @@ import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.world.ChunkLoadEvent; -import org.bukkit.event.world.ChunkUnloadEvent; -import org.bukkit.event.world.WorldUnloadEvent; import java.util.Arrays; import java.util.Collections; @@ -41,11 +39,10 @@ import java.util.Set; import java.util.UUID; -public class ChunksListener implements Listener { +public class ChunksListener extends AbstractGameEventListener { private final Map> pendingLoadedChunks = new ArrayMap<>(); - private final SuperiorSkyblockPlugin plugin; private final LazyReference worldRecordService = new LazyReference() { @Override protected WorldRecordService create() { @@ -54,21 +51,28 @@ protected WorldRecordService create() { }; public ChunksListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } + super(plugin); - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onChunkUnloadMonitor(ChunkUnloadEvent e) { - handleChunkUnload(e.getChunk()); + registerCallback(GameEventType.CHUNK_UNLOAD_EVENT, GameEventPriority.MONITOR, this::onChunkUnload); + registerCallback(GameEventType.WORLD_UNLOAD_EVENT, GameEventPriority.MONITOR, this::onWorldUnload); + registerCallback(GameEventType.CHUNK_LOAD_EVENT, GameEventPriority.MONITOR, this::onChunkLoad); } + private void onChunkUnload(GameEvent e) { + handleChunkUnload(e.getArgs().chunk); + } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onWorldUnload(WorldUnloadEvent e) { - for (Chunk loadedChunk : e.getWorld().getLoadedChunks()) + private void onWorldUnload(GameEvent e) { + for (Chunk loadedChunk : e.getArgs().world.getLoadedChunks()) handleChunkUnload(loadedChunk); } + private void onChunkLoad(GameEvent e) { + handleChunkLoad(e.getArgs().chunk, e.getArgs().isNewChunk); + } + + /* INTERNAL */ + private void handleChunkUnload(Chunk chunk) { if (!plugin.getGrid().isIslandsWorld(chunk.getWorld())) return; @@ -92,11 +96,6 @@ private void handleIslandChunkUnload(Island island, Chunk chunk) { Arrays.stream(chunk.getEntities()).forEach(this.worldRecordService.get()::recordEntityDespawn); } - @EventHandler - private void onChunkLoad(ChunkLoadEvent e) { - handleChunkLoad(e.getChunk(), e.isNewChunk()); - } - private void handleChunkLoad(Chunk chunk, boolean isNewChunk) { if (!plugin.getGrid().isIslandsWorld(chunk.getWorld())) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java index e364716772..9eb1c58c0c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java @@ -3,22 +3,12 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.core.LazyReference; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.module.BuiltinModules; -import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.event.entity.EntityDeathEvent; -import org.bukkit.event.hanging.HangingPlaceEvent; -import org.bukkit.event.vehicle.VehicleCreateEvent; -import org.bukkit.event.vehicle.VehicleDestroyEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; -public class EntityTrackingListener implements Listener { +public class EntityTrackingListener extends AbstractGameEventListener { private final LazyReference worldRecordService = new LazyReference() { @Override @@ -26,85 +16,25 @@ protected WorldRecordService create() { return plugin.getServices().getService(WorldRecordService.class); } }; - private final SuperiorSkyblockPlugin plugin; public EntityTrackingListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - this.registerDeathListener(); + super(plugin); + this.registerListeners(); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onEntitySpawn(CreatureSpawnEvent e) { - if (!e.getEntity().isDead()) - this.worldRecordService.get().recordEntitySpawn(e.getEntity()); + private void onEntitySpawn(GameEvent e) { + this.worldRecordService.get().recordEntitySpawn(e.getArgs().entity); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onHangingPlace(HangingPlaceEvent e) { - if (!e.getEntity().isDead()) - this.worldRecordService.get().recordEntitySpawn(e.getEntity()); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onVehicleSpawn(VehicleCreateEvent e) { - if (!e.getVehicle().isDead()) - this.worldRecordService.get().recordEntitySpawn(e.getVehicle()); + private void onEntityDeath(GameEvent e) { + worldRecordService.get().recordEntityDespawn(e.getArgs().entity); } /* INTERNAL */ - private void registerDeathListener() { - Listener deathListener; - - try { - Class.forName("com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent"); - deathListener = new PaperDeathListener(); - } catch (ClassNotFoundException error) { - deathListener = new SpigotDeathListener(); - } - - plugin.getServer().getPluginManager().registerEvents(deathListener, plugin); - } - - private class PaperDeathListener implements Listener { - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onEntityRemove(com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent e) { - if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class) || - !BukkitEntities.canHaveLimit(e.getEntityType()) || - BukkitEntities.canBypassEntityLimit(e.getEntity())) - return; - - Location entityLocation = e.getEntity().getLocation(); - - BukkitExecutor.sync(() -> { - if (e.getEntity().isValid() && !e.getEntity().isDead()) - return; - - World world = entityLocation.getWorld(); - int chunkX = entityLocation.getBlockX() >> 4; - int chunkZ = entityLocation.getBlockZ() >> 4; - // We don't want to track entities that are removed due to chunk being unloaded. - if (world.isChunkLoaded(chunkX, chunkZ)) { - worldRecordService.get().recordEntityDespawn(e.getEntity()); - } - }, 1L); - } - - } - - private class SpigotDeathListener implements Listener { - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onEntityDeath(EntityDeathEvent e) { - worldRecordService.get().recordEntityDespawn(e.getEntity()); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onVehicleDestroy(VehicleDestroyEvent e) { - worldRecordService.get().recordEntityDespawn(e.getVehicle()); - } - + private void registerListeners() { + registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.MONITOR, this::onEntitySpawn); + registerCallback(GameEventType.ENTITY_DEATH_EVENT, GameEventPriority.MONITOR, this::onEntityDeath); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java index 3253e115ac..441e0de2a6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java @@ -1,16 +1,10 @@ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.events.IslandCreateEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandTransferEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandWorthCalculatedEvent; -import com.bgsoftware.superiorskyblock.api.events.MissionCompleteEvent; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; @@ -18,37 +12,42 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; -import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; +import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.event.Event; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; import org.bukkit.event.block.Action; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.player.PlayerCommandPreprocessEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.inventory.ItemStack; +import java.lang.reflect.Field; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Function; -public class FeaturesListener implements Listener { +public class FeaturesListener extends AbstractGameEventListener { - private final Map, EventMethods> CACHED_EVENT_METHODS = new ArrayMap<>(); + private static final EnumerateMap, PlaceholdersPopulator> POPULATORS = new EnumerateMap<>(PluginEventType.values()); @Nullable private static final Material VAULT = EnumHelper.getEnum(Material.class, "VAULT"); @@ -59,7 +58,6 @@ public class FeaturesListener implements Listener { @Nullable private static final Material SCULK_SHRIEKER = EnumHelper.getEnum(Material.class, "SCULK_SHRIEKER"); - private final SuperiorSkyblockPlugin plugin; private final LazyReference protectionManager = new LazyReference() { @Override protected RegionManagerService create() { @@ -68,56 +66,24 @@ protected RegionManagerService create() { }; public FeaturesListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - if (VAULT != null && TRIAL_SPAWNER != null) - plugin.getServer().getPluginManager().registerEvents(new TrialsTracker(), plugin); - if (VAULT != null && TRIAL_SPAWNER != null) - plugin.getServer().getPluginManager().registerEvents(new SculkSensorTracker(), plugin); + super(plugin); + registerListeners(); } /* EVENT COMMANDS */ - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onIslandEvent(IslandEvent event) { - handleEventCommands(event); - } - - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onIslandEvent(MissionCompleteEvent event) { - handleEventCommands(event); - } - - private void handleEventCommands(Event event) { - List commands = plugin.getSettings().getEventCommands().get(event.getClass().getSimpleName().toLowerCase(Locale.ENGLISH)); + private void onGeneralPluginEvent(PluginEvent event) { + List commands = plugin.getSettings().getEventCommands().get(event.getType().getBukkitEventName()); if (commands == null) return; - EventMethods eventMethods = CACHED_EVENT_METHODS.computeIfAbsent(event.getClass(), EventMethods::new); - Map placeholdersReplaces = new HashMap<>(); - if (event instanceof IslandEvent) - placeholdersReplaces.put("%island%", ((IslandEvent) event).getIsland().getName()); - - eventMethods.getPlayer(event).ifPresent(playerName -> placeholdersReplaces.put("%player%", playerName)); - eventMethods.getTarget(event).ifPresent(targetName -> placeholdersReplaces.put("%target%", targetName)); - - if (event instanceof IslandCreateEvent) { - placeholdersReplaces.put("%schematic%", ((IslandCreateEvent) event).getSchematic()); - } else if (event instanceof IslandEnterEvent) { - placeholdersReplaces.put("%enter-cause%", ((IslandEnterEvent) event).getCause().name()); - } else if (event instanceof IslandLeaveEvent) { - placeholdersReplaces.put("%leave-cause%", ((IslandLeaveEvent) event).getCause().name()); - } else if (event instanceof IslandTransferEvent) { - placeholdersReplaces.put("%old-owner%", ((IslandTransferEvent) event).getOldOwner().getName()); - placeholdersReplaces.put("%new-owner%", ((IslandTransferEvent) event).getNewOwner().getName()); - } else if (event instanceof IslandWorthCalculatedEvent) { - placeholdersReplaces.put("%worth%", ((IslandWorthCalculatedEvent) event).getWorth().toString()); - placeholdersReplaces.put("%level%", ((IslandWorthCalculatedEvent) event).getLevel().toString()); - } else if (event instanceof MissionCompleteEvent) { - placeholdersReplaces.put("%mission%", ((MissionCompleteEvent) event).getMission().getName()); - } + PlaceholdersPopulator placeholdersPopulator = POPULATORS.computeIfAbsent(event.getType(), + type -> createPlaceholdersPopulator(event.getArgs().getClass())); + if (placeholdersPopulator != null) + placeholdersPopulator.populate(event.getArgs(), placeholdersReplaces); BukkitExecutor.ensureMain(() -> { for (String command : commands) { @@ -130,85 +96,90 @@ private void handleEventCommands(Event event) { /* OBSIDIAN TO LAVA */ - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onObsidianClick(PlayerInteractEvent e) { - if (!plugin.getSettings().isObsidianToLava() || e.getItem() == null || e.getClickedBlock() == null || - e.getItem().getType() != Material.BUCKET || e.getClickedBlock().getType() != Material.OBSIDIAN) + private void onObsidianClick(GameEvent e) { + if (!plugin.getSettings().isObsidianToLava()) return; - if (plugin.getStackedBlocks().getStackedBlockAmount(e.getClickedBlock()) != 1) + Player player = e.getArgs().player; + ItemStack handItem = e.getArgs().usedItem; + Block clickedBlock = e.getArgs().clickedBlock; + + if (handItem == null || clickedBlock == null || handItem.getType() != Material.BUCKET || + clickedBlock.getType() != Material.OBSIDIAN) + return; + + if (!plugin.getGrid().isIslandsWorld(clickedBlock.getWorld())) return; - if (!plugin.getGrid().isIslandsWorld(e.getClickedBlock().getWorld())) + if (plugin.getStackedBlocks().getStackedBlockAmount(clickedBlock) != 1) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleBlockBreak(superiorPlayer, e.getClickedBlock()); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); + InteractionResult interactionResult = this.protectionManager.get().handleBlockBreak(superiorPlayer, clickedBlock); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation(wrapper.getHandle())); + island = plugin.getGrid().getIslandAt(clickedBlock.getLocation(wrapper.getHandle())); } if (island == null) return; - e.setCancelled(true); + e.setCancelled(); - ItemStack inHandItem = e.getItem().clone(); + ItemStack inHandItem = handItem.clone(); inHandItem.setAmount(inHandItem.getAmount() - 1); - PlayerHand usedItem = BukkitItems.getHand(e); - BukkitItems.setHandItem(e.getPlayer(), usedItem, inHandItem.getAmount() == 0 ? null : inHandItem); + PlayerHand usedHand = e.getArgs().usedHand; + BukkitItems.setHandItem(player, usedHand, inHandItem.getAmount() == 0 ? null : inHandItem); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - BukkitItems.addItem(new ItemStack(Material.LAVA_BUCKET), e.getPlayer().getInventory(), - e.getPlayer().getLocation(wrapper.getHandle())); + BukkitItems.addItem(new ItemStack(Material.LAVA_BUCKET), player.getInventory(), + player.getLocation(wrapper.getHandle())); } island.handleBlockBreak(ConstantKeys.OBSIDIAN, 1); - e.getClickedBlock().setType(Material.AIR); + clickedBlock.setType(Material.AIR); } /* VISITORS BLOCKED COMMANDS */ - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onPlayerCommand(PlayerCommandPreprocessEvent e) { + private void onPlayerCommand(GameEvent e) { if (plugin.getSettings().getBlockedVisitorsCommands().isEmpty()) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + Player player = e.getArgs().player; + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer.hasBypassModeEnabled()) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(e.getPlayer().getLocation(wrapper.getHandle())); + island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); } if (island == null || island.isSpawn() || !island.isVisitor(superiorPlayer, true)) return; - String[] message = e.getMessage().toLowerCase(Locale.ENGLISH).split(" "); + String[] message = e.getArgs().command.toLowerCase(Locale.ENGLISH).split(" "); String commandLabel = message[0].toCharArray()[0] == '/' ? message[0].substring(1) : message[0]; if (plugin.getSettings().getBlockedVisitorsCommands().stream().anyMatch(commandLabel::contains)) { - e.setCancelled(true); + e.setCancelled(); Message.VISITOR_BLOCK_COMMAND.send(superiorPlayer); } } /* BLOCKS TRACKING */ - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onChunkLoad(ChunkLoadEvent e) { - List chunkIslands = plugin.getGrid().getIslandsAt(e.getChunk()); - chunkIslands.forEach(island -> handleIslandChunkLoad(island, e.getChunk())); + private void onChunkLoad(GameEvent e) { + List chunkIslands = plugin.getGrid().getIslandsAt(e.getArgs().chunk); + chunkIslands.forEach(island -> handleIslandChunkLoad(island, e.getArgs().chunk)); } private void handleIslandChunkLoad(Island island, Chunk chunk) { @@ -225,89 +196,149 @@ private void handleIslandChunkLoad(Island island, Chunk chunk) { /* VAULTS & TRIAL SPAWNERS */ - private class TrialsTracker implements Listener { + private void onTrialBlockPlace(GameEvent e) { + Block block = e.getArgs().block; + Material blockType = block.getType(); - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onBlockPlace(BlockPlaceEvent e) { - Material blockType = e.getBlock().getType(); - - if (blockType != VAULT && blockType != TRIAL_SPAWNER) - return; + if (blockType != VAULT && blockType != TRIAL_SPAWNER) + return; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location blockLocation = e.getBlock().getLocation(wrapper.getHandle()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = block.getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(blockLocation); + Island island = plugin.getGrid().getIslandAt(blockLocation); - if (island == null) - return; + if (island == null) + return; - plugin.getNMSWorld().replaceTrialBlockPlayerDetector(island, blockLocation); - } + plugin.getNMSWorld().replaceTrialBlockPlayerDetector(island, blockLocation); } - } /* SCULK SENSORS */ - private class SculkSensorTracker implements Listener { + private void onSculkSensorPlace(GameEvent e) { + Block block = e.getArgs().block; + Material blockType = block.getType(); + + if (blockType != SCULK_SENSOR) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = block.getLocation(wrapper.getHandle()); - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onSculkSensorPlace(BlockPlaceEvent e) { - Material blockType = e.getBlock().getType(); + Island island = plugin.getGrid().getIslandAt(blockLocation); - if (blockType != SCULK_SENSOR) + if (island == null) return; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location blockLocation = e.getBlock().getLocation(wrapper.getHandle()); + plugin.getNMSWorld().replaceSculkSensorListener(island, blockLocation); + } + } - Island island = plugin.getGrid().getIslandAt(blockLocation); + private void onSculkShriekerInteract(GameEvent e) { + Action action = e.getArgs().action; + Block clickedBlock = e.getArgs().clickedBlock; - if (island == null) - return; + if (action != Action.PHYSICAL || !plugin.getGrid().isIslandsWorld(clickedBlock.getWorld()) || + clickedBlock.getType() != SCULK_SHRIEKER) + return; - plugin.getNMSWorld().replaceSculkSensorListener(island, blockLocation); - } + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + Location blockLocation = clickedBlock.getLocation(wrapper.getHandle()); + interactionResult = protectionManager.get().handleCustomInteraction(superiorPlayer, + blockLocation, IslandPrivileges.SCULK_SENSOR); } + if (ProtectionHelper.shouldPreventInteraction(interactionResult, null, false)) + e.setCancelled(); + } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onSculkShriekerInteract(PlayerInteractEvent e) { - if (e.getAction() != Action.PHYSICAL || !plugin.getGrid().isIslandsWorld(e.getClickedBlock().getWorld()) || - e.getClickedBlock().getType() != SCULK_SHRIEKER) - return; + /* INTERNAL */ - InteractionResult interactionResult; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - Location blockLocation = e.getClickedBlock().getLocation(wrapper.getHandle()); - interactionResult = protectionManager.get().handleCustomInteraction(superiorPlayer, - blockLocation, IslandPrivileges.SCULK_SENSOR); - } - if (ProtectionHelper.shouldPreventInteraction(interactionResult, null, false)) - e.setCancelled(true); + private void registerListeners() { + for (PluginEventType eventType : PluginEventType.values()) { + if (eventType.getBukkitEventName() != null) + plugin.getPluginEventsDispatcher().registerCallback(eventType, this::onGeneralPluginEvent); + } + + registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.HIGHEST, this::onObsidianClick); + registerCallback(GameEventType.PLAYER_COMMAND_EVENT, GameEventPriority.HIGHEST, this::onPlayerCommand); + registerCallback(GameEventType.CHUNK_LOAD_EVENT, GameEventPriority.MONITOR, this::onChunkLoad); + + if (VAULT != null && TRIAL_SPAWNER != null) { + registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.MONITOR, this::onTrialBlockPlace); } + if (SCULK_SENSOR != null && SCULK_SHRIEKER != null) { + registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.MONITOR, this::onSculkSensorPlace); + registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.MONITOR, this::onSculkShriekerInteract); + } } - /* INTERNAL */ + private static PlaceholdersPopulator createPlaceholdersPopulator(Class argsClass) { + List> fieldsData = new LinkedList<>(); + + collectAllFields(argsClass, field -> { + ReflectField reflectField = new ReflectField<>(field.getDeclaringClass(), field.getType(), field.getName()); + if (reflectField.isValid()) { + String placeholder = "%" + field.getName() + "%"; + FieldData fieldData = createFieldData(reflectField, field, placeholder); + fieldsData.add(fieldData); + if (field.getName().equals("superiorPlayer")) + fieldsData.add(new FieldData(fieldData.reflectField, "%player%", fieldData.toStringMethod)); + else if (field.getName().equals("targetPlayer")) + fieldsData.add(new FieldData(fieldData.reflectField, "%target%", fieldData.toStringMethod)); + } + }); - private static class EventMethods { + return (args, placeholders) -> { + for (FieldData fieldData : fieldsData) { + Optional.ofNullable(fieldData.reflectField.get(args)).ifPresent(value -> + placeholders.put(fieldData.placeholder, (String) fieldData.toStringMethod.apply(value))); + } + }; - private final ReflectMethod getPlayerMethod; - private final ReflectMethod getTargetMethod; + } - EventMethods(Class eventClass) { - getPlayerMethod = new ReflectMethod<>(eventClass, "getPlayer"); - getTargetMethod = new ReflectMethod<>(eventClass, "getTarget"); - } + private static FieldData createFieldData(ReflectField reflectField, Field field, String placeholder) { + if (field.getType() == SuperiorPlayer.class) + return new FieldData<>((ReflectField) reflectField, placeholder, SuperiorPlayer::getName); + else if (field.getType() == Island.class) + return new FieldData<>((ReflectField) reflectField, placeholder, Island::getName); + else if (field.getType() == Mission.class) + return new FieldData<>((ReflectField) reflectField, placeholder, Mission::getName); + else if (field.getType() == String.class) + return new FieldData<>((ReflectField) reflectField, placeholder, s -> s); + else + return new FieldData<>(reflectField, placeholder, String::valueOf); + } - Optional getPlayer(Event event) { - return getPlayerMethod.isValid() ? Optional.ofNullable(getPlayerMethod.invoke(event)).map(SuperiorPlayer::getName) : Optional.empty(); + private static void collectAllFields(Class clazz, Consumer consumer) { + while (clazz != null && clazz != Object.class) { + for (Field field : clazz.getFields()) + consumer.accept(field); + clazz = clazz.getSuperclass(); } + } + + private interface PlaceholdersPopulator { + + void populate(T args, Map placeholders); + + } + + private static class FieldData { + + private final ReflectField reflectField; + private final Function toStringMethod; + private final String placeholder; - Optional getTarget(Event event) { - return getTargetMethod.isValid() ? Optional.ofNullable(getTargetMethod.invoke(event)).map(SuperiorPlayer::getName) : Optional.empty(); + FieldData(ReflectField reflectField, String placeholder, Function toStringMethod) { + this.reflectField = reflectField; + this.toStringMethod = toStringMethod; + this.placeholder = placeholder; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java index 4ce1791373..11f614b2f8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java @@ -8,35 +8,26 @@ import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalMap; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.world.BukkitEntities; -import com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.Block; import org.bukkit.entity.Chicken; import org.bukkit.entity.Enderman; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Fireball; import org.bukkit.entity.Ghast; +import org.bukkit.entity.Item; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockBurnEvent; -import org.bukkit.event.block.BlockFromToEvent; -import org.bukkit.event.block.BlockGrowEvent; import org.bukkit.event.block.BlockIgniteEvent; import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.event.entity.EntityChangeBlockEvent; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityExplodeEvent; -import org.bukkit.event.entity.ItemSpawnEvent; -import org.bukkit.event.entity.ProjectileHitEvent; -import org.bukkit.event.hanging.HangingBreakByEntityEvent; import org.bukkit.event.hanging.HangingBreakEvent; -import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.potion.PotionEffectType; import org.bukkit.projectiles.ProjectileSource; @@ -48,28 +39,23 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; -public class IslandFlagsListener implements Listener { +public class IslandFlagsListener extends AbstractGameEventListener { private static final EnumSet NATURAL_SPAWN_REASONS = initializeNaturalSpawnReasons(); private final Map originalFireballsDamager = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS); - private final SuperiorSkyblockPlugin plugin; - public IslandFlagsListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - this.registerPaperListener(); + super(plugin); + this.registerListeners(); } /* ENTITY SPAWNING */ - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onEntitySpawn(CreatureSpawnEvent e) { - if (preventEntitySpawn(e.getLocation(), e.getSpawnReason(), e.getEntityType())) - e.setCancelled(true); - } + private void onAttemptEntitySpawn(GameEvent e) { + EntityType entityType = e.getArgs().entityType; + CreatureSpawnEvent.SpawnReason spawnReason = e.getArgs().spawnReason; - public boolean preventEntitySpawn(Location location, CreatureSpawnEvent.SpawnReason spawnReason, EntityType entityType) { IslandFlag actionFlag; if (spawnReason == CreatureSpawnEvent.SpawnReason.SPAWNER || @@ -82,7 +68,7 @@ public boolean preventEntitySpawn(Location location, CreatureSpawnEvent.SpawnRea actionFlag = IslandFlags.SPAWNER_MONSTER_SPAWN; break; default: - return false; + return; } } else if (NATURAL_SPAWN_REASONS.contains(spawnReason)) { switch (BukkitEntities.getCategory(entityType)) { @@ -93,62 +79,71 @@ public boolean preventEntitySpawn(Location location, CreatureSpawnEvent.SpawnRea actionFlag = IslandFlags.NATURAL_MONSTER_SPAWN; break; default: - return false; + return; } } else { - return false; + return; } - return preventAction(location, actionFlag); + Location location = e.getArgs().spawnLocation; + if (!preventAction(location, actionFlag)) + return; + + e.setCancelled(); } /* ENTITY EXPLOSIONS */ - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onHangingBreakByEntity(HangingBreakByEntityEvent e) { + private void onHangingBreakByEntity(GameEvent e) { + Entity entity = e.getArgs().entity; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location entityLocation = e.getEntity().getLocation(wrapper.getHandle()); + Location entityLocation = entity.getLocation(wrapper.getHandle()); - if (e.getCause() == HangingBreakEvent.RemoveCause.EXPLOSION) { - if (e.getRemover() instanceof Player) { + HangingBreakEvent.RemoveCause removeCause = e.getArgs().removeCause; + Entity remover = e.getArgs().remover; + + if (removeCause == HangingBreakEvent.RemoveCause.EXPLOSION) { + if (remover instanceof Player) { // Explosion was set by TNT. if (preventAction(entityLocation, IslandFlags.TNT_EXPLOSION)) { - e.setCancelled(true); + e.setCancelled(); return; } - } else if (e.getRemover() instanceof Ghast) { + } else if (remover instanceof Ghast) { // Explosion was set by TNT. if (preventAction(entityLocation, IslandFlags.GHAST_FIREBALL)) { - e.setCancelled(true); + e.setCancelled(); return; } } } - if (preventEntityExplosion(e.getRemover(), entityLocation)) { - e.setCancelled(true); + if (preventEntityExplosion(remover, entityLocation)) { + e.setCancelled(); } } } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onEntityExplode(EntityExplodeEvent e) { - if (preventEntityExplosion(e.getEntity(), e.getLocation())) - e.blockList().clear(); + private void onEntityExplode(GameEvent e) { + Entity entity = e.getArgs().entity; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + if (preventEntityExplosion(entity, entity.getLocation(wrapper.getHandle()))) + e.getArgs().blocks.clear(); + } } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onEntityChangeBlock(EntityChangeBlockEvent e) { + private void onEntityChangeBlock(GameEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventEntityExplosion(e.getEntity(), e.getBlock().getLocation(wrapper.getHandle()))) - e.setCancelled(true); + if (preventEntityExplosion(e.getArgs().entity, e.getArgs().block.getLocation(wrapper.getHandle()))) + e.setCancelled(); } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onFireballDamage(EntityDamageByEntityEvent e) { - if (e.getEntity() instanceof Fireball) { - originalFireballsDamager.put(e.getEntity().getUniqueId(), ((Fireball) e.getEntity()).getShooter()); + private void onFireballDamage(GameEvent e) { + Entity entity = e.getArgs().entity; + if (entity instanceof Fireball) { + originalFireballsDamager.put(entity.getUniqueId(), ((Fireball) entity).getShooter()); } } @@ -185,70 +180,71 @@ public boolean preventEntityExplosion(Entity source, Location explodeLocation) { /* GENERAL EVENTS */ - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onBlockFlow(BlockFromToEvent e) { - IslandFlag islandFlag = plugin.getNMSWorld().isWaterLogged(e.getBlock()) ? + private void onBlockFlow(GameEvent e) { + Block block = e.getArgs().block; + Block toBlock = e.getArgs().toBlock; + + IslandFlag islandFlag = plugin.getNMSWorld().isWaterLogged(block) ? IslandFlags.WATER_FLOW : IslandFlags.LAVA_FLOW; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventAction(e.getToBlock().getLocation(wrapper.getHandle()), islandFlag)) - e.setCancelled(true); + if (preventAction(toBlock.getLocation(wrapper.getHandle()), islandFlag)) + e.setCancelled(); } } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onCropsGrowth(BlockGrowEvent e) { + private void onCropsGrowth(GameEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventAction(e.getBlock().getLocation(wrapper.getHandle()), IslandFlags.CROPS_GROWTH)) - e.setCancelled(true); + if (preventAction(e.getArgs().block.getLocation(wrapper.getHandle()), IslandFlags.CROPS_GROWTH)) + e.setCancelled(); } } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onTreeGrowth(StructureGrowEvent e) { - if (preventAction(e.getLocation(), IslandFlags.TREE_GROWTH)) - e.setCancelled(true); + private void onTreeGrowth(GameEvent e) { + if (preventAction(e.getArgs().location, IslandFlags.TREE_GROWTH)) + e.setCancelled(); } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onFireSpread(BlockBurnEvent e) { + private void onFireSpread(GameEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventAction(e.getBlock().getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD)) - e.setCancelled(true); + if (preventAction(e.getArgs().block.getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD)) + e.setCancelled(); } } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onBlockIgnite(BlockIgniteEvent e) { - if (e.getCause() != BlockIgniteEvent.IgniteCause.SPREAD) + private void onBlockIgnite(GameEvent e) { + if (e.getArgs().igniteCause != BlockIgniteEvent.IgniteCause.SPREAD) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventAction(e.getBlock().getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD)) - e.setCancelled(true); + if (preventAction(e.getArgs().block.getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD)) + e.setCancelled(); } } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onEndermanGrief(EntityChangeBlockEvent e) { - if (!(e.getEntity() instanceof Enderman)) + private void onEndermanGrief(GameEvent e) { + if (!(e.getArgs().entity instanceof Enderman)) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventAction(e.getBlock().getLocation(wrapper.getHandle()), IslandFlags.ENDERMAN_GRIEF)) - e.setCancelled(true); + if (preventAction(e.getArgs().block.getLocation(wrapper.getHandle()), IslandFlags.ENDERMAN_GRIEF)) + e.setCancelled(); } } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onEggLay(ItemSpawnEvent e) { - if (e.getEntity().getItemStack().getType() != Material.EGG) + private void onEggLay(GameEvent e) { + if (!(e.getArgs().entity instanceof Item)) + return; + + Item item = (Item) e.getArgs().entity; + + if (item.getItemStack().getType() != Material.EGG) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventAction(e.getEntity().getLocation(wrapper.getHandle()), IslandFlags.EGG_LAY)) { - for (Entity entity : e.getEntity().getNearbyEntities(1, 1, 1)) { + if (preventAction(item.getLocation(wrapper.getHandle()), IslandFlags.EGG_LAY)) { + for (Entity entity : item.getNearbyEntities(1, 1, 1)) { if (entity instanceof Chicken) { - e.setCancelled(true); + e.setCancelled(); return; } } @@ -256,22 +252,24 @@ private void onEggLay(ItemSpawnEvent e) { } } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onPoisonAttack(ProjectileHitEvent e) { - if (e.getEntityType() != EntityType.SPLASH_POTION) + private void onPoisonAttack(GameEvent e) { + Entity entity = e.getArgs().entity; + EntityType entityType = entity.getType(); + + if (entityType != EntityType.SPLASH_POTION) return; - BukkitEntities.getPlayerSource(e.getEntity()).ifPresent(shooterPlayer -> { + BukkitEntities.getPlayerSource(entity).ifPresent(shooterPlayer -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (!preventAction(e.getEntity().getLocation(wrapper.getHandle()), IslandFlags.PVP)) + if (!preventAction(entity.getLocation(wrapper.getHandle()), IslandFlags.PVP)) return; } - List nearbyEntities = e.getEntity().getNearbyEntities(2, 2, 2); + List nearbyEntities = entity.getNearbyEntities(2, 2, 2); - BukkitExecutor.sync(() -> nearbyEntities.forEach(entity -> { - if (entity instanceof LivingEntity && !entity.getUniqueId().equals(shooterPlayer.getUniqueId())) - ((LivingEntity) entity).removePotionEffect(PotionEffectType.POISON); + BukkitExecutor.sync(() -> nearbyEntities.forEach(nearbyEntity -> { + if (nearbyEntity instanceof LivingEntity && !nearbyEntity.getUniqueId().equals(shooterPlayer.getUniqueId())) + ((LivingEntity) nearbyEntity).removePotionEffect(PotionEffectType.POISON); }), 1L); }); } @@ -292,12 +290,20 @@ private boolean preventAction(Location location, IslandFlag islandFlag, Flag... return !island.hasSettingsEnabled(islandFlag); } - private void registerPaperListener() { - try { - Class.forName("com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent"); - Bukkit.getPluginManager().registerEvents(new PaperListener(), plugin); - } catch (Throwable ignored) { - } + private void registerListeners() { + registerCallback(GameEventType.ATTEMPT_ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onAttemptEntitySpawn); + registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.LOWEST, this::onEntityExplode); + registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.LOWEST, this::onEntityChangeBlock); + registerCallback(GameEventType.HANGING_BREAK_EVENT, GameEventPriority.LOWEST, this::onHangingBreakByEntity); + registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.MONITOR, this::onFireballDamage); + registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.LOWEST, this::onBlockFlow); + registerCallback(GameEventType.BLOCK_GROW_EVENT, GameEventPriority.LOWEST, this::onCropsGrowth); + registerCallback(GameEventType.STRUCTURE_GROW_EVENT, GameEventPriority.LOWEST, this::onTreeGrowth); + registerCallback(GameEventType.BLOCK_BURN_EVENT, GameEventPriority.LOWEST, this::onFireSpread); + registerCallback(GameEventType.BLOCK_IGNITE_EVENT, GameEventPriority.LOWEST, this::onBlockIgnite); + registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.LOWEST, this::onEndermanGrief); + registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onEggLay); + registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.LOWEST, this::onPoisonAttack); } private static EnumSet initializeNaturalSpawnReasons() { @@ -321,18 +327,6 @@ private static EnumSet initializeNaturalSpawnRea return naturalSpawnReasons; } - private class PaperListener implements Listener { - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onEntitySpawn(PreCreatureSpawnEvent e) { - if (preventEntitySpawn(e.getSpawnLocation(), e.getReason(), e.getType())) { - e.setCancelled(true); - e.setShouldAbortSpawn(true); - } - } - - } - private enum Flag { ALLOW_OUTSIDE diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java index 36b06a4373..f0d6c02455 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java @@ -5,121 +5,107 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerInteractAtEntityEvent; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.vehicle.VehicleEnterEvent; -import org.bukkit.event.vehicle.VehicleMoveEvent; -public class IslandOutsideListener implements Listener { - - private final SuperiorSkyblockPlugin plugin; +public class IslandOutsideListener extends AbstractGameEventListener { public IslandOutsideListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); + + registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.NORMAL, this::onMinecartRightClick); + registerCallback(GameEventType.ENTITY_RIDE_EVENT, GameEventPriority.NORMAL, this::onEntityRide); + registerCallback(GameEventType.ENTITY_MOVE_EVENT, GameEventPriority.NORMAL, this::onEntityMove); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - private void onMinecartRightClick(PlayerInteractAtEntityEvent e) { + private void onMinecartRightClick(GameEvent e) { if (!plugin.getSettings().isStopLeaving()) return; - if (!plugin.getGrid().isIslandsWorld(e.getRightClicked().getWorld())) + Entity rightClicked = e.getArgs().clickedEntity; + if (rightClicked == null) + return; + + if (!plugin.getGrid().isIslandsWorld(rightClicked.getWorld())) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + Player player = e.getArgs().player; + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer.hasBypassModeEnabled()) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location entityLocation = e.getRightClicked().getLocation(wrapper.getHandle()); + Location entityLocation = rightClicked.getLocation(wrapper.getHandle()); Island entityIsland = plugin.getGrid().getIslandAt(entityLocation); if (entityIsland != null && entityIsland.isInsideRange(entityLocation, 1D)) return; } - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - private void onMinecartRightClick(VehicleEnterEvent e) { + private void onEntityRide(GameEvent e) { if (!plugin.getSettings().isStopLeaving()) return; - if (!plugin.getGrid().isIslandsWorld(e.getVehicle().getWorld())) + Entity vehicle = e.getArgs().vehicle; + + if (!plugin.getGrid().isIslandsWorld(vehicle.getWorld())) return; - if (e.getEntered() instanceof Player && plugin.getPlayers().getSuperiorPlayer(e.getEntered()).hasBypassModeEnabled()) + Entity entity = e.getArgs().entity; + + if (entity instanceof Player && plugin.getPlayers().getSuperiorPlayer(entity).hasBypassModeEnabled()) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location vehicleLocation = e.getVehicle().getLocation(wrapper.getHandle()); + Location vehicleLocation = vehicle.getLocation(wrapper.getHandle()); Island entityIsland = plugin.getGrid().getIslandAt(vehicleLocation); if (entityIsland != null && entityIsland.isInsideRange(vehicleLocation, 1D)) return; } - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onVehicleRide(VehicleMoveEvent e) { + private void onEntityMove(GameEvent e) { if (!plugin.getSettings().isStopLeaving()) return; - World world = e.getTo().getWorld(); - - if (!plugin.getGrid().isIslandsWorld(world)) - return; - - if (!e.getVehicle().getWorld().equals(world)) - return; - - Location from = e.getFrom(); - Location to = e.getTo(); - - if (from.getBlockX() == to.getBlockX() && from.getBlockZ() == to.getBlockZ()) - return; - - Entity passenger = e.getVehicle().getPassenger(); - SuperiorPlayer superiorPlayer = passenger instanceof Player ? plugin.getPlayers().getSuperiorPlayer(passenger) : null; - - if (superiorPlayer == null) - return; - - handlePlayerMove(superiorPlayer, from, to, false, true); - } + Location to = e.getArgs().to; + World destinationWorld = to.getWorld(); - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - private void onPlayerMove(PlayerMoveEvent e) { - if (!plugin.getSettings().isStopLeaving()) + if (!plugin.getGrid().isIslandsWorld(destinationWorld)) return; - World world = e.getTo().getWorld(); + Entity entity = e.getArgs().entity; - if (!plugin.getGrid().isIslandsWorld(world)) + if (!entity.getWorld().equals(destinationWorld)) return; - if (!e.getPlayer().getWorld().equals(world)) - return; + Location from = e.getArgs().from; - Location from = e.getFrom(); - Location to = e.getTo(); + if (entity instanceof Player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity); + if (handlePlayerMove(superiorPlayer, from, to, true, false)) + e.setCancelled(); + } else { + Entity passenger = entity.getPassenger(); + SuperiorPlayer superiorPlayer = passenger instanceof Player ? plugin.getPlayers().getSuperiorPlayer(passenger) : null; - if (from.getBlockX() == to.getBlockX() && from.getBlockZ() == to.getBlockZ()) - return; + if (superiorPlayer == null) + return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - if (handlePlayerMove(superiorPlayer, from, to, true, false)) - e.setCancelled(true); + handlePlayerMove(superiorPlayer, from, to, false, true); + } } private boolean handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, Location to, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java index e73301a3ba..017d31bccb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java @@ -2,25 +2,27 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer; import org.bukkit.GameMode; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; -public class IslandPreviewListener implements Listener { - - private final SuperiorSkyblockPlugin plugin; +public class IslandPreviewListener extends AbstractGameEventListener { public IslandPreviewListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); + + registerCallback(GameEventType.PLAYER_QUIT_EVENT, GameEventPriority.MONITOR, this::onPlayerQuit); + registerCallback(GameEventType.ENTITY_TELEPORT_EVENT, GameEventPriority.NORMAL, this::onPlayerTeleport); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerQuit(PlayerQuitEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + private void onPlayerQuit(GameEvent e) { + Player player = e.getArgs().player; + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer instanceof SuperiorNPCPlayer) return; @@ -30,22 +32,25 @@ private void onPlayerQuit(PlayerQuitEvent e) { plugin.getGrid().cancelIslandPreview(superiorPlayer); /* cancelIslandPreview changes the GameMode and teleports the player later. In this case tho, we want the things to be instant - no async, no nothing. */ - e.getPlayer().setGameMode(GameMode.SURVIVAL); - e.getPlayer().teleport(plugin.getGrid().getSpawnIsland().getCenter( + player.setGameMode(GameMode.SURVIVAL); + player.teleport(plugin.getGrid().getSpawnIsland().getCenter( plugin.getSettings().getWorlds().getDefaultWorldDimension())); } } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - private void onPlayerTeleport(PlayerTeleportEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + private void onPlayerTeleport(GameEvent e) { + Entity entity = e.getArgs().entity; + if (!(entity instanceof Player)) + return; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity); if (superiorPlayer instanceof SuperiorNPCPlayer) return; - if (e.getPlayer().getGameMode() == GameMode.SPECTATOR && + if (((Player) entity).getGameMode() == GameMode.SPECTATOR && plugin.getGrid().getIslandPreview(superiorPlayer) != null) - e.setCancelled(true); + e.setCancelled(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java index 3db1c9e84e..429bb043ce 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java @@ -6,16 +6,15 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.Location; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockRedstoneEvent; -import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.entity.Entity; -public class IslandWorldEventsListener implements Listener { +public class IslandWorldEventsListener extends AbstractGameEventListener { - private final SuperiorSkyblockPlugin plugin; private final LazyReference hologramsService = new LazyReference() { @Override protected HologramsService create() { @@ -24,17 +23,19 @@ protected HologramsService create() { }; public IslandWorldEventsListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); + + registerCallback(GameEventType.BLOCK_REDSTONE_EVENT, GameEventPriority.HIGHEST, this::onBlockRedstone); + registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.HIGHEST, this::onEntitySpawn); } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onBlockRedstone(BlockRedstoneEvent e) { + private void onBlockRedstone(GameEvent e) { if (!plugin.getSettings().isDisableRedstoneOffline() && !plugin.getSettings().getAFKIntegrations().isDisableRedstone()) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); + island = plugin.getGrid().getIslandAt(e.getArgs().block.getLocation(wrapper.getHandle())); } if (island == null || island.isSpawn()) @@ -43,25 +44,26 @@ private void onBlockRedstone(BlockRedstoneEvent e) { if ((plugin.getSettings().isDisableRedstoneOffline() && !island.isCurrentlyActive()) || (plugin.getSettings().getAFKIntegrations().isDisableRedstone() && island.getAllPlayersInside().stream().allMatch(SuperiorPlayer::isAFK))) { - e.setNewCurrent(0); + e.setCancelled(); } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onEntitySpawn(CreatureSpawnEvent e) { + private void onEntitySpawn(GameEvent e) { + Entity entity = e.getArgs().entity; + if (!plugin.getSettings().getAFKIntegrations().isDisableSpawning() || - hologramsService.get().isHologram(e.getEntity())) + hologramsService.get().isHologram(entity)) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle())); + island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle())); } if (island == null || island.isSpawn() || !island.getAllPlayersInside().stream().allMatch(SuperiorPlayer::isAFK)) return; - e.setCancelled(true); + e.setCancelled(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/MenusListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/MenusListener.java index 8090242194..b408b9463a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/MenusListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/MenusListener.java @@ -1,85 +1,99 @@ package com.bgsoftware.superiorskyblock.listener; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalMap; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.StackedBlocksDepositMenu; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.ItemStack; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; -@SuppressWarnings({"rawtypes", "unchecked"}) -public class MenusListener implements Listener { +public class MenusListener extends AbstractGameEventListener { private final Map latestClickedItem = AutoRemovalMap.newHashMap(1, TimeUnit.SECONDS); + public MenusListener(SuperiorSkyblockPlugin plugin) { + super(plugin); + + registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.MONITOR, false, this::onInventoryClickDupePatch); + registerCallback(GameEventType.INVENTORY_CLOSE_EVENT, GameEventPriority.MONITOR, false, this::onInventoryCloseDupePatch); + registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.NORMAL, this::onMenuClick); + registerCallback(GameEventType.INVENTORY_CLOSE_EVENT, GameEventPriority.NORMAL, this::onMenuClose); + } + /* * The following two events are here for patching a dupe glitch caused - * by shift clicking and closing the inventory in the same time. + * by shift clicking and closing the inventory at the same time. */ - @EventHandler(priority = EventPriority.MONITOR) - private void onInventoryClickMonitor(InventoryClickEvent e) { - if (e.getCurrentItem() != null && e.isCancelled() && e.getClickedInventory().getHolder() instanceof MenuView) { - latestClickedItem.put(e.getWhoClicked().getUniqueId(), e.getCurrentItem()); + private void onInventoryClickDupePatch(GameEvent e) { + if (!e.isCancelled()) + return; + + ItemStack clickedItem = e.getArgs().bukkitEvent.getCurrentItem(); + Inventory inventory = e.getArgs().bukkitEvent.getClickedInventory(); + + if (clickedItem != null && inventory != null && inventory.getHolder() instanceof MenuView) { + latestClickedItem.put(e.getArgs().bukkitEvent.getWhoClicked().getUniqueId(), clickedItem); } } - @EventHandler(priority = EventPriority.MONITOR) - private void onInventoryCloseMonitor(InventoryCloseEvent e) { - ItemStack clickedItem = latestClickedItem.get(e.getPlayer().getUniqueId()); + private void onInventoryCloseDupePatch(GameEvent e) { + Player player = (Player) e.getArgs().bukkitEvent.getPlayer(); + ItemStack clickedItem = latestClickedItem.get(player.getUniqueId()); if (clickedItem != null) { BukkitExecutor.sync(() -> { - e.getPlayer().getInventory().removeItem(clickedItem); - ((Player) e.getPlayer()).updateInventory(); + player.getInventory().removeItem(clickedItem); + player.updateInventory(); }, 1L); } } /* MENU INTERACTIONS HANDLING */ + private void onMenuClick(GameEvent e) { + InventoryView inventoryView = e.getArgs().bukkitEvent.getView(); + Inventory clickedInventory = e.getArgs().bukkitEvent.getClickedInventory(); + + Inventory topInventory = inventoryView.getTopInventory(); - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - private void onMenuClick(InventoryClickEvent e) { - if (!(e.getWhoClicked() instanceof Player) || e.getView().getTopInventory() == null || - e.getClickedInventory() == null) + if (topInventory == null || clickedInventory == null) return; - InventoryHolder inventoryHolder = e.getView().getTopInventory().getHolder(); + InventoryHolder inventoryHolder = topInventory.getHolder(); if (inventoryHolder instanceof MenuView) { - e.setCancelled(true); + e.setCancelled(); - if (e.getClickedInventory().equals(e.getView().getTopInventory())) { + if (clickedInventory.equals(topInventory)) { MenuView menuView = (MenuView) inventoryHolder; - menuView.getMenu().onClick(e, menuView); + menuView.getMenu().onClick(e.getArgs().bukkitEvent, menuView); } } else if (inventoryHolder instanceof StackedBlocksDepositMenu) { - ((StackedBlocksDepositMenu) inventoryHolder).onInteract(e); + ((StackedBlocksDepositMenu) inventoryHolder).onInteract(e.getArgs().bukkitEvent); } } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - private void onMenuClose(InventoryCloseEvent e) { - InventoryHolder inventoryHolder = e.getInventory() == null ? null : e.getInventory().getHolder(); - - if (!(e.getPlayer() instanceof Player)) - return; + private void onMenuClose(GameEvent e) { + Inventory topInventory = e.getArgs().bukkitEvent.getView().getTopInventory(); + InventoryHolder inventoryHolder = topInventory == null ? null : topInventory.getHolder(); if (inventoryHolder instanceof MenuView) { MenuView menuView = (MenuView) inventoryHolder; - menuView.getMenu().onClose(e, menuView); + menuView.getMenu().onClose(e.getArgs().bukkitEvent, menuView); } else if (inventoryHolder instanceof StackedBlocksDepositMenu) { - ((StackedBlocksDepositMenu) inventoryHolder).onClose(e); + ((StackedBlocksDepositMenu) inventoryHolder).onClose(e.getArgs().bukkitEvent); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java index b1b63d7ba7..96dacb701c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java @@ -1,6 +1,5 @@ package com.bgsoftware.superiorskyblock.listener; -import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.HitActionResult; import com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent; @@ -14,7 +13,10 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.PlayerHand; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -24,41 +26,33 @@ import com.bgsoftware.superiorskyblock.island.SIslandChest; import com.bgsoftware.superiorskyblock.island.notifications.IslandNotifications; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import com.bgsoftware.superiorskyblock.player.respawn.RespawnActions; import com.bgsoftware.superiorskyblock.world.BukkitEntities; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; +import org.bukkit.block.Block; import org.bukkit.entity.Arrow; import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; import org.bukkit.event.block.Action; -import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.player.AsyncPlayerChatEvent; -import org.bukkit.event.player.PlayerChangedWorldEvent; -import org.bukkit.event.player.PlayerGameModeChangeEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.event.player.PlayerLoginEvent; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerRespawnEvent; -import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; import java.util.Collections; import java.util.List; import java.util.Locale; -public class PlayersListener implements Listener { +public class PlayersListener extends AbstractGameEventListener { private final LazyReference regionManagerService = new LazyReference() { @Override @@ -66,25 +60,25 @@ protected RegionManagerService create() { return plugin.getServices().getService(RegionManagerService.class); } }; - private final SuperiorSkyblockPlugin plugin; public PlayersListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - registerChatListener(); + super(plugin); + registerListeners(); } /* PLAYER NOTIFIERS */ - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerLogin(PlayerLoginEvent e) { + private void onPlayerLogin(GameEvent e) { + Player player = e.getArgs().player; + List duplicatedPlayers = plugin.getPlayers().matchAllPlayers(superiorPlayer -> - superiorPlayer.getName().equalsIgnoreCase(e.getPlayer().getName()) && - !superiorPlayer.getUniqueId().equals(e.getPlayer().getUniqueId())); + superiorPlayer.getName().equalsIgnoreCase(player.getName()) && + !superiorPlayer.getUniqueId().equals(player.getUniqueId())); if (!duplicatedPlayers.isEmpty()) { - Log.info("Changing UUID of " + e.getPlayer().getName() + " to " + e.getPlayer().getUniqueId()); + Log.info("Changing UUID of " + player.getName() + " to " + player.getUniqueId()); - SuperiorPlayer playerWithNewUUID = plugin.getPlayers().getSuperiorPlayer(e.getPlayer().getUniqueId(), false); + SuperiorPlayer playerWithNewUUID = plugin.getPlayers().getSuperiorPlayer(player.getUniqueId(), false); if (playerWithNewUUID != null) { // Even tho we have duplicates, there's already a record for the new player. @@ -103,7 +97,7 @@ private void onPlayerLogin(PlayerLoginEvent e) { duplicatedPlayers.forEach(plugin.getPlayers().getPlayersContainer()::removePlayer); // We now want to create the new player. - SuperiorPlayer newPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer().getUniqueId(), true, false); + SuperiorPlayer newPlayer = plugin.getPlayers().getSuperiorPlayer(player.getUniqueId(), true, false); // We now want to replace all existing players duplicatedPlayers.forEach(originalPlayer -> { @@ -114,16 +108,17 @@ private void onPlayerLogin(PlayerLoginEvent e) { } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerJoin(PlayerJoinEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + private void onPlayerJoin(GameEvent e) { + Player player = e.getArgs().player; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer instanceof SuperiorNPCPlayer) return; // Updating the name of the player. - if (!superiorPlayer.getName().equals(e.getPlayer().getName())) { - plugin.getEventsBus().callPlayerChangeNameEvent(superiorPlayer, e.getPlayer().getName()); + if (!superiorPlayer.getName().equals(player.getName())) { + PluginEventsFactory.callPlayerChangeNameEvent(superiorPlayer, player.getName()); superiorPlayer.updateName(); } @@ -135,7 +130,7 @@ private void onPlayerJoin(PlayerJoinEvent e) { Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location playerLocation = e.getPlayer().getLocation(wrapper.getHandle()); + Location playerLocation = player.getLocation(wrapper.getHandle()); island = plugin.getGrid().getIslandAt(playerLocation); moveResult = this.regionManagerService.get().handlePlayerJoin(superiorPlayer, playerLocation); } @@ -143,7 +138,7 @@ private void onPlayerJoin(PlayerJoinEvent e) { boolean teleportToSpawn = moveResult != MoveResult.SUCCESS; BukkitExecutor.sync(() -> { - if (!e.getPlayer().isOnline()) + if (!player.isOnline()) return; // Updating skin of the player @@ -153,7 +148,7 @@ private void onPlayerJoin(PlayerJoinEvent e) { if (!superiorPlayer.hasBypassModeEnabled()) { Island delayedIsland; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - delayedIsland = plugin.getGrid().getIslandAt(e.getPlayer().getLocation(wrapper.getHandle())); + delayedIsland = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); } // Checking if the player is in the islands world, not inside an island. if ((delayedIsland == island && teleportToSpawn) || @@ -165,20 +160,20 @@ private void onPlayerJoin(PlayerJoinEvent e) { } // Checking auto language detection - if (plugin.getSettings().isAutoLanguageDetection() && !e.getPlayer().hasPlayedBefore()) { - Locale playerLocale = plugin.getNMSPlayers().getPlayerLocale(e.getPlayer()); + if (plugin.getSettings().isAutoLanguageDetection() && !player.hasPlayedBefore()) { + Locale playerLocale = plugin.getNMSPlayers().getPlayerLocale(player); if (playerLocale != null && PlayerLocales.isValidLocale(playerLocale) && !superiorPlayer.getUserLocale().equals(playerLocale)) { - if (plugin.getEventsBus().callPlayerChangeLanguageEvent(superiorPlayer, playerLocale)) + if (PluginEventsFactory.callPlayerChangeLanguageEvent(superiorPlayer, playerLocale)) superiorPlayer.setUserLocale(playerLocale); } } }, 5L); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerQuit(PlayerQuitEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + private void onPlayerQuit(GameEvent e) { + Player player = e.getArgs().player; + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer instanceof SuperiorNPCPlayer) return; @@ -186,7 +181,7 @@ private void onPlayerQuit(PlayerQuitEvent e) { // Removing coop status from other islands. for (Island _island : plugin.getGrid().getIslands()) { if (_island.isCoop(superiorPlayer)) { - if (plugin.getEventsBus().callIslandUncoopPlayerEvent(_island, null, superiorPlayer, IslandUncoopPlayerEvent.UncoopReason.SERVER_LEAVE)) { + if (PluginEventsFactory.callIslandUncoopPlayerEvent(_island, null, superiorPlayer, IslandUncoopPlayerEvent.UncoopReason.SERVER_LEAVE)) { _island.removeCoop(superiorPlayer); IslandUtils.sendMessage(_island, Message.UNCOOP_LEFT_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); } @@ -212,101 +207,99 @@ private void onPlayerQuit(PlayerQuitEvent e) { } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.regionManagerService.get().handlePlayerQuit(superiorPlayer, e.getPlayer().getLocation(wrapper.getHandle())); + this.regionManagerService.get().handlePlayerQuit(superiorPlayer, player.getLocation(wrapper.getHandle())); } // Remove all player chat-listeners - PlayerChat.remove(e.getPlayer()); + PlayerChat.remove(player); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerGameModeChange(PlayerGameModeChangeEvent e) { - if (e.getNewGameMode() == GameMode.SPECTATOR) { - IslandNotifications.notifyPlayerQuit(plugin.getPlayers().getSuperiorPlayer(e.getPlayer())); - } else if (e.getPlayer().getGameMode() == GameMode.SPECTATOR) { - IslandNotifications.notifyPlayerJoin(plugin.getPlayers().getSuperiorPlayer(e.getPlayer())); + private void onPlayerGameModeChange(GameEvent e) { + Player player = e.getArgs().player; + if (e.getArgs().newGamemode == GameMode.SPECTATOR) { + IslandNotifications.notifyPlayerQuit(plugin.getPlayers().getSuperiorPlayer(player)); + } else if (player.getGameMode() == GameMode.SPECTATOR) { + IslandNotifications.notifyPlayerJoin(plugin.getPlayers().getSuperiorPlayer(player)); } } /* PLAYER MOVES */ - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - private void onPlayerMove(PlayerMoveEvent e) { - Location from = e.getFrom(); - Location to = e.getTo(); - - boolean movedFullBlock = from.getBlockX() != to.getBlockX() || from.getBlockZ() != to.getBlockZ() || - from.getBlockY() != to.getBlockY(); - - if (!movedFullBlock) + private void onPlayerMove(GameEvent e) { + if (!(e.getArgs().entity instanceof Player)) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + Player player = (Player) e.getArgs().entity; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer instanceof SuperiorNPCPlayer || superiorPlayer.hasPlayerStatus(PlayerStatus.VOID_TELEPORT)) return; - MoveResult moveResult = this.regionManagerService.get().handlePlayerMove(superiorPlayer, from, to); + MoveResult moveResult = this.regionManagerService.get().handlePlayerMove( + superiorPlayer, e.getArgs().from, e.getArgs().to); switch (moveResult) { case VOID_TELEPORT: case SUCCESS: break; default: - e.setCancelled(true); + e.setCancelled(); break; } } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onPlayerTeleport(PlayerTeleportEvent e) { - if (e.getTo() == null) + private void onPlayerTeleport(GameEvent e) { + if (e.getArgs().to == null || !(e.getArgs().entity instanceof Player)) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getArgs().entity); if (superiorPlayer == null || superiorPlayer instanceof SuperiorNPCPlayer) return; - MoveResult moveResult = this.regionManagerService.get().handlePlayerTeleport(superiorPlayer, e.getFrom(), e.getTo()); + MoveResult moveResult = this.regionManagerService.get().handlePlayerTeleport( + superiorPlayer, e.getArgs().from, e.getArgs().to); if (moveResult != MoveResult.SUCCESS) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - private void onPlayerChangeWorld(PlayerChangedWorldEvent e) { + private void onPlayerChangeWorld(GameEvent e) { + Player player = e.getArgs().player; + Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(e.getPlayer().getLocation(wrapper.getHandle())); + island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); } - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); - if (island != null && superiorPlayer.hasIslandFlyEnabled() && !e.getPlayer().getAllowFlight() && - island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) + if (island != null && superiorPlayer.hasIslandFlyEnabled() && !player.getAllowFlight() && + island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) { BukkitExecutor.sync(() -> { - e.getPlayer().setAllowFlight(true); - e.getPlayer().setFlying(true); + player.setAllowFlight(true); + player.setFlying(true); }, 1L); + } } /* PVP */ - @EventHandler(priority = EventPriority.NORMAL /* Set to NORMAL, so it doesn't conflict with vanish plugins */, ignoreCancelled = true) - private void onPlayerDamage(EntityDamageEvent e) { - if (!(e.getEntity() instanceof Player)) + private void onPlayerDamage(GameEvent e) { + if (!(e.getArgs().entity instanceof Player)) return; - SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getEntity()); + Player player = (Player) e.getArgs().entity; + SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (targetPlayer instanceof SuperiorNPCPlayer) return; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle())); + island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); } - SuperiorPlayer damagerPlayer = !(e instanceof EntityDamageByEntityEvent) ? null : - BukkitEntities.getPlayerSource(((EntityDamageByEntityEvent) e).getDamager()) + SuperiorPlayer damagerPlayer = e.getArgs().damager == null ? null : + BukkitEntities.getPlayerSource(e.getArgs().damager) .map(plugin.getPlayers()::getSuperiorPlayer).orElse(null); // Some plugins, such as Sentinel, may actually cause a NPC to attack. @@ -318,7 +311,7 @@ private void onPlayerDamage(EntityDamageEvent e) { if (island.isSpawn() ? (plugin.getSettings().getSpawn().isProtected() && !plugin.getSettings().getSpawn().isPlayersDamage()) : ((!plugin.getSettings().isVisitorsDamage() && island.isVisitor(targetPlayer, false)) || (!plugin.getSettings().isCoopDamage() && island.isCoop(targetPlayer)))) - e.setCancelled(true); + e.setCancelled(); } return; @@ -346,91 +339,93 @@ private void onPlayerDamage(EntityDamageEvent e) { } if (cancelEvent) - e.setCancelled(true); + e.setCancelled(); if (messageToSend != null) messageToSend.send(damagerPlayer); Player target = targetPlayer.asPlayer(); - if (target != null && cancelFlames && ((EntityDamageByEntityEvent) e).getDamager() instanceof Arrow && - target.getFireTicks() > 0) + if (target != null && cancelFlames && e.getArgs().damager instanceof Arrow && target.getFireTicks() > 0) target.setFireTicks(0); } /* CHAT */ - private boolean checkPlayerChatListener(Player player, String message) { - PlayerChat playerChat = PlayerChat.getChatListener(player); - return playerChat != null && playerChat.supply(message); + private void onPlayerChatLowest(GameEvent e) { + PlayerChat playerChat = PlayerChat.getChatListener(e.getArgs().player); + if (playerChat != null && playerChat.supply(e.getArgs().message)) + e.setCancelled(); } - @Nullable - private ChatEventResult handlePlayerChat(Player player, String message, String format) { - ChatEventResult chatEventResult = new ChatEventResult(); - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); + private void onPlayerChat(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); Island island = superiorPlayer.getIsland(); if (superiorPlayer.hasTeamChatEnabled()) { if (island == null) { - if (!plugin.getEventsBus().callPlayerToggleTeamChatEvent(superiorPlayer)) - return null; + if (!PluginEventsFactory.callPlayerToggleTeamChatEvent(superiorPlayer)) + return; superiorPlayer.toggleTeamChat(); - return null; + return; } - chatEventResult.cancelled = true; + e.setCancelled(); + + String message = e.getArgs().message; - EventResult eventResult = plugin.getEventsBus().callIslandChatEvent(island, superiorPlayer, - superiorPlayer.hasPermissionWithoutOP("superior.chat.color") ? - Formatters.COLOR_FORMATTER.format(message) : message); + PluginEvent event = PluginEventsFactory.callIslandChatEvent(island, superiorPlayer, + superiorPlayer.hasPermissionWithoutOP("superior.chat.color") ? Formatters.COLOR_FORMATTER.format(message) : message); - if (eventResult.isCancelled()) - return chatEventResult; + if (event.isCancelled()) + return; IslandUtils.sendMessage(island, Message.TEAM_CHAT_FORMAT, Collections.emptyList(), - superiorPlayer.getPlayerRole(), superiorPlayer.getName(), eventResult.getResult()); + superiorPlayer.getPlayerRole(), superiorPlayer.getName(), event.getArgs().message); Message.SPY_TEAM_CHAT_FORMAT.send(Bukkit.getConsoleSender(), superiorPlayer.getPlayerRole().getDisplayName(), - superiorPlayer.getName(), eventResult.getResult()); + superiorPlayer.getName(), event.getArgs().message); for (Player _onlinePlayer : Bukkit.getOnlinePlayers()) { SuperiorPlayer onlinePlayer = plugin.getPlayers().getSuperiorPlayer(_onlinePlayer); if (onlinePlayer.hasAdminSpyEnabled()) Message.SPY_TEAM_CHAT_FORMAT.send(onlinePlayer, superiorPlayer.getPlayerRole().getDisplayName(), - superiorPlayer.getName(), eventResult.getResult()); + superiorPlayer.getName(), event.getArgs().message); } - } else if (format != null) { - chatEventResult.format = Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(format, superiorPlayer, island)); + } else if (e.getArgs().format != null) { + e.getArgs().format = Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(e.getArgs().format, superiorPlayer, island)); } - - return chatEventResult; } /* SCHEMATICS */ - @EventHandler - private void onSchematicSelection(PlayerInteractEvent e) { - if (e.getItem() == null || e.getItem().getType() != Materials.GOLDEN_AXE.toBukkitType() || - !(e.getAction() == Action.RIGHT_CLICK_BLOCK || e.getAction() == Action.LEFT_CLICK_BLOCK)) + private void onSchematicSelection(GameEvent e) { + Action action = e.getArgs().action; + if (action != Action.RIGHT_CLICK_BLOCK && action != Action.LEFT_CLICK_BLOCK) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + Player player = e.getArgs().player; + ItemStack usedItem = e.getArgs().usedItem; + + if (usedItem == null || usedItem.getType() != Materials.GOLDEN_AXE.toBukkitType()) + return; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (!superiorPlayer.hasSchematicModeEnabled()) return; - e.setCancelled(true); + e.setCancelled(); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = e.getClickedBlock().getLocation(wrapper.getHandle()); - if (e.getAction() == Action.RIGHT_CLICK_BLOCK || e.getAction() == Action.RIGHT_CLICK_AIR) { + Block clickedBlock = e.getArgs().clickedBlock; + Location location = clickedBlock.getLocation(wrapper.getHandle()); + if (action == Action.RIGHT_CLICK_BLOCK) { Message.SCHEMATIC_RIGHT_SELECT.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(location)); - superiorPlayer.setSchematicPos1(e.getClickedBlock()); + superiorPlayer.setSchematicPos1(clickedBlock); } else { Message.SCHEMATIC_LEFT_SELECT.send(superiorPlayer, Formatters.LOCATION_FORMATTER.format(location)); - superiorPlayer.setSchematicPos2(e.getClickedBlock()); + superiorPlayer.setSchematicPos2(clickedBlock); } } @@ -440,9 +435,10 @@ private void onSchematicSelection(PlayerInteractEvent e) { /* ISLAND CHESTS */ - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onIslandChestInteract(InventoryClickEvent e) { - InventoryHolder inventoryHolder = e.getView().getTopInventory() == null ? null : e.getView().getTopInventory().getHolder(); + private void onIslandChestInteract(GameEvent e) { + InventoryView inventoryView = e.getArgs().bukkitEvent.getView(); + + InventoryHolder inventoryHolder = inventoryView.getTopInventory() == null ? null : inventoryView.getTopInventory().getHolder(); if (!(inventoryHolder instanceof IslandChest)) return; @@ -450,7 +446,7 @@ private void onIslandChestInteract(InventoryClickEvent e) { SIslandChest islandChest = (SIslandChest) inventoryHolder; if (islandChest.isUpdating()) { - e.setCancelled(true); + e.setCancelled(); } else { islandChest.updateContents(); } @@ -458,100 +454,49 @@ private void onIslandChestInteract(InventoryClickEvent e) { /* VOID TELEPORT */ - @EventHandler - private void onPlayerFall(EntityDamageEvent e) { - if (e.getCause() != EntityDamageEvent.DamageCause.FALL || !(e.getEntity() instanceof Player)) + private void onPlayerFall(GameEvent e) { + if (e.getArgs().damageCause != EntityDamageEvent.DamageCause.FALL || + !(e.getArgs().entity instanceof Player)) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getEntity()); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getArgs().entity); if (superiorPlayer.hasPlayerStatus(PlayerStatus.FALL_DAMAGE_IMMUNED)) { - e.setCancelled(true); + e.setCancelled(); } } /* PLAYER DEATH */ - @EventHandler - private void onPlayerRespawn(PlayerRespawnEvent event) { + private void onPlayerRespawn(GameEvent e) { + PlayerRespawnEvent bukkitRespawnEvent = e.getArgs().bukkitEvent; for (RespawnAction respawnAction : plugin.getSettings().getPlayerRespawn()) { - if (respawnAction == RespawnActions.VANILLA || respawnAction.canPerform(event)) { - respawnAction.perform(event); - return; - } - } - - } - - private void registerChatListener() { - if (plugin.getSettings().getChatSigningSupport()) { - try { - Class.forName("io.papermc.paper.event.player.AsyncChatEvent"); - Bukkit.getPluginManager().registerEvents(new PaperChatListener(), plugin); + if (respawnAction == RespawnActions.VANILLA || respawnAction.canPerform(bukkitRespawnEvent)) { + respawnAction.perform(bukkitRespawnEvent); return; - } catch (Exception ignored) { } } - - Bukkit.getPluginManager().registerEvents(new SpigotChatListener(), plugin); - } - - private class PaperChatListener implements Listener { - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onPlayerAsyncChatLowest(io.papermc.paper.event.player.AsyncChatEvent e) { - // PlayerChat should be on LOWEST priority so other chat plugins don't conflict. - String message = LegacyComponentSerializer.legacyAmpersand().serialize(e.message()); - - if (checkPlayerChatListener(e.getPlayer(), message)) - e.setCancelled(true); - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - private void onPlayerAsyncChat(io.papermc.paper.event.player.AsyncChatEvent e) { - String message = LegacyComponentSerializer.legacyAmpersand().serialize(e.message()); - ChatEventResult eventResult = handlePlayerChat(e.getPlayer(), message, null); - if (eventResult == null) - return; - - if (eventResult.cancelled) - e.setCancelled(true); - - // Instead of the old AsyncPlayerChatEvent#setFormat method - plugin.getNMSAlgorithms().handlePaperChatRenderer(e); - } - } - private class SpigotChatListener implements Listener { - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - private void onPlayerAsyncChatLowest(AsyncPlayerChatEvent e) { - // PlayerChat should be on LOWEST priority so other chat plugins don't conflict. - if (checkPlayerChatListener(e.getPlayer(), e.getMessage())) - e.setCancelled(true); - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - private void onPlayerAsyncChat(AsyncPlayerChatEvent e) { - ChatEventResult eventResult = handlePlayerChat(e.getPlayer(), e.getMessage(), e.getFormat()); - if (eventResult == null) - return; - - if (eventResult.cancelled) - e.setCancelled(true); - - if (eventResult.format != null) - e.setFormat(eventResult.format); - } - - } - - private static class ChatEventResult { - - private boolean cancelled = false; - private String format = null; - + /* INTERNAL */ + + private void registerListeners() { + registerCallback(GameEventType.PLAYER_LOGIN_EVENT, GameEventPriority.MONITOR, this::onPlayerLogin); + registerCallback(GameEventType.PLAYER_JOIN_EVENT, GameEventPriority.MONITOR, this::onPlayerJoin); + registerCallback(GameEventType.PLAYER_QUIT_EVENT, GameEventPriority.MONITOR, this::onPlayerQuit); + registerCallback(GameEventType.PLAYER_GAMEMODE_CHANGE, GameEventPriority.MONITOR, this::onPlayerGameModeChange); + registerCallback(GameEventType.ENTITY_MOVE_EVENT, GameEventPriority.NORMAL, this::onPlayerMove); + registerCallback(GameEventType.ENTITY_TELEPORT_EVENT, GameEventPriority.HIGHEST, this::onPlayerTeleport); + registerCallback(GameEventType.PLAYER_CHANGED_WORLD_EVENT, GameEventPriority.MONITOR, this::onPlayerChangeWorld); + /* Set to NORMAL, so it doesn't conflict with vanish plugins */ + registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.NORMAL, this::onPlayerDamage); + registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.NORMAL, false, this::onSchematicSelection); + registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.LOWEST, this::onIslandChestInteract); + registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.NORMAL, this::onPlayerFall); + registerCallback(GameEventType.PLAYER_RESPAWN_EVENT, GameEventPriority.NORMAL, this::onPlayerRespawn); + // PlayerChat should be on LOWEST priority so other chat plugins don't conflict. + registerCallback(GameEventType.PLAYER_CHAT_EVENT, GameEventPriority.LOWEST, this::onPlayerChatLowest); + registerCallback(GameEventType.PLAYER_CHAT_EVENT, GameEventPriority.NORMAL, this::onPlayerChat); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java index 06f56bdbcc..a8999d8728 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java @@ -13,6 +13,10 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import org.bukkit.Bukkit; @@ -21,17 +25,11 @@ import org.bukkit.Material; import org.bukkit.PortalType; import org.bukkit.World; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; -import org.bukkit.event.Cancellable; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityPortalEnterEvent; -import org.bukkit.event.entity.EntityPortalEvent; -import org.bukkit.event.player.PlayerPortalEvent; import org.bukkit.event.player.PlayerTeleportEvent; -public class PortalsListener implements Listener { +public class PortalsListener extends AbstractGameEventListener { private final LazyReference portalsManager = new LazyReference() { @Override @@ -40,63 +38,49 @@ protected PortalsManagerService create() { } }; - private final SuperiorSkyblockPlugin plugin; - public PortalsListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); + registerListeners(); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onPlayerPortal(PlayerPortalEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - - if (superiorPlayer instanceof SuperiorNPCPlayer) - return; - - PortalType portalType = (e.getCause() == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? - PortalType.NETHER : PortalType.ENDER; - - EntityPortalResult portalResult = this.portalsManager.get().handlePlayerPortal(superiorPlayer, e.getFrom(), - portalType, e.getTo(), true); - handleEntityPortal(portalResult, e); + private void registerListeners() { + registerCallback(GameEventType.ENTITY_PORTAL_EVENT, GameEventPriority.MONITOR, this::onEntityPortal); + registerCallback(GameEventType.ENTITY_ENTER_PORTAL_EVENT, GameEventPriority.HIGHEST, this::onEntityEnterPortal); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onEntityPortal(EntityPortalEvent e) { - if (e.getTo() == null || e.getTo().getWorld() == null || e.getFrom() == null || e.getFrom().getWorld() == null) - return; - - PortalType portalType = e.getTo().getWorld().getEnvironment() == World.Environment.THE_END || - e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ? PortalType.ENDER : PortalType.NETHER; - - EntityPortalResult portalResult = this.portalsManager.get().handleEntityPortal(e.getEntity(), e.getFrom(), - portalType, e.getTo()); - handleEntityPortal(portalResult, e); + private void onEntityPortal(GameEvent e) { + if (e.getArgs().entity instanceof Player) + handlePlayerPortal(e); + else + handleEntityPortalResult(e); } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onEntityPortalEnter(EntityPortalEnterEvent e) { + private void onEntityEnterPortal(GameEvent e) { // Simulate portals in the following cases: // - Using an end portal in the end // - The target world is disabled + Entity entity = e.getArgs().entity; + Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(e.getEntity().getLocation(wrapper.getHandle())); + island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle())); } if (island == null) return; - World world = e.getLocation().getWorld(); + Location portalLocation = e.getArgs().portalLocation; + + World world = portalLocation.getWorld(); // Simulate end portal if (world.getEnvironment() == World.Environment.THE_END) { /* We teleport the player to his island instead of cancelling the event. Therefore, we must prevent the player from acting like he entered another island or left his island.*/ - SuperiorPlayer teleportedPlayer = e.getEntity() instanceof Player ? - plugin.getPlayers().getSuperiorPlayer((Player) e.getEntity()) : null; + SuperiorPlayer teleportedPlayer = entity instanceof Player ? + plugin.getPlayers().getSuperiorPlayer((Player) entity) : null; if (teleportedPlayer != null) teleportedPlayer.setPlayerStatus(PlayerStatus.LEAVING_ISLAND); @@ -108,7 +92,7 @@ public void onEntityPortalEnter(EntityPortalEnterEvent e) { if (teleportedPlayer != null) teleportedPlayer.removePlayerStatus(PlayerStatus.LEAVING_ISLAND); }).ifLeft(unused -> { - EntityTeleports.teleportUntilSuccess(e.getEntity(), + EntityTeleports.teleportUntilSuccess(entity, island.getIslandHome(dimension), 5, () -> { if (teleportedPlayer != null) teleportedPlayer.removePlayerStatus(PlayerStatus.LEAVING_ISLAND); @@ -122,9 +106,9 @@ public void onEntityPortalEnter(EntityPortalEnterEvent e) { if (ServerVersion.isLessThan(ServerVersion.v1_16)) return; - boolean isPlayer = e.getEntity() instanceof Player; + boolean isPlayer = entity instanceof Player; - Material originalMaterial = e.getLocation().getBlock().getType(); + Material originalMaterial = portalLocation.getBlock().getType(); PortalType portalType = originalMaterial == Materials.NETHER_PORTAL.toBukkitType() ? PortalType.NETHER : PortalType.ENDER; @@ -132,21 +116,53 @@ public void onEntityPortalEnter(EntityPortalEnterEvent e) { return; if (portalType == PortalType.NETHER) { - int ticksDelay = !isPlayer ? 0 : ((Player) e.getEntity()).getGameMode() == GameMode.CREATIVE ? 1 : 80; - int portalTicks = plugin.getNMSEntities().getPortalTicks(e.getEntity()); + int ticksDelay = !isPlayer ? 0 : ((Player) entity).getGameMode() == GameMode.CREATIVE ? 1 : 80; + int portalTicks = plugin.getNMSEntities().getPortalTicks(entity); if (portalTicks != ticksDelay) return; } if (isPlayer) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getEntity()); - this.portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, e.getLocation(), portalType, true); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(entity); + this.portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, portalLocation, portalType, true); } else { - this.portalsManager.get().handleEntityPortalFromIsland(e.getEntity(), island, e.getLocation(), portalType); + this.portalsManager.get().handleEntityPortalFromIsland(entity, island, portalLocation, portalType); } } - private void handleEntityPortal(EntityPortalResult portalResult, Cancellable event) { + private void handlePlayerPortal(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getArgs().entity); + + if (superiorPlayer instanceof SuperiorNPCPlayer) + return; + + PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? + PortalType.NETHER : PortalType.ENDER; + + EntityPortalResult portalResult = this.portalsManager.get().handlePlayerPortal( + superiorPlayer, e.getArgs().from, portalType, e.getArgs().to, true); + + handleEntityPortalResult(portalResult, e); + } + + public void handleEntityPortalResult(GameEvent e) { + Location from = e.getArgs().from; + Location to = e.getArgs().to; + + if (to == null || to.getWorld() == null || from == null || from.getWorld() == null) + return; + + Entity entity = e.getArgs().entity; + + PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? + PortalType.NETHER : PortalType.ENDER; + + EntityPortalResult portalResult = this.portalsManager.get().handleEntityPortal(entity, from, portalType, to); + + handleEntityPortalResult(portalResult, e); + } + + private void handleEntityPortalResult(EntityPortalResult portalResult, GameEvent event) { switch (portalResult) { case PORTAL_NOT_IN_ISLAND: return; @@ -159,7 +175,7 @@ private void handleEntityPortal(EntityPortalResult portalResult, Cancellable eve case WORLD_NOT_UNLOCKED: case DESTINATION_ISLAND_NOT_PERMITTED: case SUCCEED: - event.setCancelled(true); + event.setCancelled(); return; default: throw new IllegalStateException("No handling for result: " + portalResult); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 79dc00d285..dbb159e5a7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; @@ -12,15 +11,16 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.superiorskyblock.world.BukkitEntities; -import com.bgsoftware.superiorskyblock.world.BukkitItems; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -31,56 +31,21 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.FishHook; +import org.bukkit.entity.Hanging; +import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Vehicle; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; import org.bukkit.event.block.Action; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.BlockDispenseEvent; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.block.EntityBlockFormEvent; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityExplodeEvent; -import org.bukkit.event.entity.EntityTargetEvent; -import org.bukkit.event.entity.PlayerLeashEntityEvent; -import org.bukkit.event.entity.ProjectileHitEvent; -import org.bukkit.event.entity.ProjectileLaunchEvent; -import org.bukkit.event.hanging.HangingBreakByEntityEvent; -import org.bukkit.event.hanging.HangingPlaceEvent; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.inventory.InventoryType; -import org.bukkit.event.player.PlayerAttemptPickupItemEvent; -import org.bukkit.event.player.PlayerBucketEmptyEvent; -import org.bukkit.event.player.PlayerBucketFillEvent; -import org.bukkit.event.player.PlayerDropItemEvent; -import org.bukkit.event.player.PlayerInteractAtEntityEvent; -import org.bukkit.event.player.PlayerInteractEntityEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerItemConsumeEvent; -import org.bukkit.event.player.PlayerPickupArrowEvent; -import org.bukkit.event.player.PlayerPickupItemEvent; -import org.bukkit.event.player.PlayerShearEntityEvent; -import org.bukkit.event.player.PlayerTakeLecternBookEvent; -import org.bukkit.event.player.PlayerUnleashEntityEvent; -import org.bukkit.event.raid.RaidTriggerEvent; -import org.bukkit.event.vehicle.VehicleDamageEvent; -import org.bukkit.event.vehicle.VehicleEnterEvent; -import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; import java.util.Iterator; -public class ProtectionListener implements Listener { +public class ProtectionListener extends AbstractGameEventListener { - private static final ReflectMethod PROJECTILE_HIT_TARGET_ENTITY = new ReflectMethod<>( - ProjectileHitEvent.class, "getHitEntity"); - private static final ReflectMethod PROJECTILE_HIT_EVENT_TARGET_BLOCK = new ReflectMethod<>( - ProjectileHitEvent.class, "getHitBlock"); @Nullable private static final Material CHORUS_FLOWER = EnumHelper.getEnum(Material.class, "CHORUS_FLOWER"); @Nullable @@ -94,7 +59,6 @@ public class ProtectionListener implements Listener { @Nullable private static final EntityType TRIDENT = EnumHelper.getEnum(EntityType.class, "TRIDENT"); - private final SuperiorSkyblockPlugin plugin; private final LazyReference protectionManager = new LazyReference() { @Override protected RegionManagerService create() { @@ -103,348 +67,344 @@ protected RegionManagerService create() { }; public ProtectionListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - this.registerPlayerArrowPickupListener(); - this.registerPlayerAttemptPickupItemListener(); - this.registerPlayerTakeLecternBookListener(); - this.registerRaidTriggerListener(); + super(plugin); + registerListeners(); } /* BLOCK INTERACTS */ - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onBlockPlace(BlockPlaceEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getBlock()); + private void onBlockPlace(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().block); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onBlockFertilize(PlayerInteractEvent e) { - if (e.getAction() != Action.RIGHT_CLICK_BLOCK || e.getItem() == null || e.getClickedBlock() == null || - !Materials.BONE_MEAL.toBukkitItem().isSimilar(e.getItem())) - return; + private void onPlayerInteract(GameEvent e) { + if (handleBlockFertilize(e)) return; + if (handleBedPlace(e)) return; + if (handleSignColorChange(e)) return; + if (handleBrushUse(e)) return; + if (handleMinecartPlace(e)) return; + if (handleEntityInteract(e)) return; + handleBlockInteract(e); + } - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleBlockFertilize(superiorPlayer, e.getClickedBlock()); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + private boolean handleBlockFertilize(GameEvent e) { + Action action = e.getArgs().action; + ItemStack usedItem = e.getArgs().usedItem; + + if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null || !Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem)) + return false; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handleBlockFertilize(superiorPlayer, e.getArgs().clickedBlock); + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { + e.setCancelled(); + return true; + } + + return false; } // Patching a dupe glitch with crops and beds: https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/1672 - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onBedPlace(PlayerInteractEvent e) { - if (e.getAction() != Action.RIGHT_CLICK_BLOCK || e.getItem() == null || !e.getItem().getType().name().contains("BED")) - return; + private boolean handleBedPlace(GameEvent e) { + Action action = e.getArgs().action; + ItemStack usedItem = e.getArgs().usedItem; + + if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null || !Materials.isBed(usedItem.getType())) + return false; // The player right-clicked a block with a bed in his hand - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getClickedBlock()); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().clickedBlock); + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { + e.setCancelled(); + return true; + } + + return false; } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onSignColorChange(PlayerInteractEvent e) { - if (e.getItem() == null || e.getAction() != Action.RIGHT_CLICK_BLOCK || ServerVersion.isLegacy() || - !Materials.isDye(e.getItem().getType())) - return; + private boolean handleSignColorChange(GameEvent e) { + Action action = e.getArgs().action; + ItemStack usedItem = e.getArgs().usedItem; + + if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null || ServerVersion.isLegacy() || !Materials.isDye(usedItem.getType())) + return false; - BlockState blockState = e.getClickedBlock().getState(); + Block clickedBlock = e.getArgs().clickedBlock; + BlockState blockState = clickedBlock.getState(); if (!(blockState instanceof Sign)) - return; + return false; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getClickedBlock()); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, clickedBlock); + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { + e.setCancelled(); + return true; + } + + return false; } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onBlockBreak(BlockBreakEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleBlockBreak(superiorPlayer, e.getBlock()); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + private boolean handleBrushUse(GameEvent e) { + Action action = e.getArgs().action; + ItemStack usedItem = e.getArgs().usedItem; + + if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null || usedItem.getType() != BRUSH) + return false; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + interactionResult = this.protectionManager.get().handleCustomInteraction( + superiorPlayer, e.getArgs().clickedBlock.getLocation(wrapper.getHandle()), IslandPrivileges.BRUSH); + } + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { + e.setCancelled(); + return true; + } + + return false; } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onBlockInteract(PlayerInteractEvent e) { - if (e.getClickedBlock() == null) + private boolean handleMinecartPlace(GameEvent e) { + Action action = e.getArgs().action; + ItemStack usedItem = e.getArgs().usedItem; + + if (action != Action.RIGHT_CLICK_BLOCK || usedItem == null) + return false; + + Material handItemType = usedItem.getType(); + Material clickedBlockType = e.getArgs().clickedBlock.getType(); + if (!Materials.isBoat(handItemType) && (!Materials.isMinecart(handItemType) || !Materials.isRail(clickedBlockType))) + return false; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + + InteractionResult interactionResult; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, + e.getArgs().clickedBlock.getLocation(wrapper.getHandle()), IslandPrivileges.MINECART_PLACE); + } + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { + e.setCancelled(); + return true; + } + + return false; + } + + private boolean handleEntityInteract(GameEvent e) { + if (e.getArgs().clickedEntity == null) + return false; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(superiorPlayer, + e.getArgs().clickedEntity, e.getArgs().player.getItemInHand()); + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { + e.setCancelled(); + return true; + } + + return false; + } + + private void handleBlockInteract(GameEvent e) { + if (e.getArgs().clickedBlock == null) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + ItemStack usedItem = e.getArgs().usedItem; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.protectionManager.get().handleBlockInteract(superiorPlayer, - e.getClickedBlock(), e.getAction(), e.getItem()); + e.getArgs().clickedBlock, e.getArgs().action, usedItem); + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) + e.setCancelled(); + } + + private void onBlockBreak(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handleBlockBreak(superiorPlayer, e.getArgs().block); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onFrostWalker(EntityBlockFormEvent e) { - if (!(e.getEntity() instanceof Player)) + private void onFrostWalker(GameEvent e) { + Entity entity = e.getArgs().entity; + if (!(entity instanceof Player)) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getEntity()); - InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getBlock()); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity); + InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().block); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, false)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onBucketEmpty(PlayerBucketEmptyEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getBlockClicked()); + private void onBucketEmpty(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().clickedBlock); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onBucketFill(PlayerBucketFillEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getBlockClicked()); + private void onBucketFill(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handleBlockPlace(superiorPlayer, e.getArgs().clickedBlock); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onBucketDispense(BlockDispenseEvent e) { - Material itemType = e.getItem().getType(); + private void onBucketDispense(GameEvent e) { + Material itemType = e.getArgs().dispensedItem.getType(); if (!(itemType == Material.BUCKET || itemType == Material.WATER_BUCKET || itemType == Material.LAVA_BUCKET)) return; - Location dispenseBlockLocation = new Location(e.getBlock().getWorld(), e.getVelocity().getBlockX(), - e.getVelocity().getBlockY(), e.getVelocity().getBlockZ()); + Vector velocity = e.getArgs().velocity; + + Location dispenseBlockLocation = new Location(e.getArgs().block.getWorld(), velocity.getBlockX(), + velocity.getBlockY(), velocity.getBlockZ()); Island island = plugin.getGrid().getIslandAt(dispenseBlockLocation); if (island != null && !island.isInsideRange(dispenseBlockLocation)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onBrushUse(PlayerInteractEvent e) { - if (e.getAction() != Action.RIGHT_CLICK_BLOCK || e.getItem() == null || e.getClickedBlock() == null || - e.getItem().getType() != BRUSH) + private void onChorusFruitConsume(GameEvent e) { + if (CHORUS_FRUIT == null || e.getArgs().consumedItem.getType() != CHORUS_FRUIT) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - - InteractionResult interactionResult; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - interactionResult = this.protectionManager.get().handleCustomInteraction( - superiorPlayer, e.getClickedBlock().getLocation(wrapper.getHandle()), IslandPrivileges.BRUSH); - } - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onChorusFruitConsume(PlayerItemConsumeEvent e) { - if (CHORUS_FRUIT == null || e.getItem().getType() != CHORUS_FRUIT) - return; - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + Player player = e.getArgs().player; + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { interactionResult = this.protectionManager.get().handlePlayerConsumeChorusFruit( - superiorPlayer, e.getPlayer().getLocation(wrapper.getHandle())); + superiorPlayer, player.getLocation(wrapper.getHandle())); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - private void onMinecartPlace(PlayerInteractEvent e) { - if (e.getAction() != Action.RIGHT_CLICK_BLOCK || e.getClickedBlock() == null) - return; - - PlayerHand playerHand = BukkitItems.getHand(e); - if (playerHand != PlayerHand.MAIN_HAND) - return; - - ItemStack handItem = BukkitItems.getHandItem(e.getPlayer(), playerHand); - - if (handItem == null) - return; - - Material handItemType = handItem.getType(); - Material clickedBlockType = e.getClickedBlock().getType(); - - if ((Materials.isMinecart(handItemType) && Materials.isRail(clickedBlockType)) || Materials.isBoat(handItemType)) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, - e.getClickedBlock().getLocation(wrapper.getHandle()), IslandPrivileges.MINECART_PLACE); - } - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); - } - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onWindChargeUse(ProjectileLaunchEvent e) { - if (e.getEntityType() != WIND_CHARGE) - return; - - BukkitEntities.getPlayerSource(e.getEntity()).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(shooerPlayer -> { - InteractionResult interactionResult; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - interactionResult = this.protectionManager.get().handlePlayerUseWindCharge(shooerPlayer, - shooerPlayer.getLocation(wrapper.getHandle())); - } - if (ProtectionHelper.shouldPreventInteraction(interactionResult, shooerPlayer, true)) - e.setCancelled(true); - }); + e.setCancelled(); } /* ENTITY INTERACTS */ - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onEntityInteract(PlayerInteractEntityEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(superiorPlayer, - e.getRightClicked(), e.getPlayer().getItemInHand()); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); - } - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onEntityInteract(PlayerInteractAtEntityEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(superiorPlayer, - e.getRightClicked(), e.getPlayer().getItemInHand()); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); - } + private void onEntityAttack(GameEvent e) { + Entity entity = e.getArgs().entity; + Entity damager = e.getArgs().damager; - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onEntityAttack(EntityDamageByEntityEvent e) { - if (e.getEntity() instanceof Player) + if (damager == null || entity instanceof Player) return; - SuperiorPlayer damagerSource = BukkitEntities.getPlayerSource(e.getDamager()) + SuperiorPlayer damagerSource = BukkitEntities.getPlayerSource(damager) .map(plugin.getPlayers()::getSuperiorPlayer).orElse(null); - InteractionResult interactionResult = this.protectionManager.get().handleEntityDamage(e.getDamager(), e.getEntity()); + InteractionResult interactionResult = this.protectionManager.get().handleEntityDamage(damager, entity); if (ProtectionHelper.shouldPreventInteraction(interactionResult, damagerSource, true)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onEntityShearing(PlayerShearEntityEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleEntityShear(superiorPlayer, e.getEntity()); + private void onEntityShearing(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handleEntityShear(superiorPlayer, e.getArgs().entity); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onHangingBreak(HangingBreakByEntityEvent e) { - BukkitEntities.getPlayerSource(e.getRemover()).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(removerPlayer -> { - InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(removerPlayer, e.getEntity(), null); + private void onHangingBreak(GameEvent e) { + BukkitEntities.getPlayerSource(e.getArgs().remover).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(removerPlayer -> { + InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(removerPlayer, e.getArgs().entity, null); if (ProtectionHelper.shouldPreventInteraction(interactionResult, removerPlayer, true)) - e.setCancelled(true); + e.setCancelled(); }); } - @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) - public void onHangingPlace(HangingPlaceEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(superiorPlayer, e.getEntity(), null); + private void onHangingPlace(GameEvent e) { + if (!(e.getArgs().entity instanceof Hanging)) + return; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handleEntityInteract(superiorPlayer, e.getArgs().entity, null); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onEntityTarget(EntityTargetEvent e) { - if (!(e.getTarget() instanceof Player)) + private void onEntityTarget(GameEvent e) { + Entity entity = e.getArgs().entity; + Entity target = e.getArgs().target; + + if (!(target instanceof Player)) return; - InteractionResult interactionResult = this.protectionManager.get().handleEntityDamage(e.getTarget(), e.getEntity()); + InteractionResult interactionResult = this.protectionManager.get().handleEntityDamage(target, entity); if (ProtectionHelper.shouldPreventInteraction(interactionResult, null, false)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler - public void onVillagerTrade(InventoryClickEvent e) { - Inventory openInventory = e.getView().getTopInventory(); + private void onVillagerTrade(GameEvent e) { + Inventory openInventory = e.getArgs().bukkitEvent.getView().getTopInventory(); if (openInventory == null || openInventory.getType() != InventoryType.MERCHANT) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getWhoClicked()); + HumanEntity humanEntity = e.getArgs().bukkitEvent.getWhoClicked(); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(humanEntity); InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = e.getWhoClicked().getLocation(wrapper.getHandle()); + Location location = humanEntity.getLocation(wrapper.getHandle()); interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, location, IslandPrivileges.VILLAGER_TRADING); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, null, false)) { - e.setCancelled(true); - e.getWhoClicked().closeInventory(); + e.setCancelled(); + humanEntity.closeInventory(); } } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerLeash(PlayerLeashEntityEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleEntityLeash(superiorPlayer, e.getEntity()); + private void onPlayerLeash(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handleEntityLeash(superiorPlayer, e.getArgs().entity); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerUnleash(PlayerUnleashEntityEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handleEntityLeash(superiorPlayer, e.getEntity()); + private void onPlayerUnleash(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handleEntityLeash(superiorPlayer, e.getArgs().entity); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + e.setCancelled(); } /* VEHICLE INTERACTS */ - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onVehicleDestroy(VehicleDamageEvent e) { - if (!(e.getAttacker() instanceof Player)) - return; - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getAttacker()); - InteractionResult interactionResult = this.protectionManager.get().handleEntityDamage(e.getAttacker(), e.getVehicle()); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); - } - - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onVehicleEnter(VehicleEnterEvent e) { - if (!(e.getEntered() instanceof Player)) + private void onVehicleEnter(GameEvent e) { + Entity rider = e.getArgs().entity; + if (!(rider instanceof Player)) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getEntered()); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(rider); InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location vehicleLocation = e.getVehicle().getLocation(wrapper.getHandle()); + Location vehicleLocation = e.getArgs().vehicle.getLocation(wrapper.getHandle()); interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, vehicleLocation, IslandPrivileges.MINECART_ENTER); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onVehicleOpen(InventoryOpenEvent e) { - InventoryHolder inventoryHolder = e.getInventory().getHolder(); + private void onVehicleOpen(GameEvent e) { + InventoryHolder inventoryHolder = e.getArgs().bukkitEvent.getInventory().getHolder(); if (!(inventoryHolder instanceof Vehicle)) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().bukkitEvent.getPlayer()); InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location minecartLocation = ((Vehicle) inventoryHolder).getLocation(wrapper.getHandle()); @@ -452,100 +412,100 @@ public void onVehicleOpen(InventoryOpenEvent e) { minecartLocation, IslandPrivileges.MINECART_OPEN); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerCollideWithVehicle(VehicleEntityCollisionEvent e) { - if (!(e.getEntity() instanceof Player)) + private void onPlayerCollideWithEntity(GameEvent e) { + Entity entity = e.getArgs().entity; + if (!(entity instanceof Player)) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getEntity()); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity); InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location vehicleLocation = e.getVehicle().getLocation(wrapper.getHandle()); + Location vehicleLocation = e.getArgs().target.getLocation(wrapper.getHandle()); interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, vehicleLocation, IslandPrivileges.MINECART_ENTER); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, false)) - e.setCancelled(true); + e.setCancelled(); } /* ITEMS */ - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerDropItem(PlayerDropItemEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handlePlayerDropItem(superiorPlayer, e.getItemDrop()); + private void onPlayerDropItem(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handlePlayerDropItem(superiorPlayer, e.getArgs().droppedItem); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerPickupItem(PlayerPickupItemEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = this.protectionManager.get().handlePlayerPickupItem(superiorPlayer, e.getItem()); + private void onPlayerPickupItem(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = this.protectionManager.get().handlePlayerPickupItem(superiorPlayer, e.getArgs().pickedUpItem); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); + e.setCancelled(); + } + + private void onPlayerPickupArrow(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + InteractionResult interactionResult = protectionManager.get().handlePlayerPickupItem(superiorPlayer, e.getArgs().pickedUpItem); + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) + e.setCancelled(); } /* PROJECTILE INTERACTS */ - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerLaunchProjectile(ProjectileLaunchEvent e) { - BukkitEntities.getPlayerSource(e.getEntity()).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(launcherPlayer -> { - IslandPrivilege islandPrivilege; + private void onPlayerLaunchProjectile(GameEvent e) { + Entity entity = e.getArgs().entity; + BukkitEntities.getPlayerSource(entity).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(launcherPlayer -> { + EntityType entityType = entity.getType(); - if (e.getEntity() instanceof FishHook && !ServerVersion.isLegacy()) { + IslandPrivilege islandPrivilege; + if (entity instanceof FishHook && !ServerVersion.isLegacy()) { islandPrivilege = IslandPrivileges.FISH; - } else if (e.getEntityType() == TRIDENT) { + } else if (entityType == TRIDENT) { islandPrivilege = IslandPrivileges.PICKUP_DROPS; - } else if (e.getEntity() instanceof Egg) { + } else if (entity instanceof Egg) { islandPrivilege = IslandPrivileges.ANIMAL_SPAWN; - } else if (e.getEntity() instanceof EnderPearl) { + } else if (entity instanceof EnderPearl) { islandPrivilege = IslandPrivileges.ENDER_PEARL; + } else if (entityType == WIND_CHARGE) { + islandPrivilege = IslandPrivileges.WIND_CHARGE; } else { return; } InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location entityLocation = e.getEntity().getLocation(wrapper.getHandle()); + Location entityLocation = entity.getLocation(wrapper.getHandle()); interactionResult = this.protectionManager.get().handleCustomInteraction(launcherPlayer, entityLocation, islandPrivilege); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, launcherPlayer, true)) - e.setCancelled(true); + e.setCancelled(); }); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onProjectileHit(ProjectileHitEvent e) { - BukkitEntities.getPlayerSource(e.getEntity()).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(shooterPlayer -> { + private void onProjectileHit(GameEvent e) { + Entity entity = e.getArgs().entity; + BukkitEntities.getPlayerSource(entity).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(shooterPlayer -> { Location location; IslandPrivilege islandPrivilege; Block hitBlock; InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (e.getEntity() instanceof FishHook) { - if (!PROJECTILE_HIT_TARGET_ENTITY.isValid()) - return; - - Entity hitEntity = PROJECTILE_HIT_TARGET_ENTITY.invoke(e); - + if (entity instanceof FishHook) { + Entity hitEntity = e.getArgs().hitEntity; if (hitEntity == null) return; location = hitEntity.getLocation(wrapper.getHandle()); - islandPrivilege = BukkitEntities.getCategory(e.getEntityType()).getDamagePrivilege(); + islandPrivilege = BukkitEntities.getCategory(entity.getType()).getDamagePrivilege(); hitBlock = null; } else { - if (!PROJECTILE_HIT_EVENT_TARGET_BLOCK.isValid()) - return; - - hitBlock = PROJECTILE_HIT_EVENT_TARGET_BLOCK.invoke(e); - + hitBlock = e.getArgs().hitBlock; if (hitBlock == null || hitBlock.getType() != CHORUS_FLOWER) return; @@ -556,7 +516,7 @@ public void onProjectileHit(ProjectileHitEvent e) { interactionResult = this.protectionManager.get().handleCustomInteraction(shooterPlayer, location, islandPrivilege); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, shooterPlayer, true)) { - e.getEntity().remove(); + entity.remove(); if (hitBlock != null) { ICachedBlock cachedBlock = plugin.getNMSWorld().cacheBlock(hitBlock); hitBlock.setType(Material.AIR); @@ -571,13 +531,13 @@ public void onProjectileHit(ProjectileHitEvent e) { }); } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - private void onWindChargeExplodeEvent(EntityExplodeEvent e) { - if (e.getEntityType() != WIND_CHARGE) + private void onWindChargeExplodeEvent(GameEvent e) { + Entity entity = e.getArgs().entity; + if (entity.getType() != WIND_CHARGE) return; - BukkitEntities.getPlayerSource(e.getEntity()).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(shooterPlayer -> { - Iterator blocksIterator = e.blockList().iterator(); + BukkitEntities.getPlayerSource(entity).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(shooterPlayer -> { + Iterator blocksIterator = e.getArgs().blocks.iterator(); while (blocksIterator.hasNext()) { Block block = blocksIterator.next(); Material blockType = block.getType(); @@ -597,91 +557,50 @@ private void onWindChargeExplodeEvent(EntityExplodeEvent e) { } - private void registerPlayerArrowPickupListener() { - try { - Class.forName("org.bukkit.event.player.PlayerPickupArrowEvent"); - Bukkit.getPluginManager().registerEvents(new PlayerArrowPickup(), plugin); - } catch (Exception ignored) { - } - } - - private void registerPlayerAttemptPickupItemListener() { - try { - Class.forName("org.bukkit.event.player.PlayerAttemptPickupItemEvent"); - Bukkit.getPluginManager().registerEvents(new PaperAttemptPickupListener(), plugin); - } catch (Exception ignored) { - } - } - - private void registerPlayerTakeLecternBookListener() { - try { - Class.forName("org.bukkit.event.player.PlayerTakeLecternBookEvent"); - Bukkit.getPluginManager().registerEvents(new PlayerTakeLecternBookListener(), plugin); - } catch (Exception ignored) { - } - } - - private void registerRaidTriggerListener() { - try { - Class.forName("org.bukkit.event.raid.RaidTriggerEvent"); - Bukkit.getPluginManager().registerEvents(new RaidTriggerListener(), plugin); - } catch (Exception ignored) { - } - } - - private class PaperAttemptPickupListener implements Listener { - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerItemPickup(PlayerAttemptPickupItemEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = protectionManager.get().handlePlayerPickupItem(superiorPlayer, e.getItem()); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); - } - - } + /* WORLD EVENTS */ - private class PlayerArrowPickup implements Listener { - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerArrowPickup(PlayerPickupArrowEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = protectionManager.get().handlePlayerPickupItem(superiorPlayer, e.getItem()); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); - } - - } - - private class PlayerTakeLecternBookListener implements Listener { - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPlayerTakeLecternBook(PlayerTakeLecternBookEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - InteractionResult interactionResult = protectionManager.get().handleBlockInteract(superiorPlayer, - e.getLectern().getBlock(), Action.RIGHT_CLICK_BLOCK, null); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(true); - } - - } - - private class RaidTriggerListener implements Listener { - - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onRaidTrigger(RaidTriggerEvent e) { - if (!plugin.getGrid().isIslandsWorld(e.getWorld())) - return; - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - Location location = e.getRaid().getLocation(); - - Island island = plugin.getGrid().getIslandAt(location); - - if (island == null || island.isSpawn() || !island.isInside(location) || !island.isMember(superiorPlayer)) - e.setCancelled(true); - } + private void onRaidTrigger(GameEvent e) { + if (!plugin.getGrid().isIslandsWorld(e.getArgs().world)) + return; + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + Location raidLocation = e.getArgs().raidLocation; + + Island island = plugin.getGrid().getIslandAt(raidLocation); + + if (island == null || island.isSpawn() || !island.isInside(raidLocation) || !island.isMember(superiorPlayer)) + e.setCancelled(); + } + + /* INTERNAL */ + + private void registerListeners() { + registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.NORMAL, this::onBlockPlace); + registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.NORMAL, this::onPlayerInteract); + registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.NORMAL, this::onBlockBreak); + registerCallback(GameEventType.ENTITY_BLOCK_FORM_EVENT, GameEventPriority.NORMAL, this::onFrostWalker); + registerCallback(GameEventType.PLAYER_EMPTY_BUCKET_EVENT, GameEventPriority.NORMAL, this::onBucketEmpty); + registerCallback(GameEventType.PLAYER_FILL_BUCKET_EVENT, GameEventPriority.NORMAL, this::onBucketFill); + registerCallback(GameEventType.BLOCK_DISPENSE_EVENT, GameEventPriority.NORMAL, this::onBucketDispense); + registerCallback(GameEventType.PLAYER_ITEM_CONSUME_EVENT, GameEventPriority.NORMAL, this::onChorusFruitConsume); + registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.NORMAL, this::onEntityAttack); + registerCallback(GameEventType.PLAYER_SHEAR_ENTITY_EVENT, GameEventPriority.NORMAL, this::onEntityShearing); + registerCallback(GameEventType.HANGING_BREAK_EVENT, GameEventPriority.NORMAL, this::onHangingBreak); + registerCallback(GameEventType.HANGING_PLACE_EVENT, GameEventPriority.NORMAL, this::onHangingPlace); + registerCallback(GameEventType.ENTITY_TARGET_EVENT, GameEventPriority.NORMAL, this::onEntityTarget); + registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.NORMAL, false, this::onVillagerTrade); + registerCallback(GameEventType.PLAYER_LEASH_ENTITY_EVENT, GameEventPriority.NORMAL, this::onPlayerLeash); + registerCallback(GameEventType.PLAYER_UNLEASH_ENTITY_EVENT, GameEventPriority.NORMAL, this::onPlayerUnleash); + registerCallback(GameEventType.ENTITY_RIDE_EVENT, GameEventPriority.NORMAL, this::onVehicleEnter); + registerCallback(GameEventType.INVENTORY_OPEN_EVENT, GameEventPriority.NORMAL, this::onVehicleOpen); + registerCallback(GameEventType.ENTITY_COLLISION_EVENT, GameEventPriority.NORMAL, this::onPlayerCollideWithEntity); + registerCallback(GameEventType.PLAYER_DROP_ITEM_EVENT, GameEventPriority.NORMAL, this::onPlayerDropItem); + registerCallback(GameEventType.PLAYER_PICKUP_ITEM_EVENT, GameEventPriority.NORMAL, this::onPlayerPickupItem); + registerCallback(GameEventType.PROJECTILE_LAUNCH_EVENT, GameEventPriority.NORMAL, this::onPlayerLaunchProjectile); + registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.NORMAL, this::onProjectileHit); + registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.NORMAL, this::onWindChargeExplodeEvent); + registerCallback(GameEventType.PLAYER_PICKUP_ARROW_EVENT, GameEventPriority.NORMAL, this::onPlayerPickupArrow); + registerCallback(GameEventType.RAID_TRIGGER_EVENT, GameEventPriority.NORMAL, this::onRaidTrigger); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java index 12089aed3a..53aa6e9afe 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java @@ -6,6 +6,10 @@ import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.world.SignType; import org.bukkit.Location; import org.bukkit.block.Block; @@ -13,43 +17,39 @@ import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.block.data.Directional; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.entity.Player; import java.util.Arrays; -public class SignsListener implements Listener { +public class SignsListener extends AbstractGameEventListener { private static final BlockFace[] NEARBY_BLOCKS = new BlockFace[]{ BlockFace.UP, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.EAST }; - private final SuperiorSkyblockPlugin plugin; - public SignsListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); + registerListeners(); } - /* SIGN PLACES */ + private void onSignPlace(GameEvent e) { + Player player = e.getArgs().player; + Block block = e.getArgs().block; + String[] lines = e.getArgs().lines; - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - private void onSignPlace(SignChangeEvent e) { String[] signLines; IslandSigns.Result result; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location warpLocation = e.getBlock().getLocation(wrapper.getHandle()); - SignType signType = plugin.getNMSWorld().getSignType(e.getBlock()); + Location warpLocation = block.getLocation(wrapper.getHandle()); + SignType signType = plugin.getNMSWorld().getSignType(block); // Hanging signs are not allowed if (signType == SignType.HANGING_SIGN || signType == SignType.HANGING_WALL_SIGN) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - signLines = e.getLines().clone(); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); + signLines = lines.clone(); result = IslandSigns.handleSignPlace(superiorPlayer, warpLocation, signLines, true); } @@ -64,13 +64,13 @@ private void onSignPlace(SignChangeEvent e) { } // Only update the lines if changed - if (Arrays.equals(signLines, e.getLines())) + if (Arrays.equals(signLines, lines)) return; // We want to update the sign only one tick later, so other plugins don't interface with it // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/1916 BukkitExecutor.sync(() -> { - BlockState blockState = e.getBlock().getState(); + BlockState blockState = block.getState(); if (blockState instanceof Sign) { Sign sign = (Sign) blockState; for (int i = 0; i < signLines.length; ++i) @@ -80,57 +80,63 @@ private void onSignPlace(SignChangeEvent e) { }, 1L); } - /* SIGN BREAKS */ - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onSignBreak(BlockBreakEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + public void onSignBreak(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); + Block block = e.getArgs().block; - if (e.getBlock().getState() instanceof Sign) { - IslandSigns.Result result = IslandSigns.handleSignBreak(superiorPlayer, (Sign) e.getBlock().getState()); + if (block.getState() instanceof Sign) { + IslandSigns.Result result = IslandSigns.handleSignBreak(superiorPlayer, (Sign) block.getState()); if (result.isCancelEvent()) - e.setCancelled(true); - } else { - for (BlockFace blockFace : NEARBY_BLOCKS) { - Block faceBlock = e.getBlock().getRelative(blockFace); - BlockState blockState = faceBlock.getState(); - if (blockState instanceof Sign) { - boolean isSignGonnaBreak; - - if (ServerVersion.isLegacy()) { - org.bukkit.material.Sign sign = (org.bukkit.material.Sign) blockState.getData(); - isSignGonnaBreak = sign.getAttachedFace().getOppositeFace() == blockFace; - } else { - Object blockData = plugin.getNMSWorld().getBlockData(faceBlock); - switch (plugin.getNMSWorld().getSignType(blockData)) { - case WALL_SIGN: - // Wall signs will only be broken if they are attached to the block - isSignGonnaBreak = ((Directional) blockData).getFacing() == blockFace; - break; - case STANDING_SIGN: - // Standing signs will only be broken if they are placed on top of the block - isSignGonnaBreak = blockFace == BlockFace.UP; - break; - case HANGING_WALL_SIGN: - case HANGING_SIGN: - // Hanging signs are not allowed as warp signs - isSignGonnaBreak = false; - break; - default: - throw new RuntimeException("Found sign that cannot be handled: " + blockData); - } - } - - if (isSignGonnaBreak) { - IslandSigns.Result result = IslandSigns.handleSignBreak(superiorPlayer, (Sign) blockState); - if (result.isCancelEvent()) { - e.setCancelled(true); - break; - } - } + e.setCancelled(); + + return; + } + + for (BlockFace blockFace : NEARBY_BLOCKS) { + Block faceBlock = block.getRelative(blockFace); + BlockState blockState = faceBlock.getState(); + if (!(blockState instanceof Sign)) + continue; + + boolean isSignGonnaBreak; + + if (ServerVersion.isLegacy()) { + org.bukkit.material.Sign sign = (org.bukkit.material.Sign) blockState.getData(); + isSignGonnaBreak = sign.getAttachedFace().getOppositeFace() == blockFace; + } else { + Object blockData = plugin.getNMSWorld().getBlockData(faceBlock); + switch (plugin.getNMSWorld().getSignType(blockData)) { + case WALL_SIGN: + // Wall signs will only be broken if they are attached to the block + isSignGonnaBreak = ((Directional) blockData).getFacing() == blockFace; + break; + case STANDING_SIGN: + // Standing signs will only be broken if they are placed on top of the block + isSignGonnaBreak = blockFace == BlockFace.UP; + break; + case HANGING_WALL_SIGN: + case HANGING_SIGN: + // Hanging signs are not allowed as warp signs + isSignGonnaBreak = false; + break; + default: + throw new RuntimeException("Found sign that cannot be handled: " + blockData); + } + } + + if (isSignGonnaBreak) { + IslandSigns.Result result = IslandSigns.handleSignBreak(superiorPlayer, (Sign) blockState); + if (result.isCancelEvent()) { + e.setCancelled(); + return; } } } } + private void registerListeners() { + registerCallback(GameEventType.SIGN_CHANGE_EVENT, GameEventPriority.NORMAL, this::onSignPlace); + registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.NORMAL, this::onSignBreak); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java index aa2ee1d6c5..f03fe1c93d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java @@ -14,26 +14,18 @@ import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.StackedBlocksDepositMenu; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.service.stackedblocks.StackedBlocksServiceHelper; import com.bgsoftware.superiorskyblock.world.BukkitItems; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; +import org.bukkit.entity.Player; import org.bukkit.event.block.Action; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.BlockFormEvent; -import org.bukkit.event.block.BlockPhysicsEvent; -import org.bukkit.event.block.BlockPistonExtendEvent; -import org.bukkit.event.block.BlockPistonRetractEvent; -import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.event.entity.EntityChangeBlockEvent; -import org.bukkit.event.entity.EntityExplodeEvent; -import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; import java.util.Arrays; @@ -43,14 +35,13 @@ import java.util.List; import java.util.Map; -public class StackedBlocksListener implements Listener { +public class StackedBlocksListener extends AbstractGameEventListener { @Nullable private static final Material COPPER_BLOCK = EnumHelper.getEnum(Material.class, "COPPER_BLOCK"); private static final Material HONEYCOMB = EnumHelper.getEnum(Material.class, "HONEYCOMB"); private final Map> ENTITY_TEMPLATE_OFFSETS = buildEntityTemplateOffsetsMap(); - private final SuperiorSkyblockPlugin plugin; private final LazyReference stackedBlocksInteractionService = new LazyReference() { @Override protected StackedBlocksInteractionService create() { @@ -59,110 +50,134 @@ protected StackedBlocksInteractionService create() { }; public StackedBlocksListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - this.registerPhysicsListener(); - this.registerSpongeListener(); + super(plugin); + this.registerListeners(); } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockStack(BlockPlaceEvent e) { - if (e.getBlockAgainst().equals(e.getBlock())) + private void onStackedBlockInteract(GameEvent e) { + if (e.getArgs().action != Action.RIGHT_CLICK_BLOCK) return; - if (plugin.getStackedBlocks().getStackedBlockAmount(e.getBlock()) > 1) - plugin.getStackedBlocks().setStackedBlock(e.getBlock(), 1); + if (handleStackedBlockPlace(e)) return; + if (handleStackedBlockUnstack(e)) return; + } + + /* STACK LISTENERS */ + + private void onStackedBlockPlace(GameEvent e) { + Block block = e.getArgs().block; + Block againstBlock = e.getArgs().againstBlock; + + if (againstBlock.equals(block)) + return; + + if (plugin.getStackedBlocks().getStackedBlockAmount(block) > 1) + plugin.getStackedBlocks().setStackedBlock(block, 1); + + Player player = e.getArgs().player; + PlayerHand usedHand = e.getArgs().usedHand; + ItemStack inHand = e.getArgs().usedItem; // We do not stack blocks when the hand items has a name or a lore. - ItemStack inHand = e.getItemInHand(); if (inHand.hasItemMeta() && (inHand.getItemMeta().hasDisplayName() || inHand.getItemMeta().hasLore())) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); - PlayerHand usedHand = BukkitItems.getHand(e); + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); InteractionResult interactionResult = this.stackedBlocksInteractionService.get().handleStackedBlockPlace( - superiorPlayer, e.getBlockAgainst(), usedHand.getEquipmentSlot()); + superiorPlayer, againstBlock, usedHand.getEquipmentSlot()); if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockStack(PlayerInteractEvent e) { - if (e.getAction() != Action.RIGHT_CLICK_BLOCK) - return; + private boolean handleStackedBlockPlace(GameEvent e) { + boolean cancelled = false; - Block clickedBlock = e.getClickedBlock(); - Material clickedBlockType = clickedBlock.getType(); + Player player = e.getArgs().player; + Block clickedBlock = e.getArgs().clickedBlock; + PlayerHand usedHand = e.getArgs().usedHand; + ItemStack usedItem = e.getArgs().usedItem; - ItemStack inHand = e.getItem(); + Material clickedBlockType = clickedBlock.getType(); if (clickedBlockType == Material.DRAGON_EGG) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (plugin.getStackedBlocks().getStackedBlockAmount(clickedBlock) > 1) { - e.setCancelled(true); - if (inHand == null) + e.setCancelled(); + if (usedItem == null) this.stackedBlocksInteractionService.get().handleStackedBlockBreak(clickedBlock, superiorPlayer); + cancelled = true; } - if (inHand != null) { - PlayerHand usedHand = BukkitItems.getHand(e); + if (usedItem != null) { InteractionResult interactionResult = this.stackedBlocksInteractionService.get() .handleStackedBlockPlace(superiorPlayer, clickedBlock, usedHand.getEquipmentSlot()); - if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) - e.setCancelled(true); + if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) { + e.setCancelled(); + cancelled = true; + } } - } else if (clickedBlockType == COPPER_BLOCK && inHand != null && inHand.getType() == HONEYCOMB && + } else if (clickedBlockType == COPPER_BLOCK && usedItem != null && usedItem.getType() == HONEYCOMB && plugin.getStackedBlocks().getStackedBlockAmount(clickedBlock) > 1) { - e.setCancelled(true); + e.setCancelled(); + cancelled = true; } + + return cancelled; } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockUnstack(BlockBreakEvent e) { - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + /* UNSTACK LISTENERS */ + + private void onStackedBlockBreak(GameEvent e) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); InteractionResult interactionResult = this.stackedBlocksInteractionService.get() - .handleStackedBlockBreak(e.getBlock(), superiorPlayer); + .handleStackedBlockBreak(e.getArgs().block, superiorPlayer); if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockUnstack(PlayerInteractEvent e) { - if (e.getAction() != Action.RIGHT_CLICK_BLOCK || e.getItem() != null || - BukkitItems.getHand(e) != PlayerHand.MAIN_HAND) - return; + private boolean handleStackedBlockUnstack(GameEvent e) { + if (e.getArgs().usedItem != null || e.getArgs().usedHand != PlayerHand.MAIN_HAND) + return false; - if (plugin.getStackedBlocks().getStackedBlockAmount(e.getClickedBlock()) <= 1) - return; + Block clickedBlock = e.getArgs().clickedBlock; + + if (plugin.getStackedBlocks().getStackedBlockAmount(clickedBlock) <= 1) + return false; + + Player player = e.getArgs().player; - if (plugin.getSettings().getStackedBlocks().getDepositMenu().isEnabled() && e.getPlayer().isSneaking()) { - StackedBlocksDepositMenu depositMenu = new StackedBlocksDepositMenu(e.getClickedBlock().getLocation()); - e.getPlayer().openInventory(depositMenu.getInventory()); + if (plugin.getSettings().getStackedBlocks().getDepositMenu().isEnabled() && player.isSneaking()) { + StackedBlocksDepositMenu depositMenu = new StackedBlocksDepositMenu(clickedBlock.getLocation()); + player.openInventory(depositMenu.getInventory()); } else { - ItemStack offHandItem = BukkitItems.getHandItem(e.getPlayer(), PlayerHand.OFF_HAND); - if (offHandItem != null && offHandItem.getType() == e.getClickedBlock().getType()) - return; + ItemStack offHandItem = BukkitItems.getHandItem(player, PlayerHand.OFF_HAND); + if (offHandItem != null && offHandItem.getType() == clickedBlock.getType()) + return false; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); InteractionResult interactionResult = this.stackedBlocksInteractionService.get() - .handleStackedBlockBreak(e.getClickedBlock(), superiorPlayer); - if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) - e.setCancelled(true); + .handleStackedBlockBreak(clickedBlock, superiorPlayer); + if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) { + e.setCancelled(); + return true; + } } + + return false; } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockUnstack(EntityChangeBlockEvent e) { + private void onStackedBlockBreakByEntity(GameEvent e) { InteractionResult interactionResult = this.stackedBlocksInteractionService.get() - .handleStackedBlockBreak(e.getBlock(), null); + .handleStackedBlockBreak(e.getArgs().block, null); if (StackedBlocksServiceHelper.shouldCancelOriginalEvent(interactionResult)) - e.setCancelled(true); + e.setCancelled(); } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onExplode(EntityExplodeEvent e) { - List blockList = new LinkedList<>(e.blockList()); + private void onStackedBlockExplode(GameEvent e) { + List blockList = new LinkedList<>(e.getArgs().blocks); ItemStack blockItem; for (Block block : blockList) { @@ -176,7 +191,7 @@ public void onExplode(EntityExplodeEvent e) { continue; // All checks are done. We can remove the block from the list. - e.blockList().remove(block); + e.getArgs().blocks.remove(block); blockItem = block.getState().getData().toItemStack(amount); @@ -196,67 +211,78 @@ public void onExplode(EntityExplodeEvent e) { } } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onPistonExtend(BlockPistonExtendEvent e) { - for (Block block : e.getBlocks()) { + /* STACKED-BLOCKS PROTECTION */ + + private void onPistonExtend(GameEvent e) { + for (Block block : e.getArgs().blocks) { if (plugin.getStackedBlocks().getStackedBlockAmount(block) > 1) { - e.setCancelled(true); + e.setCancelled(); break; } } } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onPistonRetract(BlockPistonRetractEvent e) { - for (Block block : e.getBlocks()) { + public void onPistonRetract(GameEvent e) { + for (Block block : e.getArgs().blocks) { if (plugin.getStackedBlocks().getStackedBlockAmount(block) > 1) { - e.setCancelled(true); + e.setCancelled(); break; } } } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onBlockChangeState(BlockFormEvent e) { - if (plugin.getStackedBlocks().getStackedBlockAmount(e.getBlock()) > 1) - e.setCancelled(true); + private void onBlockChangeState(GameEvent e) { + if (plugin.getStackedBlocks().getStackedBlockAmount(e.getArgs().block) > 1) + e.setCancelled(); } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) - public void onGolemCreate(CreatureSpawnEvent e) { - List entityTemplateOffsets = ENTITY_TEMPLATE_OFFSETS.get(e.getSpawnReason()); + private void onGolemCreate(GameEvent e) { + List entityTemplateOffsets = ENTITY_TEMPLATE_OFFSETS.get(e.getArgs().spawnReason); if (entityTemplateOffsets == null) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location entityLocation = e.getEntity().getLocation(wrapper.getHandle()); + Location entityLocation = e.getArgs().entity.getLocation(wrapper.getHandle()); if (plugin.getStackedBlocks().getStackedBlockAmount(entityLocation) > 1) { - e.setCancelled(true); + e.setCancelled(); return; } for (BlockOffset blockOffset : entityTemplateOffsets) { if (plugin.getStackedBlocks().getStackedBlockAmount(blockOffset.applyToLocation(entityLocation)) > 1) { - e.setCancelled(true); + e.setCancelled(); return; } } } } - private void registerPhysicsListener() { - if (plugin.getSettings().isPhysicsListener()) - Bukkit.getPluginManager().registerEvents(new PhysicsListener(), plugin); + private void onSpongeAbsorb(GameEvent e) { + if (plugin.getStackedBlocks().getStackedBlockAmount(e.getArgs().block) > 1) + e.setCancelled(); } - private void registerSpongeListener() { - try { - Class.forName("org.bukkit.event.block.SpongeAbsorbEvent"); - Bukkit.getPluginManager().registerEvents(new SpongeAbsorbListener(), plugin); - } catch (Throwable ignored) { - } + private void onStackedBlockPhysics(GameEvent e) { + if (plugin.getStackedBlocks().getStackedBlockAmount(e.getArgs().block) > 1) + e.setCancelled(); + } + + /* INTERNAL */ + + private void registerListeners() { + registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockPlace); + registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockBreak); + registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockInteract); + registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockBreakByEntity); + registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockExplode); + registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.LOWEST, this::onPistonExtend); + registerCallback(GameEventType.PISTON_RETRACT_EVENT, GameEventPriority.LOWEST, this::onPistonRetract); + registerCallback(GameEventType.BLOCK_FORM_EVENT, GameEventPriority.LOWEST, this::onBlockChangeState); + registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onGolemCreate); + registerCallback(GameEventType.BLOCK_PHYSICS_EVENT, GameEventPriority.LOWEST, this::onStackedBlockPhysics); + registerCallback(GameEventType.SPONGE_ABSORB_EVENT, GameEventPriority.LOWEST, this::onSpongeAbsorb); } private static Map> buildEntityTemplateOffsetsMap() { @@ -292,24 +318,4 @@ private static Map> buildEntit return Collections.unmodifiableMap(offsetsMap); } - private class PhysicsListener implements Listener { - - @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) - public void onStackedBlockPhysics(BlockPhysicsEvent e) { - if (plugin.getStackedBlocks().getStackedBlockAmount(e.getBlock()) > 1) - e.setCancelled(true); - } - - } - - private class SpongeAbsorbListener implements Listener { - - @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) - public void onSpongeAbsorb(org.bukkit.event.block.SpongeAbsorbEvent e) { - if (plugin.getStackedBlocks().getStackedBlockAmount(e.getBlock()) > 1) - e.setCancelled(true); - } - - } - } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java index 3aafa2de02..7b1c7bcd52 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java @@ -4,73 +4,64 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.Location; import org.bukkit.block.Block; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockFromToEvent; -import org.bukkit.event.block.BlockPistonExtendEvent; -import org.bukkit.event.block.BlockPistonRetractEvent; -import org.bukkit.event.block.BlockSpreadEvent; -import org.bukkit.event.world.StructureGrowEvent; import java.util.List; import java.util.function.Function; -public class WorldDestructionListener implements Listener { - - private final SuperiorSkyblockPlugin plugin; +public class WorldDestructionListener extends AbstractGameEventListener { public WorldDestructionListener(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); + registerListeners(); } //Checking for structures growing outside island. - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onStructureGrow(StructureGrowEvent e) { - Island island = plugin.getGrid().getIslandAt(e.getLocation()); - if (island != null && plugin.getGrid().isIslandsWorld(e.getLocation().getWorld())) { + private void onStructureGrow(GameEvent e) { + Location location = e.getArgs().location; + Island island = plugin.getGrid().getIslandAt(location); + if (island != null && plugin.getGrid().isIslandsWorld(location.getWorld())) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - e.getBlocks().removeIf(blockState -> + e.getArgs().blocks.removeIf(blockState -> !island.isInsideRange(blockState.getLocation(wrapper.getHandle()))); } } } //Checking for chorus flower spread outside island. - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - private void onBlockSpread(BlockSpreadEvent e) { + private void onBlockSpread(GameEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventDestruction(e.getSource().getLocation(wrapper.getHandle())) || - preventDestruction(e.getBlock().getLocation(wrapper.getHandle()))) - e.setCancelled(true); + if (preventDestruction(e.getArgs().source.getLocation(wrapper.getHandle())) || + preventDestruction(e.getArgs().block.getLocation(wrapper.getHandle()))) + e.setCancelled(); } } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPistonExtend(BlockPistonExtendEvent e) { + public void onPistonExtend(GameEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventMultiDestruction(e.getBlock().getLocation(wrapper.getHandle()), e.getBlocks(), null)) - e.setCancelled(true); + if (preventMultiDestruction(e.getArgs().block.getLocation(wrapper.getHandle()), e.getArgs().blocks, null)) + e.setCancelled(); } } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onPistonRetract(BlockPistonRetractEvent e) { + public void onPistonRetract(GameEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventMultiDestruction(e.getBlock().getLocation(wrapper.getHandle()), e.getBlocks(), - block -> block.getRelative(e.getDirection()))) - e.setCancelled(true); + if (preventMultiDestruction(e.getArgs().block.getLocation(wrapper.getHandle()), e.getArgs().blocks, + block -> block.getRelative(e.getArgs().direction))) + e.setCancelled(); } } - @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) - public void onBlockFlow(BlockFromToEvent e) { + private void onBlockFlow(GameEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location blockLocation = e.getBlock().getRelative(e.getFace()).getLocation(wrapper.getHandle()); + Location blockLocation = e.getArgs().toBlock.getLocation(wrapper.getHandle()); if (preventDestruction(blockLocation)) - e.setCancelled(true); + e.setCancelled(); } } @@ -100,4 +91,12 @@ private boolean preventMultiDestruction(Location islandLocation, List blo return false; } + private void registerListeners() { + registerCallback(GameEventType.STRUCTURE_GROW_EVENT, GameEventPriority.NORMAL, this::onStructureGrow); + registerCallback(GameEventType.BLOCK_SPREAD_EVENT, GameEventPriority.NORMAL, this::onBlockSpread); + registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.NORMAL, this::onPistonExtend); + registerCallback(GameEventType.PISTON_RETRACT_EVENT, GameEventPriority.NORMAL, this::onPistonRetract); + registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.NORMAL, this::onBlockFlow); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java index ffc3b284d2..dfc5fab977 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java @@ -13,8 +13,9 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.events.EventResult; -import com.bgsoftware.superiorskyblock.core.events.EventsBus; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.io.FileClassLoader; import com.bgsoftware.superiorskyblock.core.io.Files; import com.bgsoftware.superiorskyblock.core.io.JarFiles; @@ -304,7 +305,7 @@ public void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, commandRewards = new ArrayList<>(missionData.getCommandRewards()); } - EventResult event = plugin.getEventsBus().callMissionCompleteEvent( + PluginEvent event = PluginEventsFactory.callMissionCompleteEvent( superiorPlayer, missionsHolder, mission, itemRewards, commandRewards); if (event.isCancelled()) { @@ -323,7 +324,7 @@ public void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, if (result != null) result.accept(true); - for (ItemStack itemStack : event.getResult().getItemRewards()) { + for (ItemStack itemStack : event.getArgs().itemRewards) { ItemStack toGive = new ItemBuilder(itemStack) .replaceAll("{0}", mission.getName()) .replaceAll("{1}", superiorPlayer.getName()) @@ -338,7 +339,7 @@ public void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, } BukkitExecutor.ensureMain(() -> { - for (String command : event.getResult().getCommandRewards()) { + for (String command : event.getArgs().commandRewards) { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command .replace("%mission%", mission.getName()) .replace("%player%", superiorPlayer.getName()) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminAddGenerator.java b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminAddGenerator.java index 2c3b28db0a..31c557249d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminAddGenerator.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminAddGenerator.java @@ -10,7 +10,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -94,7 +96,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (dimension == null) return; - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { if (percentage) { @@ -107,24 +109,24 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab int generatorRate = island.getGeneratorAmount(material, dimension) + amount; if (generatorRate <= 0) { - if (!plugin.getEventsBus().callIslandRemoveGeneratorRateEvent(sender, island, material, dimension)) + if (!PluginEventsFactory.callIslandRemoveGeneratorRateEvent(island, sender, material, dimension)) continue; island.removeGeneratorAmount(material, dimension); } else { - EventResult eventResult = plugin.getEventsBus().callIslandChangeGeneratorRateEvent(sender, - island, material, dimension, island.getGeneratorAmount(material, dimension) + amount); + PluginEvent event = PluginEventsFactory.callIslandChangeGeneratorRateEvent( + island, sender, material, dimension, island.getGeneratorAmount(material, dimension) + amount); - if (eventResult.isCancelled()) + if (event.isCancelled()) continue; - island.setGeneratorAmount(material, eventResult.getResult(), dimension); + island.setGeneratorAmount(material, event.getArgs().generatorRate, dimension); } } - anyIslandChanged = true; + ++islandsChangedCount; } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; if (islands.size() != 1) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java index 098432df18..9ebbad8b1d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -67,18 +68,18 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (dimension == null) return; - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - if (!plugin.getEventsBus().callIslandClearGeneratorRatesEvent(sender, island, dimension)) + if (!PluginEventsFactory.callIslandClearGeneratorRatesEvent(island, sender, dimension)) continue; - anyIslandChanged = true; + ++islandsChangedCount; island.clearGeneratorAmounts(dimension); } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; if (islands.size() != 1) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminSetGenerator.java b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminSetGenerator.java index ec46291afd..570c7d86b4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminSetGenerator.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminSetGenerator.java @@ -10,7 +10,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -94,7 +96,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (dimension == null) return; - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { if (percentage) { @@ -104,24 +106,24 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab } } else { if (amount <= 0) { - if (!plugin.getEventsBus().callIslandRemoveGeneratorRateEvent(sender, island, material, dimension)) + if (!PluginEventsFactory.callIslandRemoveGeneratorRateEvent(island, sender, material, dimension)) continue; island.removeGeneratorAmount(material, dimension); } else { - EventResult eventResult = plugin.getEventsBus().callIslandChangeGeneratorRateEvent(sender, - island, material, dimension, amount); + PluginEvent event = PluginEventsFactory.callIslandChangeGeneratorRateEvent( + island, sender, material, dimension, amount); - if (eventResult.isCancelled()) + if (event.isCancelled()) continue; - island.setGeneratorAmount(material, eventResult.getResult(), dimension); + island.setGeneratorAmount(material, event.getArgs().generatorRate, dimension); } } - anyIslandChanged = true; + ++islandsChangedCount; } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; if (islands.size() != 1) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdAdminMission.java b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdAdminMission.java index e4ec512ebe..29a9b0e22c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdAdminMission.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdAdminMission.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; @@ -74,17 +75,17 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, Superio } else if (args[3].equalsIgnoreCase("reset")) { Island island = targetPlayer.getIsland(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Mission mission : missions) { IMissionsHolder missionsHolder = mission.getIslandMission() ? island : targetPlayer; - if (missionsHolder != null && plugin.getEventsBus().callMissionResetEvent(sender, missionsHolder, mission)) { - anyIslandChanged = true; + if (missionsHolder != null && PluginEventsFactory.callMissionResetEvent(sender, missionsHolder, mission)) { + ++islandsChangedCount; missionsHolder.resetMission(mission); } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; if (missions.size() == 1) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddCropGrowth.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddCropGrowth.java index 1148f21db3..ea8a1c1ebb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddCropGrowth.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddCropGrowth.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -69,20 +71,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab double multiplier = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeCropGrowthEvent(sender, - island, island.getCropGrowthMultiplier() + multiplier); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setCropGrowthMultiplier(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeCropGrowthEvent( + island, sender, island.getCropGrowthMultiplier() + multiplier); + if (!event.isCancelled()) { + island.setCropGrowthMultiplier(event.getArgs().cropGrowth); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_CROP_GROWTH_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_CROP_GROWTH_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddEffect.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddEffect.java index 326614c25d..047c40968b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddEffect.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddEffect.java @@ -8,7 +8,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -78,27 +80,29 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab int level = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { int newLevel = island.getPotionEffectLevel(effectType) + level; if (newLevel <= 0) { - if (plugin.getEventsBus().callIslandRemoveEffectEvent(sender, island, effectType)) { - anyIslandChanged = true; + if (PluginEventsFactory.callIslandRemoveEffectEvent(island, sender, effectType)) { + ++islandsChangedCount; island.removePotionEffect(effectType); } } else { - EventResult eventResult = plugin.getEventsBus().callIslandChangeEffectLevelEvent(sender, island, effectType, newLevel); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setPotionEffect(effectType, eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeEffectLevelEvent( + island, sender, effectType, newLevel); + if (!event.isCancelled()) { + island.setPotionEffect(effectType, event.getArgs().effectLevel); + ++islandsChangedCount; + } } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_ISLAND_EFFECT_LEVEL_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName())); else if (targetPlayer == null) Message.CHANGED_ISLAND_EFFECT_LEVEL_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName()), islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddMobDrops.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddMobDrops.java index 6b2e3ccd73..5ae843455e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddMobDrops.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddMobDrops.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -69,20 +71,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab double multiplier = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeMobDropsEvent(sender, - island, island.getMobDropsMultiplier() + multiplier); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setMobDropsMultiplier(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeMobDropsEvent( + island, sender, island.getMobDropsMultiplier() + multiplier); + if (!event.isCancelled()) { + island.setMobDropsMultiplier(event.getArgs().mobDrops); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_MOB_DROPS_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_MOB_DROPS_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddSpawnerRates.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddSpawnerRates.java index 76577bcc89..f2a76eef09 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddSpawnerRates.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddSpawnerRates.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -69,20 +71,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab double multiplier = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeSpawnerRatesEvent(sender, - island, island.getSpawnerRatesMultiplier() + multiplier); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setSpawnerRatesMultiplier(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeSpawnerRatesEvent( + island, sender, island.getSpawnerRatesMultiplier() + multiplier); + if (!event.isCancelled()) { + island.setSpawnerRatesMultiplier(event.getArgs().spawnerRates); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_SPAWNER_RATES_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_SPAWNER_RATES_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRankup.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRankup.java index 7a22b9702c..96682b8dd2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRankup.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRankup.java @@ -12,8 +12,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.LazyReference; -import com.bgsoftware.superiorskyblock.core.events.EventResult; -import com.bgsoftware.superiorskyblock.core.events.EventsBus; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; @@ -89,13 +90,13 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab UpgradeLevel currentLevel = island.getUpgradeLevel(upgrade); UpgradeLevel nextLevel = upgrade.getUpgradeLevel(currentLevel.getLevel() + 1); - EventResult event = plugin.getEventsBus().callIslandUpgradeEvent( - playerSender, island, upgrade, currentLevel, nextLevel, IslandUpgradeEvent.Cause.PLAYER_RANKUP); + PluginEvent event = PluginEventsFactory.callIslandUpgradeEvent( + island, playerSender, upgrade, currentLevel, nextLevel, IslandUpgradeEvent.Cause.PLAYER_RANKUP); if (!event.isCancelled()) { SuperiorPlayer owner = island.getOwner(); - for (String command : event.getResult().getCommands()) { + for (String command : event.getArgs().commands) { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), placeholdersService.get().parsePlaceholders(owner.asOfflinePlayer(), command .replace("%player%", owner.getName()) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetCropGrowth.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetCropGrowth.java index 58b260d292..03b3a6bd88 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetCropGrowth.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetCropGrowth.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -69,19 +71,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab double multiplier = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeCropGrowthEvent(sender, island, multiplier); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setCropGrowthMultiplier(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeCropGrowthEvent( + island, sender, multiplier); + if (!event.isCancelled()) { + island.setCropGrowthMultiplier(event.getArgs().cropGrowth); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_CROP_GROWTH_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_CROP_GROWTH_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetEffect.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetEffect.java index d9262e9f2d..6b6fd2041d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetEffect.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetEffect.java @@ -8,7 +8,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -78,26 +80,28 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab int level = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { if (level <= 0) { - if (plugin.getEventsBus().callIslandRemoveEffectEvent(sender, island, effectType)) { - anyIslandChanged = true; + if (PluginEventsFactory.callIslandRemoveEffectEvent(island, sender, effectType)) { + ++islandsChangedCount; island.removePotionEffect(effectType); } } else { - EventResult eventResult = plugin.getEventsBus().callIslandChangeEffectLevelEvent(sender, island, effectType, level); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setPotionEffect(effectType, eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeEffectLevelEvent( + island, sender, effectType, level); + if (!event.isCancelled()) { + island.setPotionEffect(effectType, event.getArgs().effectLevel); + ++islandsChangedCount; + } } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_ISLAND_EFFECT_LEVEL_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName())); else if (targetPlayer == null) Message.CHANGED_ISLAND_EFFECT_LEVEL_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(effectType.getName()), islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetMobDrops.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetMobDrops.java index 2534318d8e..7371ec20e5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetMobDrops.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetMobDrops.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -69,19 +71,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab double multiplier = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeMobDropsEvent(sender, island, multiplier); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setMobDropsMultiplier(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeMobDropsEvent( + island, sender, multiplier); + if (!event.isCancelled()) { + island.setMobDropsMultiplier(event.getArgs().mobDrops); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_MOB_DROPS_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_MOB_DROPS_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetSpawnerRates.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetSpawnerRates.java index 4609a34016..fbbc212f6e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetSpawnerRates.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetSpawnerRates.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -69,19 +71,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab double multiplier = arguments.getNumber(); - boolean anyIslandChanged = false; + int islandsChangedCount = 0; for (Island island : islands) { - EventResult eventResult = plugin.getEventsBus().callIslandChangeSpawnerRatesEvent(sender, island, multiplier); - anyIslandChanged |= !eventResult.isCancelled(); - if (!eventResult.isCancelled()) - island.setSpawnerRatesMultiplier(eventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeSpawnerRatesEvent( + island, sender, multiplier); + if (!event.isCancelled()) { + island.setSpawnerRatesMultiplier(event.getArgs().spawnerRates); + ++islandsChangedCount; + } } - if (!anyIslandChanged) + if (islandsChangedCount <= 0) return; - if (islands.size() > 1) + if (islandsChangedCount > 1) Message.CHANGED_SPAWNER_RATES_ALL.send(sender); else if (targetPlayer == null) Message.CHANGED_SPAWNER_RATES_NAME.send(sender, islands.get(0).getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetUpgrade.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetUpgrade.java index e0ee3523e1..9a5be76cea 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetUpgrade.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetUpgrade.java @@ -10,8 +10,9 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.events.EventResult; -import com.bgsoftware.superiorskyblock.core.events.EventsBus; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -84,10 +85,10 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; } - EventResult eventResult = plugin.getEventsBus().callIslandUpgradeEvent( - sender, island, upgrade, upgrade.getUpgradeLevel(level), IslandUpgradeEvent.Cause.ADMIN_SET_UPGRADE); + PluginEvent event = PluginEventsFactory.callIslandUpgradeEvent( + island, sender, upgrade, upgrade.getUpgradeLevel(level), IslandUpgradeEvent.Cause.ADMIN_SET_UPGRADE); - if (eventResult.isCancelled()) + if (event.isCancelled()) return; island.setUpgradeLevel(upgrade, level); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java index b5c310feab..f6b2b76937 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java @@ -15,8 +15,9 @@ import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.LazyReference; -import com.bgsoftware.superiorskyblock.core.events.EventResult; -import com.bgsoftware.superiorskyblock.core.events.EventsBus; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -115,10 +116,10 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer Message.CUSTOM.send(superiorPlayer, requiredCheckFailure, false); hasNextLevel = false; } else { - EventResult event = plugin.getEventsBus().callIslandUpgradeEvent( - superiorPlayer, island, upgrade, currentLevel, nextLevel, IslandUpgradeEvent.Cause.PLAYER_RANKUP); + PluginEvent event = PluginEventsFactory.callIslandUpgradeEvent( + island, superiorPlayer, upgrade, currentLevel, nextLevel, IslandUpgradeEvent.Cause.PLAYER_RANKUP); - UpgradeCost upgradeCost = event.getResult().getUpgradeCost(); + UpgradeCost upgradeCost = event.getArgs().upgradeCost; if (event.isCancelled()) { hasNextLevel = false; @@ -130,7 +131,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer } else { upgradeCost.withdrawCost(superiorPlayer); - for (String command : event.getResult().getCommands()) { + for (String command : event.getArgs().commands) { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), placeholdersService.get().parsePlaceholders(superiorPlayer.asOfflinePlayer(), command .replace("%player%", superiorPlayer.getName()) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/IPlatform.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/IPlatform.java new file mode 100644 index 0000000000..f69d340324 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/IPlatform.java @@ -0,0 +1,11 @@ +package com.bgsoftware.superiorskyblock.platform; + +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs; + +public interface IPlatform { + + void notifyGameEvent(GameEvent gameEvent, GameEventPriority priority); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEvent.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEvent.java new file mode 100644 index 0000000000..919cd34a11 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEvent.java @@ -0,0 +1,36 @@ +package com.bgsoftware.superiorskyblock.platform.event; + +import com.bgsoftware.superiorskyblock.core.events.IEvent; +import com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs; + +public class GameEvent implements IEvent> { + + private final GameEventType type; + private final Args args; + + private boolean cancelled = false; + + public GameEvent(GameEventType type, Args args) { + this.type = type; + this.args = args; + } + + @Override + public GameEventType getType() { + return type; + } + + @Override + public boolean isCancelled() { + return this.cancelled; + } + + public Args getArgs() { + return args; + } + + public void setCancelled() { + this.cancelled = true; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventCallback.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventCallback.java new file mode 100644 index 0000000000..0b70acf311 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventCallback.java @@ -0,0 +1,10 @@ +package com.bgsoftware.superiorskyblock.platform.event; + +import com.bgsoftware.superiorskyblock.core.events.EventCallback; +import com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs; + +public interface GameEventCallback extends EventCallback> { + + void execute(GameEvent gameEvent); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventPriority.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventPriority.java new file mode 100644 index 0000000000..734fefc651 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventPriority.java @@ -0,0 +1,12 @@ +package com.bgsoftware.superiorskyblock.platform.event; + +public enum GameEventPriority { + + LOWEST, + LOW, + NORMAL, + HIGH, + HIGHEST, + MONITOR + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java new file mode 100644 index 0000000000..e63fcfda64 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java @@ -0,0 +1,96 @@ +package com.bgsoftware.superiorskyblock.platform.event; + +import com.bgsoftware.superiorskyblock.core.events.EventType; +import com.bgsoftware.superiorskyblock.platform.event.args.IEventArgs; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.*; + +public class GameEventType extends EventType> { + + private static final List> ALL_TYPES = new LinkedList<>(); + + public static final GameEventType PLAYER_JOIN_EVENT = register(PlayerJoinEvent.class); + public static final GameEventType PLAYER_QUIT_EVENT = register(PlayerQuitEvent.class); + public static final GameEventType BLOCK_PLACE_EVENT = register(BlockPlaceEvent.class); + public static final GameEventType PLAYER_EMPTY_BUCKET_EVENT = register(PlayerEmptyBucketEvent.class); + public static final GameEventType PLAYER_FILL_BUCKET_EVENT = register(PlayerFillBucketEvent.class); + public static final GameEventType STRUCTURE_GROW_EVENT = register(StructureGrowEvent.class); + public static final GameEventType BLOCK_GROW_EVENT = register(BlockGrowEvent.class); + public static final GameEventType BLOCK_FORM_EVENT = register(BlockFormEvent.class); + public static final GameEventType BLOCK_SPREAD_EVENT = register(BlockSpreadEvent.class); + public static final GameEventType PLAYER_INTERACT_EVENT = register(PlayerInteractEvent.class); + public static final GameEventType ENTITY_CHANGE_BLOCK_EVENT = register(EntityChangeBlockEvent.class); + public static final GameEventType BLOCK_BREAK_EVENT = register(BlockBreakEvent.class); + public static final GameEventType BLOCK_DESTROY_EVENT = register(BlockDestroyEvent.class); + public static final GameEventType ENTITY_DEATH_EVENT = register(EntityDeathEvent.class); + public static final GameEventType PISTON_EXTEND_EVENT = register(PistonExtendEvent.class); + public static final GameEventType PISTON_RETRACT_EVENT = register(PistonRetractEvent.class); + public static final GameEventType LEAVES_DECAY_EVENT = register(LeavesDecayEvent.class); + public static final GameEventType BLOCK_FROM_TO_EVENT = register(BlockFromToEvent.class); + public static final GameEventType ENTITY_EXPLODE_EVENT = register(EntityExplodeEvent.class); + public static final GameEventType PROJECTILE_HIT_EVENT = register(ProjectileHitEvent.class); + public static final GameEventType PROJECTILE_LAUNCH_EVENT = register(ProjectileLaunchEvent.class); + public static final GameEventType SPONGE_ABSORB_EVENT = register(SpongeAbsorbEvent.class); + public static final GameEventType CHUNK_LOAD_EVENT = register(ChunkLoadEvent.class); + public static final GameEventType CHUNK_UNLOAD_EVENT = register(ChunkUnloadEvent.class); + public static final GameEventType WORLD_UNLOAD_EVENT = register(WorldUnloadEvent.class); + public static final GameEventType ENTITY_SPAWN_EVENT = register(EntitySpawnEvent.class); + public static final GameEventType ATTEMPT_ENTITY_SPAWN_EVENT = register(AttemptEntitySpawnEvent.class); + public static final GameEventType PLAYER_COMMAND_EVENT = register(PlayerCommandEvent.class); + public static final GameEventType HANGING_BREAK_EVENT = register(HangingBreakEvent.class); + public static final GameEventType ENTITY_DAMAGE_EVENT = register(EntityDamageEvent.class); + public static final GameEventType BLOCK_BURN_EVENT = register(BlockBurnEvent.class); + public static final GameEventType BLOCK_IGNITE_EVENT = register(BlockIgniteEvent.class); + public static final GameEventType ENTITY_RIDE_EVENT = register(EntityRideEvent.class); + public static final GameEventType ENTITY_MOVE_EVENT = register(EntityMoveEvent.class); + public static final GameEventType ENTITY_TELEPORT_EVENT = register(EntityTeleportEvent.class); + public static final GameEventType BLOCK_REDSTONE_EVENT = register(BlockRedstoneEvent.class); + public static final GameEventType INVENTORY_CLICK_EVENT = register(InventoryClickEvent.class); + public static final GameEventType INVENTORY_CLOSE_EVENT = register(InventoryCloseEvent.class); + public static final GameEventType INVENTORY_OPEN_EVENT = register(InventoryOpenEvent.class); + public static final GameEventType PLAYER_LOGIN_EVENT = register(PlayerLoginEvent.class); + public static final GameEventType PLAYER_GAMEMODE_CHANGE = register(PlayerGamemodeChangeEvent.class); + public static final GameEventType PLAYER_CHANGED_WORLD_EVENT = register(PlayerChangedWorldEvent.class); + public static final GameEventType PLAYER_RESPAWN_EVENT = register(PlayerRespawnEvent.class); + public static final GameEventType PLAYER_CHAT_EVENT = register(PlayerChatEvent.class); + public static final GameEventType ENTITY_PORTAL_EVENT = register(EntityPortalEvent.class); + public static final GameEventType ENTITY_ENTER_PORTAL_EVENT = register(EntityEnterPortalEvent.class); + public static final GameEventType ENTITY_BLOCK_FORM_EVENT = register(EntityBlockFormEvent.class); + public static final GameEventType BLOCK_DISPENSE_EVENT = register(BlockDispenseEvent.class); + public static final GameEventType PLAYER_ITEM_CONSUME_EVENT = register(PlayerItemConsumeEvent.class); + public static final GameEventType PLAYER_SHEAR_ENTITY_EVENT = register(PlayerShearEntityEvent.class); + public static final GameEventType HANGING_PLACE_EVENT = register(HangingPlaceEvent.class); + public static final GameEventType ENTITY_TARGET_EVENT = register(EntityTargetEvent.class); + public static final GameEventType PLAYER_LEASH_ENTITY_EVENT = register(PlayerLeashEntityEvent.class); + public static final GameEventType PLAYER_UNLEASH_ENTITY_EVENT = register(PlayerUnleashEntityEvent.class); + public static final GameEventType ENTITY_COLLISION_EVENT = register(EntityCollisionEvent.class); + public static final GameEventType PLAYER_DROP_ITEM_EVENT = register(PlayerDropItemEvent.class); + public static final GameEventType PLAYER_PICKUP_ITEM_EVENT = register(PlayerPickupItemEvent.class); + public static final GameEventType PLAYER_PICKUP_ARROW_EVENT = register(PlayerPickupArrowEvent.class); + public static final GameEventType RAID_TRIGGER_EVENT = register(RaidTriggerEvent.class); + public static final GameEventType SIGN_CHANGE_EVENT = register(SignChangeEvent.class); + public static final GameEventType BLOCK_PHYSICS_EVENT = register(BlockPhysicsEvent.class); + + private GameEventType() { + } + + public GameEvent createEvent(Args args) { + return new GameEvent<>(this, args); + } + + private static GameEventType register(Class eventArgsType) { + GameEventType eventType = new GameEventType<>(); + ALL_TYPES.add(eventType); + return eventType; + } + + public static Collection> values() { + return Collections.unmodifiableList(ALL_TYPES); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventsDispatcher.java new file mode 100644 index 0000000000..a3149a6947 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventsDispatcher.java @@ -0,0 +1,17 @@ +package com.bgsoftware.superiorskyblock.platform.event; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.core.events.EventsDispatcher; +import com.bgsoftware.superiorskyblock.listener.AbstractGameEventListener; + +public class GameEventsDispatcher extends EventsDispatcher< + AbstractGameEventListener, + GameEventType, + GameEventPriority, + GameEvent> { + + public GameEventsDispatcher(SuperiorSkyblockPlugin plugin) { + super(plugin, GameEventPriority.class, GameEventType.values()); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java new file mode 100644 index 0000000000..bccbc1e688 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java @@ -0,0 +1,445 @@ +package com.bgsoftware.superiorskyblock.platform.event.args; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.PlayerHand; +import org.bukkit.Chunk; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.entity.Vehicle; +import org.bukkit.event.block.Action; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.player.PlayerTeleportEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +import java.util.List; + +public class GameEventArgs implements IEventArgs { + + private GameEventArgs() { + + } + + public static class AttemptEntitySpawnEvent extends GameEventArgs { + + public EntityType entityType; + public Location spawnLocation; + public CreatureSpawnEvent.SpawnReason spawnReason; + + } + + public static class BlockFromToEvent extends BlockEvent { + + public Block toBlock; + + } + + public static class BlockIgniteEvent extends BlockEvent { + + public org.bukkit.event.block.BlockIgniteEvent.IgniteCause igniteCause; + + } + + public static class PistonExtendEvent extends PistonEvent { + + } + + public static class PistonRetractEvent extends PistonEvent { + + } + + public static class BlockPlaceEvent extends BlockEvent { + + public Player player; + public Block againstBlock; + public BlockState replacedState; + public PlayerHand usedHand; + public ItemStack usedItem; + + } + + public static class ChunkLoadEvent extends ChunkEvent { + + public boolean isNewChunk; + + } + + public static class EntityChangeBlockEvent extends EntityEvent { + + public Block block; + public Key newType; + + } + + public static class EntityDamageEvent extends EntityEvent { + + public org.bukkit.event.entity.EntityDamageEvent.DamageCause damageCause; + @Nullable + public Entity damager; + + } + + public static class EntityMoveEvent extends EntityEvent { + + public Location from; + public Location to; + + } + + public static class EntityRideEvent extends EntityEvent { + + public Vehicle vehicle; + + } + + public static class HangingBreakEvent extends EntityEvent { + + public Entity remover; + public org.bukkit.event.hanging.HangingBreakEvent.RemoveCause removeCause; + + } + + public static class HangingPlaceEvent extends EntitySpawnEvent { + + public Player player; + + } + + public static class EntityTargetEvent extends EntityEvent { + + public Entity target; + + } + + public static class InventoryClickEvent extends GameEventArgs { + + public org.bukkit.event.inventory.InventoryClickEvent bukkitEvent; + + } + + public static class PlayerChangedWorldEvent extends PlayerEvent { + + public World from; + + } + + public static class PlayerChatEvent extends PlayerEvent { + + public String message; + @Nullable + public String format; + + } + + public static class PlayerCommandEvent extends PlayerEvent { + + public String command; + + } + + public static class PlayerGamemodeChangeEvent extends PlayerEvent { + + public GameMode newGamemode; + + } + + public static class PlayerInteractEvent extends PlayerEvent { + + public Action action; + @Nullable + public PlayerHand usedHand; + @Nullable + public ItemStack usedItem; + @Nullable + public Block clickedBlock; + @Nullable + public Entity clickedEntity; + + } + + public static class PlayerRespawnEvent extends PlayerEvent { + + public org.bukkit.event.player.PlayerRespawnEvent bukkitEvent; + + } + + public static class SpongeAbsorbEvent extends BlockEvent { + + public List blocks; + + } + + public static class StructureGrowEvent extends WorldEvent { + + public Location location; + public List blocks; + + } + + public static class PlayerJoinEvent extends PlayerEvent { + + } + + public static class PlayerQuitEvent extends PlayerEvent { + + } + + public static class PlayerEmptyBucketEvent extends PlayerBucketEvent { + + } + + public static class PlayerFillBucketEvent extends PlayerBucketEvent { + + } + + public static class BlockGrowEvent extends BlockTransformEvent { + + } + + public static class BlockFormEvent extends BlockTransformEvent { + + } + + public static class BlockSpreadEvent extends BlockTransformEvent { + + public Block source; + + } + + public static class BlockBreakEvent extends BlockEvent { + + public Player player; + + } + + public static class BlockDestroyEvent extends BlockEvent { + + } + + public static class EntityDeathEvent extends EntityEvent { + + } + + public static class LeavesDecayEvent extends BlockEvent { + + } + + public static class EntityExplodeEvent extends EntityEvent { + + public List blocks; + + } + + public static class ProjectileHitEvent extends EntityEvent { + + @Nullable + public Block hitBlock; + @Nullable + public Entity hitEntity; + + } + + public static class ProjectileLaunchEvent extends EntityEvent { + + } + + public static class ChunkUnloadEvent extends ChunkEvent { + + } + + public static class WorldUnloadEvent extends WorldEvent { + + } + + public static class EntitySpawnEvent extends EntityEvent { + + public CreatureSpawnEvent.SpawnReason spawnReason; + + } + + public static class BlockBurnEvent extends BlockEvent { + + } + + public static class EntityTeleportEvent extends EntityMoveEvent { + + public PlayerTeleportEvent.TeleportCause cause; + + } + + public static class BlockRedstoneEvent extends BlockEvent { + + } + + public static class InventoryCloseEvent extends GameEventArgs { + + public org.bukkit.event.inventory.InventoryCloseEvent bukkitEvent; + + } + + public static class InventoryOpenEvent extends GameEventArgs { + + public org.bukkit.event.inventory.InventoryOpenEvent bukkitEvent; + + } + + public static class PlayerLoginEvent extends PlayerEvent { + + } + + public static class EntityPortalEvent extends EntityTeleportEvent { + + } + + public static class EntityEnterPortalEvent extends EntityEvent { + + public Location portalLocation; + + } + + public static class EntityBlockFormEvent extends BlockFormEvent { + + public Entity entity; + + } + + + public static class BlockDispenseEvent extends BlockEvent { + + public ItemStack dispensedItem; + public Vector velocity; + + } + + + public static class PlayerItemConsumeEvent extends PlayerEvent { + + public ItemStack consumedItem; + + } + + + public static class PlayerShearEntityEvent extends PlayerEvent { + + public Entity entity; + + } + + + public static class PlayerLeashEntityEvent extends PlayerEvent { + + public Entity entity; + + } + + + public static class PlayerUnleashEntityEvent extends PlayerEvent { + + public Entity entity; + + } + + + public static class EntityCollisionEvent extends EntityEvent { + + public Entity target; + + } + + + public static class PlayerDropItemEvent extends PlayerEvent { + + public Item droppedItem; + + } + + + public static class PlayerPickupItemEvent extends PlayerEvent { + + public Item pickedUpItem; + + } + + public static class PlayerPickupArrowEvent extends PlayerPickupItemEvent { + + } + + public static class RaidTriggerEvent extends WorldEvent { + + public Player player; + public Location raidLocation; + + } + + public static class SignChangeEvent extends BlockEvent { + + public Player player; + public String[] lines; + + } + + public static class BlockPhysicsEvent extends BlockEvent { + + } + + private static class BlockEvent extends GameEventArgs { + + public Block block; + + } + + private static class PistonEvent extends BlockEvent { + + public List blocks; + public BlockFace direction; + + } + + private static class ChunkEvent extends GameEventArgs { + + public Chunk chunk; + + } + + private static class EntityEvent extends GameEventArgs { + + public Entity entity; + + } + + private static class PlayerEvent extends GameEventArgs { + + public Player player; + + } + + private static class WorldEvent extends GameEventArgs { + + public World world; + + } + + private static class BlockTransformEvent extends BlockEvent { + + public BlockState newState; + + } + + private static class PlayerBucketEvent extends PlayerEvent { + + public Material bucket; + public Block clickedBlock; + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/IEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/IEventArgs.java new file mode 100644 index 0000000000..99f6b15623 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/IEventArgs.java @@ -0,0 +1,4 @@ +package com.bgsoftware.superiorskyblock.platform.event.args; + +public interface IEventArgs { +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/PlayersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/player/PlayersManagerImpl.java index 4cd327df03..341bf43a24 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/PlayersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/PlayersManagerImpl.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; @@ -168,7 +169,7 @@ public void replacePlayers(SuperiorPlayer originPlayer, @Nullable SuperiorPlayer PlayersDatabaseBridge.deletePlayer(originPlayer); } else { newPlayer.merge(originPlayer); - plugin.getEventsBus().callPlayerReplaceEvent(originPlayer, newPlayer); + PluginEventsFactory.callPlayerReplaceEvent(originPlayer, newPlayer); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java index 15b76c4bd1..ad9105510b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java @@ -16,8 +16,9 @@ import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; -import com.bgsoftware.superiorskyblock.core.events.EventResult; -import com.bgsoftware.superiorskyblock.core.events.EventsBus; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer; @@ -186,16 +187,16 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island boolean ignoreInvalidSchematic; if (superiorPlayer != null) { - EventResult eventResult = plugin.getEventsBus().callIslandEnterPortalEvent( - superiorPlayer, island, portalType, originalDestination, schematicGenerated ? null : originalSchematic, + PluginEvent event = PluginEventsFactory.callIslandEnterPortalEvent( + island, superiorPlayer, portalType, originalDestination, schematicGenerated ? null : originalSchematic, schematicGenerated); - if (eventResult.isCancelled()) + if (event.isCancelled()) return EntityPortalResult.PORTAL_EVENT_CANCELLED; - destination = eventResult.getResult().getDestination(); - schematic = eventResult.getResult().getSchematic(); - ignoreInvalidSchematic = eventResult.getResult().isIgnoreInvalidSchematic(); + destination = event.getArgs().destination; + schematic = event.getArgs().schematic; + ignoreInvalidSchematic = event.getArgs().ignoreInvalidSchematic; } else { destination = originalDestination; schematic = schematicGenerated ? null : originalSchematic; @@ -248,17 +249,17 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island if (destinationConfig != null && destinationConfig.isSchematicOffset()) { { BigDecimal schematicWorth = island.getRawWorth().subtract(originalWorth); - EventResult bonusEventResult = plugin.getEventsBus().callIslandChangeWorthBonusEvent(null, island, - IslandChangeWorthBonusEvent.Reason.SCHEMATIC, island.getBonusWorth().subtract(schematicWorth)); - if (!bonusEventResult.isCancelled()) - island.setBonusWorth(bonusEventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeWorthBonusEvent( + island, (SuperiorPlayer) null, IslandChangeWorthBonusEvent.Reason.SCHEMATIC, island.getBonusWorth().subtract(schematicWorth)); + if (!event.isCancelled()) + island.setBonusWorth(event.getArgs().worthBonus); } { BigDecimal schematicLevel = island.getRawLevel().subtract(originalLevel); - EventResult bonusEventResult = plugin.getEventsBus().callIslandChangeLevelBonusEvent(null, island, - IslandChangeLevelBonusEvent.Reason.SCHEMATIC, island.getBonusLevel().subtract(schematicLevel)); - if (!bonusEventResult.isCancelled()) - island.setBonusLevel(bonusEventResult.getResult()); + PluginEvent event = PluginEventsFactory.callIslandChangeLevelBonusEvent( + island, (SuperiorPlayer) null, IslandChangeLevelBonusEvent.Reason.SCHEMATIC, island.getBonusLevel().subtract(schematicLevel)); + if (!event.isCancelled()) + island.setBonusLevel(event.getArgs().levelBonus); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index e391b7eb01..ec13a96c7e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -20,7 +20,9 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; -import com.bgsoftware.superiorskyblock.core.events.CallbacksBus; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; @@ -98,8 +100,8 @@ public RegionManagerServiceImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } - public static void registerCallbacks(CallbacksBus bus) { - bus.registerCallback(CallbacksBus.CallbackType.SETTINGS_UPDATE, RegionManagerServiceImpl::onSettingsUpdate); + public static void registerCallbacks(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, RegionManagerServiceImpl::onSettingsUpdate); } private static void onSettingsUpdate() { @@ -618,14 +620,14 @@ private MoveResult handlePlayerEnterIslandInternal(SuperiorPlayer superiorPlayer // Checking if the player is banned from the island. if (toIsland.isBanned(superiorPlayer) && !superiorPlayer.hasBypassModeEnabled() && !superiorPlayer.hasPermissionWithoutOP("superior.admin.ban.bypass")) { - plugin.getEventsBus().callIslandRestrictMoveEvent(superiorPlayer, IslandRestrictMoveEvent.RestrictReason.BANNED_FROM_ISLAND); + PluginEventsFactory.callIslandRestrictMoveEvent(toIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.BANNED_FROM_ISLAND); Message.BANNED_FROM_ISLAND.send(superiorPlayer); return MoveResult.BANNED_FROM_ISLAND; } // Checking if the player is locked to visitors. if (toIsland.isLocked() && !toIsland.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS)) { - plugin.getEventsBus().callIslandRestrictMoveEvent(superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LOCKED_ISLAND); + PluginEventsFactory.callIslandRestrictMoveEvent(toIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LOCKED_ISLAND); Message.NO_CLOSE_BYPASS.send(superiorPlayer); return MoveResult.ISLAND_LOCKED; } @@ -637,8 +639,8 @@ private MoveResult handlePlayerEnterIslandInternal(SuperiorPlayer superiorPlayer boolean fromInsideRange = from != null && fromIsland != null && fromIsland.isInsideRange(from); boolean equalWorlds = from != null && to.getWorld().equals(from.getWorld()); - if (toInsideRange && (!equalIslands || !fromInsideRange) && !plugin.getEventsBus().callIslandEnterProtectedEvent(superiorPlayer, toIsland, enterCause)) { - plugin.getEventsBus().callIslandRestrictMoveEvent(superiorPlayer, IslandRestrictMoveEvent.RestrictReason.ENTER_PROTECTED_EVENT_CANCELLED); + if (toInsideRange && (!equalIslands || !fromInsideRange) && !PluginEventsFactory.callIslandEnterProtectedEvent(toIsland, superiorPlayer, enterCause)) { + PluginEventsFactory.callIslandRestrictMoveEvent(toIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.ENTER_PROTECTED_EVENT_CANCELLED); return MoveResult.ENTER_EVENT_CANCELLED; } @@ -654,8 +656,8 @@ private MoveResult handlePlayerEnterIslandInternal(SuperiorPlayer superiorPlayer return MoveResult.SUCCESS; } - if (!plugin.getEventsBus().callIslandEnterEvent(superiorPlayer, toIsland, enterCause)) { - plugin.getEventsBus().callIslandRestrictMoveEvent(superiorPlayer, IslandRestrictMoveEvent.RestrictReason.ENTER_EVENT_CANCELLED); + if (!PluginEventsFactory.callIslandEnterEvent(toIsland, superiorPlayer, enterCause)) { + PluginEventsFactory.callIslandRestrictMoveEvent(toIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.ENTER_EVENT_CANCELLED); return MoveResult.ENTER_EVENT_CANCELLED; } @@ -723,15 +725,15 @@ private MoveResult handlePlayerLeaveIslandInternal(SuperiorPlayer superiorPlayer //Checking for the stop leaving feature. if (plugin.getSettings().isStopLeaving() && fromInsideRange && !toInsideRange && !superiorPlayer.hasBypassModeEnabled() && !fromIsland.isSpawn() && equalWorlds) { - plugin.getEventsBus().callIslandRestrictMoveEvent(superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LEAVE_ISLAND_TO_OUTSIDE); + PluginEventsFactory.callIslandRestrictMoveEvent(fromIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LEAVE_ISLAND_TO_OUTSIDE); superiorPlayer.setPlayerStatus(PlayerStatus.LEAVING_ISLAND); return MoveResult.LEAVE_ISLAND_TO_OUTSIDE; } // Handling the leave protected event if (fromInsideRange && (!equalIslands || !toInsideRange)) { - if (!plugin.getEventsBus().callIslandLeaveProtectedEvent(superiorPlayer, fromIsland, leaveCause, to)) { - plugin.getEventsBus().callIslandRestrictMoveEvent(superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LEAVE_PROTECTED_EVENT_CANCELLED); + if (!PluginEventsFactory.callIslandLeaveProtectedEvent(fromIsland, superiorPlayer, leaveCause, to)) { + PluginEventsFactory.callIslandRestrictMoveEvent(fromIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LEAVE_PROTECTED_EVENT_CANCELLED); return MoveResult.ENTER_EVENT_CANCELLED; } } @@ -739,8 +741,8 @@ private MoveResult handlePlayerLeaveIslandInternal(SuperiorPlayer superiorPlayer if (equalIslands) return MoveResult.SUCCESS; - if (!plugin.getEventsBus().callIslandLeaveEvent(superiorPlayer, fromIsland, leaveCause, to)) { - plugin.getEventsBus().callIslandRestrictMoveEvent(superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LEAVE_EVENT_CANCELLED); + if (!PluginEventsFactory.callIslandLeaveEvent(fromIsland, superiorPlayer, leaveCause, to)) { + PluginEventsFactory.callIslandRestrictMoveEvent(fromIsland, superiorPlayer, IslandRestrictMoveEvent.RestrictReason.LEAVE_EVENT_CANCELLED); return MoveResult.ENTER_EVENT_CANCELLED; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java index c7effd5df3..0b0caf03f3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java @@ -17,10 +17,11 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.service.IService; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.superiorskyblock.world.BukkitItems; @@ -129,7 +130,7 @@ public InteractionResult handleStackedBlockBreak(Block block, @Nullable Superior int leftAmount = blockAmount - amountToBreak; - if (!plugin.getEventsBus().callBlockUnstackEvent(block, onlinePlayer, blockAmount, leftAmount)) + if (!PluginEventsFactory.callBlockUnstackEvent(block, onlinePlayer, blockAmount, leftAmount)) return InteractionResult.EVENT_CANCELLED; if (!plugin.getStackedBlocks().setStackedBlock(block, leftAmount)) @@ -249,7 +250,7 @@ private InteractionResult handleBlockStackInternal(SuperiorPlayer superiorPlayer int newStackedBlockAmount = blockAmount + amountToDeposit; - if (onlinePlayer != null && !plugin.getEventsBus().callBlockStackEvent(stackedBlock, onlinePlayer, blockAmount, newStackedBlockAmount)) + if (onlinePlayer != null && !PluginEventsFactory.callBlockStackEvent(stackedBlock, onlinePlayer, blockAmount, newStackedBlockAmount)) return InteractionResult.EVENT_CANCELLED; if (!plugin.getStackedBlocks().setStackedBlock(stackedBlockLocation, blockKey, newStackedBlockAmount)) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitItems.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitItems.java index 70e103eb9c..bf232f2a45 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitItems.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitItems.java @@ -52,6 +52,7 @@ public static void removeHandItem(Player onlinePlayer, PlayerHand usedHand, int } } + @Nullable public static PlayerHand getHand(Event event) { ReflectMethod reflectMethod; @@ -67,15 +68,18 @@ public static PlayerHand getHand(Event event) { EquipmentSlot equipmentSlot = reflectMethod.isValid() ? reflectMethod.invoke(event) : EquipmentSlot.HAND; - return PlayerHand.of(equipmentSlot); + return equipmentSlot == null ? null : PlayerHand.of(equipmentSlot); } - public static ItemStack getHandItem(Player onlinePlayer, PlayerHand usedHand) { - if (usedHand == PlayerHand.OFF_HAND) { + @Nullable + public static ItemStack getHandItem(Player onlinePlayer, @Nullable PlayerHand usedHand) { + if (usedHand == null) { + return null; + } else if (usedHand == PlayerHand.OFF_HAND) { return GET_ITEM_IN_OFF_HAND.invoke(onlinePlayer.getInventory()); + } else { + return onlinePlayer.getItemInHand(); } - - return onlinePlayer.getItemInHand(); } public static void setHandItem(Player player, PlayerHand playerHand, @Nullable ItemStack itemStack) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java index 8a46f5ea50..7a3ed6f02a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java @@ -7,10 +7,13 @@ import com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.events.EventResult; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; @@ -234,13 +237,14 @@ private static Location adjustLocationToHome(Island island, Block block, float y Location location = block.getLocation(wrapper.getHandle()).add(0.5, 0, 0.5); location.setYaw(yaw); location.setPitch(pitch); - EventResult eventResult = plugin.getEventsBus().callIslandSetHomeEvent(island, location, - IslandSetHomeEvent.Reason.SAFE_HOME, null); - if (eventResult.isCancelled()) { + PluginEvent event = PluginEventsFactory.callIslandSetHomeEvent( + island, (SuperiorPlayer) null, location, IslandSetHomeEvent.Reason.SAFE_HOME); + + if (event.isCancelled()) { newHomeLocation = location; } else { - newHomeLocation = eventResult.getResult(); + newHomeLocation = event.getArgs().islandHome; island.setIslandHome(newHomeLocation); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java index e9867981f3..3ff4c4989a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.VarintArray; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; @@ -301,7 +302,7 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long island.handleBlocksPlace(cachedCounts); - plugin.getEventsBus().callIslandSchematicPasteEvent(island, name, location); + PluginEventsFactory.callIslandSchematicPasteEvent(island, null, name, location); Profiler.end(profiler); From ac2eadd7e16903ba96be30e391481e3e4f07ccf1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 7 Mar 2025 23:51:05 +0200 Subject: [PATCH 089/600] Fixed cancelling game events when not necessary (#2365) --- .../superiorskyblock/listener/BukkitEventsListener.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index 151b156f5d..f93c288c3a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -795,11 +795,15 @@ private void createEventListenerForPr if (gameEvent == null) return; - if (event instanceof Cancellable && ((Cancellable) event).isCancelled()) + boolean cancelledBeforeDispatch = false; + + if (event instanceof Cancellable && ((Cancellable) event).isCancelled()) { gameEvent.setCancelled(); + cancelledBeforeDispatch = true; + } plugin.getGameEventsDispatcher().onGameEvent(gameEvent, gameEventPriority); - if (gameEvent.isCancelled()) { + if (!cancelledBeforeDispatch && gameEvent.isCancelled()) { if (event instanceof Cancellable) ((Cancellable) event).setCancelled(true); } From 56033d0da782867a2328cc4bec7b193100627973 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 7 Mar 2025 23:59:35 +0200 Subject: [PATCH 090/600] Fixed taking fall damage when using teleport commands (#2371) --- .../bgsoftware/superiorskyblock/player/SSuperiorPlayer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index 4977407b91..3951f5ce5a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -444,7 +444,8 @@ public void teleport(Island island, Dimension dimension, @Nullable Consumer { boolean successful = error == null && result; - BukkitExecutor.sync(() -> removePlayerStatus(PlayerStatus.FALL_DAMAGE_IMMUNED), 40L); + player.setFallDistance(0f); + removePlayerStatus(PlayerStatus.FALL_DAMAGE_IMMUNED); if (teleportResult != null) teleportResult.accept(successful); From bd82ebcf11c894739001f6828943199da41b0b43 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 8 Mar 2025 00:29:34 +0200 Subject: [PATCH 091/600] Fixed UAF on ChunkPosition in some cases (#2336) --- .../com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/core/ChunkPosition.java | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java index 0b680d88f6..5f0f117e70 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java @@ -103,7 +103,7 @@ private static void runActionOnChunksInternal(Collection chunksCo if (chunk != null) { loadedChunks.add(chunk); } else { - unloadedChunks.add(chunkPosition); + unloadedChunks.add(chunkPosition.copy()); } }); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java index 82fb296da3..10104ccf75 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java @@ -108,7 +108,7 @@ private static void runActionOnChunksInternal(Collection chunksCo if (chunkAccess instanceof Chunk) { loadedChunks.add((Chunk) chunkAccess); } else { - unloadedChunks.add(chunkPosition); + unloadedChunks.add(chunkPosition.copy()); } }); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java index fe523413f7..24e8947f33 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java @@ -128,7 +128,7 @@ private static void runActionOnChunksInternal(Collection chunksCo if (chunkAccess instanceof LevelChunk levelChunk) { loadedChunks.add(levelChunk); } else { - unloadedChunks.add(chunkPosition); + unloadedChunks.add(chunkPosition.copy()); } }); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java index 0f8166d25c..0d979ab932 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java @@ -132,7 +132,7 @@ private static void runActionOnChunksInternal(Collection chunksCo if (chunkAccess instanceof LevelChunk levelChunk) { loadedChunks.add(levelChunk); } else { - unloadedChunks.add(chunkPosition); + unloadedChunks.add(chunkPosition.copy()); } }); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java index 379b2362d1..e7e0381337 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java @@ -136,7 +136,7 @@ private static void runActionOnChunksInternal(Collection chunksCo if (chunkAccess instanceof LevelChunk levelChunk) { loadedChunks.add(levelChunk); } else { - unloadedChunks.add(chunkPosition); + unloadedChunks.add(chunkPosition.copy()); } }); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java index e57838ea55..34c4f3860b 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java @@ -137,7 +137,7 @@ private static void runActionOnChunksInternal(Collection chunksCo if (chunkAccess instanceof LevelChunk levelChunk) { loadedChunks.add(levelChunk); } else { - unloadedChunks.add(chunkPosition); + unloadedChunks.add(chunkPosition.copy()); } }); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java index 0e3d7b7684..ff893d7bd4 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java @@ -136,7 +136,7 @@ private static void runActionOnChunksInternal(Collection chunksCo if (chunkAccess instanceof LevelChunk levelChunk) { loadedChunks.add(levelChunk); } else { - unloadedChunks.add(chunkPosition); + unloadedChunks.add(chunkPosition.copy()); } }); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java index 196f8c203a..9387e5a661 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java @@ -140,7 +140,7 @@ private static void runActionOnChunksInternal(Collection chunksCo if (chunkAccess instanceof LevelChunk levelChunk) { loadedChunks.add(levelChunk); } else { - unloadedChunks.add(chunkPosition); + unloadedChunks.add(chunkPosition.copy()); } }); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java index 4bb43cf3d2..9954abb664 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java @@ -141,7 +141,7 @@ private static void runActionOnChunksInternal(Collection chunksCo if (chunkAccess instanceof LevelChunk levelChunk) { loadedChunks.add(levelChunk); } else { - unloadedChunks.add(chunkPosition); + unloadedChunks.add(chunkPosition.copy()); } }); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java index 71af4f20cb..ba96213ca7 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java @@ -141,7 +141,7 @@ private static void runActionOnChunksInternal(Collection chunksCo if (chunkAccess instanceof LevelChunk levelChunk) { loadedChunks.add(levelChunk); } else { - unloadedChunks.add(chunkPosition); + unloadedChunks.add(chunkPosition.copy()); } }); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java index 5817846438..b3ce4fe2d9 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java @@ -80,7 +80,7 @@ public static void runActionOnChunks(Collection chunksCoords, if (chunk != null) { loadedChunks.add(chunk); } else { - unloadedChunks.add(chunkPosition); + unloadedChunks.add(chunkPosition.copy()); } }); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java index e66e64d808..ca2f37a63b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java @@ -133,7 +133,7 @@ public void release() { } public ChunkPosition copy() { - return new ChunkPosition().initialize(this.worldInfo, this.x, this.z); + return new ChunkPosition(false).initialize(this.worldInfo, this.x, this.z); } @Override From 4d07cddd87eaad33dcebe7cfa7304fa3c6fbf2a2 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 8 Mar 2025 12:22:42 +0200 Subject: [PATCH 092/600] Fixed `/is admin reload` not updating command aliases properly (#2375) --- .../bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index cf51cbf83d..0f2523ca47 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -453,10 +453,10 @@ public void reloadPlugin(PluginReloadReason reloadReason) throws ManagerLoadExce // The reload was requested by a command. We want to reload the commands, settings and call the // module lifecycles that are not called regularly. If the reload was due to a startup, then // all of that is called already in the onEnable callback of the plugin. - commandsHandler.loadData(); - settingsHandler.loadData(); + commandsHandler.loadData(); + modulesHandler.runModuleLifecycle(ModuleLoadTime.PLUGIN_INITIALIZE, true); modulesHandler.runModuleLifecycle(ModuleLoadTime.BEFORE_WORLD_CREATION, true); modulesHandler.runModuleLifecycle(ModuleLoadTime.NORMAL, true); From 07d78b83eb47bb83201dc06eac5448765a2f9461 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 8 Mar 2025 12:32:36 +0200 Subject: [PATCH 093/600] Potential fix for NPE when calling WorkerExecutor#stop (#2345) --- .../world/chunk/ChunksProvider.java | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunksProvider.java b/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunksProvider.java index 02162cd56b..171e7b0e32 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunksProvider.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunksProvider.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.profiler.ProfileType; import com.bgsoftware.superiorskyblock.core.profiler.Profiler; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.Chunk; import java.util.HashSet; @@ -34,6 +35,15 @@ private ChunksProvider() { public static CompletableFuture loadChunk(ChunkPosition chunkPosition, ChunkLoadReason chunkLoadReason, @Nullable Consumer onLoadConsumer) { + try { + return loadChunkInternal(chunkPosition, chunkLoadReason, onLoadConsumer); + } finally { + chunkPosition.release(); + } + } + + private static CompletableFuture loadChunkInternal(ChunkPosition chunkPosition, ChunkLoadReason chunkLoadReason, + @Nullable Consumer onLoadConsumer) { if (stopped) return new CompletableFuture<>(); @@ -45,7 +55,6 @@ public static CompletableFuture loadChunk(ChunkPosition chunkPosition, Ch processPendingChunkLoadRequest(loadedChunk, chunkPosition); if (onLoadConsumer != null) onLoadConsumer.accept(loadedChunk); - chunkPosition.release(); return CompletableFuture.completedFuture(loadedChunk); } @@ -54,7 +63,6 @@ public static CompletableFuture loadChunk(ChunkPosition chunkPosition, Ch if (pendingRequest != null) { if (onLoadConsumer != null) pendingRequest.callbacks.add(onLoadConsumer); - chunkPosition.release(); return pendingRequest.completableFuture; } else { CompletableFuture completableFuture = new CompletableFuture<>(); @@ -65,13 +73,13 @@ public static CompletableFuture loadChunk(ChunkPosition chunkPosition, Ch // Copy pool resource ChunkPosition clonedChunkPos = chunkPosition.copy(); - chunkPosition.release(); pendingRequests.put(clonedChunkPos, new PendingChunkLoadRequest(completableFuture, chunkConsumers)); - chunksExecutor.addWorker(new ChunkLoadWorker(clonedChunkPos, chunkLoadReason)); - - if (!chunksExecutor.isRunning()) - start(); + BukkitExecutor.ensureMain(() -> { + chunksExecutor.addWorker(new ChunkLoadWorker(clonedChunkPos, chunkLoadReason)); + if (!chunksExecutor.isRunning()) + start(); + }); return completableFuture; } From 62c04938c64053c37a3480eaf0c3558e990b4022 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 8 Mar 2025 12:58:11 +0200 Subject: [PATCH 094/600] Debug message to UAF on ChunkPosition (#2336) --- .../superiorskyblock/core/ChunkPosition.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java index ca2f37a63b..1ea7ab364f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java @@ -25,6 +25,8 @@ public class ChunkPosition implements ObjectsPool.Releasable, AutoCloseable { protected WeakReference cachedBukkitWorld = new WeakReference<>(null); private final boolean isPool; + private Thread holder = Thread.currentThread(); + public static ChunkPosition of(Location location) { World world = location.getWorld(); return of(WorldInfo.of(world), location.getBlockX() >> 4, location.getBlockZ() >> 4).withBukkitWorld(world); @@ -74,10 +76,18 @@ private ChunkPosition initialize(WorldInfo worldInfo, int x, int z) { this.worldInfo = worldInfo; this.x = x; this.z = z; + this.holder = Thread.currentThread(); return this; } + private void checkAccess() { + if (isPool && Thread.currentThread() != this.holder) + throw new RuntimeException("Accessed ChunkPosition from " + Thread.currentThread() + " but holder is " + this.holder); + } + public World getWorld() { + checkAccess(); + World cachedBukkitWorld = this.cachedBukkitWorld.get(); if (cachedBukkitWorld == null) { cachedBukkitWorld = Bukkit.getWorld(getWorldName()); @@ -88,22 +98,27 @@ public World getWorld() { } public WorldInfo getWorldsInfo() { + checkAccess(); return this.worldInfo; } public String getWorldName() { + checkAccess(); return this.worldInfo.getName(); } public int getX() { + checkAccess(); return x; } public int getZ() { + checkAccess(); return z; } public long asPair() { + checkAccess(); if (this.pairedXZ < 0) pairedXZ = (long) this.x & 4294967295L | ((long) this.z & 4294967295L) << 32; @@ -111,11 +126,13 @@ public long asPair() { } public boolean isInsideChunk(Location location) { + checkAccess(); return location.getWorld().getName().equals(worldInfo.getName()) && location.getBlockX() >> 4 == x && location.getBlockZ() >> 4 == z; } public int distanceSquared(ChunkPosition other) { + checkAccess(); int deltaX = this.x - other.x; int deltaZ = this.z - other.z; return (deltaX * deltaX) + (deltaZ * deltaZ); @@ -129,6 +146,7 @@ public void release() { this.worldInfo = null; this.pairedXZ = -1; this.cachedBukkitWorld.clear(); + this.holder = null; POOL.release(this); } @@ -162,6 +180,7 @@ public String toString() { } private ChunkPosition withBukkitWorld(World world) { + checkAccess(); this.cachedBukkitWorld = new WeakReference<>(world); return this; } From 42fa8f1ae1bdb59df9b2aa7de6371e851c7dc889 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 8 Mar 2025 13:25:03 +0200 Subject: [PATCH 095/600] Adds "already opened" and "already closed" messages to `/is open` and `/is close` (#2376) --- .../superiorskyblock/commands/admin/CmdAdminClose.java | 4 +++- .../superiorskyblock/commands/admin/CmdAdminOpen.java | 4 +++- .../superiorskyblock/commands/player/CmdClose.java | 6 ++++-- .../superiorskyblock/commands/player/CmdOpen.java | 6 ++++-- .../bgsoftware/superiorskyblock/core/messages/Message.java | 2 ++ src/main/resources/lang/de-DE.yml | 2 ++ src/main/resources/lang/en-US.yml | 2 ++ src/main/resources/lang/es-ES.yml | 2 ++ src/main/resources/lang/fr-FR.yml | 2 ++ src/main/resources/lang/it-IT.yml | 2 ++ src/main/resources/lang/iw-IL.yml | 2 ++ src/main/resources/lang/pl-PL.yml | 2 ++ src/main/resources/lang/pt-BR.yml | 2 ++ src/main/resources/lang/ru-RU.yml | 2 ++ src/main/resources/lang/vi-VN.yml | 2 ++ src/main/resources/lang/zh-CN.yml | 2 ++ 16 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java index 74c699aa50..d941b115ec 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java @@ -59,7 +59,9 @@ public boolean supportMultipleIslands() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { - if (PluginEventsFactory.callIslandCloseEvent(island, sender)) { + if (island.isLocked()) { + Message.ISLAND_ALREADY_CLOSED.send(sender); + } else if (PluginEventsFactory.callIslandCloseEvent(island, sender)) { island.setLocked(true); Message.ISLAND_CLOSED.send(sender); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java index 5516f0bd55..10859a6d68 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java @@ -58,7 +58,9 @@ public boolean supportMultipleIslands() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { - if (PluginEventsFactory.callIslandOpenEvent(island, sender)) { + if (!island.isLocked()) { + Message.ISLAND_ALREADY_OPENED.send(sender); + } else if (PluginEventsFactory.callIslandOpenEvent(island, sender)) { island.setLocked(false); Message.ISLAND_OPENED.send(sender); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdClose.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdClose.java index 4b38f98c03..a4930debb4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdClose.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdClose.java @@ -4,9 +4,9 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Arrays; @@ -61,7 +61,9 @@ public Message getPermissionLackMessage() { @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { - if (PluginEventsFactory.callIslandCloseEvent(island, superiorPlayer)) { + if (island.isLocked()) { + Message.ISLAND_ALREADY_CLOSED.send(superiorPlayer); + } else if (PluginEventsFactory.callIslandCloseEvent(island, superiorPlayer)) { island.setLocked(true); Message.ISLAND_CLOSED.send(superiorPlayer); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdOpen.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdOpen.java index 6562051bbc..ba40ca3706 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdOpen.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdOpen.java @@ -4,9 +4,9 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import java.util.Arrays; @@ -61,7 +61,9 @@ public Message getPermissionLackMessage() { @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { - if (PluginEventsFactory.callIslandOpenEvent(island, superiorPlayer)) { + if (!island.isLocked()) { + Message.ISLAND_ALREADY_OPENED.send(superiorPlayer); + } else if (PluginEventsFactory.callIslandOpenEvent(island, superiorPlayer)) { island.setLocked(false); Message.ISLAND_OPENED.send(superiorPlayer); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index e3df90a0c3..5aba1eed41 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -452,7 +452,9 @@ public void send(CommandSender sender, Locale locale, Object... args) { INVITE_ANNOUNCEMENT, INVITE_BANNED_PLAYER, INVITE_TO_FULL_ISLAND, + ISLAND_ALREADY_CLOSED, ISLAND_ALREADY_EXIST, + ISLAND_ALREADY_OPENED, ISLAND_BANK_EMPTY, ISLAND_BANK_SHOW, ISLAND_BANK_SHOW_OTHER, diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 92a231cfa7..50f431ac31 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -521,7 +521,9 @@ INVITE_BANNED_PLAYER: '&c&lError | &7Dieser Spieler ist von der Insel gesperrt u kann nicht eingeladen werden.' INVITE_TO_FULL_ISLAND: '&c&lError | &7Du kannst keine weiteren Mitglieder auf Ihre Insel einladen.' +ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lError | &7Eine Insel mit diesem Namen existiert bereits.' +ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBank | &7Inselbank ist leer.' ISLAND_BANK_SHOW: '&e&lBank | &7Deine Insel hat ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lBank | Die Insel von &7{0} hat ${1}.' diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 9d9863245e..fc65a644ff 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -408,7 +408,9 @@ INVALID_WORLD: '&c&lError | &7Invalid world {0}.' INVITE_ANNOUNCEMENT: '&e&lIsland | &7{0} invited {1} to the island.' INVITE_BANNED_PLAYER: '&c&lError | &7This player is banned from the island and cannot get invited.' INVITE_TO_FULL_ISLAND: '&c&lError | &7You cannot invite more members to your island.' +ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lError | &7An island with that name already exists.' +ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBank | &7Island bank is empty.' ISLAND_BANK_SHOW: '&e&lBank | &7Your island has ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lBank | &7{0}''s island has ${1}.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 3987ac40e1..6d49326546 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -408,7 +408,9 @@ INVALID_WORLD: '&c&lError | &7Mundo invalido {0}.' INVITE_ANNOUNCEMENT: '&e&lIsla | &7{0} ha invitado a {1} a la isla.' INVITE_BANNED_PLAYER: '&c&lError | &7Este jugador está PROHIBIDO de la isla y no puede ser invitado.' INVITE_TO_FULL_ISLAND: '&c&lError | &7No puedes invitar a más miembros a tu isla.' +ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lError | &7Ya existe una isla con ese nombre.' +ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBanco | &7El banco de la isla está vacío.' ISLAND_BANK_SHOW: '&e&lBanco | &7Tu isla tiene ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lBanco | &7La isla de {0} tiene ${1}.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 6ed597f242..f5737a0426 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -408,7 +408,9 @@ INVALID_WORLD: '&c&lErreur | &7Monde {0} invalide.' INVITE_ANNOUNCEMENT: '&e&lIle | &7{0} a invité {1} sur l''île.' INVITE_BANNED_PLAYER: '&c&lErreur | &7Ce joueur est banni de l''île et ne peut pas être invité.' INVITE_TO_FULL_ISLAND: '&c&lErreur | &7Vous ne pouvez pas inviter plus de membres sur l''île.' +ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lErreur | &7Une île portant ce nom existe déjà.' +ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBanque | &7La banque de l''île est vide.' ISLAND_BANK_SHOW: '&e&lBanque | &7Votre île possède {0} crystaux !' ISLAND_BANK_SHOW_OTHER: '&e&lBanque | &7L''île de {0} possède {1} crystaux !' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index fab18f535a..05e3c3b41a 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -412,7 +412,9 @@ INVALID_WORLD: '&c&lErrore| &7Mondo invalido {0}.' INVITE_ANNOUNCEMENT: '&e&lIsola | &7{0} ha invitato {1} nella squadra dell''isola.' INVITE_BANNED_PLAYER: '&c&lErrore | &7Questo giocatore è bannato dall''isola e non può essere invitato.' INVITE_TO_FULL_ISLAND: '&c&lErrore | &7Non puoi invitare altri membri sulla tua isola.' +ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lErrore | &7Un''isola con quel nome esiste già.' +ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBanca | &7La banca dell''isola è vuota.' ISLAND_BANK_SHOW: '&e&lBanca | &7La tua isola ha ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lBanca | &7L''isola di {0} ha ${1}.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 6169bad3d5..fe4020a4da 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -424,7 +424,9 @@ INVALID_WORLD: '&c&lError | &7Invalid world {0}.' INVITE_ANNOUNCEMENT: '&e&lיא | &7יאה לא {1} תא ןימזה {0}.' INVITE_BANNED_PLAYER: '&c&lהאיגש | &7הנמזה לבקל לוכי אל ןכלו יאה ןמ קחרומ הזה ןקחשה.' INVITE_TO_FULL_ISLAND: '&c&lהאיגש | &7ךלש יאל םישנא דוע ןימזהל לוכי אל התא.' +ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lהאיגש | &7םייק רבכ {0} םשה םע יא.' +ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lקנב | &7קיר יאה קנב.' ISLAND_BANK_SHOW: '&e&lBank | &7Your island has ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lBank | &7{0}''s island has ${1}.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index d38a0ce796..45d1a06004 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -410,7 +410,9 @@ INVALID_WORLD: '&c&lBlad | &7Nieprawidlowy swiat {0}.' INVITE_ANNOUNCEMENT: '&e&lWyspa | &7{0} zaprosil {1} na wyspe.' INVITE_BANNED_PLAYER: '&c&lBlad | &7Ten gracz ma zakaz wstepu na wyspe i nie moze zostac zaproszony.' INVITE_TO_FULL_ISLAND: '&c&lBlad | &7Nie mozesz zaprosic wiecej czlonków na swoja wyspe.' +ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lBlad | &7Wyspa o tej nazwie juz istnieje.' +ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBank | &7Bank na wyspie jest pusty.' ISLAND_BANK_SHOW: '&e&lBank | &7Twoja wyspa ma {0}$.' ISLAND_BANK_SHOW_OTHER: '&e&lBank | Wyspa &7{0} ma {1}$.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index d277f1a73c..7caefff9a7 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -408,7 +408,9 @@ INVALID_WORLD: '&c&lErro | &7Mundo inválido {0}.' INVITE_ANNOUNCEMENT: '&e&lIlha | &7{0} convidou {1} para a ilha.' INVITE_BANNED_PLAYER: '&c&lErro | &7Este jogador foi banido da ilha e não pode ser convidado.' INVITE_TO_FULL_ISLAND: '&c&lErro | &7Você não pode convidar mais membros para sua ilha.' +ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lErro | &7Uma ilha com esse nome já existe.' +ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lBanco | &7O banco da ilha está vazio.' ISLAND_BANK_SHOW: '&e&lBanco | &7Sua ilha tem ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lBanco | &7A ilha de {0} tem ${1}.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 612bfb3c19..ad289e9d1e 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -408,7 +408,9 @@ INVALID_WORLD: '&c&lОшибка | &7Недопустимый мир {0}.' INVITE_ANNOUNCEMENT: '&e&lОстров | &7{0} пригласил {1} на остров.' INVITE_BANNED_PLAYER: '&c&lОшибка | &7Этот игрок забанен на острове и не может быть приглашен.' INVITE_TO_FULL_ISLAND: '&c&lОшибка | &7Вы не можете пригласить больше участников на ваш остров.' +ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lОшибка | &7Остров с таким именем уже существует.' +ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lБанк | &7Банк острова пуст.' ISLAND_BANK_SHOW: '&e&lБанк | &7Ваш остров имеет ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lБанк | &7Остров {0} имеет ${1}.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index fe82449acf..ea95a6225c 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -462,7 +462,9 @@ INVITE_BANNED_PLAYER: '&c&lLỗi | &7Người chơi này bị cấm từ đảo mời.' INVITE_TO_FULL_ISLAND: '&c&lLỗi | &7Bạn không thể mời thêm thành viên đến đảo của bạn.' +ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&lLỗi | &7Một hòn đảo với tên đó đã tồn tại.' +ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&lNgân Hàng | &7Đảo ngân hàng trống rỗng.' ISLAND_BANK_SHOW: '&e&lNgân Hàng | &7Đảo bạn có ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lNgân Hàng | &7Đảo của {0} có ${1}.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index e588c7133c..1ac2159f4b 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -408,7 +408,9 @@ INVALID_WORLD: '&c&l错误 | &7I无效世界 {0}.' INVITE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 将玩家 {1} 邀请至了岛屿.' INVITE_BANNED_PLAYER: '&c&l错误 | &7该玩家已从岛屿被封禁, 不可接受任何邀请.' INVITE_TO_FULL_ISLAND: '&c&l错误 | &7你不能再向岛屿邀请更多成员了.' +ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' ISLAND_ALREADY_EXIST: '&c&l错误 | &7已存在名称相同的岛屿.' +ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' ISLAND_BANK_EMPTY: '&e&l银行 | &7岛屿银行中没有存款.' ISLAND_BANK_SHOW: '&e&l银行 | &7你的岛屿银行存款为 ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&l银行 | &7玩家 {0} 的岛屿银行存款为 ${1}.' From 63b1ce0cc4756df53934c08f75ffdf4469d7c7b5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 10 Mar 2025 16:43:23 +0200 Subject: [PATCH 096/600] Adds stack trace to ChunkPosition#release call for debugging purposes (#2336) --- .../superiorskyblock/core/ChunkPosition.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java index 1ea7ab364f..b4b3618813 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java @@ -26,6 +26,7 @@ public class ChunkPosition implements ObjectsPool.Releasable, AutoCloseable { private final boolean isPool; private Thread holder = Thread.currentThread(); + private StackTraceElement[] releaseStackTrace; public static ChunkPosition of(Location location) { World world = location.getWorld(); @@ -81,8 +82,17 @@ private ChunkPosition initialize(WorldInfo worldInfo, int x, int z) { } private void checkAccess() { - if (isPool && Thread.currentThread() != this.holder) - throw new RuntimeException("Accessed ChunkPosition from " + Thread.currentThread() + " but holder is " + this.holder); + if (isPool && Thread.currentThread() != this.holder) { + StringBuilder builder = new StringBuilder("Accessed ChunkPosition from " + Thread.currentThread() + " but holder is " + this.holder); + if (this.releaseStackTrace != null && this.releaseStackTrace.length > 0) { + builder.append("\n\n\tRelease stacktrace:"); + for (StackTraceElement traceElement : this.releaseStackTrace) { + builder.append("\n\t\tat ").append(traceElement); + } + builder.append("\n"); + } + throw new RuntimeException(builder.toString()); + } } public World getWorld() { @@ -147,6 +157,7 @@ public void release() { this.pairedXZ = -1; this.cachedBukkitWorld.clear(); this.holder = null; + this.releaseStackTrace = Thread.currentThread().getStackTrace(); POOL.release(this); } From 593f704b00c97c10e51add26f3b6a74c6517d3af Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 15 Mar 2025 13:26:22 +0200 Subject: [PATCH 097/600] More debug messages to ChunkPosition#release method (#2336) --- .../com/bgsoftware/superiorskyblock/core/ChunkPosition.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java index b4b3618813..9b0dd57326 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java @@ -153,6 +153,8 @@ public void release() { if (!isPool) return; + checkAccess(); + this.worldInfo = null; this.pairedXZ = -1; this.cachedBukkitWorld.clear(); From 70558b96baab948183a8c4e67210a1b154c88162 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 16 Mar 2025 09:52:10 +0200 Subject: [PATCH 098/600] Fix some ChunkPositions being released twice, causing other bugs (#2336) --- .../superiorskyblock/island/SIsland.java | 28 +++++++++---------- .../schematic/SchematicsManagerImpl.java | 4 +-- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index a074a990bb..4ab944dd70 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -1984,20 +1984,20 @@ private CompletableFuture getBiomeAsyncTask(CompletableFuture curr World world = islandWorldResult.getLeft(); - try (ChunkPosition centerChunkPosition = ChunkPosition.of(world, - centerBlockPosition.getX() >> 4, centerBlockPosition.getZ() >> 4)) { - ChunksProvider.loadChunk(centerChunkPosition, ChunkLoadReason.BIOME_REQUEST, null) - .thenApply(chunk -> centerBlockPosition.parse(world).getBlock().getBiome()) - .whenComplete((biome, error) -> { - if (error != null) - newTask.completeExceptionally(error); - else { - this.biome = biome; - biomeGetterTask.set((CompletableFuture) null); - newTask.complete(biome); - } - }); - } + ChunkPosition centerChunkPosition = + ChunkPosition.of(world, centerBlockPosition.getX() >> 4, centerBlockPosition.getZ() >> 4); + + ChunksProvider.loadChunk(centerChunkPosition, ChunkLoadReason.BIOME_REQUEST, null) + .thenApply(chunk -> centerBlockPosition.parse(world).getBlock().getBiome()) + .whenComplete((biome, error) -> { + if (error != null) + newTask.completeExceptionally(error); + else { + this.biome = biome; + biomeGetterTask.set((CompletableFuture) null); + newTask.complete(biome); + } + }); }); return newTask; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index f412464d1c..6f26c056fb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -216,9 +216,7 @@ public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY int maxChunkZ = maxBlockZ >> 4; for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) { for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) { - try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) { - worldReader.prepareChunk(chunkPosition); - } + worldReader.prepareChunk(ChunkPosition.of(world, chunkX, chunkZ)); } } From 5973a83c676ca145b0114ef2f5aa6baae0d528a5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 19 Mar 2025 09:28:51 +0200 Subject: [PATCH 099/600] Fix biome names in the `CHANGED_BIOME` message (#2388) --- .../superiorskyblock/core/menu/button/impl/BiomeButton.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java index 9185bc7220..960523095e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; @@ -26,7 +27,6 @@ import java.util.Collections; import java.util.List; -import java.util.Locale; import java.util.Objects; public class BiomeButton extends AbstractMenuViewButton { @@ -87,7 +87,8 @@ public void onButtonClick(InventoryClickEvent clickEvent) { command.replace("%player%", inventoryViewer.getName()))); menuView.getIsland().setBiome(event.getArgs().biome); - Message.CHANGED_BIOME.send(inventoryViewer, event.getArgs().biome.name().toLowerCase(Locale.ENGLISH)); + Message.CHANGED_BIOME.send(inventoryViewer, + Formatters.CAPITALIZED_FORMATTER.format(event.getArgs().biome.name())); BukkitExecutor.sync(menuView::closeView, 1L); } From e6897c19ac45ddcef5db9b1342e3a6cb5dd1e18a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 29 Mar 2025 14:47:30 +0300 Subject: [PATCH 100/600] Fixed opening the deposit menu for stacked blocks not working correctly (#2386) --- .../superiorskyblock/world/BukkitItems.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitItems.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitItems.java index bf232f2a45..337b97ef47 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitItems.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitItems.java @@ -75,11 +75,17 @@ public static PlayerHand getHand(Event event) { public static ItemStack getHandItem(Player onlinePlayer, @Nullable PlayerHand usedHand) { if (usedHand == null) { return null; - } else if (usedHand == PlayerHand.OFF_HAND) { - return GET_ITEM_IN_OFF_HAND.invoke(onlinePlayer.getInventory()); + } + + ItemStack handItem; + + if (usedHand == PlayerHand.OFF_HAND) { + handItem = GET_ITEM_IN_OFF_HAND.invoke(onlinePlayer.getInventory()); } else { - return onlinePlayer.getItemInHand(); + handItem = onlinePlayer.getItemInHand(); } + + return handItem == null || handItem.getType() == Material.AIR ? null : handItem; } public static void setHandItem(Player player, PlayerHand playerHand, @Nullable ItemStack itemStack) { From a0c85cd77084d266a014095aa1dadcc929be16a3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 29 Mar 2025 15:10:44 +0300 Subject: [PATCH 101/600] Uncoop player when clicking its head in the coops menu (#2390) --- .../core/menu/button/impl/CoopsPagedObjectButton.java | 2 +- src/main/resources/menus/coops.yml | 2 ++ src/main/resources/menus/coops1_13.yml | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CoopsPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CoopsPagedObjectButton.java index 02e3934b25..9b26484aa3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CoopsPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CoopsPagedObjectButton.java @@ -18,7 +18,7 @@ private CoopsPagedObjectButton(MenuTemplateButton templateButton @Override public void onButtonClick(InventoryClickEvent clickEvent) { - // Dummy button + plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "uncoop", pagedObject.getName()); } @Override diff --git a/src/main/resources/menus/coops.yml b/src/main/resources/menus/coops.yml index 0eaa50eb55..e572e7f9d4 100644 --- a/src/main/resources/menus/coops.yml +++ b/src/main/resources/menus/coops.yml @@ -26,6 +26,8 @@ items: type: SKULL_ITEM data: 3 name: '&e{0}' + lore: + - '&7Click to uncoop the player.' '%': type: PAPER name: '{0}Previous Page' diff --git a/src/main/resources/menus/coops1_13.yml b/src/main/resources/menus/coops1_13.yml index 568b66bd88..ceb602b7ff 100644 --- a/src/main/resources/menus/coops1_13.yml +++ b/src/main/resources/menus/coops1_13.yml @@ -25,6 +25,8 @@ items: '@': type: PLAYER_HEAD name: '&e{0}' + lore: + - '&7Click to uncoop the player.' '%': type: PAPER name: '{0}Previous Page' From b585d7b12176034d4f573e2b93b158323d115ffc Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 29 Mar 2025 15:49:03 +0300 Subject: [PATCH 102/600] Fixed portals not working when nether and end worlds are enabled (#2392) --- .../listener/BukkitEventsListener.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index f93c288c3a..154bf16411 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -75,6 +75,7 @@ import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.event.player.PlayerPortalEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerShearEntityEvent; @@ -154,6 +155,7 @@ public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { createEventListener(GameEventType.PLAYER_GAMEMODE_CHANGE, PlayerGameModeChangeEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_CHANGED_WORLD_EVENT, PlayerChangedWorldEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_RESPAWN_EVENT, PlayerRespawnEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_PORTAL_EVENT, PlayerPortalEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_PORTAL_EVENT, EntityPortalEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_ENTER_PORTAL_EVENT, EntityPortalEnterEvent.class, this::createGameEvent); createEventListener(GameEventType.PROJECTILE_LAUNCH_EVENT, ProjectileLaunchEvent.class, this::createGameEvent); @@ -721,12 +723,23 @@ private GameEvent createGameEvent(GameEvent return eventType.createEvent(playerPickupItemEvent); } + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerPortalEvent e) { + GameEventArgs.EntityPortalEvent entityPortalEvent = new GameEventArgs.EntityPortalEvent(); + entityPortalEvent.entity = e.getPlayer(); + entityPortalEvent.cause = e.getTo().getWorld().getEnvironment() == World.Environment.THE_END || + e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ? + PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL; + entityPortalEvent.from = e.getFrom(); + entityPortalEvent.to = e.getTo(); + return eventType.createEvent(entityPortalEvent); + } + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityPortalEvent e) { GameEventArgs.EntityPortalEvent entityPortalEvent = new GameEventArgs.EntityPortalEvent(); entityPortalEvent.entity = e.getEntity(); entityPortalEvent.cause = e.getTo().getWorld().getEnvironment() == World.Environment.THE_END || e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ? - PlayerTeleportEvent.TeleportCause.NETHER_PORTAL : PlayerTeleportEvent.TeleportCause.END_PORTAL; + PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL; entityPortalEvent.from = e.getFrom(); entityPortalEvent.to = e.getTo(); return eventType.createEvent(entityPortalEvent); From 32eb6735a598132ddf6cf70375e1b46b7b1acd85 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 29 Mar 2025 15:54:46 +0300 Subject: [PATCH 103/600] Potential fix for chunk snapshots not cached error with WildStacker (#2366) --- .../external/WildStackerSnapshotsContainer.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java index 623bb6d97b..f8cd017a80 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java @@ -1,25 +1,27 @@ package com.bgsoftware.superiorskyblock.external; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.wildstacker.api.WildStackerAPI; import com.bgsoftware.wildstacker.api.objects.StackedSnapshot; import org.bukkit.Chunk; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - public class WildStackerSnapshotsContainer { - private static final Map cachedSnapshots = new ConcurrentHashMap<>(); + private static final Chunk2ObjectMap cachedSnapshots = new Chunk2ObjectMap<>(); private WildStackerSnapshotsContainer() { } public static void takeSnapshot(Chunk chunk) { - ChunkPosition chunkPosition = ChunkPosition.of(chunk, false); + try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { + takeSnapshotInternal(chunk, chunkPosition); + } + } + private static void takeSnapshotInternal(Chunk chunk, ChunkPosition chunkPosition) { if (cachedSnapshots.containsKey(chunkPosition)) return; From 4c4632d2b91b43006141f8c6cfb0f999fb5692f8 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 4 Apr 2025 15:37:18 +0300 Subject: [PATCH 104/600] Support to air blocks in schematics (#2396) --- .../api/handlers/FactoriesManager.java | 9 +- .../api/handlers/SchematicManager.java | 32 ++++++- .../api/schematic/SchematicOptions.java | 86 +++++++++++++++++++ .../commands/admin/CmdAdminSchematic.java | 10 ++- .../superiorskyblock/core/VarintArray.java | 4 + .../core/factory/FactoriesManagerImpl.java | 8 ++ .../core/messages/Message.java | 1 + .../schematic/SchematicsManagerImpl.java | 68 +++++++++++---- .../schematic/impl/SuperiorSchematic.java | 2 +- .../options/SchematicOptionsBuilderImpl.java | 42 +++++++++ .../options/SchematicOptionsImpl.java | 57 ++++++++++++ src/main/resources/lang/de-DE.yml | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + 22 files changed, 304 insertions(+), 26 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/schematic/SchematicOptions.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/schematic/options/SchematicOptionsBuilderImpl.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/schematic/options/SchematicOptionsImpl.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java index 38c06f09c3..fbc53e6810 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.factory.PlayersFactory; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; +import com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; @@ -169,8 +170,14 @@ BankTransaction createTransaction(@Nullable UUID player, BankAction action, int * @param sound The sound to play. * @param volume The volume to play the sound. * @param pitch The pitch to play the sound. - * @return */ GameSound createGameSound(Sound sound, float volume, float pitch); + /** + * Create a new builder for a {@link SchematicOptions} object. + * + * @param schematicName The name of the schematic to create. + */ + SchematicOptions.Builder createSchematicOptionsBuilder(String schematicName); + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/SchematicManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/SchematicManager.java index fa4f8c1008..3c1ffd8491 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/SchematicManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/SchematicManager.java @@ -2,6 +2,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; +import com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Location; @@ -41,13 +42,23 @@ public interface SchematicManager { /** * Save a schematic. - * Calls the saveSchematic(Location, Location, Integer, Integer, Integer, String, Runnable) method with default values. + * Calls the {@link #saveSchematic(SuperiorPlayer, String, boolean)} with saveAir set to false. * * @param superiorPlayer The player who saves the schematic. * @param schematicName The schematic name. */ void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName); + /** + * Save a schematic. + * Calls the {@link #saveSchematic(Location, Location, SchematicOptions, Runnable)} method with default values. + * + * @param superiorPlayer The player who saves the schematic. + * @param schematicName The schematic name. + * @param saveAir Whether to save air blocks into the schematic. + */ + void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName, boolean saveAir); + /** * Save a schematic. * @@ -102,4 +113,23 @@ public interface SchematicManager { */ void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, float yaw, float pitch, String schematicName, @Nullable Runnable callable); + /** + * Save a schematic. + * + * @param pos1 First position for the schematic. + * @param pos2 Second position for the schematic. + * @param schematicOptions The options for creating the new schematic. + */ + void saveSchematic(Location pos1, Location pos2, SchematicOptions schematicOptions); + + /** + * Save a schematic. + * + * @param pos1 First position for the schematic. + * @param pos2 Second position for the schematic. + * @param schematicOptions The options for creating the new schematic. + * @param callable A runnable that will be ran after the task is completed. + */ + void saveSchematic(Location pos1, Location pos2, SchematicOptions schematicOptions, @Nullable Runnable callable); + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/schematic/SchematicOptions.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/schematic/SchematicOptions.java new file mode 100644 index 0000000000..734318f09f --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/schematic/SchematicOptions.java @@ -0,0 +1,86 @@ +package com.bgsoftware.superiorskyblock.api.schematic; + +import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; + +/** + * This class represents options for creating schematics. + */ +public interface SchematicOptions { + + /** + * Get the name of the schematic. + */ + String getSchematicName(); + + /** + * Get the offset in the x-axis of the schematic. + */ + int getOffsetX(); + + /** + * Get the offset in the y-axis of the schematic. + */ + int getOffsetY(); + + /** + * Get the offset in the z-axis of the schematic. + */ + int getOffsetZ(); + + /** + * Get the yaw of the schematic. + */ + float getYaw(); + + /** + * Get the pitch of the schematic. + */ + float getPitch(); + + /** + * Get whether the schematic should save air blocks. + */ + boolean shouldSaveAir(); + + /** + * Create a new builder for a {@link SchematicOptions} object. + * + * @param schematicName The name of the schematic to create. + */ + static Builder newBuilder(String schematicName) { + return SuperiorSkyblockAPI.getFactory().createSchematicOptionsBuilder(schematicName); + } + + interface Builder { + + default Builder setOffsetX(int offsetX) { + return setOffset(offsetX, 0, 0); + } + + default Builder setOffsetY(int offsetY) { + return setOffset(0, offsetY, 0); + } + + default Builder setOffsetZ(int offsetZ) { + return setOffset(0, 0, offsetZ); + } + + Builder setOffset(int offsetX, int offsetY, int offsetZ); + + default Builder setYaw(float yaw) { + return setDirection(yaw, 0f); + } + + default Builder setPitch(float pitch) { + return setDirection(0f, pitch); + } + + Builder setDirection(float yaw, float pitch); + + Builder setSaveAir(boolean saveAir); + + SchematicOptions build(); + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java index d0abca4254..3597f0b3e5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java @@ -2,8 +2,8 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; @@ -24,7 +24,8 @@ public String getPermission() { @Override public String getUsage(java.util.Locale locale) { - return "admin schematic [" + Message.COMMAND_ARGUMENT_SCHEMATIC_NAME.getMessage(locale) + "]"; + return "admin schematic [" + Message.COMMAND_ARGUMENT_SCHEMATIC_NAME.getMessage(locale) + "] [" + + Message.COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR.getMessage(locale) + "]"; } @Override @@ -39,7 +40,7 @@ public int getMinArgs() { @Override public int getMaxArgs() { - return 3; + return 4; } @Override @@ -66,9 +67,10 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ } String schematicName = args[2]; + boolean saveAir = args.length == 4 && Boolean.parseBoolean(args[3]); Message.SCHEMATIC_PROCCESS_REQUEST.send(superiorPlayer); - plugin.getSchematics().saveSchematic(superiorPlayer, schematicName); + plugin.getSchematics().saveSchematic(superiorPlayer, schematicName, saveAir); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/VarintArray.java b/src/main/java/com/bgsoftware/superiorskyblock/core/VarintArray.java index c6a991d5ac..073560289f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/VarintArray.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/VarintArray.java @@ -8,6 +8,7 @@ public class VarintArray { private static final byte[] VARINT_BUF = new byte[10]; + private static final byte[] ZERO_BYTE = new byte[]{0}; private final ByteBigArray backend; private int size; @@ -40,6 +41,9 @@ public Itr iterator() { } private static byte[] serializeVarint(long value) { + if (value == 0) + return ZERO_BYTE; + int varintBytesCount = 0; while (value != 0) { byte nextByte = (byte) (value & 0x7f); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java index fdf9794ce0..1247e07ff8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm; +import com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; @@ -44,6 +45,7 @@ import com.bgsoftware.superiorskyblock.player.algorithm.DefaultPlayerTeleportAlgorithm; import com.bgsoftware.superiorskyblock.player.builder.SuperiorPlayerBuilderImpl; import com.bgsoftware.superiorskyblock.world.Dimensions; +import com.bgsoftware.superiorskyblock.world.schematic.options.SchematicOptionsBuilderImpl; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -193,6 +195,12 @@ public GameSound createGameSound(Sound sound, float volume, float pitch) { return new GameSoundImpl(sound, volume, pitch); } + @Override + public SchematicOptions.Builder createSchematicOptionsBuilder(String schematicName) { + Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null"); + return new SchematicOptionsBuilderImpl(schematicName); + } + public IslandBank createIslandBank(Island island, Supplier isGiveInterestFailed) { return banksFactory.createIslandBank(island, new SIslandBank(island, isGiveInterestFailed)); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 5aba1eed41..1e56aada7b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -159,6 +159,7 @@ public enum Message { COMMAND_ARGUMENT_RATING("rating"), COMMAND_ARGUMENT_ROWS("rows"), COMMAND_ARGUMENT_SCHEMATIC_NAME("schematic-name"), + COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR("save-air"), COMMAND_ARGUMENT_SETTINGS("settings"), COMMAND_ARGUMENT_SIZE("size"), COMMAND_ARGUMENT_TIME("time"), diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index 6f26c056fb..777a41e61b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.handlers.SchematicManager; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; +import com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParseException; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser; import com.bgsoftware.superiorskyblock.api.world.Dimension; @@ -135,6 +136,11 @@ public List getSchematicParsers() { @Override public void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName) { + saveSchematic(superiorPlayer, schematicName, false); + } + + @Override + public void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName, boolean saveAir) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkArgument(superiorPlayer.isOnline(), "superiorPlayer must be online."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); @@ -145,17 +151,20 @@ public void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName) { Location offset; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location min = new Location(pos1.getWorld(), + offset = superiorPlayer.getLocation(wrapper.getHandle()).subtract( Math.min(pos1.getX(), pos2.getX()), - Math.min(pos1.getY(), pos2.getY()), + Math.min(pos1.getY(), pos2.getY()) + 1, Math.min(pos1.getZ(), pos2.getZ()) ); - - offset = superiorPlayer.getLocation(wrapper.getHandle()).subtract(min.add(0, 1, 0)); } - saveSchematic(pos1.parse(), pos2.parse(), offset.getBlockX(), offset.getBlockY(), offset.getBlockZ(), - offset.getYaw(), offset.getPitch(), schematicName, () -> Message.SCHEMATIC_SAVED.send(superiorPlayer)); + SchematicOptions schematicOptions = SchematicOptions.newBuilder(schematicName) + .setOffset(offset.getBlockX(), offset.getBlockY(), offset.getBlockZ()) + .setDirection(offset.getYaw(), offset.getPitch()) + .setSaveAir(saveAir) + .build(); + + saveSchematic(pos1.parse(), pos2.parse(), schematicOptions, () -> Message.SCHEMATIC_SAVED.send(superiorPlayer)); superiorPlayer.setSchematicPos1(null); superiorPlayer.setSchematicPos2(null); @@ -186,13 +195,34 @@ public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY } @Override - public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, - float yaw, float pitch, String schematicName, @Nullable Runnable runnable) { + public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY, int offsetZ, float yaw, float pitch, + String schematicName, @Nullable Runnable callable) { Preconditions.checkNotNull(pos1, "pos1 parameter cannot be null."); Preconditions.checkNotNull(pos2, "pos2 parameter cannot be null."); Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); - Log.debug(Debug.SAVE_SCHEMATIC, pos1, pos2, offsetX, offsetY, offsetZ, yaw, pitch, schematicName); + SchematicOptions schematicOptions = SchematicOptions.newBuilder(schematicName) + .setOffset(offsetX, offsetY, offsetZ) + .setDirection(yaw, pitch) + .build(); + + saveSchematic(pos1, pos2, schematicOptions, callable); + } + + @Override + public void saveSchematic(Location pos1, Location pos2, SchematicOptions schematicOptions) { + saveSchematic(pos1, pos2, schematicOptions, null); + } + + @Override + public void saveSchematic(Location pos1, Location pos2, SchematicOptions schematicOptions, @Nullable Runnable callable) { + Preconditions.checkNotNull(pos1, "pos1 parameter cannot be null."); + Preconditions.checkNotNull(pos2, "pos2 parameter cannot be null."); + Preconditions.checkNotNull(schematicOptions, "schematicOptions parameter cannot be null."); + + Log.debug(Debug.SAVE_SCHEMATIC, pos1, pos2, schematicOptions.getOffsetX(), schematicOptions.getOffsetY(), + schematicOptions.getOffsetZ(), schematicOptions.getYaw(), schematicOptions.getPitch(), + schematicOptions.shouldSaveAir(), schematicOptions.getSchematicName()); World world = pos1.getWorld(); @@ -236,7 +266,7 @@ public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY for (int chunkBlockY = minBlockY; chunkBlockY <= maxBlockY; ++chunkBlockY) { Material blockType = chunkReader.getType(chunkBlockX, chunkBlockY, chunkBlockZ); - if (blockType == Material.AIR) + if (!schematicOptions.shouldSaveAir() && blockType == Material.AIR) continue; short blockData = chunkReader.getData(chunkBlockX, chunkBlockY, chunkBlockZ); @@ -281,22 +311,22 @@ public void saveSchematic(Location pos1, Location pos2, int offsetX, int offsetY compoundValue.put("zSize", new IntTag(zSize)); compoundValue.put("blocks", new ListTag(CompoundTag.class, blocks)); compoundValue.put("entities", new ListTag(CompoundTag.class, entities)); - compoundValue.put("offsetX", new IntTag(offsetX)); - compoundValue.put("offsetY", new IntTag(offsetY)); - compoundValue.put("offsetZ", new IntTag(offsetZ)); - compoundValue.put("yaw", new FloatTag(yaw)); - compoundValue.put("pitch", new FloatTag(pitch)); + compoundValue.put("offsetX", new IntTag(schematicOptions.getOffsetX())); + compoundValue.put("offsetY", new IntTag(schematicOptions.getOffsetY())); + compoundValue.put("offsetZ", new IntTag(schematicOptions.getOffsetZ())); + compoundValue.put("yaw", new FloatTag(schematicOptions.getYaw())); + compoundValue.put("pitch", new FloatTag(schematicOptions.getPitch())); compoundValue.put("version", new StringTag(ServerVersion.getBukkitVersion())); if (!ServerVersion.isLegacy()) compoundValue.put("minecraftDataVersion", new IntTag(plugin.getNMSAlgorithms().getDataVersion())); CompoundTag schematicTag = new CompoundTag(compoundValue); - SuperiorSchematic schematic = new SuperiorSchematic(schematicName, schematicTag); + SuperiorSchematic schematic = new SuperiorSchematic(schematicOptions.getSchematicName(), schematicTag); this.schematicsContainer.addSchematic(schematic); - saveIntoFile(schematicName, schematicTag); + saveIntoFile(schematicOptions.getSchematicName(), schematicTag); - if (runnable != null) - BukkitExecutor.sync(runnable); + if (callable != null) + BukkitExecutor.sync(callable); }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java index 3ff4c4989a..b0ae4769bd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java @@ -102,7 +102,7 @@ public SuperiorSchematic(String name, CompoundTag compoundTag) { for (Tag tag : blocksList) { SchematicBlockData schematicBlock = SuperiorSchematicDeserializer.deserializeSchematicBlock((CompoundTag) tag, dataVersion); - if (schematicBlock != null && schematicBlock.getCombinedId() > 0) { + if (schematicBlock != null) { schematicBlocks.add(schematicBlock); readBlock(schematicBlock); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/options/SchematicOptionsBuilderImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/options/SchematicOptionsBuilderImpl.java new file mode 100644 index 0000000000..7a5ef81f5e --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/options/SchematicOptionsBuilderImpl.java @@ -0,0 +1,42 @@ +package com.bgsoftware.superiorskyblock.world.schematic.options; + +import com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; +import com.bgsoftware.superiorskyblock.core.SBlockOffset; + +public class SchematicOptionsBuilderImpl implements SchematicOptions.Builder { + + private final String schematicName; + private BlockOffset blockOffset = SBlockOffset.ZERO; + private float yaw = 0f; + private float pitch = 0f; + private boolean saveAir = false; + + public SchematicOptionsBuilderImpl(String schematicName) { + this.schematicName = schematicName; + } + + @Override + public SchematicOptionsBuilderImpl setOffset(int offsetX, int offsetY, int offsetZ) { + this.blockOffset = SBlockOffset.fromOffsets(offsetX, offsetY, offsetZ); + return this; + } + + @Override + public SchematicOptionsBuilderImpl setDirection(float yaw, float pitch) { + this.yaw = yaw; + this.pitch = pitch; + return this; + } + + @Override + public SchematicOptionsBuilderImpl setSaveAir(boolean saveAir) { + this.saveAir = saveAir; + return this; + } + + @Override + public SchematicOptions build() { + return new SchematicOptionsImpl(this.schematicName, this.blockOffset, this.yaw, this.pitch, this.saveAir); + } +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/options/SchematicOptionsImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/options/SchematicOptionsImpl.java new file mode 100644 index 0000000000..b81866a82f --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/options/SchematicOptionsImpl.java @@ -0,0 +1,57 @@ +package com.bgsoftware.superiorskyblock.world.schematic.options; + +import com.bgsoftware.superiorskyblock.api.schematic.SchematicOptions; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; + +public class SchematicOptionsImpl implements SchematicOptions { + + private final String schematicName; + private final BlockOffset blockOffset; + private final float yaw; + private final float pitch; + private final boolean saveAir; + + public SchematicOptionsImpl(String schematicName, BlockOffset blockOffset, float yaw, float pitch, boolean saveAir) { + this.schematicName = schematicName; + this.blockOffset = blockOffset; + this.yaw = yaw; + this.pitch = pitch; + this.saveAir = saveAir; + } + + @Override + public String getSchematicName() { + return this.schematicName; + } + + @Override + public int getOffsetX() { + return this.blockOffset.getOffsetX(); + } + + @Override + public int getOffsetY() { + return this.blockOffset.getOffsetY(); + } + + @Override + public int getOffsetZ() { + return this.blockOffset.getOffsetZ(); + } + + @Override + public float getYaw() { + return this.yaw; + } + + @Override + public float getPitch() { + return this.pitch; + } + + @Override + public boolean shouldSaveAir() { + return this.saveAir; + } + +} diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 50f431ac31..cd71d6e928 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -185,6 +185,7 @@ COMMAND_ARGUMENT_PRIVATE: privat COMMAND_ARGUMENT_RATING: Bewertung COMMAND_ARGUMENT_ROWS: Zeilen COMMAND_ARGUMENT_SCHEMATIC_NAME: schema-name +COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: Einstellungen COMMAND_ARGUMENT_SIZE: Größe COMMAND_ARGUMENT_TIME: Zeit diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index fc65a644ff..99b25beaf1 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -133,6 +133,7 @@ COMMAND_ARGUMENT_PRIVATE: 'private' COMMAND_ARGUMENT_RATING: 'rating' COMMAND_ARGUMENT_ROWS: 'rows' COMMAND_ARGUMENT_SCHEMATIC_NAME: 'schematic-name' +COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: 'settings' COMMAND_ARGUMENT_SIZE: 'size' COMMAND_ARGUMENT_TIME: 'time' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 6d49326546..a76fd8429b 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -133,6 +133,7 @@ COMMAND_ARGUMENT_PRIVATE: 'privado' COMMAND_ARGUMENT_RATING: 'clasificacion' COMMAND_ARGUMENT_ROWS: 'fila' COMMAND_ARGUMENT_SCHEMATIC_NAME: 'nombre-schematic' +COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: 'configuracion' COMMAND_ARGUMENT_SIZE: 'tamaño' COMMAND_ARGUMENT_TIME: 'tiempo' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index f5737a0426..cef5a8f95f 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -137,6 +137,7 @@ COMMAND_ARGUMENT_PRIVATE: privé COMMAND_ARGUMENT_RATING: note COMMAND_ARGUMENT_ROWS: lignes COMMAND_ARGUMENT_SCHEMATIC_NAME: nom-du-schémas +COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: paramètres COMMAND_ARGUMENT_SIZE: taille COMMAND_ARGUMENT_UPGRADE_NAME: nom-de-l'amélioration diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 05e3c3b41a..abdf1e21f1 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -136,6 +136,7 @@ COMMAND_ARGUMENT_PRIVATE: privato COMMAND_ARGUMENT_RATING: valutazione COMMAND_ARGUMENT_ROWS: righe COMMAND_ARGUMENT_SCHEMATIC_NAME: nome-schematica +COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: impostazioni COMMAND_ARGUMENT_SIZE: dimensione COMMAND_ARGUMENT_TIME: tempo diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index fe4020a4da..8bc8a99a7b 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -141,6 +141,7 @@ COMMAND_ARGUMENT_PRIVATE: יטרפ COMMAND_ARGUMENT_RATING: גוריד COMMAND_ARGUMENT_ROWS: rows COMMAND_ARGUMENT_SCHEMATIC_NAME: הנבמה םש +COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: תורדגה COMMAND_ARGUMENT_SIZE: לדוג COMMAND_ARGUMENT_TIME: ןמז diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 45d1a06004..64dc7b9512 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -135,6 +135,7 @@ COMMAND_ARGUMENT_PRIVATE: 'prywatny' COMMAND_ARGUMENT_RATING: 'ocena' COMMAND_ARGUMENT_ROWS: 'wiersze' COMMAND_ARGUMENT_SCHEMATIC_NAME: 'nazwa schematu' +COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: 'ustawienia' COMMAND_ARGUMENT_SIZE: 'rozmiar' COMMAND_ARGUMENT_TIME: 'czas' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 7caefff9a7..54deb19ee7 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -133,6 +133,7 @@ COMMAND_ARGUMENT_PRIVATE: 'privado' COMMAND_ARGUMENT_RATING: 'avaliação' COMMAND_ARGUMENT_ROWS: 'linhas' COMMAND_ARGUMENT_SCHEMATIC_NAME: 'nome-da-esquema' +COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: 'configurações' COMMAND_ARGUMENT_SIZE: 'tamanho' COMMAND_ARGUMENT_TIME: 'tempo' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index ad289e9d1e..88ce4dad59 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -133,6 +133,7 @@ COMMAND_ARGUMENT_PRIVATE: 'приватный' COMMAND_ARGUMENT_RATING: 'рейтинг' COMMAND_ARGUMENT_ROWS: 'строки' COMMAND_ARGUMENT_SCHEMATIC_NAME: 'название-схемы' +COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: 'настройки' COMMAND_ARGUMENT_SIZE: 'размер' COMMAND_ARGUMENT_TIME: 'время' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index ea95a6225c..b5fc6ea4b0 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -158,6 +158,7 @@ COMMAND_ARGUMENT_PRIVATE: rieng-tu COMMAND_ARGUMENT_RATING: danh-gia COMMAND_ARGUMENT_ROWS: so-dong COMMAND_ARGUMENT_SCHEMATIC_NAME: ten-schematic +COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: cai-dat COMMAND_ARGUMENT_SIZE: kich-thuoc COMMAND_ARGUMENT_TIME: thoi-gian diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 1ac2159f4b..90c4ffbe0f 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -133,6 +133,7 @@ COMMAND_ARGUMENT_PRIVATE: '私有' COMMAND_ARGUMENT_RATING: '评分' COMMAND_ARGUMENT_ROWS: '行数' COMMAND_ARGUMENT_SCHEMATIC_NAME: '结构名称' +COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: 'save-air' COMMAND_ARGUMENT_SETTINGS: '设置' COMMAND_ARGUMENT_SIZE: '大小' COMMAND_ARGUMENT_TIME: '事件' From 546d528768721987faa4e5af53dcccb8779e5e96 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 4 Apr 2025 19:27:35 +0300 Subject: [PATCH 105/600] Extended the possibilities of the MenusProvider --- .../api/hooks/MenusProvider.java | 9 + .../api/menu/MenuIslandCreationConfig.java | 61 +++++++ .../commands/admin/CmdAdminChest.java | 4 +- .../commands/player/CmdChest.java | 4 +- .../commands/player/CmdCreate.java | 17 +- .../commands/player/CmdWarp.java | 6 +- .../core/menu/MenuActions.java | 155 ++++++++++++++++++ .../core/menu/MenuConfig.java | 84 ++++++++++ .../button/impl/BankCustomDepositButton.java | 4 +- .../button/impl/BankCustomWithdrawButton.java | 4 +- .../menu/button/impl/BankDepositButton.java | 4 +- .../menu/button/impl/BankWithdrawButton.java | 4 +- .../impl/GlobalWarpsPagedObjectButton.java | 4 +- .../button/impl/IslandCreationButton.java | 15 +- .../impl/TopIslandsSelfIslandButton.java | 3 +- .../impl/WarpCategoryManageWarpsButton.java | 4 +- .../impl/WarpCategoryPagedObjectButton.java | 2 +- .../button/impl/WarpPagedObjectButton.java | 3 +- .../core/menu/impl/MenuIslandBank.java | 65 -------- .../core/menu/impl/MenuIslandChest.java | 13 -- .../core/menu/impl/MenuIslandCreation.java | 71 -------- .../core/menu/impl/MenuWarpCategories.java | 13 -- .../core/menu/impl/MenuWarps.java | 48 ------ .../external/menus/MenusProvider_Default.java | 76 ++++++++- .../island/GridManagerImpl.java | 13 +- .../island/preview/SIslandPreview.java | 19 ++- .../module/bank/commands/CmdDeposit.java | 4 +- .../module/bank/commands/CmdWithdraw.java | 4 +- 28 files changed, 454 insertions(+), 259 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/MenuIslandCreationConfig.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/MenusProvider.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/MenusProvider.java index 6fa588736a..cca16ebb22 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/MenusProvider.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/MenusProvider.java @@ -9,7 +9,9 @@ import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu; +import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; +import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; public interface MenusProvider { @@ -205,6 +207,13 @@ public interface MenusProvider { */ void refreshIslandChest(Island island); + /** + * Get island creation config for specific schematic. + * + * @param schematic The schematic to get the creation config for. + */ + MenuIslandCreationConfig getIslandCreationConfig(Schematic schematic); + /** * Open the islands-creation menu. * Used when creating a new island. diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/MenuIslandCreationConfig.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/MenuIslandCreationConfig.java new file mode 100644 index 0000000000..1f216b0a92 --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/MenuIslandCreationConfig.java @@ -0,0 +1,61 @@ +package com.bgsoftware.superiorskyblock.api.menu; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.handlers.GridManager; +import com.bgsoftware.superiorskyblock.api.schematic.Schematic; +import com.bgsoftware.superiorskyblock.api.world.GameSound; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; +import org.bukkit.block.Biome; + +import java.math.BigDecimal; +import java.util.Collection; + +/** + * Configuration for creation of new islands. + * The values from this configuration are used in {@link GridManager#createIsland} + */ +public interface MenuIslandCreationConfig { + + /** + * Get the schematic that will be used to create the island. + */ + Schematic getSchematic(); + + /** + * Get the sound to play when the island is successfully created. + */ + @Nullable + GameSound getSound(); + + /** + * Get the commands to execute when island is successfully created. + */ + Collection getCommands(); + + /** + * Get whether the island-values (worth & level) should be offset to 0 when the island is created. + */ + boolean shouldOffsetIslandValue(); + + /** + * Custom worth bonus when the island is created. + */ + BigDecimal getBonusWorth(); + + /** + * Custom level bonus when the island is created. + */ + BigDecimal getBonusLevel(); + + /** + * Get the spawn offset of the island's home location from where the schematic was placed. + */ + @Nullable + BlockOffset getSpawnOffset(); + + /** + * Get the biome to set to the new island. + */ + Biome getBiome(); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminChest.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminChest.java index 55cb8ede71..af5a97ae19 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminChest.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminChest.java @@ -5,7 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; -import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -59,7 +59,7 @@ public boolean supportMultipleIslands() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - Menus.MENU_ISLAND_CHEST.openMenu(superiorPlayer, superiorPlayer.getOpenedView(), island); + plugin.getMenus().openIslandChest(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdChest.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdChest.java index 0a102f90c3..8d17ee742a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdChest.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdChest.java @@ -9,7 +9,7 @@ import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.NumberArgument; -import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -83,7 +83,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer islandChests[page].openChest(superiorPlayer); } else { - Menus.MENU_ISLAND_CHEST.openMenu(superiorPlayer, superiorPlayer.getOpenedView(), island); + plugin.getMenus().openIslandChest(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCreate.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCreate.java index 11fe33f41f..7d780399d4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCreate.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCreate.java @@ -1,11 +1,13 @@ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; -import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.MenuActions; +import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandNames; import org.bukkit.command.CommandSender; @@ -83,7 +85,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ } String islandName = ""; - String schematicName = null; + Schematic schematic = null; if (plugin.getSettings().getIslandNames().isRequiredForCreation()) { if (args.length >= 2) { @@ -95,18 +97,19 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ if (plugin.getSettings().isSchematicNameArgument() && args.length == (plugin.getSettings().getIslandNames().isRequiredForCreation() ? 3 : 2)) { - schematicName = args[plugin.getSettings().getIslandNames().isRequiredForCreation() ? 2 : 1]; - Schematic schematic = plugin.getSchematics().getSchematic(schematicName); + String schematicName = args[plugin.getSettings().getIslandNames().isRequiredForCreation() ? 2 : 1]; + schematic = plugin.getSchematics().getSchematic(schematicName); if (schematic == null || schematicName.endsWith("_nether") || schematicName.endsWith("_the_end")) { Message.INVALID_SCHEMATIC.send(sender, schematicName); return; } } - if (schematicName == null) { - Menus.MENU_ISLAND_CREATION.openMenu(superiorPlayer, superiorPlayer.getOpenedView(), islandName); + if (schematic == null) { + plugin.getMenus().openIslandCreation(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), islandName); } else { - Menus.MENU_ISLAND_CREATION.simulateClick(superiorPlayer, islandName, schematicName, false, superiorPlayer.getOpenedView()); + MenuIslandCreationConfig creationConfig = plugin.getProviders().getMenusProvider().getIslandCreationConfig(schematic); + MenuActions.simulateIslandCreationClick(superiorPlayer, islandName, creationConfig, false, superiorPlayer.getOpenedView()); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java index 696867e9f8..a617e96cf8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java @@ -9,7 +9,7 @@ import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -93,13 +93,13 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ if (islandWarp == null) { switch (args.length) { case 1: - Menus.MENU_WARP_CATEGORIES.openMenu(superiorPlayer, superiorPlayer.getOpenedView(), targetIsland); + plugin.getMenus().openWarpCategories(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), targetIsland); break; case 2: IslandArgument arguments = CommandArguments.getIsland(plugin, sender, args[1]); targetIsland = arguments.getIsland(); if (targetIsland != null) { - Menus.MENU_WARP_CATEGORIES.openMenu(superiorPlayer, superiorPlayer.getOpenedView(), targetIsland); + plugin.getMenus().openWarpCategories(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), targetIsland); } break; case 3: diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java new file mode 100644 index 0000000000..4ee05b8b65 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java @@ -0,0 +1,155 @@ +package com.bgsoftware.superiorskyblock.core.menu; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; +import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; +import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; +import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; +import com.bgsoftware.superiorskyblock.api.schematic.Schematic; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.GameSound; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.GameSoundImpl; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +import java.math.BigDecimal; +import java.util.Locale; + +public class MenuActions { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + public static void handleDeposit(SuperiorPlayer superiorPlayer, Island island, BankTransaction bankTransaction, + @Nullable GameSound successSound, @Nullable GameSound failSound, BigDecimal amount) { + if (bankTransaction.getFailureReason().isEmpty()) { + superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, successSound)); + } else { + superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, failSound)); + + String failureReason = bankTransaction.getFailureReason(); + + if (!failureReason.isEmpty()) { + switch (failureReason) { + case "No permission": + Message.NO_DEPOSIT_PERMISSION.send(superiorPlayer, island.getRequiredPlayerRole(IslandPrivileges.DEPOSIT_MONEY)); + break; + case "Invalid amount": + Message.INVALID_AMOUNT.send(superiorPlayer, Formatters.NUMBER_FORMATTER.format(amount)); + break; + case "Not enough money": + Message.NOT_ENOUGH_MONEY_TO_DEPOSIT.send(superiorPlayer, Formatters.NUMBER_FORMATTER.format(amount)); + break; + case "Exceed bank limit": + Message.BANK_LIMIT_EXCEED.send(superiorPlayer); + break; + default: + Message.DEPOSIT_ERROR.send(superiorPlayer, failureReason); + break; + } + } + } + } + + public static void handleWithdraw(SuperiorPlayer superiorPlayer, Island island, BankTransaction bankTransaction, + GameSound successSound, GameSound failSound, BigDecimal amount) { + if (bankTransaction.getFailureReason().isEmpty()) { + superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, successSound)); + } else { + superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, failSound)); + + String failureReason = bankTransaction.getFailureReason(); + + if (!failureReason.isEmpty()) { + switch (failureReason) { + case "No permission": + Message.NO_WITHDRAW_PERMISSION.send(superiorPlayer, island.getRequiredPlayerRole(IslandPrivileges.WITHDRAW_MONEY)); + break; + case "Invalid amount": + Message.INVALID_AMOUNT.send(superiorPlayer, Formatters.NUMBER_FORMATTER.format(amount)); + break; + case "Bank is empty": + Message.ISLAND_BANK_EMPTY.send(superiorPlayer); + break; + default: + Message.WITHDRAW_ERROR.send(superiorPlayer, failureReason); + break; + } + } + } + } + + public static void simulateIslandCreationClick(SuperiorPlayer clickedPlayer, String islandName, + MenuIslandCreationConfig creationConfig, boolean isPreviewMode, + @Nullable MenuView menuView) { + Schematic schematic = creationConfig.getSchematic(); + + // Checking for preview of islands. + if (isPreviewMode) { + Location previewLocation = plugin.getSettings().getPreviewIslands().get(schematic.getName().toLowerCase(Locale.ENGLISH)); + if (previewLocation != null) { + plugin.getGrid().startIslandPreview(clickedPlayer, schematic, islandName); + return; + } + } + + Player whoClicked = clickedPlayer.asPlayer(); + + GameSoundImpl.playSound(whoClicked, creationConfig.getSound()); + + creationConfig.getCommands().forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), + command.replace("%player%", clickedPlayer.getName()))); + + Message.ISLAND_CREATE_PROCCESS_REQUEST.send(clickedPlayer); + + if (menuView != null) + menuView.closeView(); + + Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); + boolean offset = creationConfig.shouldOffsetIslandValue() || + plugin.getSettings().getWorlds().getDimensionConfig(dimension).isSchematicOffset(); + + BlockOffset spawnOffset = creationConfig.getSpawnOffset(); + + plugin.getGrid().createIsland(clickedPlayer, schematic.getName(), creationConfig.getBonusWorth(), + creationConfig.getBonusLevel(), creationConfig.getBiome(), islandName, offset, spawnOffset); + } + + public static void simulateWarpsClick(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp) { + if (!superiorPlayer.hasBypassModeEnabled() && plugin.getSettings().getChargeOnWarp() > 0) { + if (plugin.getProviders().getEconomyProvider().getBalance(superiorPlayer) + .compareTo(BigDecimal.valueOf(plugin.getSettings().getChargeOnWarp())) < 0) { + Message.NOT_ENOUGH_MONEY_TO_WARP.send(superiorPlayer); + return; + } + + plugin.getProviders().getEconomyProvider().withdrawMoney(superiorPlayer, + plugin.getSettings().getChargeOnWarp()); + } + + BukkitExecutor.sync(() -> { + superiorPlayer.runIfOnline(player -> { + MenuView currentView = superiorPlayer.getOpenedView(); + if (currentView == null) { + player.closeInventory(); + } else { + currentView.closeView(); + } + island.warpPlayer(superiorPlayer, islandWarp.getName()); + }); + }, 1L); + } + + private MenuActions() { + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java new file mode 100644 index 0000000000..b7cb7b8df8 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java @@ -0,0 +1,84 @@ +package com.bgsoftware.superiorskyblock.core.menu; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; +import com.bgsoftware.superiorskyblock.api.schematic.Schematic; +import com.bgsoftware.superiorskyblock.api.world.GameSound; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; +import com.bgsoftware.superiorskyblock.core.EnumHelper; +import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandCreationButton; +import org.bukkit.block.Biome; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.Collections; + +public class MenuConfig { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private MenuConfig() { + + } + + public static class IslandCreation implements MenuIslandCreationConfig { + + private final Schematic schematic; + @Nullable + private final IslandCreationButton.Template template; + private final Biome biome; + + public IslandCreation(IslandCreationButton.Template template) { + this(template.getSchematic(), template); + } + + public IslandCreation(Schematic schematic, IslandCreationButton.Template template) { + this.schematic = schematic; + this.template = template; + this.biome = template == null ? EnumHelper.getEnum(Biome.class, plugin.getSettings().getWorlds().getDimensionConfig( + plugin.getSettings().getWorlds().getDefaultWorldDimension()).getBiome()) : template.getBiome(); + } + + @Override + public Schematic getSchematic() { + return this.schematic; + } + + @Override + public GameSound getSound() { + return this.template == null ? null : this.template.getAccessSound(); + } + + @Override + public Collection getCommands() { + return this.template == null ? Collections.emptyList() : this.template.getAccessCommands(); + } + + @Override + public boolean shouldOffsetIslandValue() { + return this.template != null && this.template.isOffset(); + } + + @Override + public BlockOffset getSpawnOffset() { + return this.template == null ? null : this.template.getSpawnOffset(); + } + + @Override + public BigDecimal getBonusWorth() { + return this.template == null ? BigDecimal.ZERO : this.template.getBonusWorth(); + } + + @Override + public BigDecimal getBonusLevel() { + return this.template == null ? BigDecimal.ZERO : this.template.getBonusLevel(); + } + + @Override + public Biome getBiome() { + return this.biome; + } + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java index b05c3ac44c..66d5f6972b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java @@ -6,7 +6,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; @@ -46,7 +46,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { try { BigDecimal newAmount = BigDecimal.valueOf(Double.parseDouble(message)); BankTransaction bankTransaction = island.getIslandBank().depositMoney(clickedPlayer, newAmount); - Menus.MENU_ISLAND_BANK.handleDeposit(clickedPlayer, island, bankTransaction, + MenuActions.handleDeposit(clickedPlayer, island, bankTransaction, getTemplate().successSound, getTemplate().failSound, newAmount); } catch (IllegalArgumentException ex) { Message.INVALID_AMOUNT.send(clickedPlayer, message); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java index c5500629eb..65a356e7a7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java @@ -6,7 +6,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; @@ -46,7 +46,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { try { BigDecimal newAmount = BigDecimal.valueOf(Double.parseDouble(message)); BankTransaction bankTransaction = island.getIslandBank().withdrawMoney(clickedPlayer, newAmount, null); - Menus.MENU_ISLAND_BANK.handleWithdraw(clickedPlayer, island, bankTransaction, + MenuActions.handleWithdraw(clickedPlayer, island, bankTransaction, getTemplate().successSound, getTemplate().failSound, newAmount); } catch (IllegalArgumentException ex) { Message.INVALID_AMOUNT.send(clickedPlayer, message); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java index 71342f2e07..b4ead2a699 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java @@ -6,7 +6,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; @@ -38,7 +38,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { .multiply(getTemplate().depositPercentage); BankTransaction bankTransaction = island.getIslandBank().depositMoney(clickedPlayer, amount); - Menus.MENU_ISLAND_BANK.handleDeposit(clickedPlayer, island, bankTransaction, + MenuActions.handleDeposit(clickedPlayer, island, bankTransaction, getTemplate().successSound, getTemplate().failSound, amount); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java index 2563e16ab4..eea8fc6f17 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java @@ -6,7 +6,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; @@ -38,7 +38,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { .multiply(getTemplate().withdrawValue); BankTransaction bankTransaction = island.getIslandBank().withdrawMoney(clickedPlayer, amount, getTemplate().withdrawCommands); - Menus.MENU_ISLAND_BANK.handleWithdraw(clickedPlayer, island, bankTransaction, + MenuActions.handleWithdraw(clickedPlayer, island, bankTransaction, getTemplate().successSound, getTemplate().failSound, amount); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java index 32d2e834fc..ec0401a4d1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuGlobalWarps; +import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; @@ -24,7 +25,8 @@ public void onButtonClick(InventoryClickEvent clickEvent) { plugin.getCommands().dispatchSubCommand(menuView.getInventoryViewer().asPlayer(), "visit", pagedObject.getOwner().getName()); } else { - Menus.MENU_WARP_CATEGORIES.openMenu(menuView.getInventoryViewer(), menuView, pagedObject); + plugin.getProviders().getMenusProvider().openWarpCategories( + menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), pagedObject); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java index 226d1a2d3c..3c8435f5d7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java @@ -1,12 +1,14 @@ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.MenuActions; +import com.bgsoftware.superiorskyblock.core.menu.MenuConfig; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; @@ -44,8 +46,8 @@ public ItemStack createViewItem() { @Override public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); - Menus.MENU_ISLAND_CREATION.simulateClick(clickedPlayer, menuView.getIslandName(), getTemplate(), - clickEvent.getClick().isRightClick(), menuView); + MenuActions.simulateIslandCreationClick(clickedPlayer, menuView.getIslandName(), + getTemplate().getCreationConfig(), clickEvent.getClick().isRightClick(), menuView); } @Override @@ -137,6 +139,8 @@ public static class Template extends MenuTemplateButtonImpl accessCommands, @Nullable TemplateItem lackPermissionItem, @Nullable List lackPermissionCommands, @@ -192,6 +196,11 @@ public Schematic getSchematic() { public BlockOffset getSpawnOffset() { return spawnOffset; } + + public MenuIslandCreationConfig getCreationConfig() { + return creationConfig; + } + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TopIslandsSelfIslandButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TopIslandsSelfIslandButton.java index b5adff435e..09cce317c4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TopIslandsSelfIslandButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TopIslandsSelfIslandButton.java @@ -85,7 +85,8 @@ public static void onButtonClick(InventoryClickEvent clickEvent, MenuTopIslands. if (Menus.MENU_GLOBAL_WARPS.isVisitorWarps()) { plugin.getCommands().dispatchSubCommand(player, "visit", island.getOwner().getName()); } else { - Menus.MENU_WARP_CATEGORIES.openMenu(menuView.getInventoryViewer(), menuView, island); + plugin.getProviders().getMenusProvider().openWarpCategories( + menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), island); } } else if (plugin.getSettings().isValuesMenu()) { plugin.getMenus().openValues(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), island); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageWarpsButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageWarpsButton.java index 722458b77f..2c0f7759ea 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageWarpsButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryManageWarpsButton.java @@ -1,11 +1,11 @@ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; -import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuWarpCategoryManage; +import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import org.bukkit.event.inventory.InventoryClickEvent; public class WarpCategoryManageWarpsButton extends AbstractMenuViewButton { @@ -17,7 +17,7 @@ private WarpCategoryManageWarpsButton(AbstractMenuTemplateButton { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryPagedObjectButton.java index ea5b75cac4..2d5039609f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpCategoryPagedObjectButton.java @@ -54,7 +54,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { if (menuView.hasManagePerms() && clickEvent.getClick().isRightClick()) { plugin.getMenus().openWarpCategoryManage(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), pagedObject); } else { - Menus.MENU_WARPS.openMenu(menuView.getInventoryViewer(), menuView, pagedObject); + plugin.getMenus().openWarps(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), pagedObject); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java index 1274f5706f..9cfc7d8b2d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; +import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; @@ -32,7 +33,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { menuView.setPreviousMove(false); plugin.getMenus().openWarpManage(clickedPlayer, MenuViewWrapper.fromView(menuView), pagedObject); } else { - Menus.MENU_WARPS.simulateClick(clickedPlayer, menuView.getWarpCategory().getIsland(), pagedObject); + MenuActions.simulateWarpsClick(clickedPlayer, menuView.getWarpCategory().getIsland(), pagedObject); BukkitExecutor.sync(() -> menuView.setPreviousMove(false), 1L); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java index 41b616fcf0..e9da2a0f46 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java @@ -2,13 +2,10 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.GameSoundImpl; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; @@ -21,11 +18,8 @@ import com.bgsoftware.superiorskyblock.core.menu.button.impl.OpenBankLogsButton; import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; -import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.configuration.file.YamlConfiguration; -import java.math.BigDecimal; import java.util.List; public class MenuIslandBank extends AbstractMenu { @@ -44,65 +38,6 @@ public void refreshViews(Island island) { refreshViews(view -> view.getIsland().equals(island)); } - public void handleDeposit(SuperiorPlayer superiorPlayer, Island island, BankTransaction bankTransaction, - @Nullable GameSound successSound, @Nullable GameSound failSound, BigDecimal amount) { - if (bankTransaction.getFailureReason().isEmpty()) { - superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, successSound)); - } else { - superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, failSound)); - - String failureReason = bankTransaction.getFailureReason(); - - if (!failureReason.isEmpty()) { - switch (failureReason) { - case "No permission": - Message.NO_DEPOSIT_PERMISSION.send(superiorPlayer, island.getRequiredPlayerRole(IslandPrivileges.DEPOSIT_MONEY)); - break; - case "Invalid amount": - Message.INVALID_AMOUNT.send(superiorPlayer, Formatters.NUMBER_FORMATTER.format(amount)); - break; - case "Not enough money": - Message.NOT_ENOUGH_MONEY_TO_DEPOSIT.send(superiorPlayer, Formatters.NUMBER_FORMATTER.format(amount)); - break; - case "Exceed bank limit": - Message.BANK_LIMIT_EXCEED.send(superiorPlayer); - break; - default: - Message.DEPOSIT_ERROR.send(superiorPlayer, failureReason); - break; - } - } - } - } - - public void handleWithdraw(SuperiorPlayer superiorPlayer, Island island, BankTransaction bankTransaction, - GameSound successSound, GameSound failSound, BigDecimal amount) { - if (bankTransaction.getFailureReason().isEmpty()) { - superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, successSound)); - } else { - superiorPlayer.runIfOnline(player -> GameSoundImpl.playSound(player, failSound)); - - String failureReason = bankTransaction.getFailureReason(); - - if (!failureReason.isEmpty()) { - switch (failureReason) { - case "No permission": - Message.NO_WITHDRAW_PERMISSION.send(superiorPlayer, island.getRequiredPlayerRole(IslandPrivileges.WITHDRAW_MONEY)); - break; - case "Invalid amount": - Message.INVALID_AMOUNT.send(superiorPlayer, Formatters.NUMBER_FORMATTER.format(amount)); - break; - case "Bank is empty": - Message.ISLAND_BANK_EMPTY.send(superiorPlayer); - break; - default: - Message.WITHDRAW_ERROR.send(superiorPlayer, failureReason); - break; - } - } - } - } - @Nullable public static MenuIslandBank createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("island-bank.yml", diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandChest.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandChest.java index 0ca45e2940..5fb2aad6c9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandChest.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandChest.java @@ -16,7 +16,6 @@ import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandChestPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.layout.PagedMenuLayoutImpl; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; -import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -40,18 +39,6 @@ public void refreshViews(Island island) { refreshViews(view -> view.island.equals(island)); } - public void openMenu(SuperiorPlayer superiorPlayer, @Nullable MenuView previousMenu, Island island) { - if (isSkipOneItem()) { - IslandChest[] islandChest = island.getChest(); - if (islandChest.length == 1) { - islandChest[0].openChest(superiorPlayer); - return; - } - } - - plugin.getMenus().openIslandChest(superiorPlayer, MenuViewWrapper.fromView(previousMenu), island); - } - @Nullable public static MenuIslandChest createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("island-chest.yml", diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java index 1ceb190cf9..9601c45075 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java @@ -7,10 +7,7 @@ import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.GameSoundImpl; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; @@ -21,22 +18,15 @@ import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; -import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; -import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; -import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.block.Biome; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Player; import java.io.File; import java.math.BigDecimal; import java.util.Arrays; -import java.util.List; import java.util.Locale; -import java.util.stream.Collectors; public class MenuIslandCreation extends AbstractMenu { @@ -50,67 +40,6 @@ protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, return new View(superiorPlayer, previousMenuView, this, args); } - public void simulateClick(SuperiorPlayer clickedPlayer, String islandName, String schematic, - boolean isPreviewMode, @Nullable MenuView menuView) { - menuLayout.getButtons().stream() - .filter(button -> IslandCreationButton.class.equals(button.getViewButtonType()) && - ((IslandCreationButton.Template) button).getSchematic().getName().equals(schematic)) - .map(button -> (IslandCreationButton.Template) button) - .findFirst().ifPresent(template -> simulateClick(clickedPlayer, islandName, template, isPreviewMode, menuView)); - } - - public void simulateClick(SuperiorPlayer clickedPlayer, String islandName, - IslandCreationButton.Template template, boolean isPreviewMode, - @Nullable MenuView menuView) { - String schematic = template.getSchematic().getName(); - - // Checking for preview of islands. - if (isPreviewMode) { - Location previewLocation = plugin.getSettings().getPreviewIslands().get(schematic); - if (previewLocation != null) { - plugin.getGrid().startIslandPreview(clickedPlayer, schematic, islandName); - return; - } - } - - Player whoClicked = clickedPlayer.asPlayer(); - - GameSoundImpl.playSound(whoClicked, template.getAccessSound()); - - template.getAccessCommands().forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), - command.replace("%player%", clickedPlayer.getName()))); - - Message.ISLAND_CREATE_PROCCESS_REQUEST.send(clickedPlayer); - - if (menuView != null) - menuView.closeView(); - - Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); - boolean offset = template.isOffset() || - plugin.getSettings().getWorlds().getDimensionConfig(dimension).isSchematicOffset(); - - BlockOffset spawnOffset = template.getSpawnOffset(); - - plugin.getGrid().createIsland(clickedPlayer, schematic, template.getBonusWorth(), - template.getBonusLevel(), template.getBiome(), islandName, offset, spawnOffset); - } - - public void openMenu(SuperiorPlayer superiorPlayer, @Nullable MenuView previousMenu, String islandName) { - if (isSkipOneItem()) { - List schematicButtons = menuLayout.getButtons().stream() - .filter(button -> IslandCreationButton.class.equals(button.getViewButtonType())) - .map(button -> ((IslandCreationButton.Template) button).getSchematic().getName()) - .collect(Collectors.toList()); - - if (schematicButtons.size() == 1) { - simulateClick(superiorPlayer, islandName, schematicButtons.get(0), false, superiorPlayer.getOpenedView()); - return; - } - } - - plugin.getMenus().openIslandCreation(superiorPlayer, MenuViewWrapper.fromView(previousMenu), islandName); - } - @Nullable public static MenuIslandCreation createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("island-creation.yml", diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java index a674d84c29..669e353ede 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java @@ -12,10 +12,8 @@ import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; -import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; -import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.configuration.file.YamlConfiguration; @@ -55,17 +53,6 @@ public void closeViews(Island island) { closeViews(view -> view.getIsland().equals(island)); } - public void openMenu(SuperiorPlayer superiorPlayer, @Nullable MenuView previousMenu, Island island) { - // The warp categories menu should be opened only if A) its enabled B) there are more than 1 categories - if (plugin.getSettings().isWarpCategories() && island.getWarpCategories().size() > 1) { - plugin.getMenus().openWarpCategories(superiorPlayer, MenuViewWrapper.fromView(previousMenu), island); - } else { - WarpCategory warpCategory = island.getWarpCategories().values().stream().findFirst() - .orElseGet(() -> island.createWarpCategory("Default Category")); - Menus.MENU_WARPS.openMenu(superiorPlayer, previousMenu, warpCategory); - } - } - @Nullable public static MenuWarpCategories createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("warp-categories.yml", diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java index 7c2d34847a..750f1331ab 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java @@ -20,10 +20,7 @@ import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; -import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; -import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.warp.WarpIcons; import org.bukkit.Material; @@ -32,10 +29,8 @@ import org.bukkit.inventory.ItemStack; import java.io.File; -import java.math.BigDecimal; import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; public class MenuWarps extends AbstractPagedMenu { @@ -64,49 +59,6 @@ public void closeViews(WarpCategory warpCategory) { closeViews(view -> view.getWarpCategory().equals(warpCategory)); } - public void simulateClick(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp) { - if (!superiorPlayer.hasBypassModeEnabled() && plugin.getSettings().getChargeOnWarp() > 0) { - if (plugin.getProviders().getEconomyProvider().getBalance(superiorPlayer) - .compareTo(BigDecimal.valueOf(plugin.getSettings().getChargeOnWarp())) < 0) { - Message.NOT_ENOUGH_MONEY_TO_WARP.send(superiorPlayer); - return; - } - - plugin.getProviders().getEconomyProvider().withdrawMoney(superiorPlayer, - plugin.getSettings().getChargeOnWarp()); - } - - BukkitExecutor.sync(() -> { - superiorPlayer.runIfOnline(player -> { - MenuView currentView = superiorPlayer.getOpenedView(); - if (currentView == null) { - player.closeInventory(); - } else { - currentView.closeView(); - } - island.warpPlayer(superiorPlayer, islandWarp.getName()); - }); - }, 1L); - } - - public void openMenu(SuperiorPlayer superiorPlayer, @Nullable MenuView previousMenu, WarpCategory warpCategory) { - // We want skip one item to only work if the player can't edit warps, otherwise he - // won't be able to edit them as the menu will get skipped if only one warp exists. - if (isSkipOneItem() && !warpCategory.getIsland().hasPermission(superiorPlayer, IslandPrivileges.SET_WARP)) { - List availableWarps = warpCategory.getIsland().isMember(superiorPlayer) ? warpCategory.getWarps() : - warpCategory.getWarps().stream() - .filter(islandWarp -> !islandWarp.hasPrivateFlag()) - .collect(Collectors.toList()); - - if (availableWarps.size() == 1) { - simulateClick(superiorPlayer, warpCategory.getIsland(), availableWarps.get(0)); - return; - } - } - - plugin.getMenus().openWarps(superiorPlayer, MenuViewWrapper.fromView(previousMenu), warpCategory); - } - @Nullable public static MenuWarps createInstance() { MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("warps.yml", diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java b/src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java index 0b6e995e2d..66722fbf9d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.MenusProvider; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandChest; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; @@ -11,12 +12,18 @@ import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.ISuperiorMenu; +import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; +import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; +import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.io.Files; import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.menu.MenuActions; +import com.bgsoftware.superiorskyblock.core.menu.MenuConfig; import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandCreationButton; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmBan; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmKick; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandCreation; @@ -32,12 +39,19 @@ import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import com.bgsoftware.superiorskyblock.core.menu.view.args.PlayerViewArgs; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.google.common.base.Preconditions; import java.io.File; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; public class MenusProvider_Default implements MenusProvider { + private final Map ISLAND_CREATION_CONFIG_CACHE = new IdentityHashMap<>(); + private final SuperiorSkyblockPlugin plugin; public MenusProvider_Default(SuperiorSkyblockPlugin plugin) { @@ -209,6 +223,14 @@ public void refreshIslandBannedPlayers(Island island) { public void openIslandChest(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); + if (Menus.MENU_ISLAND_CHEST.isSkipOneItem()) { + IslandChest[] islandChest = targetIsland.getChest(); + if (islandChest.length == 1) { + islandChest[0].openChest(targetPlayer); + return; + } + } + Menus.MENU_ISLAND_CHEST.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); } @@ -218,10 +240,37 @@ public void refreshIslandChest(Island island) { Menus.MENU_ISLAND_CHEST.refreshViews(island); } + @Override + public MenuIslandCreationConfig getIslandCreationConfig(Schematic schematic) { + return ISLAND_CREATION_CONFIG_CACHE.computeIfAbsent(schematic, unused -> { + for (MenuTemplateButton button : Menus.MENU_ISLAND_CREATION.getLayout().getButtons()) { + if (IslandCreationButton.class.equals(button.getViewButtonType()) && + ((IslandCreationButton.Template) button).getSchematic().equals(schematic)) { + return ((IslandCreationButton.Template) button).getCreationConfig(); + } + } + + return new MenuConfig.IslandCreation(schematic, null); + }); + } + @Override public void openIslandCreation(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, String islandName) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); + if (Menus.MENU_ISLAND_CREATION.isSkipOneItem()) { + List schematicButtons = Menus.MENU_ISLAND_CREATION.getLayout().getButtons().stream() + .filter(button -> IslandCreationButton.class.equals(button.getViewButtonType())) + .map(button -> ((IslandCreationButton.Template) button).getSchematic()) + .collect(Collectors.toList()); + + if (schematicButtons.size() == 1) { + MenuIslandCreationConfig creationConfig = getIslandCreationConfig(schematicButtons.get(0)); + MenuActions.simulateIslandCreationClick(targetPlayer, islandName, creationConfig, false, targetPlayer.getOpenedView()); + return; + } + } + Menus.MENU_ISLAND_CREATION.createView(targetPlayer, new MenuIslandCreation.Args(islandName), previousMenu); } @@ -442,7 +491,17 @@ public void refreshVisitors(Island island) { public void openWarpCategories(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); - Menus.MENU_WARP_CATEGORIES.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); + + // The warp categories menu should be opened only if: + // A) its enabled + // B) there are more than 1 category + if (plugin.getSettings().isWarpCategories() && targetIsland.getWarpCategories().size() > 1) { + Menus.MENU_WARP_CATEGORIES.createView(targetPlayer, new IslandViewArgs(targetIsland), previousMenu); + } else { + WarpCategory warpCategory = targetIsland.getWarpCategories().values().stream().findFirst() + .orElseGet(() -> targetIsland.createWarpCategory("Default Category")); + openWarps(targetPlayer, previousMenu, warpCategory); + } } @Override @@ -501,6 +560,21 @@ public void refreshWarpManage(IslandWarp islandWarp) { public void openWarps(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, WarpCategory targetCategory) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); Preconditions.checkNotNull(targetCategory, "targetCategory parameter cannot be null."); + + // We want skip one item to only work if the player can't edit warps, otherwise he + // won't be able to edit them as the menu will get skipped if only one warp exists. + if (Menus.MENU_WARPS.isSkipOneItem() && !targetCategory.getIsland().hasPermission(targetPlayer, IslandPrivileges.SET_WARP)) { + List availableWarps = targetCategory.getIsland().isMember(targetPlayer) ? targetCategory.getWarps() : + targetCategory.getWarps().stream() + .filter(islandWarp -> !islandWarp.hasPrivateFlag()) + .collect(Collectors.toList()); + + if (availableWarps.size() == 1) { + MenuActions.simulateWarpsClick(targetPlayer, targetCategory.getIsland(), availableWarps.get(0)); + return; + } + } + Menus.MENU_WARPS.createView(targetPlayer, new MenuWarps.Args(targetCategory), previousMenu); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index 3ba4db55e2..2c527d9b99 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -415,17 +415,22 @@ public boolean hasActiveCreateRequest(SuperiorPlayer superiorPlayer) { @Override public void startIslandPreview(SuperiorPlayer superiorPlayer, String schemName, String islandName) { - Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(schemName, "schemName parameter cannot be null."); + startIslandPreview(superiorPlayer, plugin.getSchematics().getSchematic(schemName), islandName); + } + + public void startIslandPreview(SuperiorPlayer superiorPlayer, Schematic schematic, String islandName) { + Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); + Preconditions.checkNotNull(schematic, "schematic parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); - Location previewLocation = plugin.getSettings().getPreviewIslands().get(schemName.toLowerCase(Locale.ENGLISH)); + Location previewLocation = plugin.getSettings().getPreviewIslands().get(schematic.getName().toLowerCase(Locale.ENGLISH)); if (previewLocation != null && previewLocation.getWorld() != null) { superiorPlayer.teleport(previewLocation, result -> { if (result) { - this.islandPreviews.startIslandPreview(new SIslandPreview(superiorPlayer, previewLocation, schemName, islandName)); + this.islandPreviews.startIslandPreview(new SIslandPreview(superiorPlayer, previewLocation, schematic, islandName)); BukkitExecutor.ensureMain(() -> superiorPlayer.runIfOnline(player -> player.setGameMode(GameMode.SPECTATOR))); - Message.ISLAND_PREVIEW_START.send(superiorPlayer, schemName); + Message.ISLAND_PREVIEW_START.send(superiorPlayer, schematic.getName()); } }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java b/src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java index 618b188f32..7d7436ac9d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java @@ -2,8 +2,10 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.IslandPreview; +import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; +import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import com.google.common.base.Preconditions; @@ -16,10 +18,10 @@ public class SIslandPreview implements IslandPreview { private final SuperiorPlayer superiorPlayer; private final Location previewLocation; - private final String schematic; + private final Schematic schematic; private final String islandName; - public SIslandPreview(SuperiorPlayer superiorPlayer, Location previewLocation, String schematic, String islandName) { + public SIslandPreview(SuperiorPlayer superiorPlayer, Location previewLocation, Schematic schematic, String islandName) { this.superiorPlayer = superiorPlayer; this.previewLocation = previewLocation; this.schematic = schematic; @@ -67,20 +69,19 @@ public Location getLocation(Location location) { @Override public String getSchematic() { - return schematic; + return this.schematic.getName(); } @Override public String getIslandName() { - return islandName; + return this.islandName; } @Override public void handleConfirm() { - Menus.MENU_ISLAND_CREATION.simulateClick(superiorPlayer, islandName, schematic, false, superiorPlayer.getOpenedView()); - Player player = superiorPlayer.asPlayer(); - assert player != null; - PlayerChat.remove(player); + MenuIslandCreationConfig creationConfig = plugin.getProviders().getMenusProvider().getIslandCreationConfig(this.schematic); + MenuActions.simulateIslandCreationClick(superiorPlayer, islandName, creationConfig, false, superiorPlayer.getOpenedView()); + superiorPlayer.runIfOnline(PlayerChat::remove); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdDeposit.java b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdDeposit.java index 0c65887b45..feaca4fcc0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdDeposit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdDeposit.java @@ -7,7 +7,7 @@ import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; -import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -74,7 +74,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ } BankTransaction transaction = island.getIslandBank().depositMoney(superiorPlayer, amount); - Menus.MENU_ISLAND_BANK.handleDeposit(superiorPlayer, island, transaction, null, null, amount); + MenuActions.handleDeposit(superiorPlayer, island, transaction, null, null, amount); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdWithdraw.java b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdWithdraw.java index 0c5472562f..5300595e4d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdWithdraw.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdWithdraw.java @@ -7,7 +7,7 @@ import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; -import com.bgsoftware.superiorskyblock.core.menu.Menus; +import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -73,7 +73,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ } BankTransaction transaction = island.getIslandBank().withdrawMoney(superiorPlayer, amount, null); - Menus.MENU_ISLAND_BANK.handleWithdraw(superiorPlayer, island, transaction, null, null, amount); + MenuActions.handleWithdraw(superiorPlayer, island, transaction, null, null, amount); } @Override From ca31767886628634cfc9865342938e8dccc77741 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 5 Apr 2025 12:03:10 +0300 Subject: [PATCH 106/600] Potential fix for NPE when creating islands (#2396) --- .../core/menu/button/impl/IslandCreationButton.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java index 3c8435f5d7..6e6634abaa 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java @@ -139,7 +139,7 @@ public static class Template extends MenuTemplateButtonImpl accessCommands, @@ -158,6 +158,7 @@ public static class Template extends MenuTemplateButtonImpl Date: Sat, 12 Apr 2025 13:50:27 +0300 Subject: [PATCH 107/600] Add debug messages to null hand items in BlockPlaceEvent (#2402) --- .../superiorskyblock/listener/StackedBlocksListener.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java index f03fe1c93d..d0c4a44de1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.StackedBlocksDepositMenu; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; @@ -78,11 +79,15 @@ private void onStackedBlockPlace(GameEvent e) { PlayerHand usedHand = e.getArgs().usedHand; ItemStack inHand = e.getArgs().usedItem; + if (inHand == null) { + Log.error("BlockPlaceEvent with null hand item:", usedHand); + throw new RuntimeException("BlockPlaceEvent with null hand item"); + } + // We do not stack blocks when the hand items has a name or a lore. if (inHand.hasItemMeta() && (inHand.getItemMeta().hasDisplayName() || inHand.getItemMeta().hasLore())) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); InteractionResult interactionResult = this.stackedBlocksInteractionService.get().handleStackedBlockPlace( From 13aee6b981fbd8e76a0d16138ac96cab0410010e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 12 Apr 2025 15:12:12 +0300 Subject: [PATCH 108/600] Fixed issues with custom sign lines in schematics (#2405) --- .../v1_20_3/world/WorldEditSessionImpl.java | 50 ++++---- .../v1_20_4/world/WorldEditSessionImpl.java | 50 ++++---- .../nms/v1_21/world/WorldEditSessionImpl.java | 51 ++++---- .../v1_21_3/world/WorldEditSessionImpl.java | 50 ++++---- .../v1_21_4/world/WorldEditSessionImpl.java | 50 ++++---- .../core/schematic/SchematicBlock.java | 113 +++++++++++++----- 6 files changed, 196 insertions(+), 168 deletions(-) diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java index 2e3e1d4fb1..df4743a1f8 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -20,6 +19,7 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.gson.JsonParseException; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -231,32 +231,8 @@ public void finish(Island island) { blockEntityCompound.putInt("y", blockPos.getY()); blockEntityCompound.putInt("z", blockPos.getZ()); - Component[] signLines = new Component[4]; - Arrays.fill(signLines, Component.empty()); - boolean hasAnySignLines = false; - // We try to convert old text sign lines - for (int i = 1; i <= 4; ++i) { - if (blockEntityCompound.contains("SSB.Text" + i)) { - String signLine = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; - hasAnySignLines = true; - } - } else { - String signLine = blockEntityCompound.getString("Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromJSON(signLine); - hasAnySignLines = true; - } - } - - } - - if (hasAnySignLines) { - SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); - } + applySignTextLines(blockEntityCompound, "front_text"); + applySignTextLines(blockEntityCompound, "back_text"); BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); if (worldBlockEntity != null) @@ -292,6 +268,26 @@ private boolean isValidPosition(BlockPos blockPos) { blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); } + private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { + if (blockEntityCompound.contains(key)) { + net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); + Component[] frontTextLines = new Component[4]; + Arrays.fill(frontTextLines, Component.empty()); + int i = 0; + for (net.minecraft.nbt.Tag lineTag : frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING)) { + try { + frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); + } catch (JsonParseException error) { + frontTextLines[i++] = CraftChatMessage.fromString(lineTag.getAsString())[0]; + } + } + + SignText signText = new SignText(frontTextLines, frontTextLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); + } + } + private class ChunkData { private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java index bbb652f9e8..ea22e2757d 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -20,6 +19,7 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.gson.JsonParseException; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -231,32 +231,8 @@ public void finish(Island island) { blockEntityCompound.putInt("y", blockPos.getY()); blockEntityCompound.putInt("z", blockPos.getZ()); - Component[] signLines = new Component[4]; - Arrays.fill(signLines, Component.empty()); - boolean hasAnySignLines = false; - // We try to convert old text sign lines - for (int i = 1; i <= 4; ++i) { - if (blockEntityCompound.contains("SSB.Text" + i)) { - String signLine = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; - hasAnySignLines = true; - } - } else { - String signLine = blockEntityCompound.getString("Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromJSON(signLine); - hasAnySignLines = true; - } - } - - } - - if (hasAnySignLines) { - SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); - } + applySignTextLines(blockEntityCompound, "front_text"); + applySignTextLines(blockEntityCompound, "back_text"); BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); if (worldBlockEntity != null) @@ -292,6 +268,26 @@ private boolean isValidPosition(BlockPos blockPos) { blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); } + private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { + if (blockEntityCompound.contains(key)) { + net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); + Component[] frontTextLines = new Component[4]; + Arrays.fill(frontTextLines, Component.empty()); + int i = 0; + for (net.minecraft.nbt.Tag lineTag : frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING)) { + try { + frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); + } catch (JsonParseException error) { + frontTextLines[i++] = CraftChatMessage.fromString(lineTag.getAsString())[0]; + } + } + + SignText signText = new SignText(frontTextLines, frontTextLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); + } + } + private class ChunkData { private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java index 666db728d1..01e9d9722b 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -20,6 +19,7 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.gson.JsonParseException; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -47,7 +47,6 @@ import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.ticks.ProtoChunkTicks; -import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; @@ -230,32 +229,8 @@ public void finish(Island island) { blockEntityCompound.putInt("y", blockPos.getY()); blockEntityCompound.putInt("z", blockPos.getZ()); - Component[] signLines = new Component[4]; - Arrays.fill(signLines, Component.empty()); - boolean hasAnySignLines = false; - // We try to convert old text sign lines - for (int i = 1; i <= 4; ++i) { - if (blockEntityCompound.contains("SSB.Text" + i)) { - String signLine = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; - hasAnySignLines = true; - } - } else { - String signLine = blockEntityCompound.getString("Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromJSON(signLine); - hasAnySignLines = true; - } - } - - } - - if (hasAnySignLines) { - SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); - } + applySignTextLines(blockEntityCompound, "front_text"); + applySignTextLines(blockEntityCompound, "back_text"); BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); if (worldBlockEntity != null) @@ -291,6 +266,26 @@ private boolean isValidPosition(BlockPos blockPos) { blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); } + private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { + if (blockEntityCompound.contains(key)) { + net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); + Component[] frontTextLines = new Component[4]; + Arrays.fill(frontTextLines, Component.empty()); + int i = 0; + for (net.minecraft.nbt.Tag lineTag : frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING)) { + try { + frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); + } catch (JsonParseException error) { + frontTextLines[i++] = CraftChatMessage.fromString(lineTag.getAsString())[0]; + } + } + + SignText signText = new SignText(frontTextLines, frontTextLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); + } + } + private class ChunkData { private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java index 4a06838b4d..3e46ee690c 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -20,6 +19,7 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.gson.JsonParseException; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -229,32 +229,8 @@ public void finish(Island island) { blockEntityCompound.putInt("y", blockPos.getY()); blockEntityCompound.putInt("z", blockPos.getZ()); - Component[] signLines = new Component[4]; - Arrays.fill(signLines, Component.empty()); - boolean hasAnySignLines = false; - // We try to convert old text sign lines - for (int i = 1; i <= 4; ++i) { - if (blockEntityCompound.contains("SSB.Text" + i)) { - String signLine = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; - hasAnySignLines = true; - } - } else { - String signLine = blockEntityCompound.getString("Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromJSON(signLine); - hasAnySignLines = true; - } - } - - } - - if (hasAnySignLines) { - SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); - } + applySignTextLines(blockEntityCompound, "front_text"); + applySignTextLines(blockEntityCompound, "back_text"); BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); if (worldBlockEntity != null) @@ -290,6 +266,26 @@ private boolean isValidPosition(BlockPos blockPos) { blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); } + private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { + if (blockEntityCompound.contains(key)) { + net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); + Component[] frontTextLines = new Component[4]; + Arrays.fill(frontTextLines, Component.empty()); + int i = 0; + for (net.minecraft.nbt.Tag lineTag : frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING)) { + try { + frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); + } catch (JsonParseException error) { + frontTextLines[i++] = CraftChatMessage.fromString(lineTag.getAsString())[0]; + } + } + + SignText signText = new SignText(frontTextLines, frontTextLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); + } + } + private class ChunkData { private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java index fa89b64c06..36052c82c1 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -20,6 +19,7 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.gson.JsonParseException; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -229,32 +229,8 @@ public void finish(Island island) { blockEntityCompound.putInt("y", blockPos.getY()); blockEntityCompound.putInt("z", blockPos.getZ()); - Component[] signLines = new Component[4]; - Arrays.fill(signLines, Component.empty()); - boolean hasAnySignLines = false; - // We try to convert old text sign lines - for (int i = 1; i <= 4; ++i) { - if (blockEntityCompound.contains("SSB.Text" + i)) { - String signLine = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; - hasAnySignLines = true; - } - } else { - String signLine = blockEntityCompound.getString("Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromJSON(signLine); - hasAnySignLines = true; - } - } - - } - - if (hasAnySignLines) { - SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); - } + applySignTextLines(blockEntityCompound, "front_text"); + applySignTextLines(blockEntityCompound, "back_text"); BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); if (worldBlockEntity != null) @@ -290,6 +266,26 @@ private boolean isValidPosition(BlockPos blockPos) { blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); } + private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { + if (blockEntityCompound.contains(key)) { + net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); + Component[] frontTextLines = new Component[4]; + Arrays.fill(frontTextLines, Component.empty()); + int i = 0; + for (net.minecraft.nbt.Tag lineTag : frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING)) { + try { + frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); + } catch (JsonParseException error) { + frontTextLines[i++] = CraftChatMessage.fromString(lineTag.getAsString())[0]; + } + } + + SignText signText = new SignText(frontTextLines, frontTextLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); + } + } + private class ChunkData { private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java index 4a079a0e42..429602348b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java @@ -7,14 +7,24 @@ import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; +import com.bgsoftware.superiorskyblock.tag.StringTag; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.event.inventory.InventoryType; +import java.util.Collections; +import java.util.function.BiConsumer; + public class SchematicBlock { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final BiConsumer SIGN_REPLACE_METHOD = ServerVersion.isAtLeast(ServerVersion.v1_20) ? + SchematicBlock::backFrontSignLinesReplace : SchematicBlock::legacySignLinesReplace; + + private static final String SIGN_ID = ServerVersion.isLegacy() ? "Sign" : "minecraft:sign"; + private static final String CHEST_ID = ServerVersion.isLegacy() ? "Chest" : "minecraft:chest"; + private final Location location; private final int blockId; @Nullable @@ -70,7 +80,8 @@ public void doPrePlace(Island island) { if (originalTileEntity == null) return; - this.tileEntityData = new CompoundTag(originalTileEntity); + + this.tileEntityData = CompoundTag.fromNBT(originalTileEntity.toNBT()); String id = this.tileEntityData.getString("id"); if (id == null) { @@ -78,32 +89,9 @@ public void doPrePlace(Island island) { throw new RuntimeException("Detected tile-entity data with no 'id' key."); } - if (id.equalsIgnoreCase(ServerVersion.isLegacy() ? "Sign" : "minecraft:sign")) { - boolean needSignFormat = false; - for (int i = 1; i <= 4; i++) { - boolean isDefaultSignLine = false; - String line; - - if ((i - 1) >= plugin.getSettings().getDefaultSign().size()) { - line = this.tileEntityData.getString("Text" + i); - } else { - line = plugin.getSettings().getDefaultSign().get(i - 1); - if (ServerVersion.isAtLeast(ServerVersion.v1_17)) { - isDefaultSignLine = true; - needSignFormat = true; - } - } - - if (line != null) { - this.tileEntityData.setString((isDefaultSignLine ? "SSB.Text" : "Text") + i, line - .replace("{player}", island.getOwner().getName()) - .replace("{island}", island.getName().isEmpty() ? island.getOwner().getName() : island.getName()) - ); - } - } - if (needSignFormat) - this.tileEntityData.setByte("SSB.HasSignLines", (byte) 1); - } else if (id.equalsIgnoreCase(ServerVersion.isLegacy() ? "Chest" : "minecraft:chest")) { + if (id.equalsIgnoreCase(SIGN_ID)) { + SIGN_REPLACE_METHOD.accept(this.tileEntityData, island); + } else if (id.equalsIgnoreCase(CHEST_ID)) { if (plugin.getSettings().getDefaultContainers().isEnabled()) { String inventoryType = this.tileEntityData.getString("inventoryType"); if (inventoryType != null) { @@ -120,11 +108,11 @@ public void doPrePlace(Island island) { } public boolean shouldPostPlace() { - return this.tileEntityData != null && (this.tileEntityData.containsKey("Text1") || - this.tileEntityData.containsKey("Text2") || - this.tileEntityData.containsKey("Text3") || - this.tileEntityData.containsKey("Text4") - ); + if (this.tileEntityData == null) + return false; + + String id = this.tileEntityData.getString("id"); + return id != null && id.equalsIgnoreCase(SIGN_ID); } public void doPostPlace(Island island) { @@ -135,6 +123,67 @@ public void doPostPlace(Island island) { } } + private static void backFrontSignLinesReplace(CompoundTag tileEntityData, Island island) { + CompoundTag frontText = tileEntityData.getCompound("front_text"); + CompoundTag backText = tileEntityData.getCompound("back_text"); + + ListTag frontTextMessages = frontText.getList("messages"); + ListTag backTextMessages = backText.getList("messages"); + ListTag newFrontTextMessages = new ListTag(StringTag.class, Collections.emptyList()); + ListTag newBackTextMessages = new ListTag(StringTag.class, Collections.emptyList()); + + for (int i = 0; i < 8; ++i) { + ListTag messages = i < 4 ? frontTextMessages : backTextMessages; + ListTag newMessages = i < 4 ? newFrontTextMessages : newBackTextMessages; + + int realIndex = i % 4; + + String line; + if (i < plugin.getSettings().getDefaultSign().size()) { + line = plugin.getSettings().getDefaultSign().get(i); + } else { + line = ((StringTag) messages.getValue().get(realIndex)).getValue(); + } + + line = line.replace("{player}", island.getOwner().getName()) + .replace("{island}", island.getName().isEmpty() ? island.getOwner().getName() : island.getName()); + + newMessages.addTag(new StringTag(line)); + } + + frontText.setTag("messages", newFrontTextMessages); + backText.setTag("messages", newBackTextMessages); + } + + private static void legacySignLinesReplace(CompoundTag tileEntityData, Island island) { + boolean needSignFormat = false; + + for (int i = 1; i <= 4; i++) { + boolean isDefaultSignLine = false; + String line; + + if ((i - 1) >= plugin.getSettings().getDefaultSign().size()) { + line = tileEntityData.getString("Text" + i); + } else { + line = plugin.getSettings().getDefaultSign().get(i - 1); + if (ServerVersion.isAtLeast(ServerVersion.v1_17)) { + isDefaultSignLine = true; + needSignFormat = true; + } + } + + if (line != null) { + tileEntityData.setString((isDefaultSignLine ? "SSB.Text" : "Text") + i, line + .replace("{player}", island.getOwner().getName()) + .replace("{island}", island.getName().isEmpty() ? island.getOwner().getName() : island.getName()) + ); + } + } + + if (needSignFormat) + tileEntityData.setByte("SSB.HasSignLines", (byte) 1); + } + public static class Extra { @Nullable From 9830a7f566a14a6a83c7e15da9496ec5ae9d4fb3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 13 Apr 2025 12:02:17 +0300 Subject: [PATCH 109/600] Fixed legacy signs not working due to recent fix --- .../v1_20_3/world/WorldEditSessionImpl.java | 30 +++++++++++++++++++ .../v1_20_4/world/WorldEditSessionImpl.java | 30 +++++++++++++++++++ .../nms/v1_21/world/WorldEditSessionImpl.java | 30 +++++++++++++++++++ .../v1_21_3/world/WorldEditSessionImpl.java | 30 +++++++++++++++++++ .../v1_21_4/world/WorldEditSessionImpl.java | 30 +++++++++++++++++++ .../core/schematic/SchematicBlock.java | 10 +++---- 6 files changed, 155 insertions(+), 5 deletions(-) diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java index df4743a1f8..e4b47a104d 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -233,6 +234,7 @@ public void finish(Island island) { applySignTextLines(blockEntityCompound, "front_text"); applySignTextLines(blockEntityCompound, "back_text"); + convertLegacySignTextLines(blockEntityCompound); BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); if (worldBlockEntity != null) @@ -288,6 +290,34 @@ private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntity } } + private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + private class ChunkData { private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java index ea22e2757d..08df1f8f27 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -233,6 +234,7 @@ public void finish(Island island) { applySignTextLines(blockEntityCompound, "front_text"); applySignTextLines(blockEntityCompound, "back_text"); + convertLegacySignTextLines(blockEntityCompound); BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); if (worldBlockEntity != null) @@ -288,6 +290,34 @@ private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntity } } + private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + private class ChunkData { private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java index 01e9d9722b..5be673782e 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -231,6 +232,7 @@ public void finish(Island island) { applySignTextLines(blockEntityCompound, "front_text"); applySignTextLines(blockEntityCompound, "back_text"); + convertLegacySignTextLines(blockEntityCompound); BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); if (worldBlockEntity != null) @@ -286,6 +288,34 @@ private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntity } } + private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + private class ChunkData { private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java index 3e46ee690c..1d490d1207 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -231,6 +232,7 @@ public void finish(Island island) { applySignTextLines(blockEntityCompound, "front_text"); applySignTextLines(blockEntityCompound, "back_text"); + convertLegacySignTextLines(blockEntityCompound); BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); if (worldBlockEntity != null) @@ -286,6 +288,34 @@ private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntity } } + private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + private class ChunkData { private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java index 36052c82c1..c57ec04948 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; @@ -231,6 +232,7 @@ public void finish(Island island) { applySignTextLines(blockEntityCompound, "front_text"); applySignTextLines(blockEntityCompound, "back_text"); + convertLegacySignTextLines(blockEntityCompound); BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); if (worldBlockEntity != null) @@ -286,6 +288,34 @@ private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntity } } + private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + private class ChunkData { private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java index 429602348b..65afef3268 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java @@ -13,15 +13,11 @@ import org.bukkit.event.inventory.InventoryType; import java.util.Collections; -import java.util.function.BiConsumer; public class SchematicBlock { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final BiConsumer SIGN_REPLACE_METHOD = ServerVersion.isAtLeast(ServerVersion.v1_20) ? - SchematicBlock::backFrontSignLinesReplace : SchematicBlock::legacySignLinesReplace; - private static final String SIGN_ID = ServerVersion.isLegacy() ? "Sign" : "minecraft:sign"; private static final String CHEST_ID = ServerVersion.isLegacy() ? "Chest" : "minecraft:chest"; @@ -90,7 +86,11 @@ public void doPrePlace(Island island) { } if (id.equalsIgnoreCase(SIGN_ID)) { - SIGN_REPLACE_METHOD.accept(this.tileEntityData, island); + if (this.tileEntityData.containsKey("front_text")) { + backFrontSignLinesReplace(this.tileEntityData, island); + } else { + legacySignLinesReplace(this.tileEntityData, island); + } } else if (id.equalsIgnoreCase(CHEST_ID)) { if (plugin.getSettings().getDefaultContainers().isEnabled()) { String inventoryType = this.tileEntityData.getString("inventoryType"); From 8df1a990ce8be197145d2ec1398f064f18f815db Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 13 Apr 2025 12:51:42 +0300 Subject: [PATCH 110/600] Adds support to 1.21.5 --- NMS/v1_21_5/build.gradle | 38 ++ .../nms/v1_21_5/NMSAlgorithmsImpl.java | 285 +++++++++ .../nms/v1_21_5/NMSChunksImpl.java | 579 ++++++++++++++++++ .../nms/v1_21_5/NMSDragonFightImpl.java | 118 ++++ .../nms/v1_21_5/NMSEntitiesImpl.java | 52 ++ .../nms/v1_21_5/NMSHologramsImpl.java | 188 ++++++ .../nms/v1_21_5/NMSPlayersImpl.java | 172 ++++++ .../nms/v1_21_5/NMSTagsImpl.java | 197 ++++++ .../nms/v1_21_5/NMSUtils.java | 509 +++++++++++++++ .../nms/v1_21_5/NMSWorldImpl.java | 420 +++++++++++++ .../nms/v1_21_5/crops/CropsBlockEntity.java | 102 +++ .../crops/CropsTickingBlockEntity.java | 31 + .../nms/v1_21_5/crops/CropsTickingMethod.java | 159 +++++ .../nms/v1_21_5/dragon/DragonUtils.java | 37 ++ .../dragon/EndWorldEndDragonFightHandler.java | 48 ++ .../v1_21_5/dragon/IslandEndDragonFight.java | 212 +++++++ .../dragon/IslandEntityEnderDragon.java | 103 ++++ .../nms/v1_21_5/dragon/SpikesCache.java | 190 ++++++ .../generator/IslandsGeneratorImpl.java | 67 ++ .../menu/MenuBrewingStandBlockEntity.java | 24 + .../menu/MenuDispenserBlockEntity.java | 24 + .../v1_21_5/menu/MenuFurnaceBlockEntity.java | 24 + .../v1_21_5/menu/MenuHopperBlockEntity.java | 26 + .../TickingSpawnerBlockEntityNotifier.java | 57 ++ .../v1_21_5/trial/IslandPlayerDetector.java | 53 ++ .../vibration/IslandVibrationUser.java | 90 +++ .../nms/v1_21_5/world/ChunkReaderImpl.java | 241 ++++++++ .../nms/v1_21_5/world/KeyBlocksCache.java | 32 + .../nms/v1_21_5/world/PropertiesMapper.java | 85 +++ .../v1_21_5/world/WorldEditSessionImpl.java | 379 ++++++++++++ build.gradle | 2 +- settings.gradle | 3 +- 32 files changed, 4545 insertions(+), 2 deletions(-) create mode 100644 NMS/v1_21_5/build.gradle create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSDragonFightImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSEntitiesImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSHologramsImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSPlayersImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsBlockEntity.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingBlockEntity.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingMethod.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/DragonUtils.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndWorldEndDragonFightHandler.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEndDragonFight.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/SpikesCache.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/generator/IslandsGeneratorImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuBrewingStandBlockEntity.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuDispenserBlockEntity.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuFurnaceBlockEntity.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuHopperBlockEntity.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/spawners/TickingSpawnerBlockEntityNotifier.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/vibration/IslandVibrationUser.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java diff --git a/NMS/v1_21_5/build.gradle b/NMS/v1_21_5/build.gradle new file mode 100644 index 0000000000..b4f455cdc5 --- /dev/null +++ b/NMS/v1_21_5/build.gradle @@ -0,0 +1,38 @@ +plugins { + id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } +} + +group 'NMS:v1_21_5' + +dependencies { + paperweight.paperDevBundle("1.21.5-R0.1-SNAPSHOT") + compileOnly project(":NMS:Spigot-1_20_3") + compileOnly project(":NMS:Paper-1_20_3") + compileOnly project(":API") + compileOnly rootProject +} + +shadowJar { + archiveFileName = "${project.name}-exclude.jar" +} + +assemble { + dependsOn(reobfJar) +} + +tasks { + reobfJar { + File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") + outputJar.set(layout.buildDirectory.file(outputFile.getPath())) + } +} + +if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java new file mode 100644 index 0000000000..b41990f17c --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java @@ -0,0 +1,285 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; +import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; +import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.menu.MenuBrewingStandBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.menu.MenuDispenserBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.menu.MenuFurnaceBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.KeyBlocksCache; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; +import io.papermc.paper.chat.ChatRenderer; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.TextReplacementConfig; +import net.minecraft.SharedConstants; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.Container; +import net.minecraft.world.entity.item.FallingBlockEntity; +import net.minecraft.world.entity.vehicle.AbstractMinecart; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; +import org.bukkit.command.defaults.BukkitCommand; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftFallingBlock; +import org.bukkit.craftbukkit.entity.CraftMinecart; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffect; +import org.jetbrains.annotations.NotNull; + +import java.util.EnumMap; +import java.util.function.BiFunction; + +public class NMSAlgorithmsImpl implements NMSAlgorithms { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final Multimap EMPTY_ATTRIBUTES_MAP = + MultimapBuilder.hashKeys().hashSetValues().build(); + + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); + + static { + MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); + } + + private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { + @Override + public byte[] processClass(byte[] classBytes, String path) { + return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); + } + }; + + @Override + public void registerCommand(BukkitCommand command) { + ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); + } + + @Override + public String parseSignLine(String original) { + return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); + } + + @Override + public int getCombinedId(Location location) { + org.bukkit.World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return 0; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(wrapper.getHandle()); + } + return Block.getId(blockState); + } + + @Override + public int getCombinedId(Material material, byte data) { + BlockState blockState; + + if (data == 0) { + Block block = CraftMagicNumbers.getBlock(material); + if (block == null) + return -1; + blockState = block.defaultBlockState(); + } else { + blockState = CraftMagicNumbers.getBlock(material, data); + } + + return blockState == null ? -1 : Block.getId(blockState); + } + + @Override + public int compareMaterials(Material o1, Material o2) { + int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); + int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); + return Integer.compare(firstMaterial, secondMaterial); + } + + @Override + public short getBlockDataValue(org.bukkit.block.BlockState blockState) { + BlockData blockData = blockState.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + BlockData blockData = block.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getMaxBlockDataValue(Material material) { + if (!material.isBlock()) + return 0; + + BlockData blockData = Bukkit.createBlockData(material); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); + } + + @Override + public Key getBlockKey(int combinedId) { + Block block = Block.stateById(combinedId).getBlock(); + return KeyBlocksCache.getBlockKey(block); + } + + @Override + public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { + AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); + Block block = minecart.getDisplayBlockState().getBlock(); + return KeyBlocksCache.getBlockKey(block); + } + + @Override + public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { + FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); + Block block = fallingBlock.getBlockState().getBlock(); + return KeyBlocksCache.getBlockKey(block); + } + + @Override + public void setCustomModel(ItemMeta itemMeta, int customModel) { + itemMeta.setCustomModelData(customModel); + } + + @Override + public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { + if (!potionMeta.hasCustomEffects()) + potionMeta.setColor(potionEffect.getType().getColor()); + potionMeta.addCustomEffect(potionEffect, true); + } + + @Override + public String getMinecraftKey(ItemStack itemStack) { + return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); + } + + @Override + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.setEnchantmentGlintOverride(true); + } + + @Nullable + @Override + public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { + MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); + return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); + } + + @Override + public int getMaxWorldSize() { + return Bukkit.getMaxWorldSize(); + } + + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + + @Override + public int getDataVersion() { + return SharedConstants.getCurrentVersion().getDataVersion().getVersion(); + } + + @Override + public ClassProcessor getClassProcessor() { + return CLASS_PROCESSOR; + } + + @Override + public void handlePaperChatRenderer(Object event) { + if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) + return; + + ChatRenderer originalRenderer = asyncChatEvent.renderer(); + asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); + } + + @Override + public void hideAttributes(ItemMeta itemMeta) { + itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); + } + + private interface MenuCreator extends BiFunction { + } + + private static class ChatRendererWrapper { + + private static final String MESSAGE_PLACEHOLDER = "{message}"; + private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = + net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); + + private final ChatRenderer renderer = new ChatRenderer() { + @Override + public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, + net.kyori.adventure.text.@NotNull Component sourceDisplayName, + net.kyori.adventure.text.@NotNull Component message, + @NotNull Audience viewer) { + String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer + .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); + Island island = superiorPlayer.getIsland(); + + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( + Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) + .replaceText(TextReplacementConfig.builder() + .matchLiteral(MESSAGE_PLACEHOLDER) + .replacement(message) + .build()); + } + }; + + private final ChatRenderer originalRenderer; + + public ChatRendererWrapper(ChatRenderer originalRenderer) { + this.originalRenderer = originalRenderer; + } + + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java new file mode 100644 index 0000000000..2115f8785c --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java @@ -0,0 +1,579 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.core.CalculatedChunk; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Counter; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.bgsoftware.superiorskyblock.nms.NMSChunks; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.crops.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.crops.CropsTickingMethod; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; +import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.BitStorage; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.SlabType; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.phys.AABB; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.entity.CraftEntityType; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.generator.ChunkGenerator; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +public class NMSChunksImpl implements NMSChunks { + + private final SuperiorSkyblockPlugin plugin; + + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + KeyBlocksCache.cacheAllBlocks(); + CropsTickingMethod.register(); + } + + @Override + public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, + Collection playersToUpdate) { + if (chunkPositions.isEmpty()) + return; + + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); + + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); + + ChunkPos chunkPos = levelChunk.getPos(); + + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + LevelChunkSection currentSection = chunkSections[i]; + if (currentSection != null) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); + } + } + + levelChunk.markUnsaved(); + + ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); + ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( + levelChunk, levelChunk.level.getLightEngine(), null, null); + + playersToUpdate.forEach(player -> { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + serverPlayer.connection.send(forgetLevelChunkPacket); + serverPlayer.connection.send(mapChunkPacket); + }); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + + Codec>> biomesCodec = PalettedContainer.codecRW( + biomesRegistry.asHolderIdMap(), + biomesRegistry.holderByNameCodec(), + PalettedContainer.Strategy.SECTION_BIOMES, + biomesRegistry.getOrThrow(Biomes.PLAINS) + ); + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); + Tag biomesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = unloadedChunkCompound.getSections(); + + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); + } + + @Override + public void onFinish() { + // Do nothing. + } + }); + } + + @Override + public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { + if (chunkPositions.isEmpty()) + return; + + chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), + chunkPosition.getX(), chunkPosition.getZ(), false)); + + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); + + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + chunkSections[i] = new LevelChunkSection(biomesRegistry); + } + + removeEntities(levelChunk); + removeBlockEntities(levelChunk); + removeBlocks(levelChunk); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + Codec> blocksCodec = PalettedContainer.codecRW( + Block.BLOCK_STATE_REGISTRY, + BlockState.CODEC, + PalettedContainer.Strategy.SECTION_STATES, + Blocks.AIR.defaultBlockState()); + + ListTag tileEntities = new ListTag(); + + unloadedChunkCompound.setEntities(new ListTag()); + unloadedChunkCompound.setBlockEntities(tileEntities); + + if (serverLevel.generator instanceof IslandsGenerator) { + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); + Tag blockStatesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = unloadedChunkCompound.getSections(); + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); + } else { + ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); + + try { + NMSUtils.buildSurfaceForChunk(serverLevel, protoChunk); + } catch (Exception ignored) { + } + + Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + Codec>> biomesCodec = PalettedContainer.codecRO( + biomesRegistry.asHolderIdMap(), + biomesRegistry.holderByNameCodec(), + PalettedContainer.Strategy.SECTION_BIOMES, + biomesRegistry.getOrThrow(Biomes.PLAINS) + ); + + LevelLightEngine lightEngine = serverLevel.getLightEngine(); + LevelChunkSection[] chunkSections = protoChunk.getSections(); + + ListTag sectionsList = new ListTag(); + + // Save blocks + for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { + int chunkSectionIndex = serverLevel.getSectionIndex(i); + + CompoundTag sectionCompound = new CompoundTag(); + + if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { + LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; + + { + DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); + sectionCompound.put("block_states", dataResult.getOrThrow()); + } + + { + DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); + sectionCompound.put("biomes", dataResult.getOrThrow()); + } + } + + if (!sectionCompound.isEmpty()) { + sectionCompound.putByte("Y", (byte) i); + sectionsList.add(sectionCompound); + } + } + + for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { + CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, + MinecraftServer.getServer().registryAccess()); + if (blockEntityCompound != null) + tileEntities.add(blockEntityCompound); + } + + unloadedChunkCompound.setSections(sectionsList); + } + } + + @Override + public void onFinish() { + if (onFinish != null) + onFinish.run(); + } + }); + } + + @Override + public CompletableFuture> calculateChunks(List chunkPositions, + Synchronized> unloadedChunksCache) { + List allCalculatedChunks = new LinkedList<>(); + List chunkPositionsToCalculate = new LinkedList<>(); + + Iterator chunkPositionsIterator = chunkPositions.iterator(); + while (chunkPositionsIterator.hasNext()) { + ChunkPosition chunkPosition = chunkPositionsIterator.next(); + CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); + if (cachedCalculatedChunk != null) { + allCalculatedChunks.add(cachedCalculatedChunk); + chunkPositionsIterator.remove(); + } else { + chunkPositionsToCalculate.add(chunkPosition); + } + } + + if (chunkPositions.isEmpty()) + return CompletableFuture.completedFuture(allCalculatedChunks); + + CompletableFuture> completableFuture = new CompletableFuture<>(); + + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + + Codec> blocksCodec = PalettedContainer.codecRW( + Block.BLOCK_STATE_REGISTRY, + BlockState.CODEC, + PalettedContainer.Strategy.SECTION_STATES, + Blocks.AIR.defaultBlockState() + ); + Codec>> biomesCodec = PalettedContainer.codecRW( + biomesRegistry.asHolderIdMap(), + biomesRegistry.holderByNameCodec(), + PalettedContainer.Strategy.SECTION_BIOMES, + biomesRegistry.getOrThrow(Biomes.PLAINS) + ); + + LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; + + ListTag sectionsList = unloadedChunkCompound.getSections(); + for (int i = 0; i < sectionsList.size(); ++i) { + CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); + byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); + int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); + + if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { + PalettedContainer blocksDataPalette; + Optional blockStatesCompound = sectionCompound.getCompound("block_states"); + if (blockStatesCompound.isPresent()) { + DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, + blockStatesCompound.get()).promotePartial((sx) -> { + }); + blocksDataPalette = dataResult.getOrThrow(); + } else { + blocksDataPalette = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + } + + PalettedContainer> biomesDataPalette; + Optional biomesCompound = sectionCompound.getCompound("biomes"); + if (biomesCompound.isPresent()) { + DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, + biomesCompound.get()).promotePartial((sx) -> { + }); + biomesDataPalette = dataResult.getOrThrow(); + } else { + biomesDataPalette = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); + } + + chunkSections[sectionIndex] = new LevelChunkSection(blocksDataPalette, biomesDataPalette); + } + + } + + CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + allCalculatedChunks.add(calculatedChunk); + unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + } + + @Override + public void onFinish() { + completableFuture.complete(allCalculatedChunks); + } + }); + + return completableFuture; + } + + @Override + public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { + CompletableFuture> completableFuture = new CompletableFuture<>(); + + KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + List unloadedChunkCompounds = new LinkedList<>(); + + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { + if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) + chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); + } + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + unloadedChunkCompounds.add(unloadedChunkCompound); + } + + @Override + public void onFinish() { + BukkitExecutor.ensureMain(() -> { + for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + for (Tag entityTag : unloadedChunkCompound.getEntities()) { + EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); + if (entityType == null) + continue; + + Entity fakeEntity = EntityType.create((CompoundTag) entityTag, serverLevel, EntitySpawnReason.NATURAL).orElse(null); + if (fakeEntity != null) { + fakeEntity.valid = false; + if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) + continue; + } + + Key entityKey = Keys.of(CraftEntityType.minecraftToBukkit(entityType)); + chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); + } + } + + completableFuture.complete(chunkEntities); + }); + } + }); + + return completableFuture; + } + + @Override + public void injectChunkSections(Chunk chunk) { + // No implementation + } + + @Override + public boolean isChunkEmpty(Chunk bukkitChunk) { + LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); + return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> + chunkSection == null || chunkSection.hasOnlyAir()); + } + + @Override + public Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); + return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; + } + + @Override + public void startTickingChunk(Island island, Chunk chunk, boolean stop) { + if (plugin.getSettings().getCropsInterval() <= 0) + return; + + if (stop) { + CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); + if (cropsBlockEntity != null) + cropsBlockEntity.remove(); + } else { + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); + CropsBlockEntity.create(island, levelChunk); + } + } + + @Override + public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { + if (chunkPositions.isEmpty()) return; + CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> + cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); + } + + @Override + public void shutdown() { + List> pendingTasks = NMSUtils.getPendingChunkActions(); + + if (pendingTasks.isEmpty()) + return; + + Log.info("Waiting for chunk tasks to complete."); + + CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); + } + + @Override + public List getBlockEntities(Chunk chunk) { + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); + List blockEntities = new LinkedList<>(); + + World bukkitWorld = chunk.getWorld(); + + levelChunk.getBlockEntities().keySet().forEach(blockPos -> + blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); + + return blockEntities; + } + + private static final ReflectField PALETTED_CONTAINER_DATA = new ReflectField<>( + PalettedContainer.class, Object.class, "d"); + + private static final ReflectField PALETTED_CONTAINER_DATA_STORAGE = new ReflectField<>( + PalettedContainer.class, BitStorage.class, "b"); + + private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { + KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); + List spawnersLocations = new LinkedList<>(); + + for (int i = 0; i < chunkSections.length; ++i) { + LevelChunkSection levelChunkSection = chunkSections[i]; + if (levelChunkSection != null && !levelChunkSection.hasOnlyAir()) { + int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4; + for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { + BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); + calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, + sectionBottomY, blockCounts, spawnersLocations); + } + } + } + + return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); + } + + private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, + int sectionBottomY, KeyMap blockCounts, + List spawnersLocations) { + Block block = blockState.getBlock(); + + if (block == Blocks.AIR) + return; + + Location location = new Location(chunkPosition.getWorld(), + (chunkPosition.getX() << 4) + x, + sectionBottomY + y, + (chunkPosition.getZ() << 4) + z); + + int blockAmount = 1; + + if (NMSUtils.isDoubleBlock(block, blockState)) { + blockAmount = 2; + blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); + } + + Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); + blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); + if (block == Blocks.SPAWNER) { + spawnersLocations.add(location); + } + } + + private static void removeEntities(ChunkAccess chunk) { + ChunkPos chunkPos = chunk.getPos(); + ServerLevel serverLevel = ((LevelChunk) chunk).level; + + int chunkWorldCoordX = chunkPos.x << 4; + int chunkWorldCoordZ = chunkPos.z << 4; + + AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinY(), chunkWorldCoordZ, + chunkWorldCoordX + 15, serverLevel.getMaxY(), chunkWorldCoordZ + 15); + + List worldEntities = new LinkedList<>(); + serverLevel.getEntities().get(chunkBounds, worldEntities::add); + + worldEntities.forEach(nmsEntity -> { + if (!(nmsEntity instanceof Player)) + nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); + }); + } + + private static void removeBlockEntities(ChunkAccess chunk) { + chunk.blockEntities.values().forEach(BlockEntity::setRemoved); + chunk.blockEntities.clear(); + } + + private static void removeBlocks(ChunkAccess chunk) { + ServerLevel serverLevel = ((LevelChunk) chunk).level; + + ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); + + if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { + NMSUtils.buildSurfaceForChunk(serverLevel, chunk); + } + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSDragonFightImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSDragonFightImpl.java new file mode 100644 index 0000000000..236654a588 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSDragonFightImpl.java @@ -0,0 +1,118 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.EndWorldEndDragonFightHandler; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.IslandEndDragonFight; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.IslandEntityEnderDragon; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.SpikesCache; +import com.google.common.cache.LoadingCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.levelgen.feature.SpikeFeature; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.advancement.Advancement; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.entity.Player; + +import java.lang.reflect.Modifier; +import java.util.List; + +public class NMSDragonFightImpl implements NMSDragonFight { + + private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( + EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) + .removeFinal(); + + private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField<>( + ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE, 1); + + private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( + SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) + .removeFinal(); + + private static boolean firstWorldPreparation = true; + + static { + ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); + } + + @Override + public void prepareEndWorld(World bukkitWorld) { + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); + + if (firstWorldPreparation) { + firstWorldPreparation = false; + SPIKE_CACHE.set(null, SpikesCache.getInstance()); + } + } + + @Nullable + @Override + public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { + World bukkitWorld = island.getCenter(dimension).getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + return null; + + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); + } + + @Override + public void startDragonBattle(Island island, Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + return; + + dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + } + + @Override + public void removeDragonBattle(Island island, Dimension dimension) { + World bukkitWorld = island.getCenter(dimension).getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + return; + + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + + if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { + islandEndDragonFight.removeBattlePlayers(); + islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); + } + } + + @Override + public void awardTheEndAchievement(Player player) { + Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); + if (advancement != null) + player.getAdvancementProgress(advancement).awardCriteria(""); + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSEntitiesImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSEntitiesImpl.java new file mode 100644 index 0000000000..cb26e74060 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSEntitiesImpl.java @@ -0,0 +1,52 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5; + +import com.bgsoftware.superiorskyblock.nms.NMSEntities; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PortalProcessor; +import org.bukkit.Material; +import org.bukkit.craftbukkit.entity.CraftAnimals; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.ItemStack; + +public class NMSEntitiesImpl implements NMSEntities { + + @Override + public ItemStack[] getEquipment(EntityEquipment entityEquipment) { + ItemStack[] itemStacks = new ItemStack[7]; + + itemStacks[0] = new ItemStack(Material.ARMOR_STAND); + itemStacks[1] = entityEquipment.getItemInMainHand(); + itemStacks[2] = entityEquipment.getItemInOffHand(); + itemStacks[3] = entityEquipment.getHelmet(); + itemStacks[4] = entityEquipment.getChestplate(); + itemStacks[5] = entityEquipment.getLeggings(); + itemStacks[6] = entityEquipment.getBoots(); + + return itemStacks; + } + + @Override + public boolean isAnimalFood(ItemStack itemStack, Animals animals) { + return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); + } + + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); + } + + @Override + public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { + Entity entity = ((CraftEntity) bukkitEntity).getHandle(); + PortalProcessor portalProcessor = entity.portalProcess; + return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSHologramsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSHologramsImpl.java new file mode 100644 index 0000000000..557fe89731 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSHologramsImpl.java @@ -0,0 +1,188 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5; + +import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; +import com.bgsoftware.superiorskyblock.nms.NMSHolograms; +import com.google.common.base.Preconditions; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftArmorStand; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.entity.Entity; + +@SuppressWarnings("unused") +public class NMSHologramsImpl implements NMSHolograms { + + @Override + public Hologram createHologram(Location location) { + Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); + serverLevel.addFreshEntity(entityHologram); + return entityHologram; + } + + @Override + public boolean isHologram(Entity entity) { + return ((CraftEntity) entity).getHandle() instanceof Hologram; + } + + public static class EntityHologram extends ArmorStand implements Hologram { + + private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); + + private CraftEntity bukkitEntity; + + EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + + setInvisible(true); + setSmall(true); + setShowArms(false); + setNoGravity(true); + setNoBasePlate(true); + setMarker(true); + forceSetBoundingBox(EMPTY_BOUND); + + super.collides = false; + super.setCustomNameVisible(true); + } + + @Override + public void setHologramName(String name) { + super.setCustomName(CraftChatMessage.fromStringOrNull(name)); + } + + @Override + public void removeHologram() { + super.remove(RemovalReason.DISCARDED); + } + + @Override + public org.bukkit.entity.ArmorStand getHandle() { + return this.getBukkitEntity(); + } + + @Override + public void inactiveTick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + @Override + public boolean repositionEntityAfterLoad() { + return false; + } + + @Override + public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { + // Prevent stand being equipped + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + + @Override + public void tick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + public void forceSetBoundingBox(AABB boundingBox) { + super.setBoundingBox(boundingBox); + } + + @Override + public CraftArmorStand getBukkitEntity() { + if (bukkitEntity == null) { + bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); + } + return (CraftArmorStand) bukkitEntity; + } + + @Override + public void remove(RemovalReason removalReason) { + // Prevent being killed. + } + + @Override + public void playSound(SoundEvent soundEvent, float volume, float pitch) { + // Remove sounds. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean isInvulnerableTo(ServerLevel serverLevel, DamageSource damageSource) { + /* + * The field Entity.invulnerable is private. + * It's only used while saving NBTTags, but since the entity would be killed + * on chunk unload, we prefer to override isInvulnerable(). + */ + return true; + } + + @Override + public void setCustomName(Component component) { + // Locks the custom name. + } + + @Override + public void setCustomNameVisible(boolean isCustomNameVisible) { + // Locks the custom name. + } + + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSPlayersImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSPlayersImpl.java new file mode 100644 index 0000000000..d5c466c570 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSPlayersImpl.java @@ -0,0 +1,172 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.player.PlayerLocales; +import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; +import com.bgsoftware.superiorskyblock.world.Dimensions; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarStyle; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; + +import java.util.Locale; +import java.util.Optional; + +public class NMSPlayersImpl implements NMSPlayers { + + private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); + private static final ReflectMethod ENTITY_SET_LEVEL = new ReflectMethod<>( + Entity.class, 1, Level.class); + + private final SuperiorSkyblockPlugin plugin; + + public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void clearInventory(OfflinePlayer offlinePlayer) { + if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { + Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); + assert player != null; + player.getInventory().clear(); + player.getEnderChest().clear(); + return; + } + + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); + Player targetPlayer = serverPlayer.getBukkitEntity(); + + targetPlayer.loadData(); + + clearInventory(targetPlayer); + + //Setting the entity to the spawn location + Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); + + if (spawnLocation != null) { + ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); + serverPlayer.absSnapTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), + spawnLocation.getYaw(), spawnLocation.getPitch()); + } + + targetPlayer.saveData(); + } + + @Override + public void setSkinTexture(SuperiorPlayer superiorPlayer) { + Player player = superiorPlayer.asPlayer(); + + if (player == null) + return; + + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() + .ifPresent(property -> setSkinTexture(superiorPlayer, property)); + } + + @Override + public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { + superiorPlayer.setTextureValue(property.value()); + } + + @SuppressWarnings("deprecation") + @Override + public void sendActionBar(Player player, String message) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); + } + + @Override + public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { + BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); + bossBar.addPlayer(player); + return bossBar; + } + + @SuppressWarnings("deprecation") + @Override + public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { + player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); + } + + @Override + public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { + return superiorPlayer.getUniqueId().equals(item.getThrower()); + } + + @Nullable + @Override + public Locale getPlayerLocale(Player player) { + if (PLAYER_LOCALE.isValid()) { + return player.locale(); + } else try { + //noinspection deprecation + return PlayerLocales.getLocale(player.getLocale()); + } catch (IllegalArgumentException error) { + return null; + } + } + + private static class BossBarImpl implements BossBar { + + private final org.bukkit.boss.BossBar bossBar; + private final BossBarTask bossBarTask; + + public BossBarImpl(String message, BarColor color, double ticksToRun) { + bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); + this.bossBarTask = BossBarTask.create(this, ticksToRun); + } + + @Override + public void addPlayer(Player player) { + this.bossBar.addPlayer(player); + this.bossBarTask.registerTask(player); + } + + @Override + public void removeAll() { + this.bossBar.removeAll(); + this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); + } + + @Override + public void setProgress(double progress) { + this.bossBar.setProgress(progress); + } + + @Override + public double getProgress() { + return this.bossBar.getProgress(); + } + + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java new file mode 100644 index 0000000000..43d0f34025 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java @@ -0,0 +1,197 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5; + +import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.nms.NMSTags; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.tag.ListTag; +import com.bgsoftware.superiorskyblock.tag.Tag; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.serialization.Dynamic; +import net.minecraft.SharedConstants; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.ByteArrayTag; +import net.minecraft.nbt.IntArrayTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.NumericTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ResolvableProfile; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.inventory.CraftItemStack; + +import java.util.Optional; +import java.util.Set; + +@SuppressWarnings({"unused"}) +public class NMSTagsImpl implements NMSTags { + + @Override + public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) + itemStack.save(MinecraftServer.getServer().registryAccess()); + tagCompound.putInt("DataVersion", SharedConstants.getCurrentVersion().getDataVersion().getVersion()); + + return CompoundTag.fromNBT(tagCompound); + } + + @Override + public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { + if (compoundTag.containsKey("NBT")) { + // Old compound version, deserialize it accordingly + return deserializeItemOld(compoundTag); + } + + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); + + int currentVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); + int itemVersion = tagCompound.getIntOr("DataVersion", 0); + if (itemVersion < currentVersion) { + tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, + new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); + } + + ItemStack itemStack = ItemStack.parse(MinecraftServer.getServer().registryAccess(), tagCompound).orElseThrow(); + + return CraftItemStack.asCraftMirror(itemStack); + } + + private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + Material type = Material.valueOf(typeName); + int amount = compoundTag.getInt("amount"); + short data = compoundTag.getShort("data"); + CompoundTag nbtData = compoundTag.getCompound("NBT"); + + org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); + + return CraftItemStack.asCraftMirror(itemStack); + } + + @Override + public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + PropertyMap propertyMap = new PropertyMap(); + propertyMap.put("textures", new Property("textures", texture)); + + ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap); + + itemStack.set(DataComponents.PROFILE, resolvableProfile); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + @SuppressWarnings("ConstantConditions") + public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { + net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); + + if (compoundTag == null) + compoundTag = new net.minecraft.nbt.CompoundTag(); + + if (!compoundTag.contains("id")) + //noinspection deprecation + compoundTag.putString("id", entityType.getName()); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { + entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); + return !serverLevel.addWithUUID(entity) ? null : entity; + }); + } + + @Override + public byte[] getNBTByteArrayValue(Object object) { + return ((ByteArrayTag) object).getAsByteArray(); + } + + @Override + public byte getNBTByteValue(Object object) { + return ((NumericTag) object).byteValue(); + } + + @Override + public Set getNBTCompoundValue(Object object) { + return ((net.minecraft.nbt.CompoundTag) object).keySet(); + } + + @Override + public double getNBTDoubleValue(Object object) { + return ((NumericTag) object).doubleValue(); + } + + @Override + public float getNBTFloatValue(Object object) { + return ((NumericTag) object).floatValue(); + } + + @Override + public int[] getNBTIntArrayValue(Object object) { + return ((IntArrayTag) object).getAsIntArray(); + } + + @Override + public int getNBTIntValue(Object object) { + return ((NumericTag) object).intValue(); + } + + @Override + public Object getNBTListIndexValue(Object object, int index) { + return ((net.minecraft.nbt.ListTag) object).get(index); + } + + @Override + public long getNBTLongValue(Object object) { + return ((NumericTag) object).longValue(); + } + + @Override + public short getNBTShortValue(Object object) { + return ((NumericTag) object).shortValue(); + } + + @Override + public String getNBTStringValue(Object object) { + return ((StringTag) object).value(); + } + + @Override + public Object parseList(ListTag listTag) { + net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); + + for (Tag tag : listTag) + nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); + + return nbtTagList; + } + + @Override + public Object getNBTCompoundTag(Object object, String key) { + return ((net.minecraft.nbt.CompoundTag) object).get(key); + } + + @Override + public void setNBTCompoundTagValue(Object object, String key, Object value) { + ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); + } + + @Override + public int getNBTTagListSize(Object object) { + return ((net.minecraft.nbt.ListTag) object).size(); + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java new file mode 100644 index 0000000000..e65fcc3a0a --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java @@ -0,0 +1,509 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.PropertiesMapper; +import com.bgsoftware.superiorskyblock.tag.ByteTag; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.tag.IntArrayTag; +import com.bgsoftware.superiorskyblock.tag.StringTag; +import com.bgsoftware.superiorskyblock.tag.Tag; +import com.google.common.base.Suppliers; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.BedBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.block.state.properties.SlabType; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +public class NMSUtils { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final ReflectMethod SEND_PACKETS_TO_RELEVANT_PLAYERS = new ReflectMethod<>( + ChunkHolder.class, 1, Packet.class, boolean.class); + private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( + ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); + private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( + ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( + EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); + + private NMSUtils() { + + } + + @Nullable + public static T getBlockEntityAt(Location location, Class type) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); + } + } + + public static void runActionOnEntityChunks(Collection chunksCoords, + ChunkCallback chunkCallback) { + runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> + runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); + } + + public static void runActionOnChunks(Collection chunksCoords, + boolean saveChunks, ChunkCallback chunkCallback) { + runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> + runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); + } + + private static void runActionOnChunksInternal(Collection chunksCoords, + ChunkCallback chunkCallback, + Consumer> onUnloadChunkAction) { + List unloadedChunks = new LinkedList<>(); + List loadedChunks = new LinkedList<>(); + + chunksCoords.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + ChunkAccess chunkAccess; + + try { + chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); + } catch (Throwable ex) { + chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); + } + + if (chunkAccess instanceof LevelChunk levelChunk) { + loadedChunks.add(levelChunk); + } else { + unloadedChunks.add(chunkPosition.copy()); + } + }); + + boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); + + if (!loadedChunks.isEmpty()) + runActionOnLoadedChunks(loadedChunks, chunkCallback); + + if (hasUnloadedChunks) { + onUnloadChunkAction.accept(unloadedChunks); + } else { + chunkCallback.onFinish(); + } + } + + private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { + chunks.forEach(chunkCallback::onLoadedChunk); + } + + private static void runActionOnUnloadedChunks(Collection chunks, + boolean saveChunks, ChunkCallback chunkCallback) { + if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { + Iterator chunksIterator = chunks.iterator(); + while (chunksIterator.hasNext()) { + ChunkPosition chunkPosition = chunksIterator.next(); + + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( + chunkPosition.getX(), chunkPosition.getZ()); + + if (cachedUnloadedChunk != null) { + chunkCallback.onLoadedChunk(cachedUnloadedChunk); + chunksIterator.remove(); + } + } + + if (chunks.isEmpty()) { + chunkCallback.onFinish(); + return; + } + } + + CompletableFuture pendingTask = new CompletableFuture<>(); + PENDING_CHUNK_ACTIONS.add(pendingTask); + + BukkitExecutor.createTask().runAsync(v -> { + List chunkCompounds = new LinkedList<>(); + + chunks.forEach(chunkPosition -> { + try { + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + + net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); + + if (chunkCompound == null) { + chunkCallback.onChunkNotExist(chunkPosition); + return; + } + + net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), + Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, + Optional.empty(), chunkPos, serverLevel); + + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + + if (saveChunks) + chunkCompounds.add(unloadedChunkCompound); + } catch (Exception error) { + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + + return chunkCompounds; + }).runSync(chunkCompounds -> { + chunkCompounds.forEach(unloadedChunkCompound -> { + + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + + ChunkPos chunkPos = unloadedChunkCompound.chunkPos(); + + try { + chunkMap.write(chunkPos, () -> unloadedChunkCompound.chunkCompound); + } catch (Exception error) { + Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); + } + }); + + chunkCallback.onFinish(); + + pendingTask.complete(null); + PENDING_CHUNK_ACTIONS.remove(pendingTask); + }); + } + + private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + CompletableFutureList readChunksTasksList = new CompletableFutureList<>(-1); + + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + CompletableFuture readTask = new CompletableFuture<>(); + readChunksTasksList.add(readTask); + + regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + readTask.completeExceptionally(error); + } else { + entityDataOptional.ifPresent(entityData -> { + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + }); + + readTask.complete(null); + } + }); + }); + + BukkitExecutor.createTask().runAsync(v -> { + readChunksTasksList.forEachCompleted(p -> { + // Wait for all chunks to load. + }, error -> { + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk:"); + }); + }).runSync(v -> { + chunkCallback.onFinish(); + }); + } else { + BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + MoonriseRegionFileIO.RegionDataController regionDataController = + serverLevel.moonrise$getEntityChunkDataController(); + int chunkX = chunkPosition.getX(); + int chunkZ = chunkPosition.getZ(); + MoonriseRegionFileIO.RegionDataController.ReadData readData = + regionDataController.readData(chunkX, chunkZ); + if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { + net.minecraft.nbt.CompoundTag entityData = readData.syncRead(); + if (entityData != null) { + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + } catch (IOException error) { + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }).runSync(v -> { + chunkCallback.onFinish(); + }); + } + } + + public static List> getPendingChunkActions() { + return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), + null); + } + + public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chunkX, int chunkZ, Packet packet) { + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); + ChunkHolder chunkHolder; + + try { + chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); + } catch (Throwable ex) { + chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); + } + + if (chunkHolder != null) { + if (SEND_PACKETS_TO_RELEVANT_PLAYERS.isValid()) { + SEND_PACKETS_TO_RELEVANT_PLAYERS.invoke(chunkHolder, packet, false); + } else { + chunkHolder.playerProvider.getPlayers(chunkPos, false).forEach(serverPlayer -> + serverPlayer.connection.send(packet)); + } + } + } + + public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, + CompoundTag statesTag, CompoundTag tileEntity) { + ServerLevel serverLevel = levelChunk.level; + + if (!isValidPosition(serverLevel, blockPos)) + return; + + BlockState blockState = Block.stateById(combinedId); + + if (statesTag != null) { + for (Map.Entry> entry : statesTag.entrySet()) { + try { + // noinspection rawtypes + Property property = PropertiesMapper.getProperty(entry.getKey()); + if (property != null) { + if (entry.getValue() instanceof ByteTag) { + // noinspection unchecked + blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); + } else if (entry.getValue() instanceof IntArrayTag) { + int[] data = ((IntArrayTag) entry.getValue()).getValue(); + // noinspection unchecked + blockState = blockState.setValue(property, data[0]); + } else if (entry.getValue() instanceof StringTag) { + String data = ((StringTag) entry.getValue()).getValue(); + // noinspection unchecked + blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); + } + } + } catch (Exception ignored) { + } + } + } + + if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || + blockState.getBlock() instanceof BedBlock) { + serverLevel.setBlock(blockPos, blockState, 3); + return; + } + + int indexY = serverLevel.getSectionIndex(blockPos.getY()); + + LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; + + int blockX = blockPos.getX() & 15; + int blockY = blockPos.getY(); + int blockZ = blockPos.getZ() & 15; + + boolean isOriginallyChunkSectionEmpty = levelChunkSection.hasOnlyAir(); + + levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); + + levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); + levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); + levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); + levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); + + levelChunk.markUnsaved(); + + boolean isChunkSectionEmpty = levelChunkSection.hasOnlyAir(); + + if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) + serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); + + serverLevel.getLightEngine().checkBlock(blockPos); + + if (tileEntity != null) { + net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); + if (tileEntityCompound != null) { + tileEntityCompound.putInt("x", blockPos.getX()); + tileEntityCompound.putInt("y", blockPos.getY()); + tileEntityCompound.putInt("z", blockPos.getZ()); + BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); + if (worldBlockEntity != null) + worldBlockEntity.loadWithComponents(tileEntityCompound, MinecraftServer.getServer().registryAccess()); + } + } + } + + public static boolean isDoubleBlock(Block block, BlockState blockState) { + return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && + blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; + } + + @Nullable + public static LevelChunk getCraftChunkHandle(CraftChunk craftChunk) { + ServerLevel serverLevel = craftChunk.getCraftWorld().getHandle(); + LevelChunk loadedChunk = serverLevel.getChunkIfLoaded(craftChunk.getX(), craftChunk.getZ()); + if (loadedChunk != null) + return loadedChunk; + + return (LevelChunk) serverLevel.getChunk(craftChunk.getX(), craftChunk.getZ(), ChunkStatus.FULL, true); + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkAccess chunkAccess) { + CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), serverLevel.generator); + + ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); + + // Unsafe: we do not provide chunks cache, even tho it is required. + // Should be fine in normal flow, as the only method that access the chunsk cache + // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 + WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); + + customChunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public record UnloadedChunkCompound(ChunkPosition chunkPosition, + net.minecraft.nbt.CompoundTag chunkCompound) { + + public ListTag getSections() { + return chunkCompound.getListOrEmpty("sections"); + } + + public ListTag getEntities() { + return chunkCompound.getListOrEmpty("Entities"); + } + + public void setSections(ListTag sectionsList) { + chunkCompound.put("sections", sectionsList); + } + + public void setEntities(ListTag entitiesList) { + chunkCompound.put("entities", entitiesList); + } + + public void setBlockEntities(ListTag blockEntitiesList) { + chunkCompound.put("block_entities", blockEntitiesList); + } + + public ServerLevel serverLevel() { + return ((CraftWorld) chunkPosition.getWorld()).getHandle(); + } + + public ChunkPos chunkPos() { + return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + } + + } + + private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { + return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && + blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && + blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); + } + + public interface ChunkCallback { + + void onLoadedChunk(LevelChunk levelChunk); + + void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + + default void onChunkNotExist(ChunkPosition chunkPosition) { + + } + + void onFinish(); + + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java new file mode 100644 index 0000000000..888cd3f6f6 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java @@ -0,0 +1,420 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; +import com.bgsoftware.superiorskyblock.nms.ICachedBlock; +import com.bgsoftware.superiorskyblock.nms.NMSWorld; +import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.generator.IslandsGeneratorImpl; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.trial.IslandPlayerDetector; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.ChunkReaderImpl; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.block.entity.SpawnerBlockEntity; +import net.minecraft.world.level.block.entity.TickingBlockEntity; +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; +import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; +import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.ChunkSnapshot; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.block.data.type.WallSign; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.block.CraftSign; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.block.SignChangeEvent; + +import java.lang.reflect.Modifier; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.function.IntFunction; + +public class NMSWorldImpl implements NMSWorld { + + private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); + private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( + Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( + SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + + private final SuperiorSkyblockPlugin plugin; + + public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + } + + @Override + public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); + Location location = new Location( + Bukkit.getWorld(chunkSnapshot.getWorldName()), + (chunkSnapshot.getX() << 4) + x, + y, + (chunkSnapshot.getZ() << 4) + z + ); + + return Keys.of(KeyBlocksCache.getBlockKey(block), location); + } + + @Override + public void listenSpawner(Location location, IntFunction delayChangeCallback) { + SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); + if (spawnerBlockEntity == null) + return; + + ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); + + List blockEntityTickers; + + if (LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.isValid()) { + blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.get(serverLevel); + } else { + blockEntityTickers = serverLevel.blockEntityTickers; + } + + Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); + List tickersToAdd = new LinkedList<>(); + + while (blockEntityTickersIterator.hasNext()) { + TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); + if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && + !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { + blockEntityTickersIterator.remove(); + tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); + } + } + + if (!tickersToAdd.isEmpty()) + blockEntityTickers.addAll(tickersToAdd); + } + + @Override + public void replaceTrialBlockPlayerDetector(Island island, Location location) { + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); + if (blockEntity == null) + return; + + if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { + VaultConfig vaultConfig = vaultBlockEntity.getConfig(); + + PlayerDetector playerDetector = vaultConfig.playerDetector(); + if (playerDetector instanceof IslandPlayerDetector) + return; + + VaultConfig newConfig = new VaultConfig( + vaultConfig.lootTable(), + vaultConfig.activationRange(), + vaultConfig.deactivationRange(), + vaultConfig.keyItem(), + vaultConfig.overrideLootTableToDisplay(), + IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), + vaultConfig.entitySelector() + ); + + vaultBlockEntity.setConfig(newConfig); + } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { + TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); + PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); + + if (playerDetector instanceof IslandPlayerDetector) + return; + + trialSpawnerBlockEntity.trialSpawner = new TrialSpawner( + trialSpawner.normalConfig, + trialSpawner.ominousConfig, + trialSpawner.getData(), + trialSpawner.getTargetCooldownLength(), + trialSpawner.getRequiredPlayerRange(), + trialSpawner.stateAccessor, + IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector), + trialSpawner.getEntitySelector() + ); + } + } + + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) + return; + + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } + + @Override + public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { + if (!plugin.getSettings().isWorldBorders()) + return; + + Player player = superiorPlayer.asPlayer(); + World world = superiorPlayer.getWorld(); + + if (world == null || player == null) + return; + + int islandSize = island == null ? 0 : island.getIslandSize(); + + boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; + + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + + WorldBorder worldBorder; + + if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { + worldBorder = serverLevel.getWorldBorder(); + } else { + Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); + if (dimension == null) + return; + + Location center = island.getCenter(dimension); + + worldBorder = new WorldBorder(); + worldBorder.world = serverLevel; + worldBorder.setWarningBlocks(0); + worldBorder.setCenter(center.getX(), center.getZ()); + + switch (superiorPlayer.getBorderColor()) { + case BLUE -> { + worldBorder.setSize((islandSize * 2) + 1D); + } + case GREEN -> { + worldBorder.setSize((islandSize * 2) + 1.001D); + worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); + } + case RED -> { + worldBorder.setSize((islandSize * 2) + 1D); + worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); + } + } + } + + ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); + ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); + } + + @Override + public Object getBlockData(org.bukkit.block.Block block) { + return block.getBlockData(); + } + + @Override + public void setBlock(Location location, int combinedId) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); + NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + } + } + + @Override + public ICachedBlock cacheBlock(org.bukkit.block.Block block) { + return NMSCachedBlock.obtain(block); + } + + @Override + public boolean isWaterLogged(org.bukkit.block.Block block) { + if (Materials.isWater(block.getType())) + return true; + + BlockData blockData = block.getBlockData(); + + return blockData instanceof BubbleColumn || + (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); + } + + @Override + public SignType getSignType(Object sign) { + if (sign instanceof WallSign) + return SignType.WALL_SIGN; + else if (sign instanceof Sign) + return SignType.STANDING_SIGN; + else if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return SignType.UNKNOWN; + } + + @Override + public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { + BlockState blockState = ((CraftBlock) block).getNMS(); + return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; + } + + @Override + public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { + return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); + } + + @Override + public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { + return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); + } + + private int getDefaultAmount(BlockState blockState) { + Block block = blockState.getBlock(); + return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; + } + + @Override + public void placeSign(Island island, Location location) { + SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); + if (signBlockEntity == null) + return; + + String[] lines = new String[4]; + Component[] messages = signBlockEntity.getFrontText().getMessages(false); + System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length); + String[] strippedLines = new String[4]; + for (int i = 0; i < 4; i++) + strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); + + Component[] newLines; + + IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); + if (result.isCancelEvent()) { + newLines = CraftSign.sanitizeLines(strippedLines); + } else { + newLines = CraftSign.sanitizeLines(lines); + } + + System.arraycopy(newLines, 0, messages, 0, 4); + } + + @SuppressWarnings("deprecation") + @Override + public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { + if (LINES_SIGN_CHANGE_EVENT.isValid()) { + for (int i = 0; i < lines.length; i++) + signChangeEvent.setLine(i, lines[i]); + } + } + + @Override + public void playGeneratorSound(Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + serverLevel.levelEvent(1501, blockPos, 0); + } + } + + @Override + public void playBreakAnimation(org.bukkit.block.Block block) { + ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(block.getX(), block.getY(), block.getZ()); + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + } + } + + @Override + public void playPlaceSound(Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); + + serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, + (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } + } + + @Override + public int getMinHeight(World world) { + return world.getMinHeight(); + } + + @Override + public void removeAntiXray(World bukkitWorld) { + // Doesn't exist in this version. + } + + @Override + public IslandsGenerator createGenerator(Dimension dimension) { + return new IslandsGeneratorImpl(dimension); + } + + @Override + public WorldEditSession createEditSession(World world) { + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); + } + + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsBlockEntity.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsBlockEntity.java new file mode 100644 index 0000000000..229f511543 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsBlockEntity.java @@ -0,0 +1,102 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.crops; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; + +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.function.Consumer; + +public class CropsBlockEntity extends BlockEntity { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); + + private final WeakReference island; + private final WeakReference chunk; + + private int currentTick = 0; + + private double cachedCropGrowthMultiplier; + + private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { + super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); + this.island = new WeakReference<>(island); + this.chunk = new WeakReference<>(levelChunk); + setLevel(levelChunk.level); + levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); + this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; + } + + public static void create(Island island, LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + long chunkPair = chunkPos.toLong(); + tickingChunks.computeIfAbsent(chunkPair, p -> { + BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); + return new CropsBlockEntity(island, levelChunk, blockPos); + }); + } + + public static CropsBlockEntity remove(long chunkPos) { + return tickingChunks.remove(chunkPos); + } + + public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { + if (tickingChunks.isEmpty()) + return; + + chunkPositions.forEach(chunkPosition -> { + long chunkKey = chunkPosition.asPair(); + CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); + if (cropsBlockEntity != null) + cropsBlockEntityConsumer.accept(cropsBlockEntity); + }); + } + + @Override + public boolean isValidBlockState(BlockState state) { + return true; + } + + public void remove() { + this.remove = true; + } + + public void tick() { + if (++currentTick <= plugin.getSettings().getCropsInterval()) + return; + + LevelChunk levelChunk = this.chunk.get(); + Island island = this.island.get(); + ServerLevel serverLevel = (ServerLevel) getLevel(); + + if (levelChunk == null || island == null || serverLevel == null) { + remove(); + return; + } + + currentTick = 0; + + int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); + int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); + if (chunkRandomTickSpeed > 0) + CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); + } + + public void setCropGrowthMultiplier(double cropGrowthMultiplier) { + this.cachedCropGrowthMultiplier = cropGrowthMultiplier; + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingBlockEntity.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingBlockEntity.java new file mode 100644 index 0000000000..12e6b7afd2 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingBlockEntity.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.crops; + +import com.bgsoftware.superiorskyblock.nms.v1_21_5.crops.CropsBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.TickingBlockEntity; + +public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { + + + @Override + public void tick() { + cropsBlockEntity.tick(); + } + + @Override + public boolean isRemoved() { + return cropsBlockEntity.isRemoved(); + } + + @Override + public BlockPos getPos() { + return cropsBlockEntity.getBlockPos(); + } + + @Override + public String getType() { + return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingMethod.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingMethod.java new file mode 100644 index 0000000000..5a776d6190 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingMethod.java @@ -0,0 +1,159 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.crops; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; + +public abstract class CropsTickingMethod { + + private static final ReflectField SERVER_LEVEL_SIMPLE_RANDOM = new ReflectField<>( + ServerLevel.class, RandomSource.class, "simpleRandom"); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_SIMPLE_RANDOM.isValid() ? + new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); + + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); + } + + protected CropsTickingMethod() { + + } + + public static void register() { + // Calls the static initializer which registers the callback. + } + + public static void tick(LevelChunk levelChunk, int tickSpeed) { + INSTANCE.doTick(levelChunk, tickSpeed); + } + + protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey materialKey) { + Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); + if (block != null && block.defaultBlockState().isRandomlyTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + + private static class PaperCropsTickingMethod extends CropsTickingMethod { + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + ServerLevel serverLevel = levelChunk.level; + LevelChunkSection[] sections = levelChunk.getSections(); + + int minSection = serverLevel.getMinSectionY(); + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + RandomSource simpleRandom = SERVER_LEVEL_SIMPLE_RANDOM.get(serverLevel); + + for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + ca.spottedleaf.moonrise.common.list.ShortList tickList = + levelChunkSection.moonrise$getTickingBlockList(); + int tickingBlocks = tickList.size(); + if (tickingBlocks <= 0) { + continue; + } + + PalettedContainer states = levelChunkSection.states; + + int offsetY = (sectionIndex + minSection) << 4; + + for (int i = 0; i < tickSpeed; ++i) { + int index = simpleRandom.nextInt() & 0xFFF; + + if (index >= tickingBlocks) { + continue; + } + + int location = (int) tickList.getRaw(index) & 0xFFFF; + BlockState blockState = states.get(location); + if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) + continue; + + // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! + BlockPos blockPos = new BlockPos((location & 15) | chunkOffsetX, + ((location >>> 8) & 15) | offsetY, + ((location >>> 4) & 15) | chunkOffsetZ); + + blockState.randomTick(serverLevel, blockPos, simpleRandom); + } + } + + } + + } + + private static class SpigotCropsTickingMethod extends CropsTickingMethod { + + private static int random = ThreadLocalRandom.current().nextInt(); + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + LevelChunkSection[] sections = levelChunk.getSections(); + ServerLevel serverLevel = levelChunk.level; + + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; + + for (int i = 0; i < tickSpeed; i++) { + random = random * 3 + 1013904223; + int factor = random >> 2; + int x = factor & 15; + int z = factor >> 8 & 15; + int y = factor >> 16 & 15; + BlockState blockState = levelChunkSection.getBlockState(x, y, z); + if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { + BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); + blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); + } + } + } + } + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/DragonUtils.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/DragonUtils.java new file mode 100644 index 0000000000..406cecc167 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/DragonUtils.java @@ -0,0 +1,37 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; + +import com.bgsoftware.common.reflection.ReflectField; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; + +import java.lang.reflect.Modifier; + +public class DragonUtils { + + private static final ReflectField END_PODIUM_LOCATION = new ReflectField( + EndPodiumFeature.class, BlockPos.class, + Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) + .removeFinal(); + + private static BlockPos currentPodiumPosition = BlockPos.ZERO; + + private DragonUtils() { + + } + + public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { + try { + END_PODIUM_LOCATION.set(null, podiumPosition); + currentPodiumPosition = podiumPosition; + runnable.run(); + } finally { + END_PODIUM_LOCATION.set(null, BlockPos.ZERO); + currentPodiumPosition = BlockPos.ZERO; + } + } + + public static BlockPos getCurrentPodiumPosition() { + return currentPodiumPosition; + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndWorldEndDragonFightHandler.java new file mode 100644 index 0000000000..e49cb190c5 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndWorldEndDragonFightHandler.java @@ -0,0 +1,48 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.IslandEndDragonFight; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class EndWorldEndDragonFightHandler extends EndDragonFight { + + private final Map worldDragonFightsMap = new HashMap<>(); + private final List worldDragonFightsList = new LinkedList<>(); + + public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + this.worldDragonFightsList.forEach(EndDragonFight::tick); + } + + public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + if (oldDragonFight != null) + this.worldDragonFightsList.remove(oldDragonFight); + this.worldDragonFightsList.add(endDragonFight); + } + + @Nullable + public IslandEndDragonFight getDragonFight(UUID uuid) { + return this.worldDragonFightsMap.get(uuid); + } + + @Nullable + public IslandEndDragonFight removeDragonFight(UUID uuid) { + IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + if (endDragonFight != null) + this.worldDragonFightsList.remove(endDragonFight); + return endDragonFight; + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEndDragonFight.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEndDragonFight.java new file mode 100644 index 0000000000..df043b3d27 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEndDragonFight.java @@ -0,0 +1,212 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.IslandEntityEnderDragon; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; +import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; +import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; +import net.minecraft.world.level.block.state.pattern.BlockInWorld; +import net.minecraft.world.level.block.state.pattern.BlockPattern; +import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; +import net.minecraft.world.level.block.state.predicate.BlockPredicate; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public class IslandEndDragonFight extends EndDragonFight { + + private static final ReflectField DRAGON_BATTLE = new ReflectField( + EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) + .removeFinal(); + private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( + EndDragonFight.class, boolean.class, Modifier.PRIVATE, 4); + private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( + EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); + + private static final ReflectField TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>( + EndDragonFight.class, int.class, Modifier.PRIVATE, 4); + private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( + DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); + + private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() + .aisle(" ", " ", " ", " # ", " ", " ", " ") + .aisle(" ", " ", " ", " # ", " ", " ", " ") + .aisle(" ", " ", " ", " # ", " ", " ", " ") + .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") + .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") + .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) + .build(); + + private final Island island; + private final BlockPos islandBlockPos; + private final Vec3 islandBlockVectored; + private final ServerLevel serverLevel; + private final IslandEntityEnderDragon entityEnderDragon; + + private byte currentTick = 0; + + public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { + this(island, serverLevel, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), null); + } + + public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, + @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + + this.island = island; + this.islandBlockPos = islandBlockPos; + this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); + this.serverLevel = serverLevel; + this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; + + SCAN_FOR_LEGACY_PORTALS.set(this, false); + WAS_DRAGON_KILLED.set(this, false); + DRAGON_BATTLE.set(this.entityEnderDragon, this); + + TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); + } + + @Override + public void tick() { + // doServerTick + + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); + + DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); + if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { + LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); + } + + if (++currentTick >= 20) { + updateBattlePlayers(); + currentTick = 0; + TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); + } + } + + @Nullable + @Override + public BlockPattern.BlockPatternMatch findExitPortal() { + int chunkX = this.islandBlockPos.getX() >> 4; + int chunkZ = this.islandBlockPos.getZ() >> 4; + + for (int x = -8; x <= 8; ++x) { + for (int z = -8; z <= 8; ++z) { + LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); + + for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { + if (blockEntity instanceof TheEndPortalBlockEntity) { + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( + this.serverLevel, blockEntity.getBlockPos()); + + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + + return blockPatternMatch; + } + } + } + } + } + + int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); + currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); + for (int y = highestBlock; y >= this.serverLevel.getMinY(); --y) { + currentPosition.setY(y); + + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); + + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + + return blockPatternMatch; + } + } + } + + return null; + } + + @Override + public void resetSpikeCrystals() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); + } + + public void removeBattlePlayers() { + List dragonEventPlayers = new SequentialListBuilder() + .build(this.dragonEvent.getPlayers()); + for (ServerPlayer serverPlayer : dragonEventPlayers) + this.dragonEvent.removePlayer(serverPlayer); + } + + public IslandEntityEnderDragon getEnderDragon() { + return this.entityEnderDragon; + } + + private void updateBattlePlayers() { + Set nearbyPlayers = new HashSet<>(); + + for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { + Player bukkitPlayer = superiorPlayer.asPlayer(); + if (bukkitPlayer != null) { + ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); + if (serverPlayer.serverLevel().equals(this.serverLevel)) { + this.dragonEvent.addPlayer(serverPlayer); + nearbyPlayers.add(serverPlayer.getUUID()); + } + } + } + + List dragonEventPlayers = new SequentialListBuilder() + .build(this.dragonEvent.getPlayers()); + + dragonEventPlayers.stream() + .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) + .forEach(this.dragonEvent::removePlayer); + } + + private IslandEntityEnderDragon spawnEnderDragon() { + IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); + + entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); + entityEnderDragon.absSnapTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), + this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); + + this.serverLevel.addFreshEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); + + this.dragonUUID = entityEnderDragon.getUUID(); + this.resetSpikeCrystals(); + + return entityEnderDragon; + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java new file mode 100644 index 0000000000..99717993a5 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java @@ -0,0 +1,103 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.config.SettingsManager; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.SpawnGroupData; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftEnderDragon; + +public class IslandEntityEnderDragon extends EnderDragon { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + @NotNull + public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { + return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : + new EnderDragon(entityTypes, level); + } + + private final ServerLevel serverLevel; + private final Dimension dimension; + private BlockPos islandBlockPos; + + public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { + this(level); + this.islandBlockPos = islandBlockPos; + } + + private IslandEntityEnderDragon(Level level) { + super(EntityType.ENDER_DRAGON, level); + this.serverLevel = (ServerLevel) level; + this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + } + + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, + DifficultyInstance difficulty, + EntitySpawnReason spawnReason, + @Nullable SpawnGroupData spawnGroupData) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + } + + @Override + public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { + // loadData + super.readAdditionalSaveData(compoundTag); + finalizeIslandEnderDragon(); + } + + @Override + public void aiStep() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); + } + + @Override + @NotNull + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + + private void finalizeIslandEnderDragon() { + if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) + return; + + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } + + if (island == null) + return; + + Location middleBlock = island.getCenter(dimension); + + SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); + if (dimensionConfig instanceof SettingsManager.Worlds.End) { + middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); + } + + this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); + + IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); + dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/SpikesCache.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/SpikesCache.java new file mode 100644 index 0000000000..03b4ed71e2 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/SpikesCache.java @@ -0,0 +1,190 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; + + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.DragonUtils; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.CacheStats; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.level.levelgen.feature.SpikeFeature; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class SpikesCache implements LoadingCache> { + + private static final SpikesCache INSTANCE = new SpikesCache(); + + private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() + .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); + + private long worldSeed; + + public static SpikesCache getInstance() { + return INSTANCE; + } + + private SpikesCache() { + + } + + @Override + public @NotNull + List get(@NotNull Long worldSeed) throws ExecutionException { + try { + this.worldSeed = worldSeed; + return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); + } finally { + this.worldSeed = 0; + } + } + + @Override + public @NotNull + List getUnchecked(@NotNull Long worldSeed) { + try { + this.worldSeed = worldSeed; + return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); + } finally { + this.worldSeed = 0; + } + } + + @Override + public @NotNull + ImmutableMap> getAll(@NotNull Iterable keys) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public List apply(@NotNull Long worldSeed) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public void refresh(@NotNull Long worldSeed) { + try { + this.worldSeed = worldSeed; + cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); + } finally { + this.worldSeed = 0; + } + } + + @Override + public @NotNull + ConcurrentMap> asMap() { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Nullable + @Override + public List getIfPresent(@NotNull Object worldSeed) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public @NotNull + List get(@NotNull Long worldSeed, + @NotNull Callable> loader) throws ExecutionException { + try { + this.worldSeed = worldSeed; + return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); + } finally { + this.worldSeed = 0; + } + } + + @Override + public @NotNull + ImmutableMap> getAllPresent(@NotNull Iterable keys) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public void put(@NotNull Long worldSeed, @NotNull List spikes) { + try { + this.worldSeed = worldSeed; + cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); + } finally { + this.worldSeed = 0; + } + } + + @Override + public void putAll(Map> spikesMap) { + spikesMap.forEach(this::put); + } + + @Override + public void invalidate(@NotNull Object worldSeed) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public void invalidateAll(@NotNull Iterable keys) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public void invalidateAll() { + this.cachedSpikes.invalidateAll(); + } + + @Override + public long size() { + return this.cachedSpikes.size(); + } + + @Override + public @NotNull + CacheStats stats() { + return this.cachedSpikes.stats(); + } + + @Override + public void cleanUp() { + this.cachedSpikes.cleanUp(); + } + + private class InternalCacheLoader extends CacheLoader> { + + @Override + public @NotNull + List load(@NotNull BlockPos blockPos) { + List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); + + Collections.shuffle(list, new Random(worldSeed)); + List spikesList = Lists.newArrayList(); + + for (int i = 0; i < 10; ++i) { + int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); + int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); + int l = list.get(i); + int radius = 2 + l / 3; + int height = 76 + l * 3; + boolean guarded = l == 1 || l == 2; + + spikesList.add(new SpikeFeature.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded)); + } + + return spikesList; + } + + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/generator/IslandsGeneratorImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/generator/IslandsGeneratorImpl.java new file mode 100644 index 0000000000..fe20e4d555 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/generator/IslandsGeneratorImpl.java @@ -0,0 +1,67 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.generator; + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.WorldInfo; + +import java.util.Collections; +import java.util.List; +import java.util.Random; + +@SuppressWarnings({"unused", "NullableProblems"}) +public class IslandsGeneratorImpl extends IslandsGenerator { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Dimension dimension; + + public IslandsGeneratorImpl(Dimension dimension) { + this.dimension = dimension; + } + + @Override + public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, + @NotNull ChunkData chunkData) { + if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { + chunkData.setBlock(0, 99, 0, Material.BEDROCK); + } + } + + @Override + public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { + return new BiomeProvider() { + @Override + public @NotNull + Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { + return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension); + } + + @Override + public @NotNull + List getBiomes(@NotNull WorldInfo worldInfo) { + return IslandUtils.getDefaultWorldBiomes(); + } + + }; + } + + @Override + public List getDefaultPopulators(World world) { + return Collections.emptyList(); + } + + @Override + public Location getFixedSpawnLocation(World world, Random random) { + return new Location(world, 0, 100, 0); + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuBrewingStandBlockEntity.java new file mode 100644 index 0000000000..7d57cc07f0 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuBrewingStandBlockEntity.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.menu; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; +import org.bukkit.inventory.InventoryHolder; + +public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { + + private final InventoryHolder holder; + + public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { + super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); + this.holder = holder; + this.name = Component.nullToEmpty(title); + } + + @Override + public InventoryHolder getOwner() { + return holder; + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuDispenserBlockEntity.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuDispenserBlockEntity.java new file mode 100644 index 0000000000..ec1ae009b0 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuDispenserBlockEntity.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.menu; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.DispenserBlockEntity; +import org.bukkit.inventory.InventoryHolder; + +public class MenuDispenserBlockEntity extends DispenserBlockEntity { + + private final InventoryHolder holder; + + public MenuDispenserBlockEntity(InventoryHolder holder, String title) { + super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); + this.holder = holder; + this.name = Component.nullToEmpty(title); + } + + @Override + public InventoryHolder getOwner() { + return holder; + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuFurnaceBlockEntity.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuFurnaceBlockEntity.java new file mode 100644 index 0000000000..d8bfab24fa --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuFurnaceBlockEntity.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.menu; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.FurnaceBlockEntity; +import org.bukkit.inventory.InventoryHolder; + +public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { + + private final InventoryHolder holder; + + public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { + super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); + this.holder = holder; + this.name = Component.nullToEmpty(title); + } + + @Override + public InventoryHolder getOwner() { + return holder; + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuHopperBlockEntity.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuHopperBlockEntity.java new file mode 100644 index 0000000000..1a40fb8664 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuHopperBlockEntity.java @@ -0,0 +1,26 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.menu; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.HopperBlock; +import net.minecraft.world.level.block.entity.HopperBlockEntity; +import org.bukkit.inventory.InventoryHolder; + +public class MenuHopperBlockEntity extends HopperBlockEntity { + + private final InventoryHolder holder; + + public MenuHopperBlockEntity(InventoryHolder holder, String title) { + super(BlockPos.ZERO, Blocks.HOPPER.defaultBlockState().setValue(HopperBlock.FACING, Direction.DOWN)); + this.holder = holder; + this.name = Component.nullToEmpty(title); + } + + @Override + public InventoryHolder getOwner() { + return holder; + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/spawners/TickingSpawnerBlockEntityNotifier.java new file mode 100644 index 0000000000..f6b3135db5 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/spawners/TickingSpawnerBlockEntityNotifier.java @@ -0,0 +1,57 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.spawners; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BaseSpawner; +import net.minecraft.world.level.block.entity.SpawnerBlockEntity; +import net.minecraft.world.level.block.entity.TickingBlockEntity; + +import java.util.function.IntFunction; + +public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { + + private final SpawnerBlockEntity spawnerBlockEntity; + private final TickingBlockEntity tickingBlockEntity; + private final IntFunction delayChangeCallback; + + public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, + IntFunction delayChangeCallback) { + this.spawnerBlockEntity = spawnerBlockEntity; + this.tickingBlockEntity = tickingBlockEntity; + this.delayChangeCallback = delayChangeCallback; + updateDelay(); + } + + @Override + public void tick() { + BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); + int startDelay = baseSpawner.spawnDelay; + try { + tickingBlockEntity.tick(); + } finally { + int newDelay = baseSpawner.spawnDelay; + if (newDelay > startDelay) + updateDelay(); + } + } + + @Override + public boolean isRemoved() { + return tickingBlockEntity.isRemoved(); + } + + @Override + public BlockPos getPos() { + return tickingBlockEntity.getPos(); + } + + @Override + public String getType() { + return tickingBlockEntity.getType(); + } + + public void updateDelay() { + BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); + baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java new file mode 100644 index 0000000000..455c4f3a7a --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java @@ -0,0 +1,53 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.trial; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +public class IslandPlayerDetector implements PlayerDetector { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final PlayerDetector original; + private final IslandPrivilege requiredPrivilege; + + public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + } + + public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + } + + private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + this.island = island; + this.original = original; + this.requiredPrivilege = requiredPrivilege; + } + + @Override + public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { + List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); + if (!players.isEmpty()) { + players = new LinkedList<>(players); + players.removeIf(uuid -> { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); + return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + }); + players = Collections.unmodifiableList(players); + } + return players; + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/vibration/IslandVibrationUser.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/vibration/IslandVibrationUser.java new file mode 100644 index 0000000000..a47f32beaf --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/vibration/IslandVibrationUser.java @@ -0,0 +1,90 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.PositionSource; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; + +import javax.annotation.Nullable; + +public class IslandVibrationUser implements VibrationSystem.User { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final VibrationSystem.User original; + + public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + this.island = island; + this.original = sculkSensorBlockEntity.getVibrationUser(); + } + + @Override + public int getListenerRadius() { + return this.original.getListenerRadius(); + } + + @Override + public PositionSource getPositionSource() { + return this.original.getPositionSource(); + } + + @Override + public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { + if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) + return false; + + if (context.sourceEntity() instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + + @Override + public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { + this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); + } + + @Override + public TagKey getListenableEvents() { + return this.original.getListenableEvents(); + } + + @Override + public boolean canTriggerAvoidVibration() { + return this.original.canTriggerAvoidVibration(); + } + + @Override + public boolean requiresAdjacentChunksToBeTicking() { + return this.original.requiresAdjacentChunksToBeTicking(); + } + + @Override + public int calculateTravelTimeInTicks(float distance) { + return this.original.calculateTravelTimeInTicks(distance); + } + + @Override + public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { + return this.original.isValidVibration(gameEvent, context); + } + + @Override + public void onDataChanged() { + this.original.onDataChanged(); + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..805cf48057 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java @@ -0,0 +1,241 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.PropertiesMapper; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.lighting.LevelLightEngine; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + private static final byte[] FULL_LIGHT = new byte[2048]; + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + static { + Arrays.fill(FULL_LIGHT, (byte) 0xFF); + } + + private final ServerLevel serverLevel; + private final int x; + private final int z; + + private final Map blockEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final PalettedContainerRO[] blockids; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(Chunk bukkitChunk) { + LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); + + this.serverLevel = levelChunk.level; + this.x = levelChunk.locX; + this.z = levelChunk.locZ; + + LevelChunkSection[] levelChunkSections = levelChunk.getSections(); + this.blockids = new PalettedContainerRO[levelChunkSections.length]; + this.skylight = new byte[levelChunkSections.length][]; + this.emitlight = new byte[levelChunkSections.length][]; + + LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); + + for (int i = 0; i < this.blockids.length; ++i) { + LevelChunkSection levelChunkSection = levelChunkSections[i]; + + this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); + + DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (skyLightArray == null) { + this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; + } else { + this.skylight[i] = new byte[2048]; + System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); + } + + DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (emitLightArray == null) { + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.emitlight[i] = new byte[2048]; + System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); + } + } + + levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { + net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + + compoundTag.remove("x"); + compoundTag.remove("y"); + compoundTag.remove("z"); + + InventoryHolder inventoryHolder = blockEntity.getOwner(); + if (inventoryHolder != null) + compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); + + blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return getBlockState(x, y, z).getBukkitMaterial(); + } + + @Override + public short getData(int x, int y, int z) { + return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); + return this.blockEntities.get(blockPos); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + BlockState blockState = getBlockState(x, y, z); + + if (blockState.getValues().isEmpty()) + return null; + + CompoundTag compoundTag = new CompoundTag(); + + blockState.getValues().forEach((property, value) -> { + String name = PropertiesMapper.getPropertyName(property); + + if (property instanceof BooleanProperty) { + compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); + } else if (property instanceof IntegerProperty integerProperty) { + compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); + } else if (property instanceof EnumProperty) { + compoundTag.setString(name, ((Enum) value).name()); + } + }); + + return compoundTag; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private BlockState getBlockState(int x, int y, int z) { + return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); + } + + private int getSectionIndex(int y) { + int sectionIndex = SectionPos.blockToSectionCoord(y); + return sectionIndex - this.serverLevel.getMinSectionY(); + } + + private int getSectionYFromSectionIndex(int index) { + return index + this.serverLevel.getMinSectionY(); + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.getX(); + this.y = entity.getY(); + this.z = entity.getZ(); + this.yaw = entity.getBukkitYaw(); + this.pitch = entity.getXRot(); + this.entityType = entity.getBukkitEntity().getType(); + + net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); + entity.save(compoundTag); + compoundTag.putFloat("Yaw", entity.getYRot()); + compoundTag.putFloat("Pitch", entity.getXRot()); + + this.entityTag = CompoundTag.fromNBT(compoundTag); + } + + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java new file mode 100644 index 0000000000..9d44c3b036 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java @@ -0,0 +1,32 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; + +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.level.block.Block; +import org.bukkit.Material; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class KeyBlocksCache { + + private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); + + private KeyBlocksCache() { + + } + + public static Key getBlockKey(Block block) { + return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { + Material blockType = CraftMagicNumbers.getMaterial(block); + return blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); + }); + } + + public static void cacheAllBlocks() { + BuiltInRegistries.BLOCK.forEach(KeyBlocksCache::getBlockKey); + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java new file mode 100644 index 0000000000..02455b9d9e --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java @@ -0,0 +1,85 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; + +import com.bgsoftware.superiorskyblock.core.logging.Log; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.Property; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Map; + +public class PropertiesMapper { + + private static final Map> nameToProperty = new HashMap<>(); + private static final Map, String> propertyToName = new HashMap<>(); + + static { + Map fieldsToNames = new IdentityHashMap<>(); + + fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); + fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); + fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); + fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); + fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); + fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); + fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); + fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); + fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); + fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); + fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); + fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); + fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); + fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); + fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); + fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); + fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); + fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); + fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); + fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); + fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); + fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); + fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); + fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); + fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); + fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); + fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); + fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); + fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); + fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); + + try { + for (Field field : BlockStateProperties.class.getFields()) { + field.setAccessible(true); + Object value = field.get(null); + if (value instanceof Property) { + Property property = (Property) value; + register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); + } + } + } catch (Exception error) { + Log.error(error, "An unexpected error occurred while loading properties mapper:"); + } + + } + + private static void register(String key, String fieldName, Property property) { + if (nameToProperty.containsKey(key)) { + Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); + } else { + nameToProperty.put(key, property); + propertyToName.put(property, key); + } + } + + public static Property getProperty(String name) { + return nameToProperty.get(name); + } + + public static String getPropertyName(Property property) { + return propertyToName.get(property); + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java new file mode 100644 index 0000000000..7adceec6df --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java @@ -0,0 +1,379 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.ByteTag; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.tag.IntArrayTag; +import com.bgsoftware.superiorskyblock.tag.StringTag; +import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.gson.JsonParseException; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.BedBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.generator.ChunkGenerator; + +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionImpl implements WorldEditSession { + + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); + private ServerLevel serverLevel; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { + return POOL.obtain().initialize(serverLevel); + } + + private WorldEditSessionImpl() { + } + + public WorldEditSessionImpl initialize(ServerLevel serverLevel) { + this.serverLevel = serverLevel; + this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + return this; + } + + @Override + public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, + @Nullable CompoundTag blockEntityData) { + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + + if (!isValidPosition(blockPos)) + return; + + BlockState blockState = Block.stateById(combinedId); + + if (statesTag != null) { + for (Map.Entry> entry : statesTag.entrySet()) { + try { + // noinspection rawtypes + Property property = PropertiesMapper.getProperty(entry.getKey()); + if (property != null) { + if (entry.getValue() instanceof ByteTag) { + // noinspection unchecked + blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); + } else if (entry.getValue() instanceof IntArrayTag) { + int[] data = ((IntArrayTag) entry.getValue()).getValue(); + // noinspection unchecked + blockState = blockState.setValue(property, data[0]); + } else if (entry.getValue() instanceof StringTag) { + String data = ((StringTag) entry.getValue()).getValue(); + // noinspection unchecked + blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); + } + } + } catch (Exception ignored) { + } + } + } + + if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || + blockState.getBlock() instanceof BedBlock) { + blocksToUpdate.add(new Pair<>(blockPos, blockState)); + return; + } + + ChunkPos chunkPos = new ChunkPos(blockPos); + + if (blockEntityData != null) + blockEntities.add(new Pair<>(blockPos, blockEntityData)); + + ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); + + if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) + chunkData.lights.add(blockPos); + + LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + + int blockX = blockPos.getX() & 15; + int blockY = blockPos.getY(); + int blockZ = blockPos.getZ() & 15; + + levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); + + chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); + chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); + chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); + chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); + } + + @Override + public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + + List chunkPositions = new LinkedList<>(); + World bukkitWorld = serverLevel.getWorld(); + LongIterator iterator = chunks.keyIterator(); + while (iterator.hasNext()) { + long chunkKey = iterator.next(); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); + } + return chunkPositions; + } + + @Override + public void applyBlocks(Chunk bukkitChunk) { + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); + ChunkPos chunkPos = levelChunk.getPos(); + + long chunkKey = chunkPos.toLong(); + ChunkData chunkData = this.chunks.remove(chunkKey); + + if (chunkData == null) + return; + + int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); + for (int i = 0; i < chunkSectionsCount; ++i) { + levelChunk.getSections()[i] = chunkData.chunkSections[i]; + } + + chunkData.heightmaps.forEach(((type, heightmap) -> { + levelChunk.setHeightmap(type, heightmap.getRawData()); + })); + + if (plugin.getSettings().isLightsUpdate()) { + if (isStarLightInterface) { + this.lightenChunks.add(chunkPos); + } else { + ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); + chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); + // Queues chunk light for this chunk. + threadedLevelLightEngine.lightChunk(levelChunk, false); + } + } + + levelChunk.markUnsaved(); + } + + @Override + public void finish(Island island) { + // Update blocks + blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); + + // Update block entities + blockEntities.forEach(data -> { + net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); + if (blockEntityCompound != null) { + BlockPos blockPos = data.getKey(); + blockEntityCompound.putInt("x", blockPos.getX()); + blockEntityCompound.putInt("y", blockPos.getY()); + blockEntityCompound.putInt("z", blockPos.getZ()); + + applySignTextLines(blockEntityCompound, "front_text"); + applySignTextLines(blockEntityCompound, "back_text"); + convertLegacySignTextLines(blockEntityCompound); + + BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); + if (worldBlockEntity != null) + worldBlockEntity.loadWithComponents(blockEntityCompound, MinecraftServer.getServer().registryAccess()); + } + }); + + if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { + ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); + threadedLevelLightEngine.starlight$serverRelightChunks(lightenChunks, chunkCallback -> { + }, completeCallback -> { + }); + this.lightenChunks.clear(); + } + + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lightenChunks.clear(); + this.serverLevel = null; + this.dimension = null; + POOL.release(this); + } + + private boolean isValidPosition(BlockPos blockPos) { + return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && + blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && + blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); + } + + private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { + blockEntityCompound.getCompound(key).ifPresent(textCompound -> { + Component[] textLines = new Component[4]; + Arrays.fill(textLines, Component.empty()); + int i = 0; + for (net.minecraft.nbt.Tag lineTag : textCompound.getListOrEmpty("messages")) { + try { + textLines[i++] = CraftChatMessage.fromJSON(lineTag.asString().orElseThrow()); + } catch (JsonParseException error) { + textLines[i++] = CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]; + } + } + + SignText signText = new SignText(textLines, textLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); + }); + } + + private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + + private class ChunkData { + private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; + private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); + private final List lights = isStarLightInterface ? Collections.emptyList() : new LinkedList<>(); + + public ChunkData(long chunkKey) { + ChunkPos chunkPos = new ChunkPos(chunkKey); + + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + + createChunkSections(biomesRegistry); + + ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), serverLevel, biomesRegistry, null); + + createHeightmaps(tempChunk); + runCustomWorldGenerator(tempChunk); + } + + private void createChunkSections(Registry biomesRegistry) { + Holder biome = CraftBiome.bukkitToMinecraftHolder( + IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); + + for (int i = 0; i < this.chunkSections.length; ++i) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + + this.chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + private void runCustomWorldGenerator(ProtoChunk tempChunk) { + ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); + + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; + + NMSUtils.buildSurfaceForChunk(serverLevel, tempChunk); + + // We want to copy the level chunk sections back + LevelChunkSection[] tempChunkSections = tempChunk.getSections(); + for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { + LevelChunkSection chunkSection = tempChunkSections[i]; + if (chunkSection != null) + this.chunkSections[i] = chunkSection; + } + } + + private void createHeightmaps(ProtoChunk tempChunk) { + for (Heightmap.Types heightmapType : Heightmap.Types.values()) { + if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { + this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); + } + } + } + + } + + +} diff --git a/build.gradle b/build.gradle index 003a348d11..cfd5c2a0aa 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b10' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b11' implementation 'com.zaxxer:HikariCP:4.0.3' implementation 'org.slf4j:slf4j-api:2.0.5' diff --git a/settings.gradle b/settings.gradle index b8d199cd5d..643bae6470 100644 --- a/settings.gradle +++ b/settings.gradle @@ -63,4 +63,5 @@ include 'NMS:v1_20_3' include 'NMS:v1_20_4' include 'NMS:v1_21' include 'NMS:v1_21_3' -include 'NMS:v1_21_4' \ No newline at end of file +include 'NMS:v1_21_4' +include 'NMS:v1_21_5' \ No newline at end of file From dda6ee4561b6cfa2ef335af6d7790b2539a6da57 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 13 Apr 2025 12:56:29 +0300 Subject: [PATCH 111/600] Removed unused methods --- .../nms/v1_12_R1/NMSWorldImpl.java | 6 ------ .../nms/v1_16_R3/NMSWorldImpl.java | 11 ----------- .../superiorskyblock/nms/v1_17/NMSWorldImpl.java | 13 ------------- .../superiorskyblock/nms/v1_18/NMSWorldImpl.java | 14 -------------- .../superiorskyblock/nms/v1_19/NMSWorldImpl.java | 12 ------------ .../superiorskyblock/nms/v1_20_3/NMSWorldImpl.java | 12 ------------ .../superiorskyblock/nms/v1_20_4/NMSWorldImpl.java | 14 -------------- .../superiorskyblock/nms/v1_21/NMSWorldImpl.java | 12 ------------ .../superiorskyblock/nms/v1_21_3/NMSWorldImpl.java | 12 ------------ .../superiorskyblock/nms/v1_21_4/NMSWorldImpl.java | 12 ------------ .../superiorskyblock/nms/v1_21_5/NMSWorldImpl.java | 10 ---------- .../superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java | 6 ------ .../bgsoftware/superiorskyblock/nms/NMSWorld.java | 3 --- 13 files changed, 137 deletions(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java index 69f33c8479..9bcf0dc798 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java @@ -48,7 +48,6 @@ import org.bukkit.craftbukkit.v1_12_R1.block.CraftSign; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; import org.bukkit.entity.Player; -import org.bukkit.event.block.SignChangeEvent; import org.bukkit.material.MaterialData; import java.lang.reflect.Modifier; @@ -246,11 +245,6 @@ public void placeSign(Island island, Location location) { System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4); } - @Override - public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { - // Not implemented - only needed for Paper 1.16+ - } - @Override public void playGeneratorSound(Location location) { WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java index bc742a27eb..9d9a448f28 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java @@ -57,13 +57,11 @@ import org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; import org.bukkit.entity.Player; -import org.bukkit.event.block.SignChangeEvent; import java.util.function.IntFunction; public class NMSWorldImpl implements NMSWorld { - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectMethod SOUND_VOLUME = new ReflectMethod<>(SoundEffectType.class, "a"); private static final ReflectMethod SOUND_PITCH = new ReflectMethod<>(SoundEffectType.class, "b"); private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(World.class, @@ -255,15 +253,6 @@ public void placeSign(Island island, Location location) { System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4); } - @Override - public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { - if (LINES_SIGN_CHANGE_EVENT.isValid()) { - for (int i = 0; i < lines.length; i++) - //noinspection deprecation - signChangeEvent.setLine(i, lines[i]); - } - } - @Override public void playGeneratorSound(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index 9c780c371f..e3205e2159 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_17; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -58,7 +57,6 @@ import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; import org.bukkit.entity.Player; -import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; import java.util.Iterator; @@ -68,9 +66,6 @@ public class NMSWorldImpl implements NMSWorld { - private static final byte[] EMPTY_LIGHTS = new byte[0]; - - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, Object.class, "chunkPacketBlockController") .removeFinal(); @@ -280,14 +275,6 @@ public void placeSign(Island island, Location location) { System.arraycopy(newLines, 0, signBlockEntity.messages, 0, 4); } - @Override - public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { - if (LINES_SIGN_CHANGE_EVENT.isValid()) { - for (int i = 0; i < lines.length; i++) - signChangeEvent.setLine(i, lines[i]); - } - } - @Override public void playGeneratorSound(Location location) { org.bukkit.World bukkitWorld = location.getWorld(); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index d33fdc2bb7..8562dfed55 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_18; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -59,7 +58,6 @@ import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; import org.bukkit.entity.Player; -import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; import java.util.Iterator; @@ -69,9 +67,6 @@ public class NMSWorldImpl implements NMSWorld { - private static final byte[] EMPTY_LIGHTS = new byte[0]; - - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, Object.class, "chunkPacketBlockController") .removeFinal(); @@ -281,15 +276,6 @@ public void placeSign(Island island, Location location) { System.arraycopy(newLines, 0, signBlockEntity.messages, 0, 4); } - @SuppressWarnings("deprecation") - @Override - public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { - if (LINES_SIGN_CHANGE_EVENT.isValid()) { - for (int i = 0; i < lines.length; i++) - signChangeEvent.setLine(i, lines[i]); - } - } - @Override public void playGeneratorSound(Location location) { org.bukkit.World bukkitWorld = location.getWorld(); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index f1b92ef700..d179836a99 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_19; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -61,7 +60,6 @@ import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; import org.bukkit.entity.Player; -import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; import java.util.Iterator; @@ -71,7 +69,6 @@ public class NMSWorldImpl implements NMSWorld { - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, Object.class, "chunkPacketBlockController") .removeFinal(); @@ -285,15 +282,6 @@ public void placeSign(Island island, Location location) { System.arraycopy(newLines, 0, signBlockEntity.messages, 0, 4); } - @SuppressWarnings("deprecation") - @Override - public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { - if (LINES_SIGN_CHANGE_EVENT.isValid()) { - for (int i = 0; i < lines.length; i++) - signChangeEvent.setLine(i, lines[i]); - } - } - @Override public void playGeneratorSound(Location location) { org.bukkit.World bukkitWorld = location.getWorld(); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index 8979e0d2b2..a173a6e6c3 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_3; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -61,7 +60,6 @@ import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; import org.bukkit.entity.Player; -import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; import java.util.Iterator; @@ -71,7 +69,6 @@ public class NMSWorldImpl implements NMSWorld { - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( @@ -289,15 +286,6 @@ public void placeSign(Island island, Location location) { System.arraycopy(newLines, 0, messages, 0, 4); } - @SuppressWarnings("deprecation") - @Override - public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { - if (LINES_SIGN_CHANGE_EVENT.isValid()) { - for (int i = 0; i < lines.length; i++) - signChangeEvent.setLine(i, lines[i]); - } - } - @Override public void playGeneratorSound(Location location) { org.bukkit.World bukkitWorld = location.getWorld(); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index 9d3e9ab9fe..94718dd03d 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_4; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -61,7 +60,6 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; -import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; import java.util.Iterator; @@ -71,9 +69,6 @@ public class NMSWorldImpl implements NMSWorld { - private static final byte[] EMPTY_LIGHTS = new byte[0]; - - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( @@ -291,15 +286,6 @@ public void placeSign(Island island, Location location) { System.arraycopy(newLines, 0, messages, 0, 4); } - @SuppressWarnings("deprecation") - @Override - public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { - if (LINES_SIGN_CHANGE_EVENT.isValid()) { - for (int i = 0; i < lines.length; i++) - signChangeEvent.setLine(i, lines[i]); - } - } - @Override public void playGeneratorSound(Location location) { World bukkitWorld = location.getWorld(); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index 9ef1f047af..081aa9c300 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_21; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -68,7 +67,6 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; -import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; import java.util.Iterator; @@ -78,7 +76,6 @@ public class NMSWorldImpl implements NMSWorld { - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( @@ -340,15 +337,6 @@ public void placeSign(Island island, Location location) { System.arraycopy(newLines, 0, messages, 0, 4); } - @SuppressWarnings("deprecation") - @Override - public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { - if (LINES_SIGN_CHANGE_EVENT.isValid()) { - for (int i = 0; i < lines.length; i++) - signChangeEvent.setLine(i, lines[i]); - } - } - @Override public void playGeneratorSound(Location location) { World bukkitWorld = location.getWorld(); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index e653696369..bdeec755bb 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_3; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -68,7 +67,6 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; -import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; import java.util.Iterator; @@ -78,7 +76,6 @@ public class NMSWorldImpl implements NMSWorld { - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( @@ -340,15 +337,6 @@ public void placeSign(Island island, Location location) { System.arraycopy(newLines, 0, messages, 0, 4); } - @SuppressWarnings("deprecation") - @Override - public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { - if (LINES_SIGN_CHANGE_EVENT.isValid()) { - for (int i = 0; i < lines.length; i++) - signChangeEvent.setLine(i, lines[i]); - } - } - @Override public void playGeneratorSound(Location location) { World bukkitWorld = location.getWorld(); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index 5e0d4ec4f0..00bf81a17e 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_4; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -68,7 +67,6 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; -import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; import java.util.Iterator; @@ -78,7 +76,6 @@ public class NMSWorldImpl implements NMSWorld { - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( @@ -340,15 +337,6 @@ public void placeSign(Island island, Location location) { System.arraycopy(newLines, 0, messages, 0, 4); } - @SuppressWarnings("deprecation") - @Override - public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { - if (LINES_SIGN_CHANGE_EVENT.isValid()) { - for (int i = 0; i < lines.length; i++) - signChangeEvent.setLine(i, lines[i]); - } - } - @Override public void playGeneratorSound(Location location) { World bukkitWorld = location.getWorld(); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java index 888cd3f6f6..1b42215bbb 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java @@ -78,7 +78,6 @@ public class NMSWorldImpl implements NMSWorld { - private static final ReflectMethod LINES_SIGN_CHANGE_EVENT = new ReflectMethod<>(SignChangeEvent.class, "lines"); private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( @@ -340,15 +339,6 @@ public void placeSign(Island island, Location location) { System.arraycopy(newLines, 0, messages, 0, 4); } - @SuppressWarnings("deprecation") - @Override - public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { - if (LINES_SIGN_CHANGE_EVENT.isValid()) { - for (int i = 0; i < lines.length; i++) - signChangeEvent.setLine(i, lines[i]); - } - } - @Override public void playGeneratorSound(Location location) { World bukkitWorld = location.getWorld(); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java index 15731b28a0..6fa1745654 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java @@ -46,7 +46,6 @@ import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; import org.bukkit.entity.Player; -import org.bukkit.event.block.SignChangeEvent; import org.bukkit.material.MaterialData; import java.lang.reflect.Modifier; @@ -248,11 +247,6 @@ public void placeSign(Island island, Location location) { System.arraycopy(newLines, 0, tileEntitySign.lines, 0, 4); } - @Override - public void setSignLines(SignChangeEvent signChangeEvent, String[] lines) { - // Not implemented - only needed for Paper 1.16+ - } - @Override public void playGeneratorSound(Location location) { WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java index e3fc2de6ad..472a5128eb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java @@ -15,7 +15,6 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; -import org.bukkit.event.block.SignChangeEvent; import java.util.function.IntFunction; @@ -57,8 +56,6 @@ default SignType getSignType(Block block) { void placeSign(Island island, Location location); - void setSignLines(SignChangeEvent signChangeEvent, String[] lines); - void playGeneratorSound(Location location); void playBreakAnimation(Block block); From b854270814ba33cd2f2ea3a4f6c2420de03bb500 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 17 Apr 2025 21:58:27 +0300 Subject: [PATCH 112/600] More debug messages to null used item in BlockPlaceEvent (#2402) --- .../superiorskyblock/listener/StackedBlocksListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java index d0c4a44de1..ecacb1dad4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java @@ -80,7 +80,7 @@ private void onStackedBlockPlace(GameEvent e) { ItemStack inHand = e.getArgs().usedItem; if (inHand == null) { - Log.error("BlockPlaceEvent with null hand item:", usedHand); + Log.error("BlockPlaceEvent by player ", player.getName(), " of block ", block.getType().name(), " with null hand item: ", usedHand); throw new RuntimeException("BlockPlaceEvent with null hand item"); } From 605e957366beaaefd914ea3be5b229b34c839f55 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 17 Apr 2025 23:26:30 +0300 Subject: [PATCH 113/600] Attempt to auto fix tile entities that do not have ids in schematics (#2326) --- .../nms/v1_12_R1/NMSAlgorithmsImpl.java | 14 +++++++ .../nms/v1_12_R1/world/BlockEntityCache.java | 34 +++++++++++++++++ .../nms/v1_16_R3/NMSAlgorithmsImpl.java | 15 ++++++++ .../nms/v1_16_R3/world/BlockEntityCache.java | 34 +++++++++++++++++ .../nms/v1_17/NMSAlgorithmsImpl.java | 15 ++++++++ .../nms/v1_17/world/BlockEntityCache.java | 34 +++++++++++++++++ .../nms/v1_18/NMSAlgorithmsImpl.java | 15 ++++++++ .../nms/v1_18/world/BlockEntityCache.java | 34 +++++++++++++++++ .../nms/v1_19/NMSAlgorithmsImpl.java | 15 ++++++++ .../nms/v1_19/world/BlockEntityCache.java | 34 +++++++++++++++++ .../nms/v1_20_3/NMSAlgorithmsImpl.java | 15 ++++++++ .../nms/v1_20_3/world/BlockEntityCache.java | 34 +++++++++++++++++ .../nms/v1_20_4/NMSAlgorithmsImpl.java | 15 ++++++++ .../nms/v1_20_4/world/BlockEntityCache.java | 34 +++++++++++++++++ .../nms/v1_21/NMSAlgorithmsImpl.java | 15 ++++++++ .../nms/v1_21/world/BlockEntityCache.java | 34 +++++++++++++++++ .../nms/v1_21_3/NMSAlgorithmsImpl.java | 15 ++++++++ .../nms/v1_21_3/world/BlockEntityCache.java | 34 +++++++++++++++++ .../nms/v1_21_4/NMSAlgorithmsImpl.java | 15 ++++++++ .../nms/v1_21_4/world/BlockEntityCache.java | 34 +++++++++++++++++ .../nms/v1_21_5/NMSAlgorithmsImpl.java | 16 +++++++- .../nms/v1_21_5/world/BlockEntityCache.java | 34 +++++++++++++++++ .../nms/v1_8_R3/NMSAlgorithmsImpl.java | 14 +++++++ .../nms/v1_8_R3/world/BlockEntityCache.java | 38 +++++++++++++++++++ .../core/schematic/SchematicBlock.java | 8 ++++ .../superiorskyblock/nms/NMSAlgorithms.java | 4 ++ .../impl/SuperiorSchematicDeserializer.java | 10 +++++ 27 files changed, 612 insertions(+), 1 deletion(-) create mode 100644 NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/BlockEntityCache.java create mode 100644 NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockEntityCache.java create mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockEntityCache.java create mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockEntityCache.java create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockEntityCache.java create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockEntityCache.java create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockEntityCache.java create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockEntityCache.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockEntityCache.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockEntityCache.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockEntityCache.java create mode 100644 NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/BlockEntityCache.java diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java index 72baa2c14e..1450dca54b 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java @@ -3,8 +3,10 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; +import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_12_R1.world.KeyBlocksCache; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockPosition; @@ -76,6 +78,18 @@ public int getCombinedId(Material material, byte data) { return material.getId() + (data << 12); } + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + IBlockData blockData = Block.getByCombinedId(combinedId); + + if (!blockData.getBlock().isTileEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getTileEntityId(blockData); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + @Override public int compareMaterials(Material o1, Material o2) { return Integer.compare(o1.ordinal(), o2.ordinal()); diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/BlockEntityCache.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/BlockEntityCache.java new file mode 100644 index 0000000000..999dc1edf5 --- /dev/null +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/BlockEntityCache.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world; + +import net.minecraft.server.v1_12_R1.Block; +import net.minecraft.server.v1_12_R1.IBlockData; +import net.minecraft.server.v1_12_R1.ITileEntity; +import net.minecraft.server.v1_12_R1.MinecraftServer; +import net.minecraft.server.v1_12_R1.TileEntity; +import net.minecraft.server.v1_12_R1.World; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getTileEntityId(IBlockData blockData) { + return BLOCK_TO_ID.computeIfAbsent(blockData.getBlock(), block -> { + if (block instanceof ITileEntity) { + World world = MinecraftServer.getServer().getWorld(); + TileEntity tileEntity = ((ITileEntity) block).a(world, block.toLegacyData(blockData)); + if (tileEntity != null) + return tileEntity.getMinecraftKeyString(); + } + + return ""; + }); + } + +} diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java index f7dd7ab84a..7f71177317 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -15,6 +16,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu.MenuTileEntityDispenser; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu.MenuTileEntityFurnace; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.menu.MenuTileEntityHopper; +import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.KeyBlocksCache; import io.papermc.paper.chat.ChatComposer; import io.papermc.paper.event.player.AsyncChatEvent; @@ -57,6 +59,7 @@ import java.lang.reflect.Field; import java.util.EnumMap; +import java.util.Optional; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { @@ -121,6 +124,18 @@ public int getCombinedId(Material material, byte data) { return blockData == null ? -1 : Block.getCombinedId(blockData); } + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + IBlockData blockData = Block.getByCombinedId(combinedId); + + if (!blockData.getBlock().isTileEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getTileEntityId(blockData); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + @Override public int compareMaterials(Material o1, Material o2) { int firstMaterial = o1.isBlock() ? Block.getCombinedId(CraftMagicNumbers.getBlock(o1).getBlockData()) : o1.ordinal(); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockEntityCache.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockEntityCache.java new file mode 100644 index 0000000000..46ad0bafc7 --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockEntityCache.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world; + +import net.minecraft.server.v1_16_R3.Block; +import net.minecraft.server.v1_16_R3.IBlockData; +import net.minecraft.server.v1_16_R3.IRegistry; +import net.minecraft.server.v1_16_R3.MinecraftKey; +import net.minecraft.server.v1_16_R3.TileEntityTypes; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getTileEntityId(IBlockData blockData) { + return BLOCK_TO_ID.computeIfAbsent(blockData.getBlock(), block -> { + for (TileEntityTypes tileEntityTypes : IRegistry.BLOCK_ENTITY_TYPE) { + if (tileEntityTypes.isValidBlock(block)) { + MinecraftKey minecraftKey = TileEntityTypes.a(tileEntityTypes); + if (minecraftKey != null) + return minecraftKey.getKey(); + } + } + + return ""; + }); + } + +} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java index 0d8eeed2da..bb271c6437 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -15,6 +16,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_17.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_17.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_17.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_17.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_17.world.KeyBlocksCache; import io.papermc.paper.chat.ChatRenderer; import net.kyori.adventure.audience.Audience; @@ -55,6 +57,7 @@ import java.lang.reflect.Field; import java.util.EnumMap; +import java.util.Optional; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { @@ -124,6 +127,18 @@ public int getCombinedId(Material material, byte data) { return blockState == null ? -1 : Block.getId(blockState); } + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + BlockState blockState = Block.stateById(combinedId); + + if (!blockState.hasBlockEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getBlockEntityId(blockState); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + @Override public int compareMaterials(Material o1, Material o2) { int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockEntityCache.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockEntityCache.java new file mode 100644 index 0000000000..7546de6212 --- /dev/null +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockEntityCache.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v1_17.world; + +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getBlockEntityId(BlockState blockState) { + return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { + for (BlockEntityType blockEntityType : Registry.BLOCK_ENTITY_TYPE) { + if (blockEntityType.isValid(blockState)) { + ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); + if (resourceLocation != null) + return resourceLocation.toString(); + } + } + + return ""; + }); + } + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java index f62b188afb..587a338be3 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -16,6 +17,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_18.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_18.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_18.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_18.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_18.world.KeyBlocksCache; import io.papermc.paper.chat.ChatRenderer; import net.kyori.adventure.audience.Audience; @@ -56,6 +58,7 @@ import java.lang.reflect.Field; import java.util.EnumMap; +import java.util.Optional; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { @@ -125,6 +128,18 @@ public int getCombinedId(Material material, byte data) { return blockState == null ? -1 : Block.getId(blockState); } + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + BlockState blockState = Block.stateById(combinedId); + + if (!blockState.hasBlockEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getBlockEntityId(blockState); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + @Override public int compareMaterials(Material o1, Material o2) { int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockEntityCache.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockEntityCache.java new file mode 100644 index 0000000000..e61a5675ea --- /dev/null +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockEntityCache.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v1_18.world; + +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getBlockEntityId(BlockState blockState) { + return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { + for (BlockEntityType blockEntityType : Registry.BLOCK_ENTITY_TYPE) { + if (blockEntityType.isValid(blockState)) { + ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); + if (resourceLocation != null) + return resourceLocation.toString(); + } + } + + return ""; + }); + } + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java index e671b2e8ba..33af50d8f8 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -16,6 +17,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_19.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_19.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_19.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_19.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_19.world.KeyBlocksCache; import io.papermc.paper.chat.ChatRenderer; import net.kyori.adventure.audience.Audience; @@ -56,6 +58,7 @@ import java.lang.reflect.Field; import java.util.EnumMap; +import java.util.Optional; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { @@ -125,6 +128,18 @@ public int getCombinedId(Material material, byte data) { return blockState == null ? -1 : Block.getId(blockState); } + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + BlockState blockState = Block.stateById(combinedId); + + if (!blockState.hasBlockEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getBlockEntityId(blockState); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + @Override public int compareMaterials(Material o1, Material o2) { int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockEntityCache.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockEntityCache.java new file mode 100644 index 0000000000..97c991f53f --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockEntityCache.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.world; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getBlockEntityId(BlockState blockState) { + return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { + for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { + if (blockEntityType.isValid(blockState)) { + ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); + if (resourceLocation != null) + return resourceLocation.toString(); + } + } + + return ""; + }); + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java index ccb7432cb2..5c0cc4f5e0 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -17,6 +18,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_20_3.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_20_3.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.KeyBlocksCache; import io.papermc.paper.chat.ChatRenderer; import net.kyori.adventure.audience.Audience; @@ -60,6 +62,7 @@ import java.util.EnumMap; import java.util.Map; +import java.util.Optional; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { @@ -132,6 +135,18 @@ public int getCombinedId(Material material, byte data) { return blockState == null ? -1 : Block.getId(blockState); } + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + BlockState blockState = Block.stateById(combinedId); + + if (!blockState.hasBlockEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getBlockEntityId(blockState); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + @Override public int compareMaterials(Material o1, Material o2) { int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockEntityCache.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockEntityCache.java new file mode 100644 index 0000000000..45ef688d63 --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockEntityCache.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getBlockEntityId(BlockState blockState) { + return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { + for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { + if (blockEntityType.isValid(blockState)) { + ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); + if (resourceLocation != null) + return resourceLocation.toString(); + } + } + + return ""; + }); + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java index 5a4b9ac6de..b656e17d00 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -14,6 +15,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_4.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_20_4.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_20_4.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.KeyBlocksCache; import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; @@ -56,6 +58,7 @@ import org.jetbrains.annotations.NotNull; import java.util.EnumMap; +import java.util.Optional; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { @@ -126,6 +129,18 @@ public int getCombinedId(Material material, byte data) { return blockState == null ? -1 : Block.getId(blockState); } + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + BlockState blockState = Block.stateById(combinedId); + + if (!blockState.hasBlockEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getBlockEntityId(blockState); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + @Override public int compareMaterials(Material o1, Material o2) { int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockEntityCache.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockEntityCache.java new file mode 100644 index 0000000000..6753f01bca --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockEntityCache.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getBlockEntityId(BlockState blockState) { + return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { + for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { + if (blockEntityType.isValid(blockState)) { + ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); + if (resourceLocation != null) + return resourceLocation.toString(); + } + } + + return ""; + }); + } + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java index 034e940a4a..652f8904ba 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -14,6 +15,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_21.world.KeyBlocksCache; import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; @@ -57,6 +59,7 @@ import org.jetbrains.annotations.NotNull; import java.util.EnumMap; +import java.util.Optional; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { @@ -127,6 +130,18 @@ public int getCombinedId(Material material, byte data) { return blockState == null ? -1 : Block.getId(blockState); } + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + BlockState blockState = Block.stateById(combinedId); + + if (!blockState.hasBlockEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getBlockEntityId(blockState); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + @Override public int compareMaterials(Material o1, Material o2) { int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockEntityCache.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockEntityCache.java new file mode 100644 index 0000000000..38add37e5f --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockEntityCache.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.world; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getBlockEntityId(BlockState blockState) { + return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { + for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { + if (blockEntityType.isValid(blockState)) { + ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); + if (resourceLocation != null) + return resourceLocation.toString(); + } + } + + return ""; + }); + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java index 8d9851249e..6a47875ac8 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -14,6 +15,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_3.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_3.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_3.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.KeyBlocksCache; import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; @@ -57,6 +59,7 @@ import org.jetbrains.annotations.NotNull; import java.util.EnumMap; +import java.util.Optional; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { @@ -127,6 +130,18 @@ public int getCombinedId(Material material, byte data) { return blockState == null ? -1 : Block.getId(blockState); } + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + BlockState blockState = Block.stateById(combinedId); + + if (!blockState.hasBlockEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getBlockEntityId(blockState); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + @Override public int compareMaterials(Material o1, Material o2) { int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockEntityCache.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockEntityCache.java new file mode 100644 index 0000000000..2fc27effc2 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockEntityCache.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getBlockEntityId(BlockState blockState) { + return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { + for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { + if (blockEntityType.isValid(blockState)) { + ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); + if (resourceLocation != null) + return resourceLocation.toString(); + } + } + + return ""; + }); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index 5bf94eaa52..2688da1993 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; @@ -14,6 +15,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; @@ -57,6 +59,7 @@ import org.jetbrains.annotations.NotNull; import java.util.EnumMap; +import java.util.Optional; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { @@ -127,6 +130,18 @@ public int getCombinedId(Material material, byte data) { return blockState == null ? -1 : Block.getId(blockState); } + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + BlockState blockState = Block.stateById(combinedId); + + if (!blockState.hasBlockEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getBlockEntityId(blockState); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + @Override public int compareMaterials(Material o1, Material o2) { int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockEntityCache.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockEntityCache.java new file mode 100644 index 0000000000..5cc780bf72 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockEntityCache.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getBlockEntityId(BlockState blockState) { + return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { + for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { + if (blockEntityType.isValid(blockState)) { + ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); + if (resourceLocation != null) + return resourceLocation.toString(); + } + } + + return ""; + }); + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java index b41990f17c..cbdcd661f9 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java @@ -6,15 +6,16 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_5.menu.MenuBrewingStandBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_5.menu.MenuDispenserBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_5.menu.MenuFurnaceBlockEntity; import com.bgsoftware.superiorskyblock.nms.v1_21_5.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.KeyBlocksCache; import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; @@ -58,6 +59,7 @@ import org.jetbrains.annotations.NotNull; import java.util.EnumMap; +import java.util.Optional; import java.util.function.BiFunction; public class NMSAlgorithmsImpl implements NMSAlgorithms { @@ -128,6 +130,18 @@ public int getCombinedId(Material material, byte data) { return blockState == null ? -1 : Block.getId(blockState); } + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + BlockState blockState = Block.stateById(combinedId); + + if (!blockState.hasBlockEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getBlockEntityId(blockState); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + @Override public int compareMaterials(Material o1, Material o2) { int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockEntityCache.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockEntityCache.java new file mode 100644 index 0000000000..f968fb4245 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockEntityCache.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getBlockEntityId(BlockState blockState) { + return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { + for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { + if (blockEntityType.isValid(blockState)) { + ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); + if (resourceLocation != null) + return resourceLocation.toString(); + } + } + + return ""; + }); + } + +} diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java index 00efa7d6d2..d737c323fa 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java @@ -3,8 +3,10 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; +import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.world.KeyBlocksCache; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockPosition; @@ -76,6 +78,18 @@ public int getCombinedId(Material material, byte data) { return material.getId() + (data << 12); } + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + IBlockData blockData = Block.getByCombinedId(combinedId); + + if (!blockData.getBlock().isTileEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getTileEntityId(blockData); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + @Override public int compareMaterials(Material o1, Material o2) { return Integer.compare(o1.ordinal(), o2.ordinal()); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/BlockEntityCache.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/BlockEntityCache.java new file mode 100644 index 0000000000..dd22c21c53 --- /dev/null +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/BlockEntityCache.java @@ -0,0 +1,38 @@ +package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world; + +import net.minecraft.server.v1_8_R3.Block; +import net.minecraft.server.v1_8_R3.IBlockData; +import net.minecraft.server.v1_8_R3.IContainer; +import net.minecraft.server.v1_8_R3.MinecraftServer; +import net.minecraft.server.v1_8_R3.NBTTagCompound; +import net.minecraft.server.v1_8_R3.TileEntity; +import net.minecraft.server.v1_8_R3.World; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getTileEntityId(IBlockData blockData) { + return BLOCK_TO_ID.computeIfAbsent(blockData.getBlock(), block -> { + if (block instanceof IContainer) { + World world = MinecraftServer.getServer().getWorld(); + TileEntity tileEntity = ((IContainer) block).a(world, block.toLegacyData(blockData)); + if (tileEntity != null) { + NBTTagCompound nbtTagCompound = new NBTTagCompound(); + tileEntity.b(nbtTagCompound); + return nbtTagCompound.getString("id"); + } + } + + return ""; + }); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java index 65afef3268..f53796dfbb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java @@ -196,6 +196,14 @@ public Extra(@Nullable CompoundTag statesTag, @Nullable CompoundTag tileEntity) this.tileEntity = tileEntity; } + public CompoundTag getTileEntity() { + return tileEntity; + } + + public CompoundTag getStatesTag() { + return statesTag; + } + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java index 0919f69d39..40698e0b77 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java @@ -17,6 +17,8 @@ import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.potion.PotionEffect; +import java.util.Optional; + public interface NMSAlgorithms { void registerCommand(BukkitCommand command); @@ -27,6 +29,8 @@ public interface NMSAlgorithms { int getCombinedId(Material material, byte data); + Optional getTileEntityIdFromCombinedId(int combinedId); + int compareMaterials(Material o1, Material o2); short getBlockDataValue(BlockState blockState); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematicDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematicDeserializer.java index 29cb27c8c0..282079c5d7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematicDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematicDeserializer.java @@ -205,6 +205,16 @@ public static SchematicBlockData deserializeSchematicBlock(CompoundTag compoundT SchematicBlock.Extra extra = deserializeSchematicBlockExtra(compoundTag, dataVersion); + if (extra != null) { + CompoundTag tileEntityTag = extra.getTileEntity(); + if (tileEntityTag != null && !tileEntityTag.containsKey("id")) { + // We try to detect the id from its combinedId + plugin.getNMSAlgorithms().getTileEntityIdFromCombinedId(combinedId).ifPresent(tileEntityId -> { + tileEntityTag.setString("id", tileEntityId); + }); + } + } + return new SchematicBlockData(combinedId, blockOffset, extra); } From b03a8baaf732c32f98dbb218d17d6f83f9cdbad6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 17 Apr 2025 23:46:41 +0300 Subject: [PATCH 114/600] Add debug message to null front_text in signs (#2405) --- .../superiorskyblock/core/schematic/SchematicBlock.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java index f53796dfbb..3fd6b72677 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java @@ -127,6 +127,11 @@ private static void backFrontSignLinesReplace(CompoundTag tileEntityData, Island CompoundTag frontText = tileEntityData.getCompound("front_text"); CompoundTag backText = tileEntityData.getCompound("back_text"); + if (frontText == null || backText == null) { + // This should never occur + Log.error("Invalid sign tile entity data: ", tileEntityData); + } + ListTag frontTextMessages = frontText.getList("messages"); ListTag backTextMessages = backText.getList("messages"); ListTag newFrontTextMessages = new ListTag(StringTag.class, Collections.emptyList()); From 0fd9333f4ea39986a40d19a0a43e2f24166108ec Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 17 Apr 2025 23:55:16 +0300 Subject: [PATCH 115/600] Do not call NMSChunks#startTickingChunk asynchronous (#2408) --- .../superiorskyblock/island/SIsland.java | 24 +++++++++++++------ .../schematic/impl/SuperiorSchematic.java | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 4ab944dd70..ecb1b7e2c0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -55,9 +55,9 @@ import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.BaseKey; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; @@ -67,6 +67,7 @@ import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; import com.bgsoftware.superiorskyblock.core.profiler.ProfileType; import com.bgsoftware.superiorskyblock.core.profiler.Profiler; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; @@ -1899,18 +1900,27 @@ public void setIslandSize(int islandSize) { private void setIslandSizeInternal(IntValue islandSize) { boolean cropGrowthEnabled = BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class); + MutableObject> oldChunks = new MutableObject<>(null); + + if (cropGrowthEnabled) { - // First, we want to remove all the current crop tile entities - getLoadedChunks(IslandChunkFlags.ONLY_PROTECTED).forEach(chunk -> - plugin.getNMSChunks().startTickingChunk(this, chunk, true)); + // We first collect all the chunks that are currently being ticked + oldChunks.setValue(getLoadedChunks(IslandChunkFlags.ONLY_PROTECTED)); } + // Changing the size of the island this.islandSize.set(islandSize); if (cropGrowthEnabled) { - // Now, we want to update the tile entities again - getLoadedChunks(IslandChunkFlags.ONLY_PROTECTED).forEach(chunk -> - plugin.getNMSChunks().startTickingChunk(this, chunk, false)); + // We now collect the new chunks after the size was changed + List newChunks = getLoadedChunks(IslandChunkFlags.ONLY_PROTECTED); + + BukkitExecutor.ensureMain(() -> { + // We stop all old chunks from being ticked. + oldChunks.getValue().forEach(chunk -> plugin.getNMSChunks().startTickingChunk(this, chunk, true)); + // We start ticking all the new chunks + newChunks.forEach(chunk -> plugin.getNMSChunks().startTickingChunk(this, chunk, false)); + }); } updateBorder(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java index b0ae4769bd..fafd1cb7c9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java @@ -268,7 +268,7 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long boolean cropGrowthEnabled = BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class); if (cropGrowthEnabled && island.isInsideRange(chunk)) { - plugin.getNMSChunks().startTickingChunk(island, chunk, false); + BukkitExecutor.ensureMain(() -> plugin.getNMSChunks().startTickingChunk(island, chunk, false)); } island.markChunkDirty(chunk.getWorld(), chunk.getX(), chunk.getZ(), true); From a2a120fdc099e3fa088c69b2822249e31d74bb28 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 18 Apr 2025 20:48:53 +0300 Subject: [PATCH 116/600] Fixed usedItem can be null in BlockPlaceEvent (#2402) --- .../listener/BukkitEventsListener.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index 154bf16411..aba534cfe4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -4,6 +4,7 @@ import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.platform.IEventsDispatcher; +import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.events.EventCallback; import com.bgsoftware.superiorskyblock.core.key.Keys; @@ -20,6 +21,7 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; @@ -91,6 +93,7 @@ import org.bukkit.event.world.ChunkUnloadEvent; import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.event.world.WorldUnloadEvent; +import org.bukkit.inventory.ItemStack; import java.util.List; import java.util.Map; @@ -254,7 +257,7 @@ private GameEvent createGameEvent(GameEventType createGameEvent(GameEventTy playerInteractEvent.player = e.getPlayer(); playerInteractEvent.action = e.getAction(); playerInteractEvent.usedHand = BukkitItems.getHand(e); - playerInteractEvent.usedItem = BukkitItems.getHandItem(e.getPlayer(), playerInteractEvent.usedHand); + playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true); playerInteractEvent.clickedBlock = e.getClickedBlock(); return eventType.createEvent(playerInteractEvent); } @@ -504,7 +507,7 @@ private GameEvent createGameEvent(GameEventTy playerInteractEvent.player = e.getPlayer(); playerInteractEvent.action = Action.RIGHT_CLICK_AIR; playerInteractEvent.usedHand = BukkitItems.getHand(e); - playerInteractEvent.usedItem = BukkitItems.getHandItem(e.getPlayer(), playerInteractEvent.usedHand); + playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true); playerInteractEvent.clickedEntity = e.getRightClicked(); return eventType.createEvent(playerInteractEvent); } @@ -514,7 +517,7 @@ private GameEvent createGameEvent(GameEventTy playerInteractEvent.player = e.getPlayer(); playerInteractEvent.action = Action.RIGHT_CLICK_AIR; playerInteractEvent.usedHand = BukkitItems.getHand(e); - playerInteractEvent.usedItem = BukkitItems.getHandItem(e.getPlayer(), playerInteractEvent.usedHand); + playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true); playerInteractEvent.clickedEntity = e.getRightClicked(); return eventType.createEvent(playerInteractEvent); } @@ -825,6 +828,14 @@ private void createEventListenerForPr }, plugin, false); } + private static ItemStack getHandItem(Player player, PlayerHand usedHand, boolean clone) { + ItemStack itemStack = BukkitItems.getHandItem(player, usedHand); + if (clone && itemStack != null) { + itemStack = itemStack.clone(); + } + return itemStack; + } + private interface GameEventCreator { @Nullable From d84223dde7e4cb61cd5ff4b02fd46947be5ffd4e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 18 Apr 2025 21:01:37 +0300 Subject: [PATCH 117/600] Changed default placeholders to support only prefixes of placeholders (#2406) --- .../placeholders/PlaceholdersServiceImpl.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index ef43980414..b73efdbab8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -294,8 +294,21 @@ public String handlePluginPlaceholder(@Nullable OfflinePlayer offlinePlayer, Str } } - return placeholderResult.orElse(plugin.getSettings().getDefaultPlaceholders() - .getOrDefault(placeholder, "")); + if (placeholderResult.isPresent()) + return placeholderResult.get(); + + String defaultPlaceholderValue = plugin.getSettings().getDefaultPlaceholders().get(placeholder); + if (defaultPlaceholderValue != null) + return defaultPlaceholderValue; + + // We try to look for prefixes of placeholders + for (Map.Entry entry : plugin.getSettings().getDefaultPlaceholders().entrySet()) { + if (placeholder.startsWith(entry.getKey())) { + return entry.getValue(); + } + } + + return ""; } @Override From 6a058c79279b8fe3928d42262573516661c52c21 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 18 Apr 2025 21:06:28 +0300 Subject: [PATCH 118/600] Fixed asynchronous issues with WildStacker's snapshots container (#2409) --- .../external/WildStackerSnapshotsContainer.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java index f8cd017a80..41b3aedc4c 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java @@ -3,13 +3,14 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.wildstacker.api.WildStackerAPI; import com.bgsoftware.wildstacker.api.objects.StackedSnapshot; import org.bukkit.Chunk; public class WildStackerSnapshotsContainer { - private static final Chunk2ObjectMap cachedSnapshots = new Chunk2ObjectMap<>(); + private static final Synchronized> cachedSnapshots = Synchronized.of(new Chunk2ObjectMap<>()); private WildStackerSnapshotsContainer() { @@ -17,11 +18,12 @@ private WildStackerSnapshotsContainer() { public static void takeSnapshot(Chunk chunk) { try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { - takeSnapshotInternal(chunk, chunkPosition); + cachedSnapshots.write(cachedSnapshots -> + takeSnapshotInternal(chunk, chunkPosition, cachedSnapshots)); } } - private static void takeSnapshotInternal(Chunk chunk, ChunkPosition chunkPosition) { + private static void takeSnapshotInternal(Chunk chunk, ChunkPosition chunkPosition, Chunk2ObjectMap cachedSnapshots) { if (cachedSnapshots.containsKey(chunkPosition)) return; @@ -44,11 +46,11 @@ private static void takeSnapshotInternal(Chunk chunk, ChunkPosition chunkPositio } public static void releaseSnapshot(ChunkPosition chunkPosition) { - cachedSnapshots.remove(chunkPosition); + cachedSnapshots.write(m -> m.remove(chunkPosition)); } public static StackedSnapshot getSnapshot(ChunkPosition chunkPosition) { - StackedSnapshot stackedSnapshot = cachedSnapshots.get(chunkPosition); + StackedSnapshot stackedSnapshot = cachedSnapshots.readAndGet(m -> m.get(chunkPosition)); if (stackedSnapshot == null) { throw new RuntimeException("Chunk " + chunkPosition + " is not cached."); From 2b7a87339300fec10e3d5b966b26c68e81484697 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 18 Apr 2025 22:28:35 +0300 Subject: [PATCH 119/600] Better detection for ItemsAdder break & place (#2394) --- .../external/ItemsAdderHook.java | 62 ++++++++++++++----- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java b/Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java index 06ebb0ed51..e80f45b65d 100644 --- a/Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java +++ b/Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java @@ -3,7 +3,6 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordFlags; @@ -13,17 +12,15 @@ import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.listener.BlockChangesListener; import dev.lone.itemsadder.api.CustomBlock; import dev.lone.itemsadder.api.CustomStack; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.block.BlockState; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; import java.util.Locale; @@ -51,23 +48,60 @@ public static void register(SuperiorSkyblockPlugin plugin) { private static class ListenerImpl implements Listener { - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onBlockPlace(BlockPlaceEvent e) { - // ItemsAdder calls BlockPlaceEvent when the block is AIR. - if (e.getBlock().getType() != Material.AIR) + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + public void onItemAdderBlockInteract(PlayerInteractEvent e) { + switch (e.getAction()) { + case RIGHT_CLICK_BLOCK: + onBlockPlace(e); + break; + case LEFT_CLICK_BLOCK: + onBlockBreak(e); + break; + } + } + + private void onBlockPlace(PlayerInteractEvent e) { + if (e.getItem() == null) + return; + + CustomBlock customBlock = CustomBlock.byItemStack(e.getItem()); + if (customBlock == null) return; - BlockState oldState = e.getBlockReplacedState(); + CustomBlock clickedBlock = CustomBlock.byAlreadyPlaced(e.getClickedBlock()); + if (clickedBlock != null) + return; + + Block placeBlock = e.getClickedBlock().getRelative(e.getBlockFace()); BukkitExecutor.sync(() -> { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - worldRecordService.get().recordBlockPlace(Keys.of(e.getBlock()), - e.getBlock().getLocation(wrapper.getHandle()), 1, - oldState, WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS); + if (placeBlock.getType() == Material.NOTE_BLOCK) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Key itemKey = Keys.of(ITEMS_ADDER_PREFIX, customBlock.getId().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + worldRecordService.get().recordBlockPlace(itemKey, + placeBlock.getLocation(wrapper.getHandle()), 1, + null, WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS); + } } - }, 1L); + } + + private void onBlockBreak(PlayerInteractEvent e) { + CustomBlock clickedBlock = CustomBlock.byAlreadyPlaced(e.getClickedBlock()); + if (clickedBlock != null) { + Key blockKey = Key.of(e.getClickedBlock()); + BukkitExecutor.sync(() -> { + if (e.getClickedBlock().getType() == Material.AIR) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + worldRecordService.get().recordBlockBreak(blockKey, + e.getClickedBlock().getLocation(wrapper.getHandle()), + 1, + WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS); + } + } + }, 1L); + } } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) From 754d48841f2c32479ed338d35b314b76a8f512a9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 19 Apr 2025 13:33:22 +0300 Subject: [PATCH 120/600] Lazy load worlds in some methods that interact with chunks of islands --- .../api/island/DelegateIsland.java | 21 +++ .../superiorskyblock/api/island/Island.java | 39 +++++ .../superiorskyblock/core/IslandWorlds.java | 30 +++- .../superiorskyblock/island/SIsland.java | 138 ++++++++++++------ .../superiorskyblock/island/SpawnIsland.java | 32 ++++ 5 files changed, 215 insertions(+), 45 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index 22eaa4e6de..47714a4b37 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Chunk; @@ -620,6 +621,11 @@ public boolean isInside(World world, int chunkX, int chunkZ) { return this.handle.isInside(world, chunkX, chunkZ); } + @Override + public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) { + return this.handle.isInside(worldInfo, chunkX, chunkZ); + } + @Override public boolean isInsideRange(Location location) { return this.handle.isInsideRange(location); @@ -1264,16 +1270,31 @@ public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) { return this.handle.isChunkDirty(worldName, chunkX, chunkZ); } + @Override + public boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ) { + return this.handle.isChunkDirty(worldInfo, chunkX, chunkZ); + } + @Override public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) { this.handle.markChunkDirty(world, chunkX, chunkZ, save); } + @Override + public void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { + this.handle.markChunkDirty(worldInfo, chunkX, chunkZ, save); + } + @Override public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) { this.handle.markChunkEmpty(world, chunkX, chunkZ, save); } + @Override + public void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { + this.handle.markChunkEmpty(worldInfo, chunkX, chunkZ, save); + } + @Override public BigInteger getBlockCountAsBigInteger(Key key) { return this.handle.getBlockCountAsBigInteger(key); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java index 407be7dc16..1a0ec192c5 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java @@ -24,6 +24,7 @@ import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Chunk; @@ -877,6 +878,15 @@ List> getAllChunksAsync(World.Environment environment, */ boolean isInside(World world, int chunkX, int chunkZ); + /** + * Check if a chunk location is inside the island's area. + * + * @param worldInfo The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + */ + boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ); + /** * Check if the location is inside the island's protected area. * @@ -1756,6 +1766,15 @@ List> getAllChunksAsync(World.Environment environment, */ boolean isChunkDirty(String worldName, int chunkX, int chunkZ); + /** + * Check whether a chunk has blocks inside it. + * + * @param worldInfo The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + */ + boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ); + /** * Mark a chunk as it has blocks inside it. * @@ -1766,6 +1785,16 @@ List> getAllChunksAsync(World.Environment environment, */ void markChunkDirty(World world, int chunkX, int chunkZ, boolean save); + /** + * Mark a chunk as it has blocks inside it. + * + * @param worldInfo The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param save Whether to save the changes to database. + */ + void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save); + /** * Mark a chunk as it has no blocks inside it. * @@ -1776,6 +1805,16 @@ List> getAllChunksAsync(World.Environment environment, */ void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save); + /** + * Mark a chunk as it has no blocks inside it. + * + * @param worldInfo The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param save Whether to save the changes to database. + */ + void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save); + /** * Get the amount of blocks that are on the island. * diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java index 55ae490aba..f40bde7b1b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java @@ -5,6 +5,8 @@ import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import org.bukkit.Bukkit; import org.bukkit.World; import java.util.function.Consumer; @@ -13,18 +15,38 @@ public class IslandWorlds { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + public static void accessIslandWorldsAsync(Island island, Consumer> consumer) { + for (Dimension dimension : Dimension.values()) { + if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && island.wasSchematicGenerated(dimension)) { + accessIslandWorldAsync(island, dimension, consumer); + } + } + } + public static void accessIslandWorldAsync(Island island, Dimension dimension, Consumer> consumer) { + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); + if (worldInfo == null) { + consumer.accept(Either.right(new NullPointerException("Cannot find world for dimension " + dimension.getName()))); + return; + } + + World world = Bukkit.getWorld(worldInfo.getName()); + if (world != null) { + consumer.accept(Either.left(world)); + return; + } + WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); if (worldsProvider instanceof LazyWorldsProvider) { ((LazyWorldsProvider) worldsProvider).prepareWorld(island, dimension, () -> - loadedWorldCallback(island, dimension, consumer)); + loadedWorldCallback(worldInfo, consumer)); } else { - loadedWorldCallback(island, dimension, consumer); + loadedWorldCallback(worldInfo, consumer); } } - private static void loadedWorldCallback(Island island, Dimension dimension, Consumer> consumer) { - World world = plugin.getGrid().getIslandsWorld(island, dimension); + private static void loadedWorldCallback(WorldInfo worldInfo, Consumer> consumer) { + World world = Bukkit.getWorld(worldInfo.getName()); if (world != null) { consumer.accept(Either.left(world)); } else { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index ecb1b7e2c0..2c02736b9e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -1266,18 +1266,40 @@ public void resetChunks(@IslandChunkFlags int flags) { @Override public void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish) { - LinkedList> worldsChunks = new LinkedList<>( - IslandUtils.getChunkCoords(this, flags | IslandChunkFlags.NO_EMPTY_CHUNKS).values()); + final int realFlags = flags | IslandChunkFlags.NO_EMPTY_CHUNKS; + for (World registeredWorld : plugin.getGrid().getRegisteredWorlds()) { + WorldInfo worldInfo = WorldInfo.of(registeredWorld); + List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, realFlags); + if (!chunkPositions.isEmpty()) + IslandUtils.deleteChunks(this, chunkPositions, null); + } - if (worldsChunks.isEmpty()) { - if (onFinish != null) - onFinish.run(); - return; + MutableObject lastDimension = new MutableObject<>(null); + boolean hasDimension = false; + + for (Dimension dimension : Dimension.values()) { + if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && wasSchematicGenerated(dimension)) { + hasDimension = true; + lastDimension.setValue(dimension); + IslandWorlds.accessIslandWorldAsync(this, dimension, result -> { + result.ifLeft(world -> { + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); + List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, realFlags); + if (!chunkPositions.isEmpty()) { + IslandUtils.deleteChunks(this, chunkPositions, + dimension == lastDimension.getValue() ? onFinish : null); + } + }).ifRight(err -> { + if (onFinish != null && dimension == lastDimension.getValue()) + onFinish.run(); + }); + }); + } } - for (List chunkPositions : worldsChunks) - IslandUtils.deleteChunks(this, chunkPositions, chunkPositions == worldsChunks.getLast() ? onFinish : null); + if (!hasDimension && onFinish != null) + onFinish.run(); } @Override @@ -1289,18 +1311,20 @@ public void resetChunks(Dimension dimension, @IslandChunkFlags int flags) { public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, @Nullable Runnable onFinish) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); - WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); - - List chunkPositions = IslandUtils.getChunkCoords(this, - worldInfo, flags | IslandChunkFlags.NO_EMPTY_CHUNKS); + IslandWorlds.accessIslandWorldAsync(this, dimension, result -> { + if (result.getRight() == null) { + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); + List chunkPositions = IslandUtils.getChunkCoords(this, + worldInfo, flags | IslandChunkFlags.NO_EMPTY_CHUNKS); + if (!chunkPositions.isEmpty()) { + IslandUtils.deleteChunks(this, chunkPositions, onFinish); + return; + } + } - if (chunkPositions.isEmpty()) { if (onFinish != null) onFinish.run(); - return; - } - - IslandUtils.deleteChunks(this, chunkPositions, onFinish); + }); } @Override @@ -1381,17 +1405,13 @@ public boolean isInside(Location location, double extraRadius) { @Override public boolean isInside(World world, int chunkX, int chunkZ) { Preconditions.checkNotNull(world, "world parameter cannot be null."); + return isIslandWorld(world) && isChunkInside(chunkX, chunkZ); + } - if (!isIslandWorld(world)) - return false; - - int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * - (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); - - try (IslandArea islandArea = IslandArea.of(this.center, islandDistance)) { - islandArea.rshift(4); - return islandArea.intercepts(chunkX, chunkZ); - } + @Override + public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) { + Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); + return isIslandWorld(worldInfo) && isChunkInside(chunkX, chunkZ); } private boolean isChunkInside(int chunkX, int chunkZ) { @@ -1453,6 +1473,18 @@ private boolean isIslandWorld(@Nullable World world) { return worldInfo.getName().equals(world.getName()); } + private boolean isIslandWorld(@Nullable WorldInfo worldInfo) { + if (worldInfo == null) + return false; + + Dimension dimension = worldInfo.getDimension(); + if (dimension == null) + return false; + + WorldInfo realWorldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); + return realWorldInfo.getName().equals(worldInfo.getName()); + } + @Override public boolean isNormalEnabled() { return isDimensionEnabled(Dimensions.NORMAL); @@ -2033,15 +2065,15 @@ public void setBiome(Biome biome, boolean updateBlocks) { List playersToUpdate = new SequentialListBuilder() .build(getAllPlayersInside(), SuperiorPlayer::asPlayer); - for (Dimension dimension : Dimension.values()) { - if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && wasSchematicGenerated(dimension)) { - WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); - Biome worldBiome = plugin.getSettings().getWorlds().getDefaultWorldDimension() == dimension ? - biome : IslandUtils.getDefaultWorldBiome(dimension); + IslandWorlds.accessIslandWorldsAsync(this, result -> { + result.ifLeft(world -> { + WorldInfo worldInfo = WorldInfo.of(world); + Biome worldBiome = plugin.getSettings().getWorlds().getDefaultWorldDimension() == worldInfo.getDimension() ? + biome : IslandUtils.getDefaultWorldBiome(worldInfo.getDimension()); List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, 0); plugin.getNMSChunks().setBiome(chunkPositions, worldBiome, playersToUpdate); - } - } + }); + }); for (World registeredWorld : plugin.getGrid().getRegisteredWorlds()) { List chunkPositions = IslandUtils.getChunkCoords(this, WorldInfo.of(registeredWorld), 0); @@ -2739,7 +2771,11 @@ public boolean isChunkDirty(World world, int chunkX, int chunkZ) { @Override public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) { Preconditions.checkNotNull(worldName, "worldName parameter cannot be null."); - WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, worldName); + return isChunkDirty(plugin.getGrid().getIslandsWorldInfo(this, worldName), chunkX, chunkZ); + } + + @Override + public boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ) { Preconditions.checkArgument(worldInfo != null && isChunkInside(chunkX, chunkZ), "Chunk must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) { @@ -2750,8 +2786,14 @@ public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) { @Override public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(world, "world parameter cannot be null."); - Preconditions.checkArgument(isInside(world, chunkX, chunkZ), "Chunk must be within the island boundaries."); - try (ChunkPosition chunkPosition = ChunkPosition.of(WorldInfo.of(world), chunkX, chunkZ)) { + markChunkDirty(WorldInfo.of(world), chunkX, chunkZ, save); + } + + @Override + public void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { + Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); + Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk must be within the island boundaries."); + try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) { this.dirtyChunksContainer.markDirty(chunkPosition, save); } } @@ -2759,8 +2801,13 @@ public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) { @Override public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(world, "world parameter cannot be null."); - Preconditions.checkArgument(isInside(world, chunkX, chunkZ), "Chunk must be within the island boundaries."); - try (ChunkPosition chunkPosition = ChunkPosition.of(WorldInfo.of(world), chunkX, chunkZ)) { + markChunkEmpty(WorldInfo.of(world), chunkX, chunkZ, save); + } + + @Override + public void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { + Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk must be within the island boundaries."); + try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) { this.dirtyChunksContainer.markEmpty(chunkPosition, save); } } @@ -5096,9 +5143,18 @@ private void notifyCropGrowthChange(double newCropGrowth) { if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class)) return; + final int flags = IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS; + double newCropGrowthMultiplier = newCropGrowth - 1; - IslandUtils.getChunkCoords(this, IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS) - .values().forEach(chunkPositions -> plugin.getNMSChunks().updateCropsTicker(chunkPositions, newCropGrowthMultiplier)); + + IslandWorlds.accessIslandWorldsAsync(this, result -> { + result.ifLeft(world -> { + WorldInfo worldInfo = WorldInfo.of(world); + List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, flags); + if (!chunkPositions.isEmpty()) + plugin.getNMSChunks().updateCropsTicker(chunkPositions, newCropGrowthMultiplier); + }); + }); } public static void registerListeners(PluginEventsDispatcher dispatcher) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index cfe9bdf6cd..9c5bc40dae 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -805,6 +805,11 @@ public boolean isInside(World world, int chunkX, int chunkZ) { return world.equals(this.spawnWorld) && isChunkInside(chunkX, chunkZ); } + @Override + public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) { + return this.spawnWorldInfo.getName().equals(worldInfo.getName()) && isChunkInside(chunkX, chunkZ); + } + public boolean isChunkInside(int chunkX, int chunkZ) { try (IslandArea islandArea = this.islandArea.copy()) { islandArea.rshift(4); @@ -1415,6 +1420,15 @@ public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) { } } + @Override + public boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ) { + Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); + Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk must be within the island boundaries."); + try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { + return this.dirtyChunksContainer.isMarkedDirty(chunkPosition); + } + } + @Override public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(world, "world parameter cannot be null."); @@ -1424,6 +1438,15 @@ public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) { } } + @Override + public void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { + Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); + Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk must be within the island boundaries."); + try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { + this.dirtyChunksContainer.markDirty(chunkPosition, save); + } + } + @Override public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(world, "world parameter cannot be null."); @@ -1433,6 +1456,15 @@ public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) { } } + @Override + public void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { + Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); + Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk must be within the island boundaries."); + try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { + this.dirtyChunksContainer.markEmpty(chunkPosition, save); + } + } + @Override public BigInteger getBlockCountAsBigInteger(Key key) { return BigInteger.ZERO; From 3e70aba99ac9495dcb1ddc2cc5b41294e3dff0bf Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 19 Apr 2025 14:08:07 +0300 Subject: [PATCH 121/600] Another attempt on fixing null hand item in BlockPlaceEvent (#2402) --- .../listener/BukkitEventsListener.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index aba534cfe4..162c6e9be5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -97,6 +97,7 @@ import java.util.List; import java.util.Map; +import java.util.function.Supplier; public class BukkitEventsListener implements Listener { @@ -257,7 +258,7 @@ private GameEvent createGameEvent(GameEventType e.getItemInHand()); return eventType.createEvent(blockPlaceEvent); } @@ -354,7 +355,7 @@ private GameEvent createGameEvent(GameEventTy playerInteractEvent.player = e.getPlayer(); playerInteractEvent.action = e.getAction(); playerInteractEvent.usedHand = BukkitItems.getHand(e); - playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true); + playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, () -> e.getItem()); playerInteractEvent.clickedBlock = e.getClickedBlock(); return eventType.createEvent(playerInteractEvent); } @@ -507,7 +508,7 @@ private GameEvent createGameEvent(GameEventTy playerInteractEvent.player = e.getPlayer(); playerInteractEvent.action = Action.RIGHT_CLICK_AIR; playerInteractEvent.usedHand = BukkitItems.getHand(e); - playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true); + playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, null); playerInteractEvent.clickedEntity = e.getRightClicked(); return eventType.createEvent(playerInteractEvent); } @@ -517,7 +518,7 @@ private GameEvent createGameEvent(GameEventTy playerInteractEvent.player = e.getPlayer(); playerInteractEvent.action = Action.RIGHT_CLICK_AIR; playerInteractEvent.usedHand = BukkitItems.getHand(e); - playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true); + playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, null); playerInteractEvent.clickedEntity = e.getRightClicked(); return eventType.createEvent(playerInteractEvent); } @@ -828,11 +829,13 @@ private void createEventListenerForPr }, plugin, false); } - private static ItemStack getHandItem(Player player, PlayerHand usedHand, boolean clone) { + private static ItemStack getHandItem(Player player, PlayerHand usedHand, boolean clone, @Nullable Supplier defItem) { ItemStack itemStack = BukkitItems.getHandItem(player, usedHand); if (clone && itemStack != null) { itemStack = itemStack.clone(); } + if (defItem != null && (itemStack == null || itemStack.getType() == Material.AIR)) + itemStack = defItem.get(); return itemStack; } From 8566bea7ffefb1b2bc9fe9df86091399c016e438 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 19 Apr 2025 18:18:11 +0300 Subject: [PATCH 122/600] Fixed out of bounds when placing signs (#2411) --- .../nms/v1_20_3/world/WorldEditSessionImpl.java | 6 ++++-- .../nms/v1_20_4/world/WorldEditSessionImpl.java | 6 ++++-- .../nms/v1_21/world/WorldEditSessionImpl.java | 6 ++++-- .../nms/v1_21_3/world/WorldEditSessionImpl.java | 6 ++++-- .../nms/v1_21_4/world/WorldEditSessionImpl.java | 6 ++++-- .../nms/v1_21_5/world/WorldEditSessionImpl.java | 6 ++++-- 6 files changed, 24 insertions(+), 12 deletions(-) diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java index e4b47a104d..73e8084b0b 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java @@ -25,6 +25,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; @@ -273,10 +274,11 @@ private boolean isValidPosition(BlockPos blockPos) { private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); - Component[] frontTextLines = new Component[4]; + ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); + Component[] frontTextLines = new Component[messages.size()]; Arrays.fill(frontTextLines, Component.empty()); int i = 0; - for (net.minecraft.nbt.Tag lineTag : frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING)) { + for (net.minecraft.nbt.Tag lineTag : messages) { try { frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); } catch (JsonParseException error) { diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java index 08df1f8f27..12164497ce 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java @@ -25,6 +25,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; @@ -273,10 +274,11 @@ private boolean isValidPosition(BlockPos blockPos) { private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); - Component[] frontTextLines = new Component[4]; + ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); + Component[] frontTextLines = new Component[messages.size()]; Arrays.fill(frontTextLines, Component.empty()); int i = 0; - for (net.minecraft.nbt.Tag lineTag : frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING)) { + for (net.minecraft.nbt.Tag lineTag : messages) { try { frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); } catch (JsonParseException error) { diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java index 5be673782e..f02058b026 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java @@ -25,6 +25,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; @@ -271,10 +272,11 @@ private boolean isValidPosition(BlockPos blockPos) { private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); - Component[] frontTextLines = new Component[4]; + ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); + Component[] frontTextLines = new Component[messages.size()]; Arrays.fill(frontTextLines, Component.empty()); int i = 0; - for (net.minecraft.nbt.Tag lineTag : frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING)) { + for (net.minecraft.nbt.Tag lineTag : messages) { try { frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); } catch (JsonParseException error) { diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java index 1d490d1207..33d19eab63 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java @@ -25,6 +25,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; @@ -271,10 +272,11 @@ private boolean isValidPosition(BlockPos blockPos) { private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); - Component[] frontTextLines = new Component[4]; + ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); + Component[] frontTextLines = new Component[messages.size()]; Arrays.fill(frontTextLines, Component.empty()); int i = 0; - for (net.minecraft.nbt.Tag lineTag : frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING)) { + for (net.minecraft.nbt.Tag lineTag : messages) { try { frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); } catch (JsonParseException error) { diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java index c57ec04948..0cffc2aa8a 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java @@ -25,6 +25,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; @@ -271,10 +272,11 @@ private boolean isValidPosition(BlockPos blockPos) { private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); - Component[] frontTextLines = new Component[4]; + ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); + Component[] frontTextLines = new Component[messages.size()]; Arrays.fill(frontTextLines, Component.empty()); int i = 0; - for (net.minecraft.nbt.Tag lineTag : frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING)) { + for (net.minecraft.nbt.Tag lineTag : messages) { try { frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); } catch (JsonParseException error) { diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java index 7adceec6df..068fb06e3c 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java @@ -25,6 +25,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; @@ -270,10 +271,11 @@ private boolean isValidPosition(BlockPos blockPos) { private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { blockEntityCompound.getCompound(key).ifPresent(textCompound -> { - Component[] textLines = new Component[4]; + ListTag messages = textCompound.getListOrEmpty("messages"); + Component[] textLines = new Component[messages.size()]; Arrays.fill(textLines, Component.empty()); int i = 0; - for (net.minecraft.nbt.Tag lineTag : textCompound.getListOrEmpty("messages")) { + for (net.minecraft.nbt.Tag lineTag : messages) { try { textLines[i++] = CraftChatMessage.fromJSON(lineTag.asString().orElseThrow()); } catch (JsonParseException error) { From 9528ec2229bc778b98b542db36b8d2175f1b2e2a Mon Sep 17 00:00:00 2001 From: Ome_R Date: Sat, 19 Apr 2025 18:33:18 +0300 Subject: [PATCH 123/600] Adds MiniMessage support (#2400) --- Hooks/MiniMessage/build.gradle | 24 +++ .../external/MiniMessageHook.java | 147 ++++++++++++++++++ gradle.properties | 1 + settings.gradle | 1 + .../SuperiorSkyblockPlugin.java | 5 +- .../core/formatting/impl/ColorFormatter.java | 71 ++++++--- .../core/messages/Message.java | 13 -- .../core/messages/MessageContent.java | 2 +- .../external/ProvidersManagerImpl.java | 19 +++ .../external/text/ITextFormatter.java | 7 + .../service/message/MessagesServiceImpl.java | 18 +++ 11 files changed, 273 insertions(+), 35 deletions(-) create mode 100644 Hooks/MiniMessage/build.gradle create mode 100644 Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/external/text/ITextFormatter.java diff --git a/Hooks/MiniMessage/build.gradle b/Hooks/MiniMessage/build.gradle new file mode 100644 index 0000000000..5b9e117a99 --- /dev/null +++ b/Hooks/MiniMessage/build.gradle @@ -0,0 +1,24 @@ +group 'Hooks:MiniMessage' + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +repositories { + mavenCentral() +} + +dependencies { + compileOnly("net.kyori:adventure-text-minimessage:4.17.0") + compileOnly("net.kyori:adventure-text-serializer-plain:4.19.0") + compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" + compileOnly project(":API") + compileOnly rootProject +} + +if (project.hasProperty('hook.compile_minimessage') && + !Boolean.valueOf(project.findProperty("hook.compile_minimessage").toString())) { + project.tasks.all { task -> task.enabled = false } +} diff --git a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java new file mode 100644 index 0000000000..bf784ca8d9 --- /dev/null +++ b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java @@ -0,0 +1,147 @@ +package com.bgsoftware.superiorskyblock.external; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; +import com.bgsoftware.superiorskyblock.api.service.message.MessagesService; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.messages.MessageContent; +import com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.TextReplacementConfig; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.ParsingException; +import net.kyori.adventure.text.minimessage.tag.standard.StandardTags; +import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MiniMessageHook { + + private static final MiniMessage MINI_MESSAGE = MiniMessage.builder().tags(StandardTags.defaults()).build(); + + private static boolean registered = false; + + public static void register(SuperiorSkyblockPlugin plugin) { + if (!registered) { + MessagesServiceImpl messagesService = (MessagesServiceImpl) plugin.getServices().getService(MessagesService.class); + messagesService.registerCustomComponentParser(MiniMessageHook::parseMiniMessage); + registered = true; + } + } + + private static Optional parseMiniMessage(YamlConfiguration config, String path) { + if (!config.isString(path)) + return Optional.empty(); + + String content = config.getString(path); + + try { + Component component = MINI_MESSAGE.deserialize(Formatters.COLOR_FORMATTER.format(content)); + return Optional.of(new MiniMessageComponent(component)); + } catch (ParsingException error) { + return Optional.empty(); + } + } + + private static class MiniMessageComponent implements IMessageComponent { + + private final Component component; + private final MessageContent content; + + MiniMessageComponent(Component component) { + this.component = component; + this.content = findTextComponentContent(component); + } + + @Override + public Type getType() { + return Type.COMPLEX_MESSAGE; + } + + @Override + public String getMessage() { + return this.content.getContent().orElse(""); + } + + @Override + public String getMessage(Object... args) { + return this.content.getContent(args).orElse(""); + } + + @Override + public void sendMessage(CommandSender sender, Object... args) { + sender.sendMessage(Translator.translate(this.component, args)); + } + + private static MessageContent findTextComponentContent(Component component) { + if (component instanceof TextComponent textComponent) + return MessageContent.parse(textComponent.content()); + + for (Component children : component.children()) { + MessageContent childrenContent = findTextComponentContent(children); + if (childrenContent != MessageContent.EMPTY) + return childrenContent; + } + + + return MessageContent.EMPTY; + } + + } + + private static class Translator { + private static final Pattern ARG_PATTERN = Pattern.compile("\\{[0-9]+}"); + + static Component translate(Component input, Object... args) { + Component output = input; + if (args.length != 0) { + output = output.replaceText(TextReplacementConfig.builder() + .match(ARG_PATTERN) + .replacement((result, builder) -> doReplacement(result, args)) + .build()); + output = translateClickEvent(output, args); + } + return translateChildren(output, args); + } + + private static Component translateChildren(Component input, Object... args) { + List children = new LinkedList<>(); + for (Component component : input.children()) { + Component output = translate(component, args); + children.add(translateChildren(output, args)); + } + return input.children(children); + } + + private static Component translateClickEvent(Component input, Object... args) { + ClickEvent event = input.clickEvent(); + if (event == null) return input; + + String value = event.value(); + Matcher matcher = ARG_PATTERN.matcher(value); + + String result = matcher.replaceAll(match -> doTextReplacement(match, args)); + return input.clickEvent(ClickEvent.clickEvent(event.action(), result)); + } + + private static Component doReplacement(MatchResult match, Object... args) { + String group = match.group(); + int index = Integer.parseInt(group.substring(1, group.length() - 1)); + return Component.text(index < args.length ? MessageContent.getArgumentString(args[index]) : group); + } + + private static String doTextReplacement(MatchResult match, Object... args) { + return PlainTextComponentSerializer.plainText().serialize(doReplacement(match, args)); + } + } + +} diff --git a/gradle.properties b/gradle.properties index 01314c5f6c..50845a498e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,6 +21,7 @@ hook.compile_itemsadder=true hook.compile_jetsminions=true hook.compile_luckperms=true hook.compile_mergedspawner=true +hook.compile_minimessage=true hook.compile_mvdwplaceholderapi=true hook.compile_oraxen=true hook.compile_papermc=true diff --git a/settings.gradle b/settings.gradle index 643bae6470..d5fea00496 100644 --- a/settings.gradle +++ b/settings.gradle @@ -24,6 +24,7 @@ include 'Hooks:ItemsAdder' include 'Hooks:JetsMinions' include 'Hooks:LuckPerms' include 'Hooks:MergedSpawner' +include 'Hooks:MiniMessage' include 'Hooks:MVdWPlaceholderAPI' include 'Hooks:Nexo' include 'Hooks:OpenJdkNashornEngine' diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index 0f2523ca47..1d5da8db53 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -28,8 +28,8 @@ import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.factory.FactoriesManagerImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemSkulls; import com.bgsoftware.superiorskyblock.core.key.KeysManagerImpl; @@ -447,6 +447,8 @@ private boolean testScriptEngine() { } public void reloadPlugin(PluginReloadReason reloadReason) throws ManagerLoadException { + providersHandler.loadData(); + ItemSkulls.readTextures(this); if (reloadReason == PluginReloadReason.COMMAND) { @@ -481,7 +483,6 @@ public void reloadPlugin(PluginReloadReason reloadReason) throws ManagerLoadExce } schematicsHandler.loadData(); - providersHandler.loadData(); menusHandler.loadData(); missionsHandler.loadData(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/ColorFormatter.java b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/ColorFormatter.java index bd3b9f3e24..9a3912dd71 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/ColorFormatter.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/ColorFormatter.java @@ -1,10 +1,13 @@ package com.bgsoftware.superiorskyblock.core.formatting.impl; import com.bgsoftware.superiorskyblock.core.ServerVersion; -import com.bgsoftware.superiorskyblock.core.formatting.IFormatter; import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.formatting.IFormatter; +import com.bgsoftware.superiorskyblock.external.text.ITextFormatter; import org.bukkit.ChatColor; +import java.util.LinkedList; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -12,6 +15,14 @@ public class ColorFormatter implements IFormatter { private static final ColorFormatter INSTANCE = new ColorFormatter(); + private static final List TEXT_FORMATTERS = new LinkedList<>(); + + static { + TEXT_FORMATTERS.add(ChatColorTextFormatter.INSTANCE); + if (ServerVersion.isAtLeast(ServerVersion.v1_16)) + TEXT_FORMATTERS.add(HexTextFormatter.INSTANCE); + } + private static final Pattern HEX_COLOR_PATTERN = Pattern.compile("([&§])(\\{HEX:([0-9A-Fa-f]*)})"); public static ColorFormatter getInstance() { @@ -27,36 +38,58 @@ public String format(String value) { if (Text.isBlank(value)) return ""; - String output = ChatColor.translateAlternateColorCodes('&', value); + String output = value; + for (ITextFormatter formatter : TEXT_FORMATTERS) { + output = formatter.format(output); + } - if (ServerVersion.isLessThan(ServerVersion.v1_16)) - return output; + return output; + } - while (true) { - Matcher matcher = HEX_COLOR_PATTERN.matcher(output); + private static class ChatColorTextFormatter implements ITextFormatter { - if (!matcher.find()) - break; + private static final ChatColorTextFormatter INSTANCE = new ChatColorTextFormatter(); - output = matcher.replaceFirst(parseHexColor(matcher.group(3))); + @Override + public String format(String value) { + return ChatColor.translateAlternateColorCodes('&', value); } - return output; } - private static String parseHexColor(String hexColor) { - if (hexColor.length() != 6 && hexColor.length() != 3) - return hexColor; + private static class HexTextFormatter implements ITextFormatter { + + private static final HexTextFormatter INSTANCE = new HexTextFormatter(); + + @Override + public String format(String value) { + while (true) { + Matcher matcher = HEX_COLOR_PATTERN.matcher(value); + + if (!matcher.find()) + break; + + value = matcher.replaceFirst(parseHexColor(matcher.group(3))); + } + + return value; + } + + private static String parseHexColor(String hexColor) { + if (hexColor.length() != 6 && hexColor.length() != 3) + return hexColor; + + StringBuilder magic = new StringBuilder(ChatColor.COLOR_CHAR + "x"); + int multiplier = hexColor.length() == 3 ? 2 : 1; - StringBuilder magic = new StringBuilder(ChatColor.COLOR_CHAR + "x"); - int multiplier = hexColor.length() == 3 ? 2 : 1; + for (char ch : hexColor.toCharArray()) { + for (int i = 0; i < multiplier; i++) + magic.append(ChatColor.COLOR_CHAR).append(ch); + } - for (char ch : hexColor.toCharArray()) { - for (int i = 0; i < multiplier; i++) - magic.append(ChatColor.COLOR_CHAR).append(ch); + return magic.toString(); } - return magic.toString(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 1e56aada7b..8481372009 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -999,17 +999,4 @@ private static void convertOldFile() { } } - public static Optional replaceArgs(String msg, Object... objects) { - if (Text.isBlank(msg)) - return Optional.empty(); - - for (int i = 0; i < objects.length; i++) { - String objectString = objects[i] instanceof BigDecimal ? - Formatters.NUMBER_FORMATTER.format((BigDecimal) objects[i]) : objects[i].toString(); - msg = msg.replace("{" + i + "}", objectString); - } - - return msg.isEmpty() ? Optional.empty() : Optional.of(msg); - } - } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java index c37be3a110..20d1b8e5bf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java @@ -84,7 +84,7 @@ public Optional getContent(Object... arguments) { return content.length() == 0 ? Optional.empty() : Optional.of(content.toString()); } - private static String getArgumentString(Object argument) { + public static String getArgumentString(Object argument) { return argument instanceof BigDecimal ? Formatters.NUMBER_FORMATTER.format((BigDecimal) argument) : String.valueOf(argument); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java index 3c7c8356b0..7dd30f893b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java @@ -122,6 +122,9 @@ public void loadData() { registerPlaceholdersProvider(); registerChunksProvider(); }); + + registerMessageProviders(); + // We try to forcefully load prices after a second the server has enabled. BukkitExecutor.sync(this::forcePricesLoad, 60L); } @@ -473,6 +476,13 @@ private void registerGeneralHooks() { registerHook("TimbruSilkSpawnersHook"); } } + + } + + private void registerMessageProviders() { + if (isHookEnabled("MiniMessage") && hasMiniMessageSupport()) { + registerHook("MiniMessageHook"); + } } private void registerSpawnersProvider() { @@ -688,6 +698,15 @@ private static boolean isOldSlimeWorldManager() { } } + private static boolean hasMiniMessageSupport() { + try { + Class.forName("net.kyori.adventure.text.minimessage.MiniMessage"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + } + private Optional createInstance(String className) { try { Class clazz = Class.forName("com.bgsoftware.superiorskyblock.external." + className); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/text/ITextFormatter.java b/src/main/java/com/bgsoftware/superiorskyblock/external/text/ITextFormatter.java new file mode 100644 index 0000000000..04fd09374c --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/text/ITextFormatter.java @@ -0,0 +1,7 @@ +package com.bgsoftware.superiorskyblock.external.text; + +public interface ITextFormatter { + + String format(String value); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java index b1247f09b7..77b8187b78 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java @@ -25,9 +25,12 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; +import java.util.Optional; public class MessagesServiceImpl implements MessagesService, IService { + private final List customComponentParsers = new LinkedList<>(); + public MessagesServiceImpl() { } @@ -43,6 +46,11 @@ public IMessageComponent parseComponent(YamlConfiguration config, String path) { if (config.isConfigurationSection(path)) { return MultipleComponents.parseSection(config.getConfigurationSection(path)); } else { + for (CustomComponentParser parser : this.customComponentParsers) { + Optional res = parser.parse(config, path); + if (res.isPresent()) + return res.get(); + } return RawMessageComponent.of(Formatters.COLOR_FORMATTER.format(config.getString(path, ""))); } } @@ -59,6 +67,16 @@ public Builder newBuilder() { return new BuilderImpl(); } + public void registerCustomComponentParser(CustomComponentParser parser) { + this.customComponentParsers.add(parser); + } + + public interface CustomComponentParser { + + Optional parse(YamlConfiguration config, String path); + + } + private static class BuilderImpl implements Builder { private final List messageComponents = new LinkedList<>(); From 72e687be5afafea33b0431b80afc6f52cca8c81d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 19 Apr 2025 18:35:44 +0300 Subject: [PATCH 124/600] Updated API version to 14 --- .../bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java index 013b575742..12dc0096f5 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java @@ -71,7 +71,7 @@ public static void setPluginInstance(SuperiorSkyblock plugin) { * Everytime a change is made to the API, the version of it changes. */ public static int getAPIVersion() { - return 13; + return 14; } /* From 8d3d981f060b6c37a5e4830424f516dc1e0bb9a7 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 19 Apr 2025 18:35:57 +0300 Subject: [PATCH 125/600] Version 2025.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cfd5c2a0aa..ca7fb66193 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'SuperiorSkyblock' -version = "2024.4" +version = "2025.1" project.ext { archiveFolder = file("archive/") From 41d23c0907ea9d83118b51ab8aa2d67c62295c32 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 25 Apr 2025 18:07:43 +0300 Subject: [PATCH 126/600] Register listeners again upon reloading the plugin --- .../SuperiorSkyblockPlugin.java | 18 +++++++----------- .../core/PluginLoadingStage.java | 1 - .../core/events/EventsDispatcher.java | 5 ++++- .../listener/BukkitListeners.java | 9 +++++++++ 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index 1d5da8db53..1b884686f3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -259,23 +259,13 @@ public void onEnable() { try { reloadPlugin(PluginReloadReason.STARTUP); } catch (ManagerLoadException error) { + Log.error(error, "An unexpected error occurred while starting up the plugin:"); ManagerLoadException.handle(error); return; } loadingStage = PluginLoadingStage.MANAGERS_INITIALIZED; - try { - bukkitListeners.registerListeners(); - } catch (RuntimeException ex) { - ManagerLoadException handlerError = new ManagerLoadException("Cannot load plugin due to a missing event: " + ex.getMessage() + " - contact @Ome_R!", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); - Log.error(handlerError, "An error occurred while registering listeners:"); - Bukkit.shutdown(); - return; - } - - loadingStage = PluginLoadingStage.EVENTS_INITIALIZED; - ChunksProvider.start(); loadingStage = PluginLoadingStage.CHUNKS_PROVIDER_INITIALIZED; @@ -511,6 +501,12 @@ public void reloadPlugin(PluginReloadReason reloadReason) throws ManagerLoadExce if (reloadReason == PluginReloadReason.STARTUP) { modulesHandler.loadModulesData(this); } + + try { + bukkitListeners.registerListeners(); + } catch (RuntimeException ex) { + throw new ManagerLoadException("Cannot load plugin due to a missing event: " + ex.getMessage() + " - contact @Ome_R!", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); + } } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/PluginLoadingStage.java b/src/main/java/com/bgsoftware/superiorskyblock/core/PluginLoadingStage.java index b9a16cd7cc..f8b9dc313f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/PluginLoadingStage.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/PluginLoadingStage.java @@ -13,7 +13,6 @@ public enum PluginLoadingStage { COMMANDS_INITIALIZED, WORLDS_PREPARED, MANAGERS_INITIALIZED, - EVENTS_INITIALIZED, CHUNKS_PROVIDER_INITIALIZED, ENABLED; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java index 1199110158..b2f3fe4a7d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java @@ -7,7 +7,6 @@ import java.util.Collection; import java.util.Collections; import java.util.EnumMap; -import java.util.IdentityHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -31,6 +30,10 @@ public void registerCallback(L listener, T type, P priority, boolean ignoreCance .add(new RegisteredListener(listener, ignoreCancelled, callback)); } + public void clearCallbacks() { + this.callbacks.clear(); + } + public void onGameEvent(E event, P priority) { if (event.isCancelled()) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java index d5550cd3d0..8eb6577e08 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import java.util.regex.Matcher; @@ -20,6 +21,8 @@ public BukkitListeners(SuperiorSkyblockPlugin plugin) { } public void registerListeners() { + unregisterListeners(); + new AdminPlayersListener(this.plugin); new BlockChangesListener(this.plugin); new ChunksListener(this.plugin); @@ -40,6 +43,12 @@ public void registerListeners() { safeEventsRegister(new BukkitEventsListener(this.plugin)); } + public void unregisterListeners() { + plugin.getGameEventsDispatcher().clearCallbacks(); + plugin.getPluginEventsDispatcher().clearCallbacks(); + HandlerList.unregisterAll(this.plugin); + } + public void registerListenerFailureFilter() { plugin.getLogger().setFilter(record -> { Matcher matcher = LISTENER_REGISTER_FAILURE.matcher(record.getMessage()); From dddc8546599de274557b4c923f3fafb0c3a7814e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 25 Apr 2025 18:13:27 +0300 Subject: [PATCH 127/600] Changed the way the detection of physics events is written --- .../superiorskyblock/listener/BukkitEventsListener.java | 5 +---- .../superiorskyblock/listener/StackedBlocksListener.java | 4 +++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index 162c6e9be5..7cf77478a9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -177,6 +177,7 @@ public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { createEventListener(GameEventType.PLAYER_PICKUP_ITEM_EVENT, PlayerPickupItemEvent.class, this::createGameEvent); createEventListener(GameEventType.PROJECTILE_HIT_EVENT, ProjectileHitEvent.class, this::createGameEvent); createEventListener(GameEventType.SIGN_CHANGE_EVENT, SignChangeEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_PHYSICS_EVENT, BlockPhysicsEvent.class, this::createGameEvent); try { Class.forName("org.bukkit.event.block.SpongeAbsorbEvent"); @@ -233,10 +234,6 @@ public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { createEventListener(GameEventType.RAID_TRIGGER_EVENT, org.bukkit.event.raid.RaidTriggerEvent.class, new RaidTriggerEventFunctions()); } catch (Exception ignored) { } - - if (plugin.getSettings().isPhysicsListener()) - createEventListener(GameEventType.BLOCK_PHYSICS_EVENT, BlockPhysicsEvent.class, this::createGameEvent); - } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerJoinEvent e) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java index ecacb1dad4..8c8c28c162 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java @@ -286,8 +286,10 @@ private void registerListeners() { registerCallback(GameEventType.PISTON_RETRACT_EVENT, GameEventPriority.LOWEST, this::onPistonRetract); registerCallback(GameEventType.BLOCK_FORM_EVENT, GameEventPriority.LOWEST, this::onBlockChangeState); registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onGolemCreate); - registerCallback(GameEventType.BLOCK_PHYSICS_EVENT, GameEventPriority.LOWEST, this::onStackedBlockPhysics); registerCallback(GameEventType.SPONGE_ABSORB_EVENT, GameEventPriority.LOWEST, this::onSpongeAbsorb); + + if (plugin.getSettings().isPhysicsListener()) + registerCallback(GameEventType.BLOCK_PHYSICS_EVENT, GameEventPriority.LOWEST, this::onStackedBlockPhysics); } private static Map> buildEntityTemplateOffsetsMap() { From 72db0659abf0446aa5bb4add92e3380da9630180 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 25 Apr 2025 18:13:44 +0300 Subject: [PATCH 128/600] Added the ability to completely disable auto tracking of blocks --- .../superiorskyblock/api/config/SettingsManager.java | 6 ++++++ .../superiorskyblock/config/SettingsContainer.java | 4 +++- .../superiorskyblock/config/SettingsManagerImpl.java | 5 +++++ .../superiorskyblock/config/section/GlobalSection.java | 4 ++++ src/main/resources/config.yml | 5 +++++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index f5df901271..0e82953223 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -84,6 +84,12 @@ public interface SettingsManager { */ boolean isRoundedIslandLevels(); + /** + * Whether to automatic track block counts when players place and break blocks. + * Config path: auto-blocks-tracking + */ + boolean isAutoBlocksTracking(); + /** * The default island-top sorting type. * Config path: island-top-order diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 516685bcbe..d9937fa35a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -23,9 +23,9 @@ import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.io.Resources; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; -import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; @@ -100,6 +100,7 @@ public class SettingsContainer { public final String stackedBlocksMenuTitle; public final String islandLevelFormula; public final boolean roundedIslandLevel; + public final boolean autoBlocksTracking; public final String islandTopOrder; public boolean coopMembers; public final ConfigurationSection islandRolesSection; @@ -277,6 +278,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config stackedBlocksMenuTitle = Formatters.COLOR_FORMATTER.format(config.getString("stacked-blocks.deposit-menu.title", "&lDeposit Blocks")); islandLevelFormula = config.getString("island-level-formula", "{} / 2"); roundedIslandLevel = config.getBoolean("rounded-island-level", false); + autoBlocksTracking = config.getBoolean("auto-blocks-tracking", true); islandTopOrder = config.getString("island-top-order", "WORTH").toUpperCase(Locale.ENGLISH); coopMembers = config.getBoolean("coop-members", true); islandRolesSection = config.getConfigurationSection("island-roles"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index ac20c67c80..fd00806834 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -136,6 +136,11 @@ public boolean isRoundedIslandLevels() { return this.global.isRoundedIslandLevels(); } + @Override + public boolean isAutoBlocksTracking() { + return this.global.isAutoBlocksTracking(); + } + @Override public String getIslandTopOrder() { return this.global.getIslandTopOrder(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index 1c990b5a62..39e2c8a40a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -44,6 +44,10 @@ public boolean isRoundedIslandLevels() { return getContainer().roundedIslandLevel; } + public boolean isAutoBlocksTracking() { + return getContainer().autoBlocksTracking; + } + public String getIslandTopOrder() { return getContainer().islandTopOrder; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 04e2e458dd..568ac60afd 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -147,6 +147,11 @@ island-level-formula: '{} / 2' # Should the island levels be a rounded integer? rounded-island-level: false +# Whether to automatic track block counts when players place and break blocks. +# If set to true, block counts, worth and levels will automatically be updated upon +# placement and breaking of blocks. +auto-blocks-tracking: true + # How should the island top be ordered by default? # Use WORTH, LEVEL, RATING or PLAYERS. island-top-order: 'WORTH' From a23fae1beb230088f0d953c8047786c383d17bcb Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 25 Apr 2025 19:30:25 +0300 Subject: [PATCH 129/600] Do not register event callbacks if not necessary --- .../listener/BukkitListeners.java | 12 +++++++++--- .../listener/FeaturesListener.java | 16 +++++++--------- .../listener/IslandOutsideListener.java | 3 --- .../listener/IslandWorldEventsListener.java | 13 ++++++------- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java index 8eb6577e08..ce1df10c67 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java @@ -24,13 +24,10 @@ public void registerListeners() { unregisterListeners(); new AdminPlayersListener(this.plugin); - new BlockChangesListener(this.plugin); new ChunksListener(this.plugin); new EntityTrackingListener(this.plugin); new FeaturesListener(this.plugin); new IslandFlagsListener(this.plugin); - new IslandOutsideListener(this.plugin); - new IslandPreviewListener(this.plugin); new IslandWorldEventsListener(this.plugin); new MenusListener(this.plugin); new PlayersListener(this.plugin); @@ -40,6 +37,15 @@ public void registerListeners() { new StackedBlocksListener(this.plugin); new WorldDestructionListener(this.plugin); + if (plugin.getSettings().isStopLeaving()) + new IslandOutsideListener(this.plugin); + + if (plugin.getSettings().isAutoBlocksTracking()) + new BlockChangesListener(this.plugin); + + if (!plugin.getSettings().getPreviewIslands().isEmpty()) + new IslandPreviewListener(this.plugin); + safeEventsRegister(new BukkitEventsListener(this.plugin)); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java index 441e0de2a6..b337df86a4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java @@ -97,9 +97,6 @@ private void onGeneralPluginEvent(PluginEvent event) { /* OBSIDIAN TO LAVA */ private void onObsidianClick(GameEvent e) { - if (!plugin.getSettings().isObsidianToLava()) - return; - Player player = e.getArgs().player; ItemStack handItem = e.getArgs().usedItem; Block clickedBlock = e.getArgs().clickedBlock; @@ -148,9 +145,6 @@ private void onObsidianClick(GameEvent e) { /* VISITORS BLOCKED COMMANDS */ private void onPlayerCommand(GameEvent e) { - if (plugin.getSettings().getBlockedVisitorsCommands().isEmpty()) - return; - Player player = e.getArgs().player; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); @@ -259,12 +253,16 @@ private void onSculkShriekerInteract(GameEvent eventType : PluginEventType.values()) { - if (eventType.getBukkitEventName() != null) + String bukkitEventName = eventType.getBukkitEventName(); + if (bukkitEventName != null && plugin.getSettings().getEventCommands().containsKey(bukkitEventName)) plugin.getPluginEventsDispatcher().registerCallback(eventType, this::onGeneralPluginEvent); } - registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.HIGHEST, this::onObsidianClick); - registerCallback(GameEventType.PLAYER_COMMAND_EVENT, GameEventPriority.HIGHEST, this::onPlayerCommand); + if (plugin.getSettings().isObsidianToLava()) + registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.HIGHEST, this::onObsidianClick); + if (!plugin.getSettings().getBlockedVisitorsCommands().isEmpty()) + registerCallback(GameEventType.PLAYER_COMMAND_EVENT, GameEventPriority.HIGHEST, this::onPlayerCommand); + registerCallback(GameEventType.CHUNK_LOAD_EVENT, GameEventPriority.MONITOR, this::onChunkLoad); if (VAULT != null && TRIAL_SPAWNER != null) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java index f0d6c02455..09c229c899 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java @@ -25,9 +25,6 @@ public IslandOutsideListener(SuperiorSkyblockPlugin plugin) { } private void onMinecartRightClick(GameEvent e) { - if (!plugin.getSettings().isStopLeaving()) - return; - Entity rightClicked = e.getArgs().clickedEntity; if (rightClicked == null) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java index 429bb043ce..92475758c6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java @@ -25,14 +25,14 @@ protected HologramsService create() { public IslandWorldEventsListener(SuperiorSkyblockPlugin plugin) { super(plugin); - registerCallback(GameEventType.BLOCK_REDSTONE_EVENT, GameEventPriority.HIGHEST, this::onBlockRedstone); - registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.HIGHEST, this::onEntitySpawn); + if (plugin.getSettings().isDisableRedstoneOffline() || plugin.getSettings().getAFKIntegrations().isDisableRedstone()) + registerCallback(GameEventType.BLOCK_REDSTONE_EVENT, GameEventPriority.HIGHEST, this::onBlockRedstone); + + if (plugin.getSettings().getAFKIntegrations().isDisableSpawning()) + registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.HIGHEST, this::onEntitySpawn); } private void onBlockRedstone(GameEvent e) { - if (!plugin.getSettings().isDisableRedstoneOffline() && !plugin.getSettings().getAFKIntegrations().isDisableRedstone()) - return; - Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(e.getArgs().block.getLocation(wrapper.getHandle())); @@ -51,8 +51,7 @@ private void onBlockRedstone(GameEvent e) { private void onEntitySpawn(GameEvent e) { Entity entity = e.getArgs().entity; - if (!plugin.getSettings().getAFKIntegrations().isDisableSpawning() || - hologramsService.get().isHologram(entity)) + if (hologramsService.get().isHologram(entity)) return; Island island; From f93e7b3cf8211a08e41f5eb9c406efbddb7550e8 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 25 Apr 2025 20:50:53 +0300 Subject: [PATCH 130/600] Fix reload command not updating island upgrades correct (#2415) --- .../superiorskyblock/island/SIsland.java | 9 +-- .../island/upgrade/UpgradesManagerImpl.java | 4 ++ .../container/DefaultUpgradesContainer.java | 5 ++ .../upgrade/container/IslandUpgrades.java | 63 +++++++++++++++++++ .../upgrade/container/UpgradesContainer.java | 2 + .../module/upgrades/UpgradesModule.java | 38 +++++------ 6 files changed, 98 insertions(+), 23 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/IslandUpgrades.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 2c02736b9e..44ae81fe99 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -87,6 +87,7 @@ import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.island.upgrade.DefaultUpgradeLevel; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; +import com.bgsoftware.superiorskyblock.island.upgrade.container.IslandUpgrades; import com.bgsoftware.superiorskyblock.island.warp.SIslandWarp; import com.bgsoftware.superiorskyblock.island.warp.SWarpCategory; import com.bgsoftware.superiorskyblock.mission.MissionData; @@ -220,7 +221,7 @@ protected PlaceholdersService create() { private final Synchronized> visitorHomes = Synchronized.of(new EnumerateMap<>(Dimension.values())); private final Map rolePermissions = new ConcurrentHashMap<>(); private final Map islandFlags = new ConcurrentHashMap<>(); - private final Map upgrades = new ConcurrentHashMap<>(); + private final IslandUpgrades upgrades = new IslandUpgrades(); private final AtomicReference islandWorth = new AtomicReference<>(BigDecimal.ZERO); private final AtomicReference islandLevel = new AtomicReference<>(BigDecimal.ZERO); private final AtomicReference bonusWorth = new AtomicReference<>(BigDecimal.ZERO); @@ -290,7 +291,7 @@ public SIsland(IslandBuilderImpl builder) { this.playerPermissions.putAll(builder.playerPermissions); this.playerPermissions.values().forEach(permissionNode -> permissionNode.setIsland(this)); this.rolePermissions.putAll(builder.rolePermissions); - this.upgrades.putAll(builder.upgrades); + this.upgrades.setUpgradeLevels(builder.upgrades); this.blockLimits.putAll(builder.blockLimits); this.ratings.putAll(builder.ratings); this.completedMissions.putAll(builder.completedMissions); @@ -2955,7 +2956,7 @@ public void setUpgradeLevel(Upgrade upgrade, int level) { if (currentLevel == level) return; - upgrades.put(upgrade.getName(), Math.min(upgrade.getMaxUpgradeLevel(), level)); + this.upgrades.setUpgradeLevel(upgrade, level); lastUpgradeTime = System.currentTimeMillis(); @@ -2975,7 +2976,7 @@ public void setUpgradeLevel(Upgrade upgrade, int level) { @Override public Map getUpgrades() { - return Collections.unmodifiableMap(upgrades); + return this.upgrades.getUpgrades(); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/UpgradesManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/UpgradesManagerImpl.java index 7f16f11ef3..a7aca2ad1a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/UpgradesManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/UpgradesManagerImpl.java @@ -76,4 +76,8 @@ public UpgradeCostLoader getUpgradeCostLoader(String id) { return this.upgradesContainer.getUpgradeCostLoader(id); } + public void clearUpgrades() { + this.upgradesContainer.clearUpgrades(); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/DefaultUpgradesContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/DefaultUpgradesContainer.java index 78fe5688cb..fa76451ce0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/DefaultUpgradesContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/DefaultUpgradesContainer.java @@ -55,4 +55,9 @@ public void addUpgrade(Upgrade upgrade) { this.upgrades.put(upgrade.getName().toLowerCase(Locale.ENGLISH), upgrade); } + @Override + public void clearUpgrades() { + this.upgrades.clear(); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/IslandUpgrades.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/IslandUpgrades.java new file mode 100644 index 0000000000..3b0e06d347 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/IslandUpgrades.java @@ -0,0 +1,63 @@ +package com.bgsoftware.superiorskyblock.island.upgrade.container; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; +import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; +import com.google.common.collect.Sets; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; + +public class IslandUpgrades { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final Set ALL_UPGRADE_CONTAINERS = Sets.newSetFromMap(new WeakHashMap<>()); + + static { + + } + + private final Map enabledUpgrades = new ConcurrentHashMap<>(); + private final Map upgrades = new ConcurrentHashMap<>(); + + public IslandUpgrades() { + ALL_UPGRADE_CONTAINERS.add(this); + } + + public void setUpgradeLevel(Upgrade upgrade, int level) { + setUpgradeLevelInternal(upgrade.getName(), Math.min(upgrade.getMaxUpgradeLevel(), level)); + } + + public void setUpgradeLevels(Map upgrades) { + upgrades.forEach(this::setUpgradeLevelInternal); + } + + public UpgradeLevel getUpgradeLevel(Upgrade upgrade) { + return upgrade.getUpgradeLevel(this.enabledUpgrades.getOrDefault(upgrade.getName(), 1)); + } + + public Map getUpgrades() { + return Collections.unmodifiableMap(this.enabledUpgrades); + } + + private void setUpgradeLevelInternal(String upgradeName, int level) { + this.enabledUpgrades.put(upgradeName, level); + this.upgrades.put(upgradeName, level); + } + + public static void onUpgradesUpdate() { + for (IslandUpgrades islandUpgrades : ALL_UPGRADE_CONTAINERS) { + islandUpgrades.enabledUpgrades.clear(); + islandUpgrades.upgrades.forEach((upgradeName, level) -> { + Upgrade upgrade = plugin.getUpgrades().getUpgrade(upgradeName); + if (upgrade != null) + islandUpgrades.setUpgradeLevel(upgrade, level); + }); + } + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/UpgradesContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/UpgradesContainer.java index 0147945368..78c486c691 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/UpgradesContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/container/UpgradesContainer.java @@ -24,4 +24,6 @@ public interface UpgradesContainer { void addUpgrade(Upgrade upgrade); + void clearUpgrades(); + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java index 71b65970fb..af5c1c0f8b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java @@ -9,15 +9,15 @@ import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCost; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoadException; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader; +import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; -import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; +import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.value.DoubleValue; import com.bgsoftware.superiorskyblock.core.value.IntValue; @@ -25,6 +25,7 @@ import com.bgsoftware.superiorskyblock.island.upgrade.SUpgrade; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; import com.bgsoftware.superiorskyblock.island.upgrade.UpgradeRequirement; +import com.bgsoftware.superiorskyblock.island.upgrade.container.IslandUpgrades; import com.bgsoftware.superiorskyblock.module.BuiltinModule; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminRankup; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetUpgrade; @@ -45,8 +46,6 @@ import java.io.File; import java.math.BigDecimal; import java.util.ArrayList; -import java.util.EnumMap; -import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; @@ -149,25 +148,26 @@ protected void updateConfig(SuperiorSkyblockPlugin plugin) { if (config.getBoolean("entity-limits", true)) enabledUpgrades.add(new UpgradeTypeEntityLimits(plugin)); - if (enabledUpgrades.isEmpty()) - return; + plugin.getUpgrades().clearUpgrades(); - ConfigurationSection upgrades = config.getConfigurationSection("upgrades"); + if (!enabledUpgrades.isEmpty()) { + ConfigurationSection upgrades = config.getConfigurationSection("upgrades"); + if (upgrades != null) { + for (String upgradeName : upgrades.getKeys(false)) { + if (upgradeName.length() > MAX_UPGRADES_NAME_LENGTH) + upgradeName = upgradeName.substring(0, MAX_UPGRADES_NAME_LENGTH); - if (upgrades == null) - return; - - for (String upgradeName : upgrades.getKeys(false)) { - if (upgradeName.length() > MAX_UPGRADES_NAME_LENGTH) - upgradeName = upgradeName.substring(0, MAX_UPGRADES_NAME_LENGTH); + SUpgrade upgrade = new SUpgrade(upgradeName); + for (String _level : upgrades.getConfigurationSection(upgradeName).getKeys(false)) { + loadUpgradeLevelFromSection(plugin, upgrade, _level, upgrades.getConfigurationSection(upgradeName + "." + _level)); + } - SUpgrade upgrade = new SUpgrade(upgradeName); - for (String _level : upgrades.getConfigurationSection(upgradeName).getKeys(false)) { - loadUpgradeLevelFromSection(plugin, upgrade, _level, upgrades.getConfigurationSection(upgradeName + "." + _level)); + plugin.getUpgrades().addUpgrade(upgrade); + } } - - plugin.getUpgrades().addUpgrade(upgrade); } + + IslandUpgrades.onUpgradesUpdate(); } @Nullable From efe567bcdba2b3b8aabf495ff54823dc3ee83a65 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 25 Apr 2025 21:13:53 +0300 Subject: [PATCH 131/600] Fix unsafe visit location (#2413) --- .../commands/player/CmdVisit.java | 50 ++++++++++++++++--- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java index fa7339a65e..40e5260022 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java @@ -1,17 +1,21 @@ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.IslandWorlds; +import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.world.WorldBlocks; import org.bukkit.Location; import org.bukkit.command.CommandSender; @@ -88,9 +92,16 @@ public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sen } private static void teleportPlayerInternal(Island targetIsland, SuperiorPlayer superiorPlayer) { - Location visitLocation = plugin.getSettings().getVisitorsSign().isRequiredForVisit() ? - targetIsland.getVisitorsLocation((Dimension) null /* unused */) : - targetIsland.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()); + Location visitLocation; + boolean isVisitorSign; + + if (plugin.getSettings().getVisitorsSign().isRequiredForVisit()) { + isVisitorSign = true; + visitLocation = targetIsland.getVisitorsLocation((Dimension) null /* unused */); + } else { + isVisitorSign = false; + visitLocation = targetIsland.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()); + } if (visitLocation == null) { Message.INVALID_VISIT_LOCATION.send(superiorPlayer); @@ -113,16 +124,28 @@ private static void teleportPlayerInternal(Island targetIsland, SuperiorPlayer s Location finalVisitLocation = visitLocation; - superiorPlayer.setTeleportTask(BukkitExecutor.sync(() -> - teleportPlayerNoWarmup(superiorPlayer, targetIsland, finalVisitLocation, true), + superiorPlayer.setTeleportTask(BukkitExecutor.sync(() -> teleportPlayerNoWarmup(superiorPlayer, + targetIsland, finalVisitLocation, isVisitorSign, true, true), plugin.getSettings().getHomeWarmup() / 50)); } else { - teleportPlayerNoWarmup(superiorPlayer, targetIsland, visitLocation, false); + teleportPlayerNoWarmup(superiorPlayer, targetIsland, visitLocation, isVisitorSign, + false, true); } } - private static void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island island, - Location visitLocation, boolean checkIslandLock) { + private static void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island island, Location visitLocation, + boolean isVisitorSign, boolean checkIslandLock, boolean shouldRetryOnNullWorld) { + if (visitLocation.getWorld() == null) { + if (shouldRetryOnNullWorld && visitLocation instanceof LazyWorldLocation && + plugin.getProviders().getWorldsProvider() instanceof LazyWorldsProvider) { + LazyWorldsProvider worldsProvider = (LazyWorldsProvider) plugin.getProviders().getWorldsProvider(); + WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(island, ((LazyWorldLocation) visitLocation).getWorldName()); + worldsProvider.prepareWorld(island, worldInfo.getDimension(), + () -> teleportPlayerNoWarmup(superiorPlayer, island, visitLocation, isVisitorSign, checkIslandLock, false)); + return; + } + } + superiorPlayer.setTeleportTask(null); if (checkIslandLock && island.isLocked() && !island.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS)) { @@ -130,6 +153,17 @@ private static void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island return; } + if (isVisitorSign && !WorldBlocks.isSafeBlock(visitLocation.getBlock())) { + Message.INVALID_VISIT_LOCATION.send(superiorPlayer); + + if (!superiorPlayer.hasBypassModeEnabled()) { + island.setVisitorsLocation(null); + return; + } + + Message.INVALID_VISIT_LOCATION_BYPASS.send(superiorPlayer); + } + superiorPlayer.teleport(visitLocation); } From b535029702aff2df1152638f48c4a04f477f5476 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 25 Apr 2025 21:14:13 +0300 Subject: [PATCH 132/600] Fix delete unsafe warps not working correctly in all cases (#2413) --- .../com/bgsoftware/superiorskyblock/island/SIsland.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 44ae81fe99..ca6b76ae20 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -4653,18 +4653,13 @@ private void warpPlayerWithoutWarmup(SuperiorPlayer superiorPlayer, IslandWarp i superiorPlayer.setTeleportTask(null); - if (!isInsideRange(location)) { + if (!isInsideRange(location) || !WorldBlocks.isSafeBlock(location.getBlock())) { Message.UNSAFE_WARP.send(superiorPlayer); if (plugin.getSettings().getDeleteUnsafeWarps()) deleteWarp(islandWarp.getName()); return; } - if (!WorldBlocks.isSafeBlock(location.getBlock())) { - Message.UNSAFE_WARP.send(superiorPlayer); - return; - } - superiorPlayer.teleport(location, success -> { if (success) { Message.TELEPORTED_TO_WARP.send(superiorPlayer); From dfd538f524d41f28a1df1747423743ae9c76acbe Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 25 Apr 2025 21:51:29 +0300 Subject: [PATCH 133/600] Fix detection of exploded warp signs (#2413) --- .../events/IslandRemoveVisitorHomeEvent.java | 8 ++- .../commands/player/CmdVisit.java | 4 +- .../island/signs/IslandSigns.java | 11 +-- .../listener/SignsListener.java | 70 +++++++++++++++---- 4 files changed, 71 insertions(+), 22 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveVisitorHomeEvent.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveVisitorHomeEvent.java index 5907487473..fbd5fe6b8a 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveVisitorHomeEvent.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveVisitorHomeEvent.java @@ -1,9 +1,8 @@ package com.bgsoftware.superiorskyblock.api.events; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.google.common.base.Preconditions; -import org.bukkit.Location; import org.bukkit.event.Cancellable; /** @@ -11,6 +10,7 @@ */ public class IslandRemoveVisitorHomeEvent extends IslandEvent implements Cancellable { + @Nullable private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; @@ -19,9 +19,10 @@ public class IslandRemoveVisitorHomeEvent extends IslandEvent implements Cancell * The constructor of the event. * * @param superiorPlayer The player that removed the island visitor home. + * If null, then the warp was deleted by the console or another source * @param island The island that the visitor home was removed. */ - public IslandRemoveVisitorHomeEvent(SuperiorPlayer superiorPlayer, Island island) { + public IslandRemoveVisitorHomeEvent(@Nullable SuperiorPlayer superiorPlayer, Island island) { super(island); this.superiorPlayer = superiorPlayer; } @@ -29,6 +30,7 @@ public IslandRemoveVisitorHomeEvent(SuperiorPlayer superiorPlayer, Island island /** * Get the player who removed the island visitor home. */ + @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java index 40e5260022..15213f3673 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; @@ -157,7 +158,8 @@ private static void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island Message.INVALID_VISIT_LOCATION.send(superiorPlayer); if (!superiorPlayer.hasBypassModeEnabled()) { - island.setVisitorsLocation(null); + if (PluginEventsFactory.callIslandRemoveVisitorHomeEvent(island, superiorPlayer)) + island.setVisitorsLocation(null); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java b/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java index f65239b573..c8f17d0c2a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.island.signs; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; @@ -50,13 +51,15 @@ public static Result handleSignPlace(SuperiorPlayer superiorPlayer, Location war return new Result(Reason.SUCCESS, false); } - public static Result handleSignBreak(SuperiorPlayer superiorPlayer, Sign sign) { + public static Result handleSignBreak(@Nullable Island island, @Nullable SuperiorPlayer superiorPlayer, Sign sign) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location signLocation = sign.getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(signLocation); - if (island == null) - return new Result(Reason.NOT_IN_ISLAND, false); + if (island == null) { + island = plugin.getGrid().getIslandAt(signLocation); + if (island == null) + return new Result(Reason.NOT_IN_ISLAND, false); + } IslandWarp islandWarp = island.getWarp(signLocation); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java index 53aa6e9afe..e1895ecb13 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java @@ -1,7 +1,10 @@ package com.bgsoftware.superiorskyblock.listener; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; @@ -17,9 +20,11 @@ import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.block.data.Directional; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import java.util.Arrays; +import java.util.Iterator; public class SignsListener extends AbstractGameEventListener { @@ -27,6 +32,11 @@ public class SignsListener extends AbstractGameEventListener { BlockFace.UP, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.EAST }; + @Nullable + private static final EntityType WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "WIND_CHARGE"); + @Nullable + private static final EntityType BREEZE_WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "BREEZE_WIND_CHARGE"); + public SignsListener(SuperiorSkyblockPlugin plugin) { super(plugin); registerListeners(); @@ -80,21 +90,54 @@ private void onSignPlace(GameEvent e) { }, 1L); } - public void onSignBreak(GameEvent e) { + private void onSignBreak(GameEvent e) { + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getArgs().block.getLocation(wrapper.getHandle())); + } + + if (island == null || island.getIslandWarps().isEmpty()) + return; + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); - Block block = e.getArgs().block; - if (block.getState() instanceof Sign) { - IslandSigns.Result result = IslandSigns.handleSignBreak(superiorPlayer, (Sign) block.getState()); - if (result.isCancelEvent()) - e.setCancelled(); + IslandSigns.Result result = handleBlockBreak(island, e.getArgs().block, superiorPlayer); + if (result.isCancelEvent()) + e.setCancelled(); + } + + private void onSignExplode(GameEvent e) { + EntityType entityType = e.getArgs().entity.getType(); + + if (entityType == WIND_CHARGE || entityType == BREEZE_WIND_CHARGE) + return; + + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getArgs().entity.getLocation(wrapper.getHandle())); + } + if (island == null || island.getIslandWarps().isEmpty()) return; + + Iterator iterator = e.getArgs().blocks.iterator(); + while (iterator.hasNext()) { + Block block = iterator.next(); + IslandSigns.Result result = handleBlockBreak(island, block, null); + if (result.isCancelEvent()) + iterator.remove(); + } + } + + private IslandSigns.Result handleBlockBreak(Island island, Block block, @Nullable SuperiorPlayer superiorPlayer) { + BlockState blockState = block.getState(); + if (blockState instanceof Sign) { + return IslandSigns.handleSignBreak(island, superiorPlayer, (Sign) blockState); } for (BlockFace blockFace : NEARBY_BLOCKS) { Block faceBlock = block.getRelative(blockFace); - BlockState blockState = faceBlock.getState(); + blockState = faceBlock.getState(); if (!(blockState instanceof Sign)) continue; @@ -125,18 +168,17 @@ public void onSignBreak(GameEvent e) { } if (isSignGonnaBreak) { - IslandSigns.Result result = IslandSigns.handleSignBreak(superiorPlayer, (Sign) blockState); - if (result.isCancelEvent()) { - e.setCancelled(); - return; - } + return IslandSigns.handleSignBreak(null, superiorPlayer, (Sign) blockState); } } + + return new IslandSigns.Result(IslandSigns.Reason.SUCCESS, false); } private void registerListeners() { - registerCallback(GameEventType.SIGN_CHANGE_EVENT, GameEventPriority.NORMAL, this::onSignPlace); - registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.NORMAL, this::onSignBreak); + registerCallback(GameEventType.SIGN_CHANGE_EVENT, GameEventPriority.MONITOR, this::onSignPlace); + registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.MONITOR, this::onSignBreak); + registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.MONITOR, this::onSignExplode); } } From f4313e603a3754ca4da24ff88383a62ffd4ab0ff Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 25 Apr 2025 22:04:23 +0300 Subject: [PATCH 134/600] Another attempt to fix out of bounds when placing signs (#2411) --- .../v1_20_3/world/WorldEditSessionImpl.java | 18 ++++++++++++------ .../v1_20_4/world/WorldEditSessionImpl.java | 18 ++++++++++++------ .../nms/v1_21/world/WorldEditSessionImpl.java | 18 ++++++++++++------ .../v1_21_3/world/WorldEditSessionImpl.java | 18 ++++++++++++------ .../v1_21_4/world/WorldEditSessionImpl.java | 18 ++++++++++++------ .../v1_21_5/world/WorldEditSessionImpl.java | 18 ++++++++++++------ 6 files changed, 72 insertions(+), 36 deletions(-) diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java index 73e8084b0b..32e0c801a3 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java @@ -59,6 +59,7 @@ import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; @@ -84,6 +85,8 @@ public class WorldEditSessionImpl implements WorldEditSession { } }).get(); + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); @@ -275,18 +278,21 @@ private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntity if (blockEntityCompound.contains(key)) { net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); - Component[] frontTextLines = new Component[messages.size()]; - Arrays.fill(frontTextLines, Component.empty()); - int i = 0; + List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { - frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); + textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); } catch (JsonParseException error) { - frontTextLines[i++] = CraftChatMessage.fromString(lineTag.getAsString())[0]; + textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); } } - SignText signText = new SignText(frontTextLines, frontTextLines, DyeColor.BLACK, false); + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java index 12164497ce..00ad9b1899 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java @@ -59,6 +59,7 @@ import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; @@ -84,6 +85,8 @@ public class WorldEditSessionImpl implements WorldEditSession { } }).get(); + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); @@ -275,18 +278,21 @@ private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntity if (blockEntityCompound.contains(key)) { net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); - Component[] frontTextLines = new Component[messages.size()]; - Arrays.fill(frontTextLines, Component.empty()); - int i = 0; + List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { - frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); + textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); } catch (JsonParseException error) { - frontTextLines[i++] = CraftChatMessage.fromString(lineTag.getAsString())[0]; + textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); } } - SignText signText = new SignText(frontTextLines, frontTextLines, DyeColor.BLACK, false); + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java index f02058b026..bd5837d5fb 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java @@ -57,6 +57,7 @@ import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; @@ -82,6 +83,8 @@ public class WorldEditSessionImpl implements WorldEditSession { } }).get(); + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); @@ -273,18 +276,21 @@ private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntity if (blockEntityCompound.contains(key)) { net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); - Component[] frontTextLines = new Component[messages.size()]; - Arrays.fill(frontTextLines, Component.empty()); - int i = 0; + List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { - frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); + textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); } catch (JsonParseException error) { - frontTextLines[i++] = CraftChatMessage.fromString(lineTag.getAsString())[0]; + textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); } } - SignText signText = new SignText(frontTextLines, frontTextLines, DyeColor.BLACK, false); + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java index 33d19eab63..1eb4e880b0 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java @@ -57,6 +57,7 @@ import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; @@ -82,6 +83,8 @@ public class WorldEditSessionImpl implements WorldEditSession { } }).get(); + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); @@ -273,18 +276,21 @@ private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntity if (blockEntityCompound.contains(key)) { net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); - Component[] frontTextLines = new Component[messages.size()]; - Arrays.fill(frontTextLines, Component.empty()); - int i = 0; + List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { - frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); + textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); } catch (JsonParseException error) { - frontTextLines[i++] = CraftChatMessage.fromString(lineTag.getAsString())[0]; + textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); } } - SignText signText = new SignText(frontTextLines, frontTextLines, DyeColor.BLACK, false); + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java index 0cffc2aa8a..c288df3590 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java @@ -57,6 +57,7 @@ import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; @@ -82,6 +83,8 @@ public class WorldEditSessionImpl implements WorldEditSession { } }).get(); + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); @@ -273,18 +276,21 @@ private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntity if (blockEntityCompound.contains(key)) { net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); - Component[] frontTextLines = new Component[messages.size()]; - Arrays.fill(frontTextLines, Component.empty()); - int i = 0; + List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { - frontTextLines[i++] = CraftChatMessage.fromJSON(lineTag.getAsString()); + textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); } catch (JsonParseException error) { - frontTextLines[i++] = CraftChatMessage.fromString(lineTag.getAsString())[0]; + textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); } } - SignText signText = new SignText(frontTextLines, frontTextLines, DyeColor.BLACK, false); + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java index 068fb06e3c..8fb2a05102 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java @@ -57,6 +57,7 @@ import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; @@ -82,6 +83,8 @@ public class WorldEditSessionImpl implements WorldEditSession { } }).get(); + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); @@ -272,18 +275,21 @@ private boolean isValidPosition(BlockPos blockPos) { private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { blockEntityCompound.getCompound(key).ifPresent(textCompound -> { ListTag messages = textCompound.getListOrEmpty("messages"); - Component[] textLines = new Component[messages.size()]; - Arrays.fill(textLines, Component.empty()); - int i = 0; + List textLines = new ArrayList<>(); for (net.minecraft.nbt.Tag lineTag : messages) { try { - textLines[i++] = CraftChatMessage.fromJSON(lineTag.asString().orElseThrow()); + textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); } catch (JsonParseException error) { - textLines[i++] = CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]; + textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); } } - SignText signText = new SignText(textLines, textLines, DyeColor.BLACK, false); + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); }); From 0ebf7cd5313316d5fd2b47e4baa6e8c81d728f66 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 26 Apr 2025 12:35:55 +0300 Subject: [PATCH 135/600] Add debug message when failing to dispatch upgrade commands (#2417) --- .../module/upgrades/commands/CmdRankup.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java index f6b2b76937..1b33b754e3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java @@ -19,6 +19,7 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; @@ -132,11 +133,15 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer upgradeCost.withdrawCost(superiorPlayer); for (String command : event.getArgs().commands) { - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), - placeholdersService.get().parsePlaceholders(superiorPlayer.asOfflinePlayer(), command - .replace("%player%", superiorPlayer.getName()) - .replace("%leader%", island.getOwner().getName())) - ); + String parsedCommand = placeholdersService.get().parsePlaceholders(superiorPlayer.asOfflinePlayer(), command + .replace("%player%", superiorPlayer.getName()) + .replace("%leader%", island.getOwner().getName())); + + try { + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), parsedCommand); + } catch (Throwable error) { + Log.error(error, "An unexpected error occurred while executing command:\n", parsedCommand); + } } hasNextLevel = true; From 2fb31b1b422cfed09c73e9cfbfb88bf8d3308573 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 26 Apr 2025 14:33:37 +0300 Subject: [PATCH 136/600] Filter out privileges that cannot be assigned to coops / guests in the permissions menu (#2412) --- .../api/island/IslandPrivilege.java | 59 +++- .../commands/CommandTabCompletes.java | 7 +- .../commands/admin/CmdAdminSetPermission.java | 17 +- .../IslandPrivilegePagedObjectButton.java | 299 ++++++++++-------- .../core/menu/impl/MenuIslandPrivileges.java | 11 + .../island/privilege/IslandPrivileges.java | 64 ++-- 6 files changed, 292 insertions(+), 165 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPrivilege.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPrivilege.java index f4f04d0f5a..9d5438564f 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPrivilege.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPrivilege.java @@ -14,10 +14,12 @@ public class IslandPrivilege implements Enumerable { private static int ordinalCounter = 0; private final String name; + private final Type type; private final int ordinal; - private IslandPrivilege(String name) { + private IslandPrivilege(String name, Type type) { this.name = name.toUpperCase(Locale.ENGLISH); + this.type = type; this.ordinal = ordinalCounter++; } @@ -26,6 +28,25 @@ public int ordinal() { return this.ordinal; } + /** + * Get the name of the island privilege. + */ + public String getName() { + return name; + } + + /** + * Get the type of the privilege. + */ + public Type getType() { + return type; + } + + @Override + public String toString() { + return "IslandPrivilege{name=" + name + ", type=" + type + "}"; + } + /** * Get all the island privileges. */ @@ -49,30 +70,48 @@ public static IslandPrivilege getByName(String name) { } /** - * Register a new island privilege. + * Register a new {@link Type#ACTION} island privilege. * * @param name The name for the island privilege. */ public static void register(String name) { + register(name, Type.ACTION); + } + + /** + * Register a new island privilege. + * + * @param name The name for the island privilege. + * @param type The type of the privilege. + */ + public static void register(String name, Type type) { Preconditions.checkNotNull(name, "name parameter cannot be null."); + Preconditions.checkNotNull(type, "name parameter cannot be null."); name = name.toUpperCase(Locale.ENGLISH); Preconditions.checkState(!islandPrivileges.containsKey(name), "IslandPrivilege with the name " + name + " already exists."); - islandPrivileges.put(name, new IslandPrivilege(name)); + islandPrivileges.put(name, new IslandPrivilege(name, type)); } /** - * Get the name of the island privilege. + * Represents the type of IslandPrivilege. */ - public String getName() { - return name; - } + public enum Type { + + /** + * The ACTION type is given for privileges that allow player to do actions on islands. + * Privileges of this type can be given to visitors, coops and players that are not part of the island team. + */ + ACTION, + + /** + * The COMMAND type is given for privileges that give access to commands on the island. + * Privileges of this type can only be given to players that are part of the island. + */ + COMMAND - @Override - public String toString() { - return "IslandPrivilege{name=" + name + "}"; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index dc68408c46..852f38ddef 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -149,8 +149,11 @@ public static List getUpgrades(SuperiorSkyblockPlugin plugin, String arg return filterByArgument(plugin.getUpgrades().getUpgrades(), Upgrade::getName, argument.toLowerCase(Locale.ENGLISH)); } - public static List getPlayerRoles(SuperiorSkyblockPlugin plugin, String argument) { - return filterByArgument(plugin.getRoles().getRoles(), PlayerRole::getName, argument.toLowerCase(Locale.ENGLISH)); + public static List getPlayerRoles(SuperiorSkyblockPlugin plugin, @Nullable IslandPrivilege islandPrivilege, String argument) { + return new SequentialListBuilder() + .filter(playerRole -> playerRole.getName().toLowerCase(Locale.ENGLISH).contains(argument) && + (islandPrivilege == null || islandPrivilege.getType() != IslandPrivilege.Type.COMMAND || playerRole.isRoleLadder())) + .map(plugin.getRoles().getRoles(), PlayerRole::getName); } public static List getPlayerRoles(SuperiorSkyblockPlugin plugin, String argument, Predicate predicate) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java index 58e3cf0db0..a452d08cc4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.command.CommandSender; import java.util.Arrays; @@ -77,6 +78,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (playerRole == null) return; + if (islandPrivilege.getType() == IslandPrivilege.Type.COMMAND && !playerRole.isRoleLadder()) { + Message.INVALID_ROLE.send(sender, args[4], SPlayerRole.getValuesString()); + return; + } + int islandsChangedCount = 0; for (Island island : islands) { @@ -100,7 +106,16 @@ else if (targetPlayer == null) @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getIslandPrivileges(args[3]) : - args.length == 5 ? CommandTabCompletes.getPlayerRoles(plugin, args[4]) : Collections.emptyList(); + args.length == 5 ? CommandTabCompletes.getPlayerRoles(plugin, getIslandPrivilegeSafe(args[3]), args[4]) : Collections.emptyList(); + } + + @Nullable + private static IslandPrivilege getIslandPrivilegeSafe(String name) { + try { + return IslandPrivilege.getByName(name); + } catch (NullPointerException error) { + return null; + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandPrivilegePagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandPrivilegePagedObjectButton.java index c4b8a923d6..f5e73e314a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandPrivilegePagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandPrivilegePagedObjectButton.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.core.menu.button.impl; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PermissionNode; @@ -17,7 +18,6 @@ import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandPrivileges; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; -import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -30,192 +30,241 @@ public class IslandPrivilegePagedObjectButton extends AbstractPagedMenuButton { + private final PrivilegeButtonActions actions; + private IslandPrivilegePagedObjectButton(MenuTemplateButton templateButton, MenuIslandPrivileges.View menuView) { super(templateButton, menuView); + + if (menuView.getPermissionHolder() instanceof PlayerRole) { + this.actions = RolePrivilegeButtonActions.INSTANCE; + } else { + this.actions = PlayerPrivilegeButtonActions.INSTANCE; + } } @Override public void onButtonClick(InventoryClickEvent clickEvent) { - Island island = menuView.getIsland(); - Object permissionHolder = menuView.getPermissionHolder(); - - if (permissionHolder instanceof PlayerRole) { - onRoleButtonClick(island, menuView.getInventoryViewer(), clickEvent); - } else if (permissionHolder instanceof SuperiorPlayer) { - onPlayerButtonClick(island, menuView.getInventoryViewer(), (SuperiorPlayer) permissionHolder); - } + this.actions.onButtonClick(clickEvent, this); } @Override public ItemStack modifyViewItem(ItemStack buttonItem) { - SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); - Island targetIsland = menuView.getIsland(); - Object permissionHolder = menuView.getPermissionHolder(); + return this.actions.modifyViewItem(buttonItem, this); + } - ItemBuilder permissionItem = new ItemBuilder(Material.AIR); + private static void onSuccessfulPermissionChange(IslandPrivilegePagedObjectButton button, + SuperiorPlayer clickedPlayer, String permissionHolderName) { + Player player = clickedPlayer.asPlayer(); - if (permissionHolder instanceof PlayerRole) { - if (pagedObject.getRoleIslandPrivilegeItem() != null) { - permissionItem = modifyRoleButtonItem(targetIsland); - } - } else if (permissionHolder instanceof SuperiorPlayer) { - IslandPrivilege islandPrivilege = pagedObject.getIslandPrivilege(); - boolean hasPermission = islandPrivilege != null && targetIsland.getPermissionNode( - (SuperiorPlayer) permissionHolder).hasPermission(islandPrivilege); - permissionItem = hasPermission ? pagedObject.getEnabledIslandPrivilegeItem() : - pagedObject.getDisabledIslandPrivilegeItem(); - } + if (player == null) + return; + + Message.UPDATED_PERMISSION.send(clickedPlayer, permissionHolderName); + + GameSoundImpl.playSound(player, button.pagedObject.getAccessSound()); + + button.pagedObject.getAccessCommands().forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), + command.replace("%player%", clickedPlayer.getName()))); - return permissionItem.build(inventoryViewer); + Menus.MENU_ISLAND_PRIVILEGES.refreshViews(); } - private void onRoleButtonClick(Island island, SuperiorPlayer clickedPlayer, InventoryClickEvent clickEvent) { - IslandPrivilege islandPrivilege = pagedObject.getIslandPrivilege(); + private static void onFailurePermissionChange(IslandPrivilegePagedObjectButton button, + SuperiorPlayer clickedPlayer, boolean sendFailMessage) { + Player player = clickedPlayer.asPlayer(); - if (islandPrivilege == null) + if (player == null) return; - PlayerRole currentRole = island.getRequiredPlayerRole(islandPrivilege); + if (sendFailMessage) + Message.LACK_CHANGE_PERMISSION.send(clickedPlayer); - if (clickedPlayer.getPlayerRole().isLessThan(currentRole)) { - onFailurePermissionChange(clickedPlayer, false); - return; + GameSoundImpl.playSound(player, button.pagedObject.getNoAccessSound()); + + button.pagedObject.getNoAccessCommands().forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), + command.replace("%player%", clickedPlayer.getName()))); + } + + private static boolean isRoleAllowed(@Nullable PlayerRole playerRole, @Nullable IslandPrivilege.Type islandPrivilegeType) { + if (!plugin.getSettings().isCoopMembers() && playerRole == SPlayerRole.coopRole()) + return false; + + if (islandPrivilegeType == IslandPrivilege.Type.COMMAND && + playerRole != null && playerRole.isLessThan(SPlayerRole.defaultRole())) { + return false; } - PlayerRole newRole = null; + return true; + } - if (clickEvent.getClick().isLeftClick()) { - newRole = SPlayerRole.of(currentRole.getWeight() - 1); + private interface PrivilegeButtonActions { - if (!plugin.getSettings().isCoopMembers() && newRole == SPlayerRole.coopRole()) { - assert newRole != null; - newRole = SPlayerRole.of(newRole.getWeight() - 1); - } + void onButtonClick(InventoryClickEvent clickEvent, IslandPrivilegePagedObjectButton button); - if (newRole == null) - newRole = clickedPlayer.getPlayerRole(); - } else { - if (clickedPlayer.getPlayerRole().isHigherThan(currentRole)) { - newRole = SPlayerRole.of(currentRole.getWeight() + 1); - } + ItemStack modifyViewItem(ItemStack buttonItem, IslandPrivilegePagedObjectButton button); + + } + + private static class RolePrivilegeButtonActions implements PrivilegeButtonActions { + + private static final RolePrivilegeButtonActions INSTANCE = new RolePrivilegeButtonActions(); + + @Override + public void onButtonClick(InventoryClickEvent clickEvent, IslandPrivilegePagedObjectButton button) { + IslandPrivilege islandPrivilege = button.pagedObject.getIslandPrivilege(); + + if (islandPrivilege == null) + return; + + Island island = button.menuView.getIsland(); + SuperiorPlayer clickedPlayer = button.menuView.getInventoryViewer(); + IslandPrivilege.Type islandPrivilegeType = islandPrivilege.getType(); + + PlayerRole currentRole = island.getRequiredPlayerRole(islandPrivilege); - if (!plugin.getSettings().isCoopMembers() && newRole == SPlayerRole.coopRole()) { - assert newRole != null; - newRole = SPlayerRole.of(newRole.getWeight() + 1); + if (clickedPlayer.getPlayerRole().isLessThan(currentRole)) { + onFailurePermissionChange(button, clickedPlayer, false); + return; } - if (newRole == null) - newRole = SPlayerRole.guestRole(); - } + PlayerRole newRole = null; + + if (clickEvent.getClick().isLeftClick()) { + newRole = currentRole; + do { + newRole = SPlayerRole.of(newRole.getWeight() - 1); + } while (newRole != null && !isRoleAllowed(newRole, islandPrivilegeType)); + + if (newRole == null) + newRole = clickedPlayer.getPlayerRole(); + } else { + if (clickedPlayer.getPlayerRole().isHigherThan(currentRole)) { + newRole = currentRole; + do { + newRole = SPlayerRole.of(newRole.getWeight() + 1); + } while (newRole != null && !isRoleAllowed(newRole, islandPrivilegeType)); + } + + if (newRole == null) { + newRole = islandPrivilegeType == IslandPrivilege.Type.COMMAND ? SPlayerRole.defaultRole() : SPlayerRole.guestRole(); + } + } - if (PluginEventsFactory.callIslandChangeRolePrivilegeEvent(island, clickedPlayer, newRole)) { - island.setPermission(newRole, islandPrivilege); - onSuccessfulPermissionChange(clickedPlayer, Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName())); + if (PluginEventsFactory.callIslandChangeRolePrivilegeEvent(island, clickedPlayer, newRole)) { + island.setPermission(newRole, islandPrivilege); + onSuccessfulPermissionChange(button, clickedPlayer, + Formatters.CAPITALIZED_FORMATTER.format(islandPrivilege.getName())); + } } - } - private void onPlayerButtonClick(Island island, SuperiorPlayer clickedPlayer, SuperiorPlayer permissionHolder) { - IslandPrivilege islandPrivilege = pagedObject.getIslandPrivilege(); + @Override + public ItemStack modifyViewItem(ItemStack buttonItem, IslandPrivilegePagedObjectButton button) { + ItemBuilder permissionItem = button.pagedObject.getRoleIslandPrivilegeItem(); + if (permissionItem == null) + return new ItemStack(Material.AIR); - if (islandPrivilege == null || !island.hasPermission(clickedPlayer, islandPrivilege)) - return; + IslandPrivilege islandPrivilege = button.pagedObject.getIslandPrivilege(); + Island island = button.menuView.getIsland(); - PermissionNode permissionNode = island.getPermissionNode(permissionHolder); + PlayerRole requiredRole = islandPrivilege == null ? null : island.getRequiredPlayerRole(islandPrivilege); + IslandPrivilege.Type islandPrivilegeType = islandPrivilege == null ? null : islandPrivilege.getType(); - String permissionHolderName = permissionHolder.getName(); + permissionItem.replaceAll("{}", requiredRole == null ? "" : requiredRole.toString()); - boolean currentValue = permissionNode.hasPermission(islandPrivilege); + if (!Menus.MENU_ISLAND_PRIVILEGES.getNoRolePermission().isEmpty() && + !Menus.MENU_ISLAND_PRIVILEGES.getExactRolePermission().isEmpty() && + !Menus.MENU_ISLAND_PRIVILEGES.getHigherRolePermission().isEmpty()) { + List roleString = new ArrayList<>(); - if (!PluginEventsFactory.callIslandChangePlayerPrivilegeEvent(island, clickedPlayer, permissionHolder, !currentValue)) - return; + int roleWeight = requiredRole == null ? Integer.MAX_VALUE : requiredRole.getWeight(); - island.setPermission(permissionHolder, islandPrivilege, !currentValue); + PlayerRole currentRole; + for (int i = -2; (currentRole = SPlayerRole.of(i)) != null; i++) { + if (!isRoleAllowed(currentRole, islandPrivilegeType)) + continue; - onSuccessfulPermissionChange(clickedPlayer, permissionHolderName); - } + if (i < roleWeight) { + roleString.add(Menus.MENU_ISLAND_PRIVILEGES.getNoRolePermission().replace("{}", currentRole + "")); + } else if (i == roleWeight) { + roleString.add(Menus.MENU_ISLAND_PRIVILEGES.getExactRolePermission().replace("{}", currentRole + "")); + } else { + roleString.add(Menus.MENU_ISLAND_PRIVILEGES.getHigherRolePermission().replace("{}", currentRole + "")); + } + } - private void onSuccessfulPermissionChange(SuperiorPlayer clickedPlayer, String permissionHolderName) { - Player player = clickedPlayer.asPlayer(); + ItemMeta itemMeta = permissionItem.getItemMeta(); - if (player == null) - return; + if (itemMeta != null) { + List lore = itemMeta.getLore(); - Message.UPDATED_PERMISSION.send(clickedPlayer, permissionHolderName); + for (int i = 0; i < lore.size(); i++) { + String line = lore.get(i); + if (line.equals("{0}")) { + lore.set(i, roleString.get(0)); + for (int j = 1; j < roleString.size(); j++) { + lore.add(i + j, roleString.get(j)); + } + i += roleString.size(); + } + } - GameSoundImpl.playSound(player, pagedObject.getAccessSound()); + permissionItem.withLore(lore); + } + } - pagedObject.getAccessCommands().forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), - command.replace("%player%", clickedPlayer.getName()))); + return permissionItem.build(button.menuView.getInventoryViewer()); + } - Menus.MENU_ISLAND_PRIVILEGES.refreshViews(); } - private void onFailurePermissionChange(SuperiorPlayer clickedPlayer, boolean sendFailMessage) { - Player player = clickedPlayer.asPlayer(); + private static class PlayerPrivilegeButtonActions implements PrivilegeButtonActions { - if (player == null) - return; + private static final PlayerPrivilegeButtonActions INSTANCE = new PlayerPrivilegeButtonActions(); - if (sendFailMessage) - Message.LACK_CHANGE_PERMISSION.send(clickedPlayer); + @Override + public void onButtonClick(InventoryClickEvent clickEvent, IslandPrivilegePagedObjectButton button) { + IslandPrivilege islandPrivilege = button.pagedObject.getIslandPrivilege(); - GameSoundImpl.playSound(player, pagedObject.getNoAccessSound()); + if (islandPrivilege == null) + return; - pagedObject.getNoAccessCommands().forEach(command -> Bukkit.dispatchCommand(Bukkit.getConsoleSender(), - command.replace("%player%", clickedPlayer.getName()))); - } + Island island = button.menuView.getIsland(); + SuperiorPlayer clickedPlayer = button.menuView.getInventoryViewer(); - private ItemBuilder modifyRoleButtonItem(Island island) { - Preconditions.checkNotNull(pagedObject.getRoleIslandPrivilegeItem(), "role item cannot be null."); + if (!island.hasPermission(clickedPlayer, islandPrivilege)) + return; - IslandPrivilege islandPrivilege = pagedObject.getIslandPrivilege(); + SuperiorPlayer permissiblePlayer = (SuperiorPlayer) button.menuView.getPermissionHolder(); - PlayerRole requiredRole = islandPrivilege == null ? null : island.getRequiredPlayerRole(islandPrivilege); - ItemBuilder permissionItem = pagedObject.getRoleIslandPrivilegeItem() - .replaceAll("{}", requiredRole == null ? "" : requiredRole.toString()); + PermissionNode permissionNode = island.getPermissionNode(permissiblePlayer); - if (!Menus.MENU_ISLAND_PRIVILEGES.getNoRolePermission().isEmpty() && - !Menus.MENU_ISLAND_PRIVILEGES.getExactRolePermission().isEmpty() && - !Menus.MENU_ISLAND_PRIVILEGES.getHigherRolePermission().isEmpty()) { - List roleString = new ArrayList<>(); + String permissionHolderName = permissiblePlayer.getName(); - int roleWeight = requiredRole == null ? Integer.MAX_VALUE : requiredRole.getWeight(); - PlayerRole currentRole; + boolean currentValue = permissionNode.hasPermission(islandPrivilege); - for (int i = -2; (currentRole = SPlayerRole.of(i)) != null; i++) { - if (!plugin.getSettings().isCoopMembers() && currentRole == SPlayerRole.coopRole()) - continue; + if (!PluginEventsFactory.callIslandChangePlayerPrivilegeEvent(island, clickedPlayer, permissiblePlayer, !currentValue)) + return; - if (i < roleWeight) { - roleString.add(Menus.MENU_ISLAND_PRIVILEGES.getNoRolePermission().replace("{}", currentRole + "")); - } else if (i == roleWeight) { - roleString.add(Menus.MENU_ISLAND_PRIVILEGES.getExactRolePermission().replace("{}", currentRole + "")); - } else { - roleString.add(Menus.MENU_ISLAND_PRIVILEGES.getHigherRolePermission().replace("{}", currentRole + "")); - } - } + island.setPermission(permissiblePlayer, islandPrivilege, !currentValue); + + onSuccessfulPermissionChange(button, clickedPlayer, permissionHolderName); + } - ItemMeta itemMeta = permissionItem.getItemMeta(); + @Override + public ItemStack modifyViewItem(ItemStack buttonItem, IslandPrivilegePagedObjectButton button) { + IslandPrivilege islandPrivilege = button.pagedObject.getIslandPrivilege(); + Island targetIsland = button.menuView.getIsland(); + SuperiorPlayer permissiblePlayer = (SuperiorPlayer) button.menuView.getPermissionHolder(); - if (itemMeta != null) { - List lore = itemMeta.getLore(); + boolean hasPermission = islandPrivilege != null && + targetIsland.getPermissionNode(permissiblePlayer).hasPermission(islandPrivilege); - for (int i = 0; i < lore.size(); i++) { - String line = lore.get(i); - if (line.equals("{0}")) { - lore.set(i, roleString.get(0)); - for (int j = 1; j < roleString.size(); j++) { - lore.add(i + j, roleString.get(j)); - } - i += roleString.size(); - } - } + ItemBuilder permissionItem = hasPermission ? button.pagedObject.getEnabledIslandPrivilegeItem() : + button.pagedObject.getDisabledIslandPrivilegeItem(); - permissionItem.withLore(lore); - } + return permissionItem.build(button.menuView.getInventoryViewer()); } - return permissionItem; } public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java index f9dacf139d..1e786f7894 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java @@ -165,6 +165,17 @@ public Object getPermissionHolder() { @Override protected List requestObjects() { + List islandPrivileges = MenuIslandPrivileges.this.islandPrivileges; + + if (this.permissionHolder instanceof SuperiorPlayer && + !island.isMember((SuperiorPlayer) this.permissionHolder)) { + islandPrivileges = new LinkedList<>(islandPrivileges); + islandPrivileges.removeIf(info -> { + IslandPrivilege islandPrivilege = info.getIslandPrivilege(); + return islandPrivilege != null && islandPrivilege.getType() == IslandPrivilege.Type.COMMAND; + }); + } + return Collections.unmodifiableList(islandPrivileges); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index 0ad05b8da6..e324595654 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -14,26 +14,26 @@ public class IslandPrivileges { public static final IslandPrivilege ANIMAL_DAMAGE = register("ANIMAL_DAMAGE"); public static final IslandPrivilege ANIMAL_SHEAR = register("ANIMAL_SHEAR"); public static final IslandPrivilege ANIMAL_SPAWN = register("ANIMAL_SPAWN"); - public static final IslandPrivilege BAN_MEMBER = register("BAN_MEMBER"); + public static final IslandPrivilege BAN_MEMBER = register("BAN_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege BREAK = register("BREAK"); public static final IslandPrivilege BRUSH = register("BRUSH", ServerVersion.isAtLeast(ServerVersion.v1_20)); public static final IslandPrivilege BUILD = register("BUILD"); - public static final IslandPrivilege CHANGE_NAME = register("CHANGE_NAME"); + public static final IslandPrivilege CHANGE_NAME = register("CHANGE_NAME", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege CHEST_ACCESS = register("CHEST_ACCESS"); public static final IslandPrivilege CHORUS_FRUIT = register("CHORUS_FRUIT", ServerVersion.isAtLeast(ServerVersion.v1_9)); public static final IslandPrivilege CLOSE_BYPASS = register("CLOSE_BYPASS"); - public static final IslandPrivilege CLOSE_ISLAND = register("CLOSE_ISLAND"); - public static final IslandPrivilege COOP_MEMBER = register("COOP_MEMBER"); - public static final IslandPrivilege DELETE_WARP = register("DELETE_WARP"); - public static final IslandPrivilege DEMOTE_MEMBERS = register("DEMOTE_MEMBERS"); - public static final IslandPrivilege DEPOSIT_MONEY = register("DEPOSIT_MONEY"); - public static final IslandPrivilege DISBAND_ISLAND = register("DISBAND_ISLAND"); + public static final IslandPrivilege CLOSE_ISLAND = register("CLOSE_ISLAND", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege COOP_MEMBER = register("COOP_MEMBER", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege DELETE_WARP = register("DELETE_WARP", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege DEMOTE_MEMBERS = register("DEMOTE_MEMBERS", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege DEPOSIT_MONEY = register("DEPOSIT_MONEY", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege DISBAND_ISLAND = register("DISBAND_ISLAND", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege DISCORD_SHOW = register("DISCORD_SHOW"); public static final IslandPrivilege DROP_ITEMS = register("DROP_ITEMS"); public static final IslandPrivilege DYE_SHEEP = register("DYE_SHEEP"); public static final IslandPrivilege ENDER_PEARL = register("ENDER_PEARL"); public static final IslandPrivilege EXPEL_BYPASS = register("EXPEL_BYPASS"); - public static final IslandPrivilege EXPEL_PLAYERS = register("EXPEL_PLAYERS"); + public static final IslandPrivilege EXPEL_PLAYERS = register("EXPEL_PLAYERS", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege FARM_TRAMPING = register("FARM_TRAMPING"); public static final IslandPrivilege FERTILIZE = register("FERTILIZE"); public static final IslandPrivilege FISH = register("FISH"); @@ -41,10 +41,10 @@ public class IslandPrivileges { public static final IslandPrivilege HORSE_INTERACT = register("HORSE_INTERACT"); public static final IslandPrivilege IGNITE_CREEPER = register("IGNITE_CREEPER"); public static final IslandPrivilege INTERACT = register("INTERACT"); - public static final IslandPrivilege INVITE_MEMBER = register("INVITE_MEMBER"); - public static final IslandPrivilege ISLAND_CHEST = register("ISLAND_CHEST"); + public static final IslandPrivilege INVITE_MEMBER = register("INVITE_MEMBER", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege ISLAND_CHEST = register("ISLAND_CHEST", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege ITEM_FRAME = register("ITEM_FRAME"); - public static final IslandPrivilege KICK_MEMBER = register("KICK_MEMBER"); + public static final IslandPrivilege KICK_MEMBER = register("KICK_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege LEASH = register("LEASH"); public static final IslandPrivilege MINECART_DAMAGE = register("MINECART_DAMAGE"); public static final IslandPrivilege MINECART_ENTER = register("MINECART_ENTER"); @@ -53,7 +53,7 @@ public class IslandPrivileges { public static final IslandPrivilege MONSTER_DAMAGE = register("MONSTER_DAMAGE"); public static final IslandPrivilege MONSTER_SPAWN = register("MONSTER_SPAWN"); public static final IslandPrivilege NAME_ENTITY = register("NAME_ENTITY"); - public static final IslandPrivilege OPEN_ISLAND = register("OPEN_ISLAND"); + public static final IslandPrivilege OPEN_ISLAND = register("OPEN_ISLAND", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege PAINTING = register("PAINTING"); public static final IslandPrivilege PAYPAL_SHOW = register("PAYPAL_SHOW"); @Nullable @@ -63,30 +63,30 @@ public class IslandPrivileges { public static final IslandPrivilege PICKUP_FISH = register("PICKUP_FISH", !ServerVersion.isLegacy()); @Nullable public static final IslandPrivilege PICKUP_LECTERN_BOOK = register("PICKUP_LECTERN_BOOK", ServerVersion.isAtLeast(ServerVersion.v1_14)); - public static final IslandPrivilege PROMOTE_MEMBERS = register("PROMOTE_MEMBERS"); - public static final IslandPrivilege RANKUP = register("RANKUP"); - public static final IslandPrivilege RATINGS_SHOW = register("RATINGS_SHOW"); + public static final IslandPrivilege PROMOTE_MEMBERS = register("PROMOTE_MEMBERS", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege RANKUP = register("RANKUP", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege RATINGS_SHOW = register("RATINGS_SHOW", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SADDLE_ENTITY = register("SADDLE_ENTITY"); @Nullable public static final IslandPrivilege SCULK_SENSOR = register("SCULK_SENSOR", ServerVersion.isAtLeast(ServerVersion.v1_17)); - public static final IslandPrivilege SET_BIOME = register("SET_BIOME"); - public static final IslandPrivilege SET_DISCORD = register("SET_DISCORD"); - public static final IslandPrivilege SET_HOME = register("SET_HOME"); - public static final IslandPrivilege SET_PAYPAL = register("SET_PAYPAL"); - public static final IslandPrivilege SET_PERMISSION = register("SET_PERMISSION"); - public static final IslandPrivilege SET_ROLE = register("SET_ROLE"); - public static final IslandPrivilege SET_SETTINGS = register("SET_SETTINGS"); - public static final IslandPrivilege SET_WARP = register("SET_WARP"); + public static final IslandPrivilege SET_BIOME = register("SET_BIOME", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege SET_DISCORD = register("SET_DISCORD", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege SET_HOME = register("SET_HOME", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege SET_PAYPAL = register("SET_PAYPAL", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege SET_PERMISSION = register("SET_PERMISSION", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege SET_ROLE = register("SET_ROLE", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege SET_SETTINGS = register("SET_SETTINGS", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege SET_WARP = register("SET_WARP", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SIGN_INTERACT = register("SIGN_INTERACT"); public static final IslandPrivilege SPAWNER_BREAK = register("SPAWNER_BREAK"); @Nullable public static final IslandPrivilege TURTLE_EGG_TRAMPING = register("TURTLE_EGG_TRAMPING", !ServerVersion.isLegacy()); - public static final IslandPrivilege UNCOOP_MEMBER = register("UNCOOP_MEMBER"); + public static final IslandPrivilege UNCOOP_MEMBER = register("UNCOOP_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege USE = register("USE"); public static final IslandPrivilege VALUABLE_BREAK = register("VALUABLE_BREAK"); public static final IslandPrivilege VILLAGER_TRADING = register("VILLAGER_TRADING"); public static final IslandPrivilege WIND_CHARGE = register("WIND_CHARGE", ServerVersion.isAtLeast(ServerVersion.v1_21)); - public static final IslandPrivilege WITHDRAW_MONEY = register("WITHDRAW_MONEY"); + public static final IslandPrivilege WITHDRAW_MONEY = register("WITHDRAW_MONEY", IslandPrivilege.Type.COMMAND); private IslandPrivileges() { @@ -101,12 +101,22 @@ private static IslandPrivilege register(String name) { return Objects.requireNonNull(register(name, true)); } + @NotNull + private static IslandPrivilege register(String name, IslandPrivilege.Type type) { + return Objects.requireNonNull(register(name, type, true)); + } + @Nullable private static IslandPrivilege register(String name, boolean registerCheck) { + return register(name, IslandPrivilege.Type.ACTION, registerCheck); + } + + @Nullable + private static IslandPrivilege register(String name, IslandPrivilege.Type type, boolean registerCheck) { if (!registerCheck) return null; - IslandPrivilege.register(name); + IslandPrivilege.register(name, type); return IslandPrivilege.getByName(name); } From 2cdfd832aba8753ea21a174dc07dce2d9168d1e1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 2 May 2025 13:16:08 +0300 Subject: [PATCH 137/600] Fix listeners of modules are not registered correctly (#2432, #2433, #2429) --- .../superiorskyblock/SuperiorSkyblockPlugin.java | 4 ++++ .../superiorskyblock/listener/BukkitListeners.java | 2 -- .../superiorskyblock/module/ModulesManagerImpl.java | 11 +++++++++++ .../module/container/DefaultModulesContainer.java | 6 ++++++ .../module/container/ModulesContainer.java | 3 +++ 5 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index 1b884686f3..6a48661b9f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -437,6 +437,10 @@ private boolean testScriptEngine() { } public void reloadPlugin(PluginReloadReason reloadReason) throws ManagerLoadException { + if (reloadReason == PluginReloadReason.COMMAND) { + bukkitListeners.unregisterListeners(); + } + providersHandler.loadData(); ItemSkulls.readTextures(this); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java index ce1df10c67..d0d1805d1b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java @@ -21,8 +21,6 @@ public BukkitListeners(SuperiorSkyblockPlugin plugin) { } public void registerListeners() { - unregisterListeners(); - new AdminPlayersListener(this.plugin); new ChunksListener(this.plugin); new EntityTrackingListener(this.plugin); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java index 21f4ff841c..46a1d74c4d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java @@ -203,6 +203,17 @@ private void reloadModuleInternal(PluginModule pluginModule) { Log.error("An unexpected error occurred while reloading the module ", pluginModule.getName(), "."); Log.error(error, "Contact ", pluginModule.getAuthor(), " regarding this, this has nothing to do with the plugin."); } + + // We register listeners again + ModuleData moduleData = this.modulesContainer.getModuleData(pluginModule); + if (moduleData != null) { + Listener[] listeners = moduleData.getListeners(); + if (listeners != null) { + for (Listener listener : listeners) + Bukkit.getPluginManager().registerEvents(listener, plugin); + } + } + } public void loadModulesData(SuperiorSkyblockPlugin plugin) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java index 9c72df99a8..90c16afe4e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java @@ -84,4 +84,10 @@ public void addModuleData(PluginModule pluginModule, ModuleData moduleData) { this.modulesData.put(pluginModule, moduleData); } + @Override + @Nullable + public ModuleData getModuleData(PluginModule module) { + return this.modulesData.get(module); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/container/ModulesContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/module/container/ModulesContainer.java index 9d44294411..dc1ea01254 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/container/ModulesContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/container/ModulesContainer.java @@ -20,4 +20,7 @@ public interface ModulesContainer { void addModuleData(PluginModule pluginModule, ModuleData moduleData); + @Nullable + ModuleData getModuleData(PluginModule module); + } From 4cc4a7ce80391052810444c3e7f958f172853fdc Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 2 May 2025 16:07:43 +0300 Subject: [PATCH 138/600] Fix support for placeholders in messages (#2430) --- .../external/MiniMessageHook.java | 4 +-- .../core/messages/MessageContent.java | 21 ++++++++++++-- .../component/impl/ActionBarComponent.java | 7 +++-- .../component/impl/BossBarComponent.java | 6 ++-- .../impl/ComplexMessageComponent.java | 28 ++++++++++--------- .../component/impl/RawMessageComponent.java | 8 ++++-- .../component/impl/TitleComponent.java | 8 +++--- 7 files changed, 51 insertions(+), 31 deletions(-) diff --git a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java index bf784ca8d9..c619e5a32a 100644 --- a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java +++ b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java @@ -69,12 +69,12 @@ public Type getType() { @Override public String getMessage() { - return this.content.getContent().orElse(""); + return this.content.getContent(null).orElse(""); } @Override public String getMessage(Object... args) { - return this.content.getContent(args).orElse(""); + return this.content.getContent(null, args).orElse(""); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java index 20d1b8e5bf..b0de09ee13 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java @@ -1,6 +1,11 @@ package com.bgsoftware.superiorskyblock.core.messages; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; +import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import org.bukkit.OfflinePlayer; import java.math.BigDecimal; import java.util.Collections; @@ -14,11 +19,18 @@ public class MessageContent { public static final MessageContent EMPTY = new MessageContent(Collections.emptyList()) { @Override - public Optional getContent(Object... arguments) { + public Optional getContent(@Nullable OfflinePlayer unused, Object... unused2) { return Optional.empty(); } }; + private static final LazyReference placeholdersService = new LazyReference() { + @Override + protected PlaceholdersService create() { + return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class); + } + }; + private static final Pattern DEFAULT_PLACEHOLDER_PATTERN = Pattern.compile("\\{(\\d+)}"); private final List contentParts = new LinkedList<>(); @@ -66,7 +78,7 @@ private MessageContent(List contentParts) { this.contentParts.addAll(contentParts); } - public Optional getContent(Object... arguments) { + public Optional getContent(@Nullable OfflinePlayer offlinePlayer, Object... arguments) { StringBuilder content = new StringBuilder(); for (IPart part : contentParts) { if (part instanceof StaticPart) { @@ -81,7 +93,10 @@ public Optional getContent(Object... arguments) { } } - return content.length() == 0 ? Optional.empty() : Optional.of(content.toString()); + if (content.length() == 0) + return Optional.empty(); + + return Optional.of(placeholdersService.get().parsePlaceholders(offlinePlayer, content.toString())); } public static String getArgumentString(Object argument) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ActionBarComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ActionBarComponent.java index 26dc0a1222..c959216c51 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ActionBarComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ActionBarComponent.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; +import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -30,17 +31,17 @@ public Type getType() { @Override public String getMessage() { - return this.content.getContent().orElse(""); + return this.content.getContent(null).orElse(""); } @Override public String getMessage(Object... args) { - return this.content.getContent(args).orElse(""); + return this.content.getContent(null, args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { - this.content.getContent(args).ifPresent(message -> + this.content.getContent((Player) sender, args).ifPresent(message -> plugin.getNMSPlayers().sendActionBar((Player) sender, message)); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/BossBarComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/BossBarComponent.java index 3e808a019c..99e4199c81 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/BossBarComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/BossBarComponent.java @@ -44,18 +44,18 @@ public Type getType() { @Override public String getMessage() { - return this.content.getContent().orElse(""); + return this.content.getContent(null).orElse(""); } @Override public String getMessage(Object... args) { - return this.content.getContent(args).orElse(""); + return this.content.getContent(null, args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { if (sender instanceof Player) { - this.content.getContent(args).ifPresent(message -> + this.content.getContent((Player) sender, args).ifPresent(message -> bossBarsService.get().createBossBar((Player) sender, message, this.color, this.ticksToRun)); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java index 9a4c162290..28323fc738 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java @@ -9,6 +9,7 @@ import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.OfflinePlayer; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -72,29 +73,29 @@ public Type getType() { @Override public String getMessage() { - return this.content.getContent().orElse(""); + return this.content.getContent(null).orElse(""); } @Override public String getMessage(Object... args) { - return this.content.getContent(args).orElse(""); + return this.content.getContent(null, args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { if (!(sender instanceof Player)) { - this.content.getContent(args).ifPresent(sender::sendMessage); + this.content.getContent(null, args).ifPresent(sender::sendMessage); } else if (components.length > 0) { BaseComponent[] components = new BaseComponent[this.components.length]; for (int i = 0; i < this.components.length; ++i) - components[i] = this.components[i].parse(args); + components[i] = this.components[i].parse((Player) sender, args); ((Player) sender).spigot().sendMessage(components); } } private interface IWrappedComponent { - BaseComponent parse(Object... args); + BaseComponent parse(OfflinePlayer offlinePlayer, Object... args); } @@ -107,7 +108,7 @@ private static class ComponentHolder implements IWrappedComponent { } @Override - public BaseComponent parse(Object... args) { + public BaseComponent parse(OfflinePlayer offlinePlayer, Object... args) { return this.handle; } @@ -129,10 +130,11 @@ private static class ContentComponent implements IWrappedComponent { } @Override - public BaseComponent parse(Object... args) { - TextComponent textComponent = (TextComponent) TextComponent.fromLegacyText(this.content.getContent(args).orElse(""))[0]; + public BaseComponent parse(OfflinePlayer offlinePlayer, Object... args) { + TextComponent textComponent = (TextComponent) TextComponent.fromLegacyText( + this.content.getContent(offlinePlayer, args).orElse(""))[0]; if (this.hoverEventContents != null) - textComponent.setHoverEvent(this.hoverEventContents.parse(args)); + textComponent.setHoverEvent(this.hoverEventContents.parse(offlinePlayer, args)); if (this.clickEvent != null) textComponent.setClickEvent(this.clickEvent); @@ -151,9 +153,9 @@ private static class HoverEventComponent implements IWrappedComponent { } @Override - public BaseComponent parse(Object... args) { + public BaseComponent parse(OfflinePlayer offlinePlayer, Object... args) { BaseComponent newComponent = this.baseComponent.duplicate(); - newComponent.setHoverEvent(this.hoverEventContents.parse(args)); + newComponent.setHoverEvent(this.hoverEventContents.parse(offlinePlayer, args)); return newComponent; } @@ -169,10 +171,10 @@ private static class HoverEventContents { this.components = parseComponents(hoverEvent.getValue()); } - HoverEvent parse(Object... args) { + HoverEvent parse(OfflinePlayer offlinePlayer, Object... args) { BaseComponent[] components = new BaseComponent[this.components.length]; for (int i = 0; i < components.length; ++i) - components[i] = this.components[i].parse(args); + components[i] = this.components[i].parse(offlinePlayer, args); return new HoverEvent(this.action, components); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/RawMessageComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/RawMessageComponent.java index 13fd276d91..ba0f5eaa43 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/RawMessageComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/RawMessageComponent.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.core.messages.MessageContent; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; public class RawMessageComponent implements IMessageComponent { @@ -26,17 +27,18 @@ public Type getType() { @Override public String getMessage() { - return this.content.getContent().orElse(""); + return this.content.getContent(null).orElse(""); } @Override public String getMessage(Object... args) { - return this.content.getContent(args).orElse(""); + return this.content.getContent(null, args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { - this.content.getContent(args).ifPresent(sender::sendMessage); + Player player = sender instanceof Player ? (Player) sender : null; + this.content.getContent(player, args).ifPresent(sender::sendMessage); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java index 9f5451fe37..31148e0ca1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java @@ -41,18 +41,18 @@ public Type getType() { @Override public String getMessage() { - return this.titleMessage.getContent().orElse(""); + return this.titleMessage.getContent(null).orElse(""); } @Override public String getMessage(Object... args) { - return this.titleMessage.getContent(args).orElse(""); + return this.titleMessage.getContent(null, args).orElse(""); } @Override public void sendMessage(CommandSender sender, Object... args) { - String titleMessage = this.titleMessage.getContent(args).orElse(null); - String subtitleMessage = this.subtitleMessage.getContent(args).orElse(null); + String titleMessage = this.titleMessage.getContent((Player) sender, args).orElse(null); + String subtitleMessage = this.subtitleMessage.getContent((Player) sender, args).orElse(null); if (titleMessage != null && subtitleMessage != null) plugin.getNMSPlayers().sendTitle((Player) sender, titleMessage, subtitleMessage, this.fadeIn, this.duration, this.fadeOut); From f650849e65e347497e0ff5f091483deca8dd36af Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 2 May 2025 18:35:57 +0300 Subject: [PATCH 139/600] Adds entity ride privilege (#2427) --- .../service/region/RegionManagerService.java | 10 ++++++ .../island/privilege/IslandPrivileges.java | 1 + .../listener/ProtectionListener.java | 16 ++++----- .../region/RegionManagerServiceImpl.java | 24 ++++++++++---- .../world/BukkitEntities.java | 12 +++++++ src/main/resources/menus/permissions.yml | 33 +++++++++++++++++++ src/main/resources/menus/permissions1_13.yml | 33 +++++++++++++++++++ src/main/resources/menus/permissions1_16.yml | 33 +++++++++++++++++++ src/main/resources/menus/permissions1_17.yml | 33 +++++++++++++++++++ src/main/resources/menus/permissions1_20.yml | 33 +++++++++++++++++++ src/main/resources/menus/permissions1_21.yml | 33 +++++++++++++++++++ src/main/resources/menus/permissions1_9.yml | 33 +++++++++++++++++++ 12 files changed, 279 insertions(+), 15 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/region/RegionManagerService.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/region/RegionManagerService.java index 9d18796a41..736fe8d231 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/region/RegionManagerService.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/region/RegionManagerService.java @@ -7,6 +7,7 @@ import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.Item; +import org.bukkit.entity.Player; import org.bukkit.event.block.Action; import org.bukkit.inventory.ItemStack; @@ -133,6 +134,15 @@ InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Block block */ InteractionResult handleEntityDamage(Entity damager, Entity entity); + /** + * Handle a player riding an entity. + * + * @param superiorPlayer The player that rides the entity. + * @param vehicle The entity that is ridden. + * @return The result of the interaction. + */ + InteractionResult handleEntityRide(SuperiorPlayer superiorPlayer, Entity vehicle); + /** * Handle a custom interaction of a player. * diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index e324595654..e7946c271c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -32,6 +32,7 @@ public class IslandPrivileges { public static final IslandPrivilege DROP_ITEMS = register("DROP_ITEMS"); public static final IslandPrivilege DYE_SHEEP = register("DYE_SHEEP"); public static final IslandPrivilege ENDER_PEARL = register("ENDER_PEARL"); + public static final IslandPrivilege ENTITY_RIDE = register("ENTITY_RIDE"); public static final IslandPrivilege EXPEL_BYPASS = register("EXPEL_BYPASS"); public static final IslandPrivilege EXPEL_PLAYERS = register("EXPEL_PLAYERS", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege FARM_TRAMPING = register("FARM_TRAMPING"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index dbb159e5a7..bc3bc7f045 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -26,6 +26,7 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; +import org.bukkit.entity.Animals; import org.bukkit.entity.Egg; import org.bukkit.entity.EnderPearl; import org.bukkit.entity.Entity; @@ -386,14 +387,8 @@ private void onVehicleEnter(GameEvent e) { if (!(rider instanceof Player)) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(rider); - - InteractionResult interactionResult; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location vehicleLocation = e.getArgs().vehicle.getLocation(wrapper.getHandle()); - interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, - vehicleLocation, IslandPrivileges.MINECART_ENTER); - } + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) rider); + InteractionResult interactionResult = this.protectionManager.get().handleEntityRide(superiorPlayer, e.getArgs().vehicle); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } @@ -404,12 +399,15 @@ private void onVehicleOpen(GameEvent e) { if (!(inventoryHolder instanceof Vehicle)) return; + IslandPrivilege islandPrivilege = BukkitEntities.isHorse((Vehicle) inventoryHolder) ? IslandPrivileges.HORSE_INTERACT : + inventoryHolder instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_OPEN; + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().bukkitEvent.getPlayer()); InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location minecartLocation = ((Vehicle) inventoryHolder).getLocation(wrapper.getHandle()); interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, - minecartLocation, IslandPrivileges.MINECART_OPEN); + minecartLocation, islandPrivilege); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index ec13a96c7e..ff9df84525 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -20,9 +20,9 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; @@ -46,14 +46,11 @@ import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Arrow; import org.bukkit.entity.Creeper; -import org.bukkit.entity.Donkey; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Fish; -import org.bukkit.entity.Horse; import org.bukkit.entity.Item; import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.Mule; import org.bukkit.entity.Painting; import org.bukkit.entity.Player; import org.bukkit.entity.Sheep; @@ -267,8 +264,7 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent } else if (entity instanceof Villager) { islandPrivilege = IslandPrivileges.VILLAGER_TRADING; closeInventory = true; - } else if (entity instanceof Horse || entityType == CAMEL_TYPE || - (ServerVersion.isAtLeast(ServerVersion.v1_11) && (entity instanceof Mule || entity instanceof Donkey))) { + } else if (BukkitEntities.isHorse(entity)) { islandPrivilege = IslandPrivileges.HORSE_INTERACT; closeInventory = true; } else if (usedItemType == Material.FLINT_AND_STEEL && entity instanceof Creeper) { @@ -334,6 +330,22 @@ public InteractionResult handleEntityDamage(Entity damager, Entity entity) { return interactionResult; } + @Override + public InteractionResult handleEntityRide(SuperiorPlayer superiorPlayer, Entity vehicle) { + Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); + Preconditions.checkNotNull(vehicle, "vehicle cannot be null"); + + IslandPrivilege islandPrivilege = BukkitEntities.isHorse(vehicle) ? IslandPrivileges.HORSE_INTERACT : + vehicle instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_ENTER; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = vehicle.getLocation(wrapper.getHandle()); + Island island = plugin.getGrid().getIslandAt(entityLocation); + return handleInteractionInternal(superiorPlayer, entityLocation, island, islandPrivilege, + 0, true, false); + } + } + @Override public InteractionResult handleEntityShear(SuperiorPlayer superiorPlayer, Entity entity) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java index f0911d54e7..6aee49bad8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java @@ -1,9 +1,12 @@ package com.bgsoftware.superiorskyblock.world; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.EntitiesProvider; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.EnumHelper; +import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.Material; @@ -11,6 +14,7 @@ import org.bukkit.entity.Ambient; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Creature; +import org.bukkit.entity.Donkey; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Flying; @@ -18,6 +22,7 @@ import org.bukkit.entity.Horse; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Monster; +import org.bukkit.entity.Mule; import org.bukkit.entity.Pig; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; @@ -45,6 +50,8 @@ public class BukkitEntities { private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); + @Nullable + private static final EntityType CAMEL_TYPE = EnumHelper.getEnum(EntityType.class, "CAMEL"); private BukkitEntities() { @@ -158,6 +165,11 @@ public static EntityCategory getCategory(EntityType entityType) { return EntityCategory.UNKNOWN; } + public static boolean isHorse(Entity entity) { + return entity instanceof Horse || entity.getType() == CAMEL_TYPE || + (ServerVersion.isAtLeast(ServerVersion.v1_11) && (entity instanceof Mule || entity instanceof Donkey)); + } + private static EnumSet createEntityTypesSet(Predicate predicate) { EnumSet entityTypes = EnumSet.noneOf(EntityType.class); for (EntityType entityType : EntityType.values()) { diff --git a/src/main/resources/menus/permissions.yml b/src/main/resources/menus/permissions.yml index b30784dca3..db4bbe3a67 100644 --- a/src/main/resources/menus/permissions.yml +++ b/src/main/resources/menus/permissions.yml @@ -745,6 +745,39 @@ permissions: volume: 0.2 pitch: 0.2 + entity_ride: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + expel_bypass: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_13.yml b/src/main/resources/menus/permissions1_13.yml index 84c5327b1b..0b36f90da9 100644 --- a/src/main/resources/menus/permissions1_13.yml +++ b/src/main/resources/menus/permissions1_13.yml @@ -768,6 +768,39 @@ permissions: volume: 0.2 pitch: 0.2 + entity_ride: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + expel_bypass: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_16.yml b/src/main/resources/menus/permissions1_16.yml index 85104f7df0..4e7ddfd20c 100644 --- a/src/main/resources/menus/permissions1_16.yml +++ b/src/main/resources/menus/permissions1_16.yml @@ -768,6 +768,39 @@ permissions: volume: 0.2 pitch: 0.2 + entity_ride: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + expel_bypass: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_17.yml b/src/main/resources/menus/permissions1_17.yml index cdeca13383..f3aa083df5 100644 --- a/src/main/resources/menus/permissions1_17.yml +++ b/src/main/resources/menus/permissions1_17.yml @@ -768,6 +768,39 @@ permissions: volume: 0.2 pitch: 0.2 + entity_ride: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + expel_bypass: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_20.yml b/src/main/resources/menus/permissions1_20.yml index 8f29987a92..c041837001 100644 --- a/src/main/resources/menus/permissions1_20.yml +++ b/src/main/resources/menus/permissions1_20.yml @@ -801,6 +801,39 @@ permissions: volume: 0.2 pitch: 0.2 + entity_ride: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + expel_bypass: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_21.yml b/src/main/resources/menus/permissions1_21.yml index b0b778b6cb..776ff72aee 100644 --- a/src/main/resources/menus/permissions1_21.yml +++ b/src/main/resources/menus/permissions1_21.yml @@ -801,6 +801,39 @@ permissions: volume: 0.2 pitch: 0.2 + entity_ride: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + expel_bypass: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_9.yml b/src/main/resources/menus/permissions1_9.yml index 61e5d38b85..c1016821e4 100644 --- a/src/main/resources/menus/permissions1_9.yml +++ b/src/main/resources/menus/permissions1_9.yml @@ -778,6 +778,39 @@ permissions: volume: 0.2 pitch: 0.2 + entity_ride: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + expel_bypass: display-menu: true permission-enabled: From 732a34eca62eda685aedd2f696e23e0367374cf3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 2 May 2025 18:42:40 +0300 Subject: [PATCH 140/600] Fix some privileges in the privileges menu not ordered alphabetically (#2427) --- src/main/resources/menus/permissions.yml | 132 +++++++++---------- src/main/resources/menus/permissions1_13.yml | 132 +++++++++---------- src/main/resources/menus/permissions1_16.yml | 132 +++++++++---------- src/main/resources/menus/permissions1_17.yml | 132 +++++++++---------- src/main/resources/menus/permissions1_20.yml | 132 +++++++++---------- src/main/resources/menus/permissions1_21.yml | 132 +++++++++---------- src/main/resources/menus/permissions1_9.yml | 132 +++++++++---------- 7 files changed, 462 insertions(+), 462 deletions(-) diff --git a/src/main/resources/menus/permissions.yml b/src/main/resources/menus/permissions.yml index db4bbe3a67..006e244ebd 100644 --- a/src/main/resources/menus/permissions.yml +++ b/src/main/resources/menus/permissions.yml @@ -1252,42 +1252,6 @@ permissions: volume: 0.2 pitch: 0.2 - monster_damage: - display-menu: true - permission-enabled: - type: SKULL_ITEM - data: 2 - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: SKULL_ITEM - data: 2 - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: SKULL_ITEM - data: 2 - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - minecart_damage: display-menu: true permission-enabled: @@ -1387,6 +1351,42 @@ permissions: volume: 0.2 pitch: 0.2 + monster_damage: + display-menu: true + permission-enabled: + type: SKULL_ITEM + data: 2 + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SKULL_ITEM + data: 2 + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SKULL_ITEM + data: 2 + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + monster_spawn: display-menu: true permission-enabled: @@ -1993,25 +1993,25 @@ permissions: volume: 0.2 pitch: 0.2 - uncoop_member: + sign_interact: display-menu: true permission-enabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' + type: SIGN + name: '&6Sign Interact' lore: - - '&7Access to remove co-op members from the island.' + - '&7Access to interact with signs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' + type: SIGN + name: '&6Sign Interact' lore: - - '&7Access to remove co-op members from the island.' + - '&7Access to interact with signs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: - type: GOLDEN_APPLE - name: '&6Uncoop Member' + type: SIGN + name: '&6Sign Interact' lore: - - '&7Access to remove co-op members from the island.' + - '&7Access to interact with signs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' @@ -2026,25 +2026,25 @@ permissions: volume: 0.2 pitch: 0.2 - sign_interact: + spawner_break: display-menu: true permission-enabled: - type: SIGN - name: '&6Sign Interact' + type: MOB_SPAWNER + name: '&6Spawner Break' lore: - - '&7Access to interact with signs inside the island.' + - '&7Access to break spawners inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: - type: SIGN - name: '&6Sign Interact' + type: MOB_SPAWNER + name: '&6Spawner Break' lore: - - '&7Access to interact with signs inside the island.' + - '&7Access to break spawners inside the island.' - '&7Currently &cDISABLED&7.' role-permission: - type: SIGN - name: '&6Sign Interact' + type: MOB_SPAWNER + name: '&6Spawner Break' lore: - - '&7Access to interact with signs inside the island.' + - '&7Access to break spawners inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' @@ -2059,25 +2059,25 @@ permissions: volume: 0.2 pitch: 0.2 - spawner_break: + uncoop_member: display-menu: true permission-enabled: - type: MOB_SPAWNER - name: '&6Spawner Break' + type: GOLDEN_APPLE + name: '&6Uncoop Member' lore: - - '&7Access to break spawners inside the island.' + - '&7Access to remove co-op members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: - type: MOB_SPAWNER - name: '&6Spawner Break' + type: GOLDEN_APPLE + name: '&6Uncoop Member' lore: - - '&7Access to break spawners inside the island.' + - '&7Access to remove co-op members from the island.' - '&7Currently &cDISABLED&7.' role-permission: - type: MOB_SPAWNER - name: '&6Spawner Break' + type: GOLDEN_APPLE + name: '&6Uncoop Member' lore: - - '&7Access to break spawners inside the island.' + - '&7Access to remove co-op members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' diff --git a/src/main/resources/menus/permissions1_13.yml b/src/main/resources/menus/permissions1_13.yml index 0b36f90da9..04272f34aa 100644 --- a/src/main/resources/menus/permissions1_13.yml +++ b/src/main/resources/menus/permissions1_13.yml @@ -1264,39 +1264,6 @@ permissions: volume: 0.2 pitch: 0.2 - monster_damage: - display-menu: true - permission-enabled: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - minecart_damage: display-menu: true permission-enabled: @@ -1429,6 +1396,39 @@ permissions: volume: 0.2 pitch: 0.2 + monster_damage: + display-menu: true + permission-enabled: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + monster_spawn: display-menu: true permission-enabled: @@ -2056,39 +2056,6 @@ permissions: volume: 0.2 pitch: 0.2 - uncoop_member: - display-menu: true - permission-enabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - sign_interact: display-menu: true permission-enabled: @@ -2188,6 +2155,39 @@ permissions: volume: 0.2 pitch: 0.2 + uncoop_member: + display-menu: true + permission-enabled: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + use: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_16.yml b/src/main/resources/menus/permissions1_16.yml index 4e7ddfd20c..6d42737087 100644 --- a/src/main/resources/menus/permissions1_16.yml +++ b/src/main/resources/menus/permissions1_16.yml @@ -1264,39 +1264,6 @@ permissions: volume: 0.2 pitch: 0.2 - monster_damage: - display-menu: true - permission-enabled: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - minecart_damage: display-menu: true permission-enabled: @@ -1429,6 +1396,39 @@ permissions: volume: 0.2 pitch: 0.2 + monster_damage: + display-menu: true + permission-enabled: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + monster_spawn: display-menu: true permission-enabled: @@ -2089,39 +2089,6 @@ permissions: volume: 0.2 pitch: 0.2 - uncoop_member: - display-menu: true - permission-enabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - sign_interact: display-menu: true permission-enabled: @@ -2221,6 +2188,39 @@ permissions: volume: 0.2 pitch: 0.2 + uncoop_member: + display-menu: true + permission-enabled: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + use: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_17.yml b/src/main/resources/menus/permissions1_17.yml index f3aa083df5..7387fa3619 100644 --- a/src/main/resources/menus/permissions1_17.yml +++ b/src/main/resources/menus/permissions1_17.yml @@ -1264,39 +1264,6 @@ permissions: volume: 0.2 pitch: 0.2 - monster_damage: - display-menu: true - permission-enabled: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - minecart_damage: display-menu: true permission-enabled: @@ -1429,6 +1396,39 @@ permissions: volume: 0.2 pitch: 0.2 + monster_damage: + display-menu: true + permission-enabled: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + monster_spawn: display-menu: true permission-enabled: @@ -2155,39 +2155,6 @@ permissions: volume: 0.2 pitch: 0.2 - uncoop_member: - display-menu: true - permission-enabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - sign_interact: display-menu: true permission-enabled: @@ -2287,6 +2254,39 @@ permissions: volume: 0.2 pitch: 0.2 + uncoop_member: + display-menu: true + permission-enabled: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + use: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_20.yml b/src/main/resources/menus/permissions1_20.yml index c041837001..a337643bc7 100644 --- a/src/main/resources/menus/permissions1_20.yml +++ b/src/main/resources/menus/permissions1_20.yml @@ -1297,39 +1297,6 @@ permissions: volume: 0.2 pitch: 0.2 - monster_damage: - display-menu: true - permission-enabled: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - minecart_damage: display-menu: true permission-enabled: @@ -1462,6 +1429,39 @@ permissions: volume: 0.2 pitch: 0.2 + monster_damage: + display-menu: true + permission-enabled: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + monster_spawn: display-menu: true permission-enabled: @@ -2188,39 +2188,6 @@ permissions: volume: 0.2 pitch: 0.2 - uncoop_member: - display-menu: true - permission-enabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - sign_interact: display-menu: true permission-enabled: @@ -2320,6 +2287,39 @@ permissions: volume: 0.2 pitch: 0.2 + uncoop_member: + display-menu: true + permission-enabled: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + use: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_21.yml b/src/main/resources/menus/permissions1_21.yml index 776ff72aee..e526b17b08 100644 --- a/src/main/resources/menus/permissions1_21.yml +++ b/src/main/resources/menus/permissions1_21.yml @@ -1297,39 +1297,6 @@ permissions: volume: 0.2 pitch: 0.2 - monster_damage: - display-menu: true - permission-enabled: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - minecart_damage: display-menu: true permission-enabled: @@ -1462,6 +1429,39 @@ permissions: volume: 0.2 pitch: 0.2 + monster_damage: + display-menu: true + permission-enabled: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + monster_spawn: display-menu: true permission-enabled: @@ -2188,39 +2188,6 @@ permissions: volume: 0.2 pitch: 0.2 - uncoop_member: - display-menu: true - permission-enabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - sign_interact: display-menu: true permission-enabled: @@ -2320,6 +2287,39 @@ permissions: volume: 0.2 pitch: 0.2 + uncoop_member: + display-menu: true + permission-enabled: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + use: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_9.yml b/src/main/resources/menus/permissions1_9.yml index c1016821e4..111ce2b540 100644 --- a/src/main/resources/menus/permissions1_9.yml +++ b/src/main/resources/menus/permissions1_9.yml @@ -1285,42 +1285,6 @@ permissions: volume: 0.2 pitch: 0.2 - monster_damage: - display-menu: true - permission-enabled: - type: SKULL_ITEM - data: 2 - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: SKULL_ITEM - data: 2 - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: SKULL_ITEM - data: 2 - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - minecart_damage: display-menu: true permission-enabled: @@ -1420,6 +1384,42 @@ permissions: volume: 0.2 pitch: 0.2 + monster_damage: + display-menu: true + permission-enabled: + type: SKULL_ITEM + data: 2 + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SKULL_ITEM + data: 2 + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SKULL_ITEM + data: 2 + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + monster_spawn: display-menu: true permission-enabled: @@ -2026,25 +2026,25 @@ permissions: volume: 0.2 pitch: 0.2 - uncoop_member: + sign_interact: display-menu: true permission-enabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' + type: SIGN + name: '&6Sign Interact' lore: - - '&7Access to remove co-op members from the island.' + - '&7Access to interact with signs inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' + type: SIGN + name: '&6Sign Interact' lore: - - '&7Access to remove co-op members from the island.' + - '&7Access to interact with signs inside the island.' - '&7Currently &cDISABLED&7.' role-permission: - type: GOLDEN_APPLE - name: '&6Uncoop Member' + type: SIGN + name: '&6Sign Interact' lore: - - '&7Access to remove co-op members from the island.' + - '&7Access to interact with signs inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' @@ -2059,25 +2059,25 @@ permissions: volume: 0.2 pitch: 0.2 - sign_interact: + spawner_break: display-menu: true permission-enabled: - type: SIGN - name: '&6Sign Interact' + type: MOB_SPAWNER + name: '&6Spawner Break' lore: - - '&7Access to interact with signs inside the island.' + - '&7Access to break spawners inside the island.' - '&7Currently &aENABLED&7.' permission-disabled: - type: SIGN - name: '&6Sign Interact' + type: MOB_SPAWNER + name: '&6Spawner Break' lore: - - '&7Access to interact with signs inside the island.' + - '&7Access to break spawners inside the island.' - '&7Currently &cDISABLED&7.' role-permission: - type: SIGN - name: '&6Sign Interact' + type: MOB_SPAWNER + name: '&6Spawner Break' lore: - - '&7Access to interact with signs inside the island.' + - '&7Access to break spawners inside the island.' - '&7Role: &e{}&7.' - '' - '{0}' @@ -2092,25 +2092,25 @@ permissions: volume: 0.2 pitch: 0.2 - spawner_break: + uncoop_member: display-menu: true permission-enabled: - type: MOB_SPAWNER - name: '&6Spawner Break' + type: GOLDEN_APPLE + name: '&6Uncoop Member' lore: - - '&7Access to break spawners inside the island.' + - '&7Access to remove co-op members from the island.' - '&7Currently &aENABLED&7.' permission-disabled: - type: MOB_SPAWNER - name: '&6Spawner Break' + type: GOLDEN_APPLE + name: '&6Uncoop Member' lore: - - '&7Access to break spawners inside the island.' + - '&7Access to remove co-op members from the island.' - '&7Currently &cDISABLED&7.' role-permission: - type: MOB_SPAWNER - name: '&6Spawner Break' + type: GOLDEN_APPLE + name: '&6Uncoop Member' lore: - - '&7Access to break spawners inside the island.' + - '&7Access to remove co-op members from the island.' - '&7Role: &e{}&7.' - '' - '{0}' From 3095dd8939ec1dc5493e93751bce77f9102a53e2 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 2 May 2025 18:43:33 +0300 Subject: [PATCH 141/600] Adds ENTITY_RIDE as default to coop members --- src/main/resources/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 568ac60afd..89d658a7c3 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -185,6 +185,7 @@ island-roles: - DROP_ITEMS - DYE_SHEEP - ENDER_PEARL + - ENTITY_RIDE - EXPEL_BYPASS - FARM_TRAMPING - FERTILIZE From a4e00ccea5557ca80a4b8598756e96cac843616e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 2 May 2025 20:00:18 +0300 Subject: [PATCH 142/600] Fix wind charge explosions breaking stacked blocks (#2422) --- .../listener/BlockChangesListener.java | 13 ++----------- .../listener/BukkitEventsListener.java | 7 +++++++ .../listener/ProtectionListener.java | 9 +++++---- .../superiorskyblock/listener/SignsListener.java | 11 +---------- .../listener/StackedBlocksListener.java | 16 ++++++++++------ .../platform/event/args/GameEventArgs.java | 1 + 6 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index abda77d4f1..974d53eff0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -10,7 +10,6 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; @@ -33,7 +32,6 @@ import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Item; import org.bukkit.entity.Minecart; -import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; import org.bukkit.event.block.Action; import org.bukkit.inventory.ItemStack; @@ -47,10 +45,6 @@ public class BlockChangesListener extends AbstractGameEventListener { @Nullable private static final Material CHORUS_FLOWER = EnumHelper.getEnum(Material.class, "CHORUS_FLOWER"); @Nullable - private static final EntityType WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "WIND_CHARGE"); - @Nullable - private static final EntityType BREEZE_WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "BREEZE_WIND_CHARGE"); - @Nullable private static final Material POINTED_DRIPSTONE = EnumHelper.getEnum(Material.class, "POINTED_DRIPSTONE"); @WorldRecordFlags @@ -294,15 +288,12 @@ private void onBlockFromTo(GameEvent e) { private void onEntityExplode(GameEvent e) { Entity entity = e.getArgs().entity; - EntityType entityType = entity.getType(); - - boolean isWindCharge = entityType == WIND_CHARGE || entityType == BREEZE_WIND_CHARGE; KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); e.getArgs().blocks.forEach(block -> { Material blockType = block.getType(); - // Wind charges only break chorus flowers and pointed drip-stones - if (isWindCharge && blockType != CHORUS_FLOWER && blockType != POINTED_DRIPSTONE) + // Soft explosions only break chorus flowers and pointed drip-stones + if (e.getArgs().isSoftExplosion && blockType != CHORUS_FLOWER && blockType != POINTED_DRIPSTONE) return; Key blockKey = Keys.of(block); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index 7cf77478a9..c4a17f0d1d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -4,6 +4,7 @@ import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.platform.IEventsDispatcher; +import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.events.EventCallback; @@ -21,6 +22,7 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; @@ -105,6 +107,10 @@ public class BukkitEventsListener implements Listener { ProjectileHitEvent.class, "getHitEntity"); private static final ReflectMethod PROJECTILE_HIT_EVENT_TARGET_BLOCK = new ReflectMethod<>( ProjectileHitEvent.class, "getHitBlock"); + @Nullable + private static final EntityType WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "WIND_CHARGE"); + @Nullable + private static final EntityType BREEZE_WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "BREEZE_WIND_CHARGE"); private final SuperiorSkyblockPlugin plugin; @@ -424,6 +430,7 @@ private GameEvent createGameEvent(GameEventTyp GameEventArgs.EntityExplodeEvent entityExplodeEvent = new GameEventArgs.EntityExplodeEvent(); entityExplodeEvent.entity = e.getEntity(); entityExplodeEvent.blocks = e.blockList(); + entityExplodeEvent.isSoftExplosion = e.getEntityType() == WIND_CHARGE || e.getEntityType() == BREEZE_WIND_CHARGE; return eventType.createEvent(entityExplodeEvent); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index bc3bc7f045..0d2eb31c48 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -529,11 +529,12 @@ private void onProjectileHit(GameEvent e) { }); } - private void onWindChargeExplodeEvent(GameEvent e) { - Entity entity = e.getArgs().entity; - if (entity.getType() != WIND_CHARGE) + private void onSoftExplodeEvent(GameEvent e) { + if (!e.getArgs().isSoftExplosion) return; + Entity entity = e.getArgs().entity; + BukkitEntities.getPlayerSource(entity).map(plugin.getPlayers()::getSuperiorPlayer).ifPresent(shooterPlayer -> { Iterator blocksIterator = e.getArgs().blocks.iterator(); while (blocksIterator.hasNext()) { @@ -596,7 +597,7 @@ private void registerListeners() { registerCallback(GameEventType.PLAYER_PICKUP_ITEM_EVENT, GameEventPriority.NORMAL, this::onPlayerPickupItem); registerCallback(GameEventType.PROJECTILE_LAUNCH_EVENT, GameEventPriority.NORMAL, this::onPlayerLaunchProjectile); registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.NORMAL, this::onProjectileHit); - registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.NORMAL, this::onWindChargeExplodeEvent); + registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.NORMAL, this::onSoftExplodeEvent); registerCallback(GameEventType.PLAYER_PICKUP_ARROW_EVENT, GameEventPriority.NORMAL, this::onPlayerPickupArrow); registerCallback(GameEventType.RAID_TRIGGER_EVENT, GameEventPriority.NORMAL, this::onRaidTrigger); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java index e1895ecb13..c0a8fc51e2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java @@ -4,7 +4,6 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; @@ -20,7 +19,6 @@ import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.block.data.Directional; -import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import java.util.Arrays; @@ -32,11 +30,6 @@ public class SignsListener extends AbstractGameEventListener { BlockFace.UP, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.EAST }; - @Nullable - private static final EntityType WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "WIND_CHARGE"); - @Nullable - private static final EntityType BREEZE_WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "BREEZE_WIND_CHARGE"); - public SignsListener(SuperiorSkyblockPlugin plugin) { super(plugin); registerListeners(); @@ -107,9 +100,7 @@ private void onSignBreak(GameEvent e) { } private void onSignExplode(GameEvent e) { - EntityType entityType = e.getArgs().entity.getType(); - - if (entityType == WIND_CHARGE || entityType == BREEZE_WIND_CHARGE) + if (e.getArgs().isSoftExplosion) return; Island island; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java index 8c8c28c162..4950e55d23 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java @@ -32,7 +32,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; -import java.util.LinkedList; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -182,10 +182,13 @@ private void onStackedBlockBreakByEntity(GameEvent e) { - List blockList = new LinkedList<>(e.getArgs().blocks); - ItemStack blockItem; + if (e.getArgs().isSoftExplosion) + return; + + Iterator blockIterator = e.getArgs().blocks.iterator(); + while (blockIterator.hasNext()) { + Block block = blockIterator.next(); - for (Block block : blockList) { // Check if block is stackable if (!plugin.getSettings().getStackedBlocks().getWhitelisted().contains(Keys.of(block))) continue; @@ -196,9 +199,9 @@ private void onStackedBlockExplode(GameEvent e continue; // All checks are done. We can remove the block from the list. - e.getArgs().blocks.remove(block); + blockIterator.remove(); - blockItem = block.getState().getData().toItemStack(amount); + ItemStack blockItem = block.getState().getData().toItemStack(amount); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = block.getLocation(wrapper.getHandle()); @@ -213,6 +216,7 @@ private void onStackedBlockExplode(GameEvent e // Dropping the item block.getWorld().dropItemNaturally(location, blockItem); } + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java index bccbc1e688..263b528c56 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java @@ -237,6 +237,7 @@ public static class LeavesDecayEvent extends BlockEvent { public static class EntityExplodeEvent extends EntityEvent { public List blocks; + public boolean isSoftExplosion; } From b83ae1a6a91b9508149f307c7d9e3946cf17e40d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 May 2025 13:29:21 +0300 Subject: [PATCH 143/600] Fix default values in config file is not updated for some values in reload (#2434) --- .../api/config/SettingsManager.java | 10 +++ .../config/SettingsContainer.java | 15 ++-- .../config/section/DefaultValuesSection.java | 21 ++++- .../superiorskyblock/core/value/Value.java | 10 +-- .../core/value/ValueFixed.java | 2 +- .../core/value/ValueFixedSynced.java | 2 +- .../core/value/ValueSuppliedSynced.java | 2 +- .../superiorskyblock/island/SIsland.java | 2 +- .../island/upgrade/DefaultUpgradeLevel.java | 16 ++-- .../island/upgrade/SUpgrade.java | 12 +-- .../island/upgrade/SUpgradeLevel.java | 78 ++++++++++--------- .../module/upgrades/UpgradesModule.java | 10 ++- 12 files changed, 105 insertions(+), 75 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 0e82953223..b1a09e59be 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -801,9 +801,19 @@ interface DefaultValues { * Represented by an array of maps with keys as the blocks, and values as the rates. * The maps are sorted by the {@link Dimension} they belong to. * Config-path: default-values.generator + * + * @deprecated See {@link #getGeneratorsMap()} */ + @Deprecated Map[] getGenerators(); + /** + * The default generator-rates for new islands. + * Represented by maps with keys as the blocks, and values as the rates. + * Config-path: default-values.generator + */ + Map> getGeneratorsMap(); + /** * The default role-limits for new islands. * Represented by a map with keys as the role ids, and values as the limit. diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index d9937fa35a..d58a58a799 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -36,7 +36,6 @@ import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.inventory.InventoryType; @@ -79,7 +78,7 @@ public class SettingsContainer { public final int defaultIslandSize; public final KeyMap defaultBlockLimits; public final KeyMap defaultEntityLimits; - public final KeyMap[] defaultGenerator; + public final EnumerateMap> defaultGenerator; public final int defaultWarpsLimit; public final int defaultTeamLimit; public final int defaultCoopLimit; @@ -381,18 +380,18 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config rateOwnIsland = config.getBoolean("rate-own-island", false); defaultSettings = Collections.unmodifiableList(config.getStringList("default-settings") .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList())); - defaultGenerator = new KeyMap[Dimension.values().size()]; + defaultGenerator = new EnumerateMap<>(Dimension.values()); if (config.isConfigurationSection("default-values.generator")) { for (String env : config.getConfigurationSection("default-values.generator").getKeys(false)) { try { - World.Environment environment = World.Environment.valueOf(env.toUpperCase(Locale.ENGLISH)); - loadGenerator(config, "default-values.generator." + env, environment.ordinal()); + Dimension dimension = Dimension.getByName(env.toUpperCase(Locale.ENGLISH)); + loadGenerator(config, "default-values.generator." + env, dimension); } catch (Exception error) { Log.errorFromFile(error, "config.yml", "An unexpected error occurred while loading default generator values for ", env + ":"); } } } else { - loadGenerator(config, "default-values.generator", 0); + loadGenerator(config, "default-values.generator", this.defaultWorldDimension); } disableRedstoneOffline = config.getBoolean("disable-redstone-offline", true); disableRedstoneAFK = config.getBoolean("afk-integrations.disable-redstone", false); @@ -593,13 +592,13 @@ private KeySet loadSafeBlocks(SuperiorSkyblockPlugin plugin) { return KeySets.unmodifiableKeySet(KeySets.createHashSet(KeyIndicator.MATERIAL, safeBlocks)); } - private void loadGenerator(YamlConfiguration config, String path, int index) { + private void loadGenerator(YamlConfiguration config, String path, Dimension dimension) { KeyMap defaultGenerator = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); loadListOrSection(config, path, "generator-rates", (key, percentage) -> { Key blockKey = Keys.ofMaterialAndData(key); defaultGenerator.put(blockKey, percentage); }); - this.defaultGenerator[index] = KeyMaps.unmodifiableKeyMap(defaultGenerator); + this.defaultGenerator.put(dimension, KeyMaps.unmodifiableKeyMap(defaultGenerator)); } private static void loadListOrSection(YamlConfiguration config, String path, String parseName, BiConsumer consumer) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java index 7d224c01e8..7d5cc67a13 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java @@ -2,7 +2,9 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; +import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; import java.math.BigDecimal; @@ -63,10 +65,25 @@ public BigDecimal getBankLimit() { @Override public Map[] getGenerators() { - return getGeneratorsUnsafe().clone(); + Map[] generators = new Map[Dimension.values().size()]; + + if (!getContainer().defaultGenerator.isEmpty()) { + for (Dimension dimension : Dimension.values()) { + Map dimensionGeneratorRates = getContainer().defaultGenerator.get(dimension); + if (dimensionGeneratorRates != null) + generators[dimension.ordinal()] = dimensionGeneratorRates; + } + } + + return generators; + } + + @Override + public Map> getGeneratorsMap() { + return getContainer().defaultGenerator.collect(Dimension.values()); } - public Map[] getGeneratorsUnsafe() { + public EnumerateMap> getRealGeneratorsMap() { return getContainer().defaultGenerator; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/value/Value.java b/src/main/java/com/bgsoftware/superiorskyblock/core/value/Value.java index ab1766317e..b52667a10e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/value/Value.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/value/Value.java @@ -4,21 +4,21 @@ import java.util.function.Supplier; -public interface Value { +public interface Value { - static Value fixed(V value) { + static Value fixed(V value) { return new ValueFixed<>(value); } - static Value syncedSupplied(Supplier supplier) { + static Value syncedSupplied(Supplier supplier) { return new ValueSuppliedSynced<>(supplier); } - static Value syncedFixed(V value) { + static Value syncedFixed(V value) { return new ValueFixedSynced<>(value); } - static V getNonSynced(@Nullable Value value, V syncedValue) { + static V getNonSynced(@Nullable Value value, V syncedValue) { return value == null ? syncedValue : value.getNonSynced(syncedValue); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueFixed.java b/src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueFixed.java index ed3b5dace0..f18f87193d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueFixed.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueFixed.java @@ -1,6 +1,6 @@ package com.bgsoftware.superiorskyblock.core.value; -public class ValueFixed implements Value { +public class ValueFixed implements Value { private final V value; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueFixedSynced.java b/src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueFixedSynced.java index 63b58137ee..8c4df0d05a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueFixedSynced.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueFixedSynced.java @@ -1,6 +1,6 @@ package com.bgsoftware.superiorskyblock.core.value; -public class ValueFixedSynced implements Value { +public class ValueFixedSynced implements Value { private final V value; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueSuppliedSynced.java b/src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueSuppliedSynced.java index 939d526742..ff5f6a45a0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueSuppliedSynced.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/value/ValueSuppliedSynced.java @@ -2,7 +2,7 @@ import java.util.function.Supplier; -public class ValueSuppliedSynced implements Value { +public class ValueSuppliedSynced implements Value { private final Supplier supplier; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index ca6b76ae20..af07f26bf3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -4860,7 +4860,7 @@ private void updateOldUpgradeValues() { this.cobbleGeneratorValues.write(cobbleGeneratorValues -> { for (Dimension dimension : Dimension.values()) { - Map defaultGenerator = plugin.getSettings().getDefaultValues().getGeneratorsUnsafe()[dimension.ordinal()]; + Map defaultGenerator = plugin.getSettings().getDefaultValues().getRealGeneratorsMap().get(dimension); if (defaultGenerator != null) { KeyMap worldGeneratorRates = cobbleGeneratorValues.get(dimension); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java index 1e660901a9..0cb95190b2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java @@ -2,8 +2,6 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.KeyMap; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.value.DoubleValue; import com.bgsoftware.superiorskyblock.core.value.IntValue; import com.bgsoftware.superiorskyblock.core.value.Value; @@ -25,12 +23,12 @@ private DefaultUpgradeLevel() { IntValue.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getWarpsLimit()), IntValue.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getCoopLimit()), IntValue.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getIslandSize()), - (KeyMap) plugin.getSettings().getDefaultValues().getBlockLimits(), - (KeyMap) plugin.getSettings().getDefaultValues().getEntityLimits(), - convertFromArray(plugin.getSettings().getDefaultValues().getGeneratorsUnsafe()), - Collections.emptyMap(), + Value.syncedSupplied(() -> (KeyMap) plugin.getSettings().getDefaultValues().getBlockLimits()), + Value.syncedSupplied(() -> (KeyMap) plugin.getSettings().getDefaultValues().getEntityLimits()), + Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getRealGeneratorsMap()), + Value.syncedFixed(Collections.emptyMap()), Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getBankLimit()), - plugin.getSettings().getDefaultValues().getRoleLimitsAsView() + Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getRoleLimitsAsView()) ); } @@ -38,8 +36,4 @@ public static DefaultUpgradeLevel getInstance() { return INSTANCE; } - private static EnumerateMap convertFromArray(V[] arr) { - return new EnumerateMap<>(arr); - } - } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java index abddd131fc..24eb5dc370 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java @@ -2,8 +2,8 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; -import com.bgsoftware.superiorskyblock.core.collections.view.EmptyInt2IntMapView; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; +import com.bgsoftware.superiorskyblock.core.collections.view.EmptyInt2IntMapView; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.value.DoubleValue; import com.bgsoftware.superiorskyblock.core.value.IntValue; @@ -33,12 +33,12 @@ public class SUpgrade implements Upgrade { IntValue.syncedFixed(-1), IntValue.syncedFixed(-1), IntValue.syncedFixed(-1), - KeyMaps.createEmptyMap(), - KeyMaps.createEmptyMap(), - new EnumerateMap<>(Collections.emptyList()), - Collections.emptyMap(), + Value.syncedFixed(KeyMaps.createEmptyMap()), + Value.syncedFixed(KeyMaps.createEmptyMap()), + Value.syncedFixed(new EnumerateMap<>(Collections.emptyList())), + Value.syncedFixed(Collections.emptyMap()), Value.syncedFixed(new BigDecimal(-2)), - EmptyInt2IntMapView.INSTANCE); + Value.syncedFixed(EmptyInt2IntMapView.INSTANCE)); private final String name; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java index 9d21093f2a..68188e4ddb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java @@ -60,12 +60,12 @@ protected PlaceholdersService create() { private final IntValue warpsLimit; private final IntValue coopLimit; private final IntValue borderSize; - private final KeyMap blockLimits; - private final KeyMap entityLimits; - private final EnumerateMap> generatorRates; - private final Map islandEffects; + private final Value> blockLimits; + private final Value> entityLimits; + private final Value>> generatorRates; + private final Value> islandEffects; private final Value bankLimit; - private final Int2IntMapView roleLimits; + private final Value roleLimits; @Nullable private ItemData itemData; @@ -73,10 +73,10 @@ protected PlaceholdersService create() { public SUpgradeLevel(int level, UpgradeCost cost, List commands, String permission, Set requirements, DoubleValue cropGrowth, DoubleValue spawnerRates, DoubleValue mobDrops, IntValue teamLimit, IntValue warpsLimit, IntValue coopLimit, - IntValue borderSize, KeyMap blockLimits, - KeyMap entityLimits, EnumerateMap> generatorRates, - Map islandEffects, Value bankLimit, - Int2IntMapView roleLimits) { + IntValue borderSize, Value> blockLimits, + Value> entityLimits, Value>> generatorRates, + Value> islandEffects, Value bankLimit, + Value roleLimits) { this.level = level; this.cost = cost; this.commands = commands; @@ -161,18 +161,18 @@ public double getMobDrops() { @Override public int getBlockLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); - return blockLimits.getOrDefault(key, -1); + return blockLimits.get().getOrDefault(key, -1); } @Override public int getExactBlockLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); - return blockLimits.getRaw(key, -1); + return blockLimits.get().getRaw(key, -1); } @Override public Map getBlockLimits() { - return Collections.unmodifiableMap(blockLimits); + return Collections.unmodifiableMap(blockLimits.get()); } @Override @@ -184,12 +184,12 @@ public int getEntityLimit(EntityType entityType) { @Override public int getEntityLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); - return entityLimits.getOrDefault(key, -1); + return entityLimits.get().getOrDefault(key, -1); } @Override public Map getEntityLimitsAsKeys() { - return Collections.unmodifiableMap(entityLimits); + return Collections.unmodifiableMap(entityLimits.get()); } @Override @@ -216,7 +216,7 @@ public int getBorderSize() { public int getGeneratorAmount(Key key, Dimension dimension) { Preconditions.checkNotNull(key, "key parameter cannot be null."); Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); - Map generatorRates = this.generatorRates.get(dimension); + Map generatorRates = this.generatorRates.get().get(dimension); return (generatorRates == null ? 0 : generatorRates.getOrDefault(key, 0)); } @@ -229,7 +229,7 @@ public int getGeneratorAmount(Key key, World.Environment environment) { @Override public Map getGeneratorAmounts(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); - Map generatorRates = this.generatorRates.get(dimension); + Map generatorRates = this.generatorRates.get().get(dimension); return generatorRates == null ? Collections.emptyMap() : generatorRates.entrySet().stream().collect(Collectors.toMap( entry -> entry.getKey().toString(), Map.Entry::getValue)); @@ -244,12 +244,12 @@ public Map getGeneratorAmounts(World.Environment environment) { @Override public int getPotionEffect(PotionEffectType potionEffectType) { Preconditions.checkNotNull(potionEffectType, "potionEffectType parameter cannot be null."); - return islandEffects.getOrDefault(potionEffectType, 0); + return islandEffects.get().getOrDefault(potionEffectType, 0); } @Override public Map getPotionEffects() { - return Collections.unmodifiableMap(islandEffects); + return Collections.unmodifiableMap(islandEffects.get()); } @Override @@ -260,25 +260,27 @@ public BigDecimal getBankLimit() { @Override public int getRoleLimit(PlayerRole playerRole) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); - return roleLimits.getOrDefault(playerRole.getId(), 0); + return roleLimits.get().getOrDefault(playerRole.getId(), 0); } @Override public Map getRoleLimits() { - if (this.roleLimits.isEmpty()) + Int2IntMapView roleLimits = this.roleLimits.get(); + + if (roleLimits.isEmpty()) return Collections.emptyMap(); - Map roleLimits = new LinkedHashMap<>(); + Map roleLimitsConverted = new LinkedHashMap<>(); - Iterator iterator = this.roleLimits.entryIterator(); + Iterator iterator = roleLimits.entryIterator(); while (iterator.hasNext()) { Int2IntMapView.Entry entry = iterator.next(); PlayerRole playerRole = SPlayerRole.fromId(entry.getKey()); if (playerRole != null) - roleLimits.put(playerRole, entry.getValue()); + roleLimitsConverted.put(playerRole, entry.getValue()); } - return roleLimits.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(roleLimits); + return roleLimitsConverted.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(roleLimitsConverted); } public DoubleValue getCropGrowthUpgradeValue() { @@ -294,14 +296,14 @@ public DoubleValue getMobDropsUpgradeValue() { } public Map getBlockLimitsUpgradeValue() { - return blockLimits.entrySet().stream().collect(Collectors.toMap( + return blockLimits.get().entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> IntValue.syncedFixed(entry.getValue())) ); } public Map getEntityLimitsUpgradeValue() { - return entityLimits.entrySet().stream().collect(Collectors.toMap( + return entityLimits.get().entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> IntValue.syncedFixed(entry.getValue())) ); @@ -324,23 +326,25 @@ public IntValue getBorderSizeUpgradeValue() { } public EnumerateMap> getGeneratorUpgradeValue() { - EnumerateMap> generatorRates = new EnumerateMap<>(Dimension.values()); + EnumerateMap> generatorRates = this.generatorRates.get(); + + EnumerateMap> generatorRatesConverted = new EnumerateMap<>(Dimension.values()); for (Dimension dimension : Dimension.values()) { - Map worldGeneratorRates = this.generatorRates.get(dimension); + Map worldGeneratorRates = generatorRates.get(dimension); if (worldGeneratorRates != null) { Map result = worldGeneratorRates.entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> IntValue.syncedFixed(entry.getValue()))); - generatorRates.put(dimension, result); + generatorRatesConverted.put(dimension, result); } } - return generatorRates; + return generatorRatesConverted; } public Map getPotionEffectsUpgradeValue() { - return islandEffects.entrySet().stream().collect(Collectors.toMap( + return islandEffects.get().entrySet().stream().collect(Collectors.toMap( Map.Entry::getKey, entry -> IntValue.syncedFixed(entry.getValue())) ); @@ -351,20 +355,22 @@ public Value getBankLimitUpgradeValue() { } public Map getRoleLimitsUpgradeValue() { - if (this.roleLimits.isEmpty()) + Int2IntMapView roleLimits = this.roleLimits.get(); + + if (roleLimits.isEmpty()) return Collections.emptyMap(); - Map roleLimits = new LinkedHashMap<>(); + Map roleLimitsConverted = new LinkedHashMap<>(); - Iterator iterator = this.roleLimits.entryIterator(); + Iterator iterator = roleLimits.entryIterator(); while (iterator.hasNext()) { Int2IntMapView.Entry entry = iterator.next(); PlayerRole playerRole = SPlayerRole.fromId(entry.getKey()); if (playerRole != null) - roleLimits.put(playerRole, IntValue.syncedFixed(entry.getValue())); + roleLimitsConverted.put(playerRole, IntValue.syncedFixed(entry.getValue())); } - return roleLimits.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(roleLimits); + return roleLimitsConverted.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(roleLimitsConverted); } public void setItemData(TemplateItem hasNextLevel, TemplateItem noNextLevel, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java index af5c1c0f8b..e7ada440de 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java @@ -269,9 +269,13 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade } } } - upgrade.addUpgradeLevel(level, new SUpgradeLevel(level, upgradeCost, commands, permission, requirements, - cropGrowth, spawnerRates, mobDrops, teamLimit, warpsLimit, coopLimit, borderSize, blockLimits, - entityLimits, generatorRates, islandEffects, bankLimit, rolesLimits)); + + SUpgradeLevel upgradeLevel = new SUpgradeLevel(level, upgradeCost, commands, permission, requirements, + cropGrowth, spawnerRates, mobDrops, teamLimit, warpsLimit, coopLimit, borderSize, + Value.syncedFixed(blockLimits), Value.syncedFixed(entityLimits), Value.syncedFixed(generatorRates), + Value.syncedFixed(islandEffects), bankLimit, Value.syncedFixed(rolesLimits)); + + upgrade.addUpgradeLevel(level, upgradeLevel); } @SuppressWarnings("ResultOfMethodCallIgnored") From 2ccaa476933f35bd7aa3890b77c7522592e469b1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 May 2025 14:04:48 +0300 Subject: [PATCH 144/600] Adds support to default island effect values (#2434) --- .../api/config/SettingsManager.java | 8 ++++++ .../api/island/DelegateIsland.java | 6 +++++ .../superiorskyblock/api/island/Island.java | 6 +++++ .../commands/admin/CmdAdminShow.java | 5 +++- .../config/SettingsContainer.java | 18 +++++++++++-- .../config/SettingsManagerImpl.java | 2 ++ .../config/section/DefaultValuesSection.java | 5 ++++ .../superiorskyblock/island/SIsland.java | 27 +++++++++++++------ .../superiorskyblock/island/SpawnIsland.java | 5 ++++ .../island/upgrade/DefaultUpgradeLevel.java | 2 +- src/main/resources/config.yml | 4 +++ 11 files changed, 76 insertions(+), 12 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index b1a09e59be..c7f261b47a 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -11,6 +11,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.math.BigInteger; @@ -821,6 +822,13 @@ interface DefaultValues { */ Map getRoleLimits(); + /** + * The default island effects for new islands. + * Represented by a map with keys as the effect types, and values as the effect levels. + * Config-path: default-values.island-effects + */ + Map getIslandEffects(); + } interface StackedBlocks { diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index 47714a4b37..8133be6814 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -33,6 +33,7 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID; @@ -1600,6 +1601,11 @@ public Map getPotionEffects() { return this.handle.getPotionEffects(); } + @Override + public Map getCustomPotionEffects() { + return this.handle.getCustomPotionEffects(); + } + @Override public void applyEffects(SuperiorPlayer superiorPlayer) { this.handle.applyEffects(superiorPlayer); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java index 1a0ec192c5..1defdefa85 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java @@ -2199,6 +2199,12 @@ List> getAllChunksAsync(World.Environment environment, */ Map getPotionEffects(); + /** + * Get a list of all custom active island effects with their levels. + */ + Map getCustomPotionEffects(); + + /** * Give all the island effects to a player. * If the player is offline, nothing will happen. diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java index 63baf20ff2..7b170dfb47 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java @@ -296,7 +296,10 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab StringBuilder blocksString = new StringBuilder(); for (Map.Entry entry : island.getPotionEffects().entrySet()) { blocksString.append(Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE.getMessage(locale, - Formatters.CAPITALIZED_FORMATTER.format(entry.getKey().getName()), entry.getValue())).append("\n"); + Formatters.CAPITALIZED_FORMATTER.format(entry.getKey().getName()), entry.getValue())); + if (!island.getCustomPotionEffects().containsKey(entry.getKey())) + blocksString.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); + blocksString.append("\n"); } infoMessage.append(Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS.getMessage(locale, blocksString)); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index d58a58a799..bb9f6419ca 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.config.section.WorldsSection; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.SBlockOffset; +import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; @@ -33,13 +34,13 @@ import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffectType; import java.io.File; import java.io.IOException; @@ -87,6 +88,7 @@ public class SettingsContainer { public final double defaultMobDrops; public final BigDecimal defaultBankLimit; public final Int2IntMapView defaultRoleLimits; + public final Map defaultIslandEffects; public final int islandsHeight; public final boolean worldBordersEnabled; public final boolean stackedBlocksEnabled; @@ -245,6 +247,16 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config loadListOrSection(config, "default-values.entity-limits", "entity limit", (entityType, limit) -> defaultEntityLimits.put(Keys.ofEntityType(entityType), limit)); this.defaultEntityLimits = KeyMaps.unmodifiableKeyMap(defaultEntityLimits); + Map defaultIslandEffects = new ArrayMap<>(); + loadListOrSection(config, "default-values.island-effects", "island effect", (effectName, effectLevel) -> { + PotionEffectType potionEffectType = PotionEffectType.getByName(effectName); + if (potionEffectType == null) { + Log.errorFromFile("config.yml", "Invalid potion effect " + effectName + ", skipping..."); + } else { + defaultIslandEffects.put(potionEffectType, effectLevel); + } + }); + this.defaultIslandEffects = Collections.unmodifiableMap(defaultIslandEffects); defaultTeamLimit = config.getInt("default-values.team-limit", 4); defaultWarpsLimit = config.getInt("default-values.warps-limit", 3); defaultCoopLimit = config.getInt("default-values.coop-limit", 8); @@ -602,7 +614,9 @@ private void loadGenerator(YamlConfiguration config, String path, Dimension dime } private static void loadListOrSection(YamlConfiguration config, String path, String parseName, BiConsumer consumer) { - Object value = Preconditions.checkNotNull(config.get(path), "Path '" + path + "' does not exist."); + Object value = config.get(path); + if (value == null) + return; if (value instanceof List) { ((List) value).forEach(line -> { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index fd00806834..cb3c696151 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -712,6 +712,8 @@ private void convertData(YamlConfiguration cfg) { if (cfg.isBoolean("worlds.end.dragon-fight")) { cfg.set("worlds.end.dragon-fight.enabled", cfg.getBoolean("worlds.end.dragon-fight")); } + if (!cfg.contains("default-values.island-effects")) + cfg.createSection("default-values.island-effects"); } private void convertInteractables(SuperiorSkyblockPlugin plugin, YamlConfiguration cfg) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java index 7d5cc67a13..05a478c310 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/DefaultValuesSection.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.view.Int2IntMapView; +import org.bukkit.potion.PotionEffectType; import java.math.BigDecimal; import java.util.Collections; @@ -96,4 +97,8 @@ public Int2IntMapView getRoleLimitsAsView() { return getContainer().defaultRoleLimits; } + @Override + public Map getIslandEffects() { + return getContainer().defaultIslandEffects; + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index af07f26bf3..1a93dcda01 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -3396,15 +3396,26 @@ public int getPotionEffectLevel(PotionEffectType type) { public Map getPotionEffects() { Map islandEffects = new ArrayMap<>(); - for (PotionEffectType potionEffectType : PotionEffectType.values()) { - if (potionEffectType != null) { - int level = getPotionEffectLevel(potionEffectType); - if (level > 0) - islandEffects.put(potionEffectType, level); - } - } + this.islandEffects.forEach((potionEffectType, levelValue) -> { + int level = levelValue.get(); + if (level > 0) + islandEffects.put(potionEffectType, level); + }); + + return islandEffects.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandEffects); + } + + @Override + public Map getCustomPotionEffects() { + Map islandEffects = new ArrayMap<>(); + + this.islandEffects.forEach((potionEffectType, levelValue) -> { + int level = levelValue.getNonSynced(-1); + if (level > 0) + islandEffects.put(potionEffectType, level); + }); - return Collections.unmodifiableMap(islandEffects); + return islandEffects.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandEffects); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 9c5bc40dae..deef71f398 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -1770,6 +1770,11 @@ public Map getPotionEffects() { return Collections.emptyMap(); } + @Override + public Map getCustomPotionEffects() { + return Collections.emptyMap(); + } + @Override public void applyEffects(SuperiorPlayer superiorPlayer) { // Do nothing. diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java index 0cb95190b2..0297591fc2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java @@ -26,7 +26,7 @@ private DefaultUpgradeLevel() { Value.syncedSupplied(() -> (KeyMap) plugin.getSettings().getDefaultValues().getBlockLimits()), Value.syncedSupplied(() -> (KeyMap) plugin.getSettings().getDefaultValues().getEntityLimits()), Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getRealGeneratorsMap()), - Value.syncedFixed(Collections.emptyMap()), + Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getIslandEffects()), Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getBankLimit()), Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getRoleLimitsAsView()) ); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 89d658a7c3..0f294d0a81 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -100,6 +100,10 @@ default-values: # Example: '1:5' will set the limit of the role with the id 1 (Moderator by default) to 5. role-limits: [ ] + # List of default island effects for new islands. + # Each key in the following section is the effect type, and it's value is the effect level. + island-effects: { } + # Set the islands height generation for islands. islands-height: 100 From 733a6de4efae4f86b9e99054a8fe4cd8f68475d9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 May 2025 14:27:54 +0300 Subject: [PATCH 145/600] Optimize admin show message a bit --- .../commands/admin/CmdAdminShow.java | 194 +++++++++--------- 1 file changed, 95 insertions(+), 99 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java index 7b170dfb47..2f823351f2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java @@ -31,7 +31,12 @@ import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; public class CmdAdminShow implements IAdminIslandCommand { @@ -166,102 +171,54 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab } // Island admin size - if (!Message.ISLAND_INFO_ADMIN_SIZE.isEmpty(locale)) { - infoMessage.append(Message.ISLAND_INFO_ADMIN_SIZE.getMessage(locale, island.getIslandSize())); - if (island.getIslandSizeRaw() != island.getIslandSize()) - infoMessage.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); - infoMessage.append("\n"); - } + collectIslandData(locale, infoMessage, island::getIslandSize, island::getIslandSizeRaw, Message.ISLAND_INFO_ADMIN_SIZE); // Island team limit - if (!Message.ISLAND_INFO_ADMIN_TEAM_LIMIT.isEmpty(locale)) { - infoMessage.append(Message.ISLAND_INFO_ADMIN_TEAM_LIMIT.getMessage(locale, island.getTeamLimit())); - if (island.getTeamLimitRaw() != island.getTeamLimit()) - infoMessage.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); - infoMessage.append("\n"); - } + collectIslandData(locale, infoMessage, island::getTeamLimit, island::getTeamLimitRaw, Message.ISLAND_INFO_ADMIN_TEAM_LIMIT); // Island warps limit - if (!Message.ISLAND_INFO_ADMIN_WARPS_LIMIT.isEmpty(locale)) { - infoMessage.append(Message.ISLAND_INFO_ADMIN_WARPS_LIMIT.getMessage(locale, island.getWarpsLimit())); - if (island.getWarpsLimitRaw() != island.getWarpsLimit()) - infoMessage.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); - infoMessage.append("\n"); - } + collectIslandData(locale, infoMessage, island::getWarpsLimit, island::getWarpsLimitRaw, Message.ISLAND_INFO_ADMIN_WARPS_LIMIT); // Island coop limit - if (plugin.getSettings().isCoopMembers() && !Message.ISLAND_INFO_ADMIN_COOP_LIMIT.isEmpty(locale)) { - infoMessage.append(Message.ISLAND_INFO_ADMIN_COOP_LIMIT.getMessage(locale, island.getCoopLimit())); - if (island.getCoopLimitRaw() != island.getCoopLimit()) - infoMessage.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); - infoMessage.append("\n"); - } + if (plugin.getSettings().isCoopMembers()) + collectIslandData(locale, infoMessage, island::getCoopLimit, island::getCoopLimitRaw, Message.ISLAND_INFO_ADMIN_COOP_LIMIT); // Island bank limit - if (!Message.ISLAND_INFO_ADMIN_BANK_LIMIT.isEmpty(locale)) { - infoMessage.append(Message.ISLAND_INFO_ADMIN_BANK_LIMIT.getMessage(locale, - Formatters.NUMBER_FORMATTER.format(island.getBankLimit()))); - if (!island.getBankLimitRaw().equals(island.getBankLimit())) - infoMessage.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); - infoMessage.append("\n"); - } + collectIslandData(locale, infoMessage, island::getBankLimit, island::getBankLimitRaw, Message.ISLAND_INFO_ADMIN_BANK_LIMIT, + Formatters.NUMBER_FORMATTER::format); if (upgradesModule) { // Island spawners multiplier - if (!Message.ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER.isEmpty(locale) && - BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeSpawnerRates.class)) { - infoMessage.append(Message.ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER.getMessage(locale, island.getSpawnerRatesMultiplier())); - if (island.getSpawnerRatesRaw() != island.getSpawnerRatesMultiplier()) - infoMessage.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); - infoMessage.append("\n"); + if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeSpawnerRates.class)) { + collectIslandData(locale, infoMessage, island::getSpawnerRatesMultiplier, island::getSpawnerRatesRaw, + Message.ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER); } + // Island drops multiplier - if (!Message.ISLAND_INFO_ADMIN_DROPS_MULTIPLIER.isEmpty(locale) && - BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeMobDrops.class)) { - infoMessage.append(Message.ISLAND_INFO_ADMIN_DROPS_MULTIPLIER.getMessage(locale, island.getMobDropsMultiplier())); - if (island.getMobDropsRaw() != island.getMobDropsMultiplier()) - infoMessage.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); - infoMessage.append("\n"); + if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeMobDrops.class)) { + collectIslandData(locale, infoMessage, island::getMobDropsMultiplier, island::getMobDropsRaw, + Message.ISLAND_INFO_ADMIN_DROPS_MULTIPLIER); } // Island crops multiplier - if (!Message.ISLAND_INFO_ADMIN_CROPS_MULTIPLIER.isEmpty(locale) && - BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class)) { - infoMessage.append(Message.ISLAND_INFO_ADMIN_CROPS_MULTIPLIER.getMessage(locale, island.getCropGrowthMultiplier())); - if (island.getCropGrowthRaw() != island.getCropGrowthMultiplier()) - infoMessage.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); - infoMessage.append("\n"); + if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class)) { + collectIslandData(locale, infoMessage, island::getCropGrowthMultiplier, island::getCropGrowthRaw, + Message.ISLAND_INFO_ADMIN_CROPS_MULTIPLIER); } // Island entity limits - if (!Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS.isEmpty(locale) && - !Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE.isEmpty(locale) && - BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class)) { - StringBuilder entitiesString = new StringBuilder(); - for (Map.Entry entry : island.getEntitiesLimitsAsKeys().entrySet()) { - entitiesString.append(Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE.getMessage(locale, - Formatters.CAPITALIZED_FORMATTER.format(entry.getKey().toString()), entry.getValue())); - if (!island.getCustomEntitiesLimits().containsKey(entry.getKey())) - entitiesString.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); - entitiesString.append("\n"); - } - infoMessage.append(Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS.getMessage(locale, entitiesString)); + if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeEntityLimits.class)) { + collectIslandData(locale, island::getEntitiesLimitsAsKeys, island::getCustomEntitiesLimits, + Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS, Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE) + .ifPresent(message -> infoMessage.append(Message.ISLAND_INFO_ADMIN_ENTITIES_LIMITS.getMessage(locale, message))); } // Island block limits - if (!Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS.isEmpty(locale) && - !Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE.isEmpty(locale) && - BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeBlockLimits.class)) { - StringBuilder blocksString = new StringBuilder(); - for (Map.Entry entry : island.getBlocksLimits().entrySet()) { - blocksString.append(Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE.getMessage(locale, - Formatters.CAPITALIZED_FORMATTER.format(entry.getKey().toString()), entry.getValue())); - if (!island.getCustomBlocksLimits().containsKey(entry.getKey())) - blocksString.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); - blocksString.append("\n"); - } - infoMessage.append(Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS.getMessage(locale, blocksString)); + if (BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeBlockLimits.class)) { + collectIslandData(locale, island::getBlocksLimits, island::getCustomBlocksLimits, + Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS, Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE) + .ifPresent(message -> infoMessage.append(Message.ISLAND_INFO_ADMIN_BLOCKS_LIMITS.getMessage(locale, message))); } } @@ -288,34 +245,17 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab } } - if (upgradesModule) { - // Island effects - if (!Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS.isEmpty(locale) && - !Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE.isEmpty(locale) && - BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeIslandEffects.class)) { - StringBuilder blocksString = new StringBuilder(); - for (Map.Entry entry : island.getPotionEffects().entrySet()) { - blocksString.append(Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE.getMessage(locale, - Formatters.CAPITALIZED_FORMATTER.format(entry.getKey().getName()), entry.getValue())); - if (!island.getCustomPotionEffects().containsKey(entry.getKey())) - blocksString.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); - blocksString.append("\n"); - } - infoMessage.append(Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS.getMessage(locale, blocksString)); - } + // Island effects + if (upgradesModule && BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeIslandEffects.class)) { + collectIslandData(locale, island::getPotionEffects, island::getCustomPotionEffects, + Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS, Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE, PotionEffectType::getName) + .ifPresent(message -> infoMessage.append(Message.ISLAND_INFO_ADMIN_ISLAND_EFFECTS.getMessage(locale, message))); } - // Island entity limits - if (!Message.ISLAND_INFO_ADMIN_ROLE_LIMITS.isEmpty(locale) && !Message.ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE.isEmpty(locale)) { - StringBuilder entitiesString = new StringBuilder(); - for (Map.Entry entry : island.getRoleLimits().entrySet()) { - entitiesString.append(Message.ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE.getMessage(locale, entry.getKey(), entry.getValue())); - if (!island.getCustomRoleLimits().containsKey(entry.getKey())) - entitiesString.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); - entitiesString.append("\n"); - } - infoMessage.append(Message.ISLAND_INFO_ADMIN_ROLE_LIMITS.getMessage(locale, entitiesString)); - } + // Island role limits + collectIslandData(locale, island::getRoleLimits, island::getCustomRoleLimits, + Message.ISLAND_INFO_ADMIN_ROLE_LIMITS, Message.ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE) + .ifPresent(message -> infoMessage.append(Message.ISLAND_INFO_ADMIN_ROLE_LIMITS.getMessage(locale, message))); // Island members if (!Message.ISLAND_INFO_ROLES.isEmpty(locale)) { @@ -340,4 +280,60 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab Message.CUSTOM.send(sender, infoMessage.toString(), false); } + private static Optional collectIslandData(Locale locale, + Supplier> dataFunction, + Supplier> customDataFunction, + Message dataMessage, Message dataLineMessage) { + return collectIslandData(locale, dataFunction, customDataFunction, dataMessage, dataLineMessage, null); + } + + private static Optional collectIslandData(Locale locale, + Supplier> dataFunction, + Supplier> customDataFunction, + Message dataMessage, Message dataLineMessage, + @Nullable Function formatter) { + if (dataMessage.isEmpty(locale) || dataLineMessage.isEmpty(locale)) + return Optional.empty(); + + StringBuilder dataValue = new StringBuilder(); + + Map islandData = dataFunction.get(); + Map islandCustomData = customDataFunction.get(); + + islandData.forEach((key, value) -> { + String keyStringValue = formatter == null ? key.toString() : formatter.apply(key); + dataValue.append(dataLineMessage.getMessage(locale, Formatters.CAPITALIZED_FORMATTER.format(keyStringValue), value)); + if (!islandCustomData.containsKey(key)) + dataValue.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); + dataValue.append("\n"); + }); + + return Optional.of(dataValue); + } + + private static void collectIslandData(Locale locale, StringBuilder message, + Supplier dataFunction, + Supplier customDataFunction, + Message dataLineMessage) { + collectIslandData(locale, message, dataFunction, customDataFunction, dataLineMessage, null); + } + + private static void collectIslandData(Locale locale, StringBuilder message, + Supplier dataFunction, + Supplier customDataFunction, + Message dataLineMessage, + @Nullable Function formatter) { + if (dataLineMessage.isEmpty(locale)) + return; + + T islandData = dataFunction.get(); + T islandCustomData = customDataFunction.get(); + + Object formattedIslandData = formatter == null ? islandData : formatter.apply(islandData); + message.append(dataLineMessage.getMessage(locale, formattedIslandData)); + if (!Objects.equals(islandData, islandCustomData)) + message.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); + message.append("\n"); + } + } From e11cf78a7d3adf2782d7bb56a48177ae696065dd Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 May 2025 14:36:18 +0300 Subject: [PATCH 146/600] Fix using warp commands bypassing charge-on-warp option (#2437) --- .../api/island/DelegateIsland.java | 9 +++++-- .../superiorskyblock/api/island/Island.java | 13 ++++++++-- .../core/menu/MenuActions.java | 11 --------- .../superiorskyblock/island/SIsland.java | 24 +++++++++++++++---- .../superiorskyblock/island/SpawnIsland.java | 7 +++++- 5 files changed, 44 insertions(+), 20 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index 8133be6814..deae4f964a 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -1716,8 +1716,13 @@ public IslandWarp getWarp(String name) { } @Override - public void warpPlayer(SuperiorPlayer superiorPlayer, String warp) { - this.handle.warpPlayer(superiorPlayer, warp); + public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName) { + this.handle.warpPlayer(superiorPlayer, warpName); + } + + @Override + public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean force) { + this.handle.warpPlayer(superiorPlayer, warpName, force); } @Override diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java index 1defdefa85..99dfcf3eec 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java @@ -2362,9 +2362,18 @@ List> getAllChunksAsync(World.Environment environment, * Teleport a player to a warp. * * @param superiorPlayer The player to teleport. - * @param warp The warp's name to teleport the player to. + * @param warpName The warp's name to teleport the player to. */ - void warpPlayer(SuperiorPlayer superiorPlayer, String warp); + void warpPlayer(SuperiorPlayer superiorPlayer, String warpName); + + /** + * Teleport a player to a warp. + * + * @param superiorPlayer The player to teleport. + * @param warpName The warp's name to teleport the player to. + * @param force Force teleportation of the player + */ + void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean force); /** * Delete a warp from the island. diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java index 4ee05b8b65..15dd536a85 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java @@ -124,17 +124,6 @@ public static void simulateIslandCreationClick(SuperiorPlayer clickedPlayer, Str } public static void simulateWarpsClick(SuperiorPlayer superiorPlayer, Island island, IslandWarp islandWarp) { - if (!superiorPlayer.hasBypassModeEnabled() && plugin.getSettings().getChargeOnWarp() > 0) { - if (plugin.getProviders().getEconomyProvider().getBalance(superiorPlayer) - .compareTo(BigDecimal.valueOf(plugin.getSettings().getChargeOnWarp())) < 0) { - Message.NOT_ENOUGH_MONEY_TO_WARP.send(superiorPlayer); - return; - } - - plugin.getProviders().getEconomyProvider().withdrawMoney(superiorPlayer, - plugin.getSettings().getChargeOnWarp()); - } - BukkitExecutor.sync(() -> { superiorPlayer.runIfOnline(player -> { MenuView currentView = superiorPlayer.getOpenedView(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 1a93dcda01..1653230ed7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -3651,17 +3651,33 @@ public IslandWarp getWarp(String name) { } @Override - public void warpPlayer(SuperiorPlayer superiorPlayer, String warp) { + public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName) { + warpPlayer(superiorPlayer, warpName, false); + } + + @Override + public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean force) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); - Preconditions.checkNotNull(warp, "warp parameter cannot be null."); + Preconditions.checkNotNull(warpName, "warp parameter cannot be null."); - IslandWarp islandWarp = getWarp(warp); + IslandWarp islandWarp = getWarp(warpName); if (islandWarp == null) { - Message.INVALID_WARP.send(superiorPlayer, warp); + Message.INVALID_WARP.send(superiorPlayer, warpName); return; } + if (!force && !superiorPlayer.hasBypassModeEnabled() && plugin.getSettings().getChargeOnWarp() > 0) { + if (plugin.getProviders().getEconomyProvider().getBalance(superiorPlayer) + .compareTo(BigDecimal.valueOf(plugin.getSettings().getChargeOnWarp())) < 0) { + Message.NOT_ENOUGH_MONEY_TO_WARP.send(superiorPlayer); + return; + } + + plugin.getProviders().getEconomyProvider().withdrawMoney(superiorPlayer, + plugin.getSettings().getChargeOnWarp()); + } + if (plugin.getSettings().getWarpsWarmup() > 0 && !superiorPlayer.hasBypassModeEnabled() && !superiorPlayer.hasPermission("superior.admin.bypass.warmup")) { Message.TELEPORT_WARMUP.send(superiorPlayer, Formatters.TIME_FORMATTER.format( diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index deef71f398..c57a6d4e0e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -1881,7 +1881,12 @@ public IslandWarp getWarp(String name) { } @Override - public void warpPlayer(SuperiorPlayer superiorPlayer, String warp) { + public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName) { + // Do nothing. + } + + @Override + public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean force) { // Do nothing. } From 71204b12a0324d7992a8db70a7c9a9129e64cded Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 May 2025 14:50:56 +0300 Subject: [PATCH 147/600] Fix bypass permission does not bypass visit warmup (#2436) --- .../commands/player/CmdTeleport.java | 17 ++++----------- .../commands/player/CmdVisit.java | 21 ++++++------------- .../superiorskyblock/island/SIsland.java | 13 +++--------- .../world/EntityTeleports.java | 21 +++++++++++++++++++ 4 files changed, 34 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java index a9aa4891cb..643e90d5df 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java @@ -3,15 +3,13 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.world.EntityTeleports; import org.bukkit.command.CommandSender; -import java.time.Duration; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -64,15 +62,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); - if (plugin.getSettings().getHomeWarmup() > 0 && !superiorPlayer.hasBypassModeEnabled() && - !superiorPlayer.hasPermission("superior.admin.bypass.warmup")) { - Message.TELEPORT_WARMUP.send(superiorPlayer, Formatters.TIME_FORMATTER.format( - Duration.ofMillis(plugin.getSettings().getHomeWarmup()), superiorPlayer.getUserLocale())); - superiorPlayer.setTeleportTask(BukkitExecutor.sync(() -> - teleportToIsland(superiorPlayer, island), plugin.getSettings().getHomeWarmup() / 50)); - } else { - teleportToIsland(superiorPlayer, island); - } + EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getHomeWarmup(), + unused -> teleportToIsland(superiorPlayer, island)); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java index 15213f3673..05d95e23b9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java @@ -12,15 +12,13 @@ import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.world.EntityTeleports; import com.bgsoftware.superiorskyblock.world.WorldBlocks; import org.bukkit.Location; import org.bukkit.command.CommandSender; -import java.time.Duration; import java.util.Collections; import java.util.List; @@ -119,19 +117,12 @@ private static void teleportPlayerInternal(Island targetIsland, SuperiorPlayer s return; } - if (plugin.getSettings().getVisitWarmup() > 0 && !superiorPlayer.hasBypassModeEnabled()) { - Message.TELEPORT_WARMUP.send(superiorPlayer, Formatters.TIME_FORMATTER.format( - Duration.ofMillis(plugin.getSettings().getVisitWarmup()), superiorPlayer.getUserLocale())); + Location finalVisitLocation = visitLocation; - Location finalVisitLocation = visitLocation; - - superiorPlayer.setTeleportTask(BukkitExecutor.sync(() -> teleportPlayerNoWarmup(superiorPlayer, - targetIsland, finalVisitLocation, isVisitorSign, true, true), - plugin.getSettings().getHomeWarmup() / 50)); - } else { - teleportPlayerNoWarmup(superiorPlayer, targetIsland, visitLocation, isVisitorSign, - false, true); - } + EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getVisitWarmup(), afterWarmup -> { + teleportPlayerNoWarmup(superiorPlayer, targetIsland, finalVisitLocation, isVisitorSign, + afterWarmup /*checkIslandLock*/, true); + }); } private static void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island island, Location visitLocation, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 1653230ed7..1d27d7b570 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -96,6 +96,7 @@ import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeIslandEffects; import com.bgsoftware.superiorskyblock.world.Dimensions; +import com.bgsoftware.superiorskyblock.world.EntityTeleports; import com.bgsoftware.superiorskyblock.world.GeneratorType; import com.bgsoftware.superiorskyblock.world.WorldBlocks; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; @@ -122,7 +123,6 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; -import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -3678,15 +3678,8 @@ public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean f plugin.getSettings().getChargeOnWarp()); } - if (plugin.getSettings().getWarpsWarmup() > 0 && !superiorPlayer.hasBypassModeEnabled() && - !superiorPlayer.hasPermission("superior.admin.bypass.warmup")) { - Message.TELEPORT_WARMUP.send(superiorPlayer, Formatters.TIME_FORMATTER.format( - Duration.ofMillis(plugin.getSettings().getWarpsWarmup()), superiorPlayer.getUserLocale())); - superiorPlayer.setTeleportTask(BukkitExecutor.sync(() -> - warpPlayerWithoutWarmup(superiorPlayer, islandWarp, true), plugin.getSettings().getWarpsWarmup() / 50)); - } else { - warpPlayerWithoutWarmup(superiorPlayer, islandWarp, true); - } + EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getWarpsWarmup(), + unused -> warpPlayerWithoutWarmup(superiorPlayer, islandWarp, true)); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java index 7a3ed6f02a..5eb69710f2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java @@ -14,8 +14,10 @@ import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; @@ -28,6 +30,7 @@ import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; +import java.time.Duration; import java.util.Comparator; import java.util.LinkedList; import java.util.Objects; @@ -42,6 +45,18 @@ public class EntityTeleports { private EntityTeleports() { } + public static void warmupTeleport(SuperiorPlayer superiorPlayer, long warmupInMillis, TeleportCallback teleportCallback) { + if (warmupInMillis > 0 && !superiorPlayer.hasBypassModeEnabled() && + !superiorPlayer.hasPermission("superior.admin.bypass.warmup")) { + Message.TELEPORT_WARMUP.send(superiorPlayer, Formatters.TIME_FORMATTER.format( + Duration.ofMillis(warmupInMillis), superiorPlayer.getUserLocale())); + + superiorPlayer.setTeleportTask(BukkitExecutor.sync(() -> teleportCallback.accept(true), warmupInMillis / 50)); + } else { + teleportCallback.accept(false); + } + } + public static void teleport(Entity entity, Location location) { teleport(entity, location, null); } @@ -254,4 +269,10 @@ private static Location adjustLocationToHome(Island island, Block block, float y return newHomeLocation; } + public interface TeleportCallback { + + void accept(boolean afterWarmup); + + } + } From 65982bc0f72da6879eb2f056943d409e5e547c62 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 May 2025 15:24:48 +0300 Subject: [PATCH 148/600] Updated crops-to-grow list to include missing crops (#2435) --- src/main/resources/config.yml | 48 ++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 0f294d0a81..5870852357 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -642,31 +642,45 @@ values-menu: true # A list of crops that will be affected by the crop growth multiplier. # You can find a list of materials here: https://bg-software.com/materials/ crops-to-grow: - - 'CACTUS' - - 'SUGAR_CANE_BLOCK' - - 'SUGAR_CANE' - - 'MELON_STEM' - - 'ATTACHED_MELON_STEM' - - 'RED_MUSHROOM' - - 'BROWN_MUSHROOM' - - 'PUMPKIN_STEM' - - 'ATTACHED_PUMPKIN_STEM' - - 'VINE' - - 'COCOA' - 'SAPLING' - - 'DARK_OAK_SAPLING' - - 'JUNGLE_SAPLING' - 'OAK_SAPLING' - - 'ACACIA_SAPLING' - - 'BIRCH_SAPLING' - 'SPRUCE_SAPLING' - - 'CROPS' + - 'BIRCH_SAPLING' + - 'JUNGLE_SAPLING' + - 'ACACIA_SAPLING' + - 'DARK_OAK_SAPLING' + - 'MANGROVE_PROPAGULE' + - 'CHERRY_SAPLING' + - 'PALE_OAK_SAPLING' + - 'BROWN_MUSHROOM' + - 'RED_MUSHROOM' + - 'BAMBOO' + - 'BAMBOO_SAPLING' + - 'SUGAR_CANE_BLOCK' + - 'SUGAR_CANE' + - 'CACTUS' + - 'WEEPING_VINES' + - 'TWISTING_VINES' + - 'VINE' + - 'CHORUS_FLOWER' - 'WHEAT' + - 'COCOA' + - 'PUMPKIN_STEM' + - 'ATTACHED_PUMPKIN_STEM' + - 'MELON_STEM' + - 'ATTACHED_MELON_STEM' + - 'BEETROOTS' + - 'TORCHFLOWER_CROP' + - 'PITCHER_CROP' + - 'CAVE_VINES' + - 'SWEET_BERRY_BUSH' + - 'NETHER_WART' + - 'KELP' - 'CARROT' - 'CARROTS' - 'POTATO' - 'POTATOES' - - 'BEETROOTS' + - 'CROPS' # How frequency should the crops task run? (in ticks) # You can disable this feature by setting it to 0. From 6e5c1ad4c9e1164a206c1b4a454bd4c2058180af Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 May 2025 15:32:07 +0300 Subject: [PATCH 149/600] Fixed reload doesn't refresh caches --- .../bgsoftware/superiorskyblock/listener/BukkitListeners.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java index d0d1805d1b..7d721dfbd8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java @@ -49,7 +49,6 @@ public void registerListeners() { public void unregisterListeners() { plugin.getGameEventsDispatcher().clearCallbacks(); - plugin.getPluginEventsDispatcher().clearCallbacks(); HandlerList.unregisterAll(this.plugin); } From 84d3c6291c8b16fecacf04e7ce611b0bd3d1048b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 May 2025 15:32:34 +0300 Subject: [PATCH 150/600] Adds pale oak to default interactables (#2425) --- src/main/resources/interactables.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index 27dab488e5..044a6c1469 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -195,6 +195,16 @@ interactables: - 'ORANGE_SHULKER_BOX' - 'OXIDIZED_COPPER_DOOR' - 'OXIDIZED_COPPER_TRAPDOOR' + - 'PALE_OAK_BUTTON' + - 'PALE_OAK_DOOR' + - 'PALE_OAK_FENCE' + - 'PALE_OAK_FENCE_GATE' + - 'PALE_OAK_HANGING_SIGN' + - 'PALE_OAK_PRESSURE_PLATE' + - 'PALE_OAK_SIGN' + - 'PALE_OAK_TRAPDOOR' + - 'PALE_OAK_WALL_HANGING_SIGN' + - 'PALE_OAK_WALL_SIGN' - 'PINK_BED' - 'PINK_CANDLE' - 'PINK_SHULKER_BOX' @@ -223,6 +233,7 @@ interactables: - 'POTTED_OAK_SAPLING' - 'POTTED_ORANGE_TULIP' - 'POTTED_OXEYE_DAISY' + - 'POTTED_PALE_OAK_SAPLING' - 'POTTED_PINK_TULIP' - 'POTTED_POPPY' - 'POTTED_RED_MUSHROOM' From 279494e5462ac069d286609c0ba2dc08fb5c4bb7 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 May 2025 15:44:56 +0300 Subject: [PATCH 151/600] Fix default island effects are not loaded the same as in upgrades (#2434) --- .../bgsoftware/superiorskyblock/config/SettingsContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index bb9f6419ca..09701e87ed 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -253,7 +253,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config if (potionEffectType == null) { Log.errorFromFile("config.yml", "Invalid potion effect " + effectName + ", skipping..."); } else { - defaultIslandEffects.put(potionEffectType, effectLevel); + defaultIslandEffects.put(potionEffectType, effectLevel - 1); } }); this.defaultIslandEffects = Collections.unmodifiableMap(defaultIslandEffects); From 2935afa83e388da9ebb670099219296db489d910 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 May 2025 15:45:13 +0300 Subject: [PATCH 152/600] Updated comments for default values sections --- src/main/resources/config.yml | 63 ++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 5870852357..6fb648803e 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -45,63 +45,72 @@ max-island-size: 200 # the upgrade, and not from here. default-values: # The default island size of all islands. - # This island size can be expanded by using the /is admin setsize command. island-size: 20 - # Set the default block limits of islands. - # This limit can be expanded by using the /is admin setblocklimit command. + # Set the default block limits of all islands. + # The following example will set a limit of 8 hoppers in islands: + # block-limits: + # HOPPER: 8 # You can find a list of materials here: https://bg-software.com/materials/ block-limits: HOPPER: 8 - # Set the default entity limits of islands. - # This limit can be expanded by using the /is admin setentitylimit command. + # Set the default entity limits of all islands. + # The following example will set a limit of 4 Minecarts in islands: + # entity-limits: + # MINECART: 4 # You can find a list of entities here: https://bg-software.com/entities/ entity-limits: MINECART: 4 - # The amount of warps an island can have - # This limit can be expanded by using the /is admin setwarpslimit command. + # Set the default warps limit of all islands. warps-limit: 3 - # Set the default team limit of islands. - # This limit can be expanded by using the /is admin setteamlimit command. + # Set the default team limit of all islands. team-limit: 4 - # Set the default coop limit of islands. - # This limit can be expanded by using the /is admin setcooplimit command. + # Set the default coop limit of all islands. coop-limit: 8 - # Set the default crop-growth multiplier of islands. - # This multiplier can be expanded by using the /is admin setcropgrowth command. + # Set the default crop-growth multiplier of all islands. crop-growth: 1 - # Set the default spawner-rates multiplier of islands. - # This multiplier can be expanded by using the /is admin setspawnerrates command. + # Set the default spawner-rates multiplier of all islands. spawner-rates: 1 - # Set the default mob-drops multiplier of islands. - # This multiplier can be expanded by using the /is admin setmobdrops command. + # Set the default mob-drops multiplier of all islands. mob-drops: 1 - # Set the default bank limit of islands. - # Set it to -1 for no bank limits. + # Set the default bank limit of all islands. bank-limit: -1 - # A list of default generator percentages for new islands. - # Example: 'DIAMOND_BLOCK:50' will set 50% chance for diamond block. + # Set the default generator percentages of all islands. + # The following example will set 0.5% chance for diamond block in the normal world, and 50% for gold block in nether: + # generator: + # normal: + # DIAMOND_BLOCK: 1 + # STONE: 199 + # nether: + # GOLD_BLOCK: 1 + # NETHERRACK: 1 # You can find a list of materials here: https://bg-software.com/materials/ generator: normal: COBBLESTONE: 95 COAL_ORE: 5 - # A list of default role limits for new islands. - # Example: '1:5' will set the limit of the role with the id 1 (Moderator by default) to 5. - role-limits: [ ] - - # List of default island effects for new islands. - # Each key in the following section is the effect type, and it's value is the effect level. + # Set the default role limits of all islands. + # The following example will set the limit of the role with the id 1 (Moderator by default) to 5: + # role-limits: + # '1': 5 + role-limits: { } + + # Set the of default island effects for all islands. + # The following example will set the effect level of Speed to 3: + # island-effects: + # SPEED: 4 + # You can find the list of valid potion effects here: + # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/potion/PotionEffectType.html island-effects: { } # Set the islands height generation for islands. From a99bdb193d15f60cc0453697eb3cf4113bce1d8b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 May 2025 16:54:07 +0300 Subject: [PATCH 153/600] Better detection for possible collision with blocks (#2424) --- .../nms/v1_12_R1/NMSWorldImpl.java | 10 ++++++++++ .../nms/v1_16_R3/NMSWorldImpl.java | 5 +++++ .../superiorskyblock/nms/v1_17/NMSWorldImpl.java | 5 +++++ .../superiorskyblock/nms/v1_18/NMSWorldImpl.java | 5 +++++ .../superiorskyblock/nms/v1_19/NMSWorldImpl.java | 5 +++++ .../nms/v1_20_3/NMSWorldImpl.java | 5 +++++ .../nms/v1_20_4/NMSWorldImpl.java | 5 +++++ .../superiorskyblock/nms/v1_21/NMSWorldImpl.java | 5 +++++ .../nms/v1_21_3/NMSWorldImpl.java | 5 +++++ .../nms/v1_21_4/NMSWorldImpl.java | 5 +++++ .../nms/v1_21_5/NMSWorldImpl.java | 7 +++++-- .../nms/v1_8_R3/NMSWorldImpl.java | 10 ++++++++++ .../superiorskyblock/nms/NMSWorld.java | 2 ++ .../superiorskyblock/world/WorldBlocks.java | 16 ++++++++-------- 14 files changed, 80 insertions(+), 10 deletions(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java index 9bcf0dc798..f95e6c4f6d 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java @@ -221,6 +221,16 @@ private int getDefaultAmount(IBlockData blockData) { return 1; } + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + WorldServer worldServer = ((CraftWorld) bukkitBlock.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.c(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); + return worldServer.getType(blockPosition).r(); + } + } + @Override public void placeSign(Island island, Location location) { TileEntitySign tileEntitySign = NMSUtils.getTileEntityAt(location, TileEntitySign.class); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java index 9d9a448f28..b0306a70fe 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java @@ -229,6 +229,11 @@ private int getDefaultAmount(IBlockData blockData) { return 1; } + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + return !bukkitBlock.isPassable(); + } + @Override public void placeSign(Island island, Location location) { TileEntitySign tileEntitySign = NMSUtils.getTileEntityAt(location, TileEntitySign.class); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index e3205e2159..a4c77f9220 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -251,6 +251,11 @@ private int getDefaultAmount(BlockState blockState) { return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; } + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + return !bukkitBlock.isPassable(); + } + @Override public void placeSign(Island island, Location location) { SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index 8562dfed55..4fe75b3490 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -252,6 +252,11 @@ private int getDefaultAmount(BlockState blockState) { return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; } + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + return !bukkitBlock.isPassable(); + } + @Override public void placeSign(Island island, Location location) { SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index d179836a99..f302716e49 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -258,6 +258,11 @@ private int getDefaultAmount(BlockState blockState) { return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; } + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + return !bukkitBlock.isPassable(); + } + @Override public void placeSign(Island island, Location location) { SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index a173a6e6c3..0a479c365f 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -261,6 +261,11 @@ private int getDefaultAmount(BlockState blockState) { return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; } + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + return !bukkitBlock.isPassable(); + } + @Override public void placeSign(Island island, Location location) { SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index 94718dd03d..48830d1098 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -261,6 +261,11 @@ private int getDefaultAmount(BlockState blockState) { return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; } + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + return !bukkitBlock.isPassable(); + } + @Override public void placeSign(Island island, Location location) { SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index 081aa9c300..997cdb8d4f 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -312,6 +312,11 @@ private int getDefaultAmount(BlockState blockState) { return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; } + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + return !bukkitBlock.isPassable(); + } + @Override public void placeSign(Island island, Location location) { SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index bdeec755bb..b0d1355dbe 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -312,6 +312,11 @@ private int getDefaultAmount(BlockState blockState) { return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; } + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + return !bukkitBlock.isPassable(); + } + @Override public void placeSign(Island island, Location location) { SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index 00bf81a17e..73bb7f1555 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -312,6 +312,11 @@ private int getDefaultAmount(BlockState blockState) { return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; } + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + return !bukkitBlock.isPassable(); + } + @Override public void placeSign(Island island, Location location) { SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java index 1b42215bbb..0d24386c24 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_5; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -68,7 +67,6 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; -import org.bukkit.event.block.SignChangeEvent; import java.lang.reflect.Modifier; import java.util.Iterator; @@ -314,6 +312,11 @@ private int getDefaultAmount(BlockState blockState) { return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; } + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + return !bukkitBlock.isPassable(); + } + @Override public void placeSign(Island island, Location location) { SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java index 6fa1745654..d508f3a8ad 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java @@ -223,6 +223,16 @@ private int getDefaultAmount(IBlockData blockData) { return 1; } + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + WorldServer worldServer = ((CraftWorld) bukkitBlock.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); + blockPosition.c(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); + return worldServer.getType(blockPosition).getBlock().w(); + } + } + @Override public void placeSign(Island island, Location location) { TileEntitySign tileEntitySign = NMSUtils.getTileEntityAt(location, TileEntitySign.class); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java index 472a5128eb..e4f46517a5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java @@ -54,6 +54,8 @@ default SignType getSignType(Block block) { int getDefaultAmount(BlockState blockState); + boolean canPlayerSuffocate(Block block); + void placeSign(Island island, Location location); void playGeneratorSound(Location location); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java b/src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java index f07d89f734..3fc3587f64 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java @@ -22,17 +22,17 @@ private WorldBlocks() { } public static boolean isSafeBlock(Block block) { - return _isSafeBlock(block) || _isSafeBlock(block.getRelative(BlockFace.DOWN)); + return isSafeBlockInternal(block) || isSafeBlockInternal(block.getRelative(BlockFace.DOWN)); } - private static boolean _isSafeBlock(Block block) { - Block feetBlock = block.getRelative(BlockFace.UP); - Block headBlock = feetBlock.getRelative(BlockFace.UP); + private static boolean isSafeBlockInternal(Block block) { + // Checks that the block in the parameter is safe for teleportation. + // This means that the block below it is considered "safe", and the two blocks above the safe blocks + // cannot suffocate the player. - if (feetBlock.getType().isSolid() || headBlock.getType().isSolid()) - return false; - - return plugin.getSettings().getSafeBlocks().contains(Keys.of(block)); + return !plugin.getNMSWorld().canPlayerSuffocate(block) && + !plugin.getNMSWorld().canPlayerSuffocate(block.getRelative(BlockFace.UP)) && + plugin.getSettings().getSafeBlocks().contains(Keys.of(block.getRelative(BlockFace.DOWN))); } public static boolean isSafeBlock(ChunkSnapshot chunkSnapshot, int x, int y, int z) { From 50138a568dfb99e488d3d7c6122b65d1ade7f2ab Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 May 2025 17:09:33 +0300 Subject: [PATCH 154/600] Fixed island warps change their position after restart --- .../bridge/IslandsDatabaseBridge.java | 35 +++++++++++-------- .../island/signs/IslandSigns.java | 3 ++ .../island/warp/SIslandWarp.java | 2 +- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index 443918e233..b626a70c30 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -24,6 +24,7 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.LegacyMasks; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.database.serialization.IslandsSerializer; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; @@ -49,8 +50,6 @@ public class IslandsDatabaseBridge { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final Location LOCATION = new Location(null, 0, 100, 0); - private static final Map>> SAVE_METHODS_TO_BE_EXECUTED = new ConcurrentHashMap<>(); private IslandsDatabaseBridge() { @@ -352,14 +351,18 @@ public static void removeRoleLimit(Island island, PlayerRole playerRole) { public static void saveWarp(Island island, IslandWarp islandWarp) { WarpCategory category = islandWarp.getCategory(); ItemStack icon = islandWarp.getRawIcon(); - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_warps", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("name", islandWarp.getName()), - new Pair<>("category", category == null ? "" : category.getName()), - new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(LOCATION))), - new Pair<>("private", islandWarp.hasPrivateFlag()), - new Pair<>("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(icon)) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + databaseBridge.insertObject("islands_warps", + new Pair<>("island", island.getUniqueId().toString()), + new Pair<>("name", islandWarp.getName()), + new Pair<>("category", category == null ? "" : category.getName()), + new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(wrapper.getHandle()))), + new Pair<>("private", islandWarp.hasPrivateFlag()), + new Pair<>("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(icon)) + ); + } + }); } public static void updateWarpName(Island island, IslandWarp islandWarp, String oldName) { @@ -370,10 +373,14 @@ public static void updateWarpName(Island island, IslandWarp islandWarp, String o } public static void updateWarpLocation(Island island, IslandWarp islandWarp) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_warps", - createFilter("island", island, new Pair<>("name", islandWarp.getName())), - new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(LOCATION))) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + databaseBridge.updateObject("islands_warps", + createFilter("island", island, new Pair<>("name", islandWarp.getName())), + new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(wrapper.getHandle()))) + ); + } + }); } public static void updateWarpPrivateStatus(Island island, IslandWarp islandWarp) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java b/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java index c8f17d0c2a..dc09679757 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java @@ -31,6 +31,9 @@ private IslandSigns() { public static Result handleSignPlace(SuperiorPlayer superiorPlayer, Location warpLocation, String[] warpLines, boolean sendMessage) { + // Adjust to the middle of the block + warpLocation.add(0.5, 0, 0.5); + Island island = plugin.getGrid().getIslandAt(warpLocation); if (island == null) return new Result(Reason.NOT_IN_ISLAND, false); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java index 3c6380215e..4a2553c509 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java @@ -26,7 +26,7 @@ public class SIslandWarp implements IslandWarp { public SIslandWarp(String name, Location location, WarpCategory warpCategory, boolean isPrivate, @Nullable ItemStack icon) { this.name = name; - this.location = location.clone().add(0.5, 0, 0.5); + this.location = location.clone(); this.warpCategory = warpCategory; this.isPrivate = isPrivate; this.icon = icon; From 60c75d54a11ad0fcef84bdfb1bfec93a6d32360e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 4 May 2025 18:09:27 +0300 Subject: [PATCH 155/600] Changed it so the default biome for schematics will be the world's default biome (#2440) --- .../superiorskyblock/core/menu/MenuConfig.java | 5 +++-- .../menu/button/impl/IslandCreationButton.java | 7 +++++-- .../core/menu/impl/MenuIslandCreation.java | 18 ++++++++++-------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java index b7cb7b8df8..10d6790c1a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java @@ -36,8 +36,9 @@ public IslandCreation(IslandCreationButton.Template template) { public IslandCreation(Schematic schematic, IslandCreationButton.Template template) { this.schematic = schematic; this.template = template; - this.biome = template == null ? EnumHelper.getEnum(Biome.class, plugin.getSettings().getWorlds().getDimensionConfig( - plugin.getSettings().getWorlds().getDefaultWorldDimension()).getBiome()) : template.getBiome(); + Biome biome = template == null ? null : template.getBiome(); + this.biome = biome == null ? EnumHelper.getEnum(Biome.class, plugin.getSettings().getWorlds().getDimensionConfig( + plugin.getSettings().getWorlds().getDefaultWorldDimension()).getBiome()) : biome; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java index 6e6634abaa..32e5977724 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/IslandCreationButton.java @@ -62,6 +62,7 @@ public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder noAccessCommands = null; + @Nullable private Biome biome; private BigDecimal bonusWorth; private BigDecimal bonusLevel; @@ -131,6 +132,7 @@ public static class Template extends MenuTemplateButtonImpl accessCommands; private final TemplateItem lackPermissionItem; private final List lackPermissionCommands; + @Nullable private final Biome biome; private final BigDecimal bonusWorth; private final BigDecimal bonusLevel; @@ -144,7 +146,7 @@ public static class Template extends MenuTemplateButtonImpl accessCommands, @Nullable TemplateItem lackPermissionItem, @Nullable List lackPermissionCommands, - Biome biome, @Nullable BigDecimal bonusWorth, @Nullable BigDecimal bonusLevel, boolean isOffset, + @Nullable Biome biome, @Nullable BigDecimal bonusWorth, @Nullable BigDecimal bonusLevel, boolean isOffset, @Nullable TemplateItem accessItem, @Nullable BlockOffset spawnOffset, Schematic schematic) { super(accessItem == null ? TemplateItem.AIR : accessItem, null, null, requiredPermission, lackPermissionSound, IslandCreationButton.class, IslandCreationButton::new); @@ -152,7 +154,7 @@ public static class Template extends MenuTemplateButtonImpl getAccessCommands() { return accessCommands; } + @Nullable public Biome getBiome() { return biome; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java index 9601c45075..b4ef393442 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java @@ -70,14 +70,16 @@ public static MenuIslandCreation createInstance() { IslandCreationButton.Builder buttonBuilder = new IslandCreationButton.Builder(schematic); { - String biomeName = itemSection.getString("biome", "PLAINS"); - try { - Biome biome = Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); - buttonBuilder.setBiome(biome); - } catch (IllegalArgumentException error) { - Log.warnFromFile("island-creation.yml", "Invalid biome name for item ", - itemSectionName, ": ", biomeName); - continue; + String biomeName = itemSection.getString("biome"); + if(biomeName != null) { + try { + Biome biome = Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + buttonBuilder.setBiome(biome); + } catch (IllegalArgumentException error) { + Log.warnFromFile("island-creation.yml", "Invalid biome name for item ", + itemSectionName, ": ", biomeName); + continue; + } } } From 21cd2aefef93ee88ab3e76000605e608aa14658e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 4 May 2025 18:17:40 +0300 Subject: [PATCH 156/600] Fixed labels of teleport and setteleport are not correct (#2451) --- .../superiorskyblock/commands/player/CmdSetTeleport.java | 2 +- .../superiorskyblock/commands/player/CmdTeleport.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java index 424306a661..fe4a006c41 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetTeleport.java @@ -21,7 +21,7 @@ public class CmdSetTeleport implements IPermissibleCommand { @Override public List getAliases() { - return Arrays.asList("settp", "setteleport", "setgo", "sethome"); + return Arrays.asList("setteleport", "settp", "setgo", "sethome"); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java index 643e90d5df..cf5d60562b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java @@ -18,7 +18,7 @@ public class CmdTeleport implements ISuperiorCommand { @Override public List getAliases() { - return Arrays.asList("tp", "teleport", "go", "home"); + return Arrays.asList("teleport", "tp", "go", "home"); } @Override From 0d27825ae077ff2c76706315cd9565b249c1efb7 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 4 May 2025 18:32:28 +0300 Subject: [PATCH 157/600] Fixed disabled-commands not updated after reload (#2450) --- .../superiorskyblock/commands/CommandsMap.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java index 4b73fbeb01..49e4ba1022 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java @@ -4,9 +4,9 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.google.common.base.Preconditions; import java.util.Collections; @@ -22,7 +22,7 @@ public abstract class CommandsMap { - private static Set DISABLED_COMMANDS_CACHE; + private static Set DISABLED_COMMANDS_CACHE; private static void onSettingsUpdate() { DISABLED_COMMANDS_CACHE = new HashSet<>(); @@ -30,7 +30,7 @@ private static void onSettingsUpdate() { plugin.getSettings().getDisabledCommands().forEach(commandLabel -> { SuperiorCommand superiorCommand = plugin.getCommands().getCommand(commandLabel); if (superiorCommand != null && !(superiorCommand instanceof IAdminIslandCommand)) - DISABLED_COMMANDS_CACHE.add(superiorCommand); + DISABLED_COMMANDS_CACHE.add(superiorCommand.getAliases().get(0).toLowerCase(Locale.ENGLISH)); }); } @@ -110,7 +110,8 @@ public List getSubCommands(boolean includeDisabled) { } private boolean isCommandEnabled(SuperiorCommand superiorCommand) { - return superiorCommand instanceof IAdminIslandCommand || !DISABLED_COMMANDS_CACHE.contains(superiorCommand); + return superiorCommand instanceof IAdminIslandCommand || + !DISABLED_COMMANDS_CACHE.contains(superiorCommand.getAliases().get(0).toLowerCase(Locale.ENGLISH)); } private void removeCommand(String label) { From b0770fea680d4a2715f03acc5c31feec16437ce5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 4 May 2025 18:40:04 +0300 Subject: [PATCH 158/600] Fixed commands are not sorted after reload (#2449) --- .../superiorskyblock/commands/CommandsMap.java | 12 ++++++++---- .../commands/admin/AdminCommandsMap.java | 2 ++ .../commands/player/PlayerCommandsMap.java | 2 ++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java index 49e4ba1022..f8f6c78981 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java @@ -62,15 +62,19 @@ public void registerCommand(SuperiorCommand superiorCommand, boolean sort) { } if (sort) { - List superiorCommands = new LinkedList<>(subCommands.values()); - superiorCommands.sort(Comparator.comparing(o -> o.getAliases().get(0))); - subCommands.clear(); - superiorCommands.forEach(s -> subCommands.put(s.getAliases().get(0), s)); + sortCommands(); } PluginEventsFactory.callCommandsUpdateEvent(); } + public void sortCommands() { + List superiorCommands = new LinkedList<>(subCommands.values()); + superiorCommands.sort(Comparator.comparing(o -> o.getAliases().get(0))); + subCommands.clear(); + superiorCommands.forEach(s -> subCommands.put(s.getAliases().get(0), s)); + } + public void unregisterCommand(SuperiorCommand superiorCommand) { Preconditions.checkNotNull(superiorCommand, "superiorCommand parameter cannot be null."); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java index 0552d47feb..c7c7741a56 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java @@ -78,6 +78,8 @@ public void loadDefaultCommands() { registerCommand(new CmdAdminTitleAll(), false); registerCommand(new CmdAdminUnignore(), false); registerCommand(new CmdAdminUnlockWorld(), false); + + sortCommands(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java index 9af88803b1..4dca66018b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java @@ -65,6 +65,8 @@ public void loadDefaultCommands() { registerCommand(new CmdVisitors(), false); registerCommand(new CmdWarp(), false); registerCommand(new CmdWarps(), false); + + sortCommands(); } } From 517d761eaa3cbe56595e0bdd2286a45c52d5222c Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 4 May 2025 18:47:47 +0300 Subject: [PATCH 159/600] Use TreeMaps to store commands in memory --- .../commands/CommandsManagerImpl.java | 19 ++- .../commands/CommandsMap.java | 18 +-- .../commands/admin/AdminCommandsMap.java | 132 +++++++++--------- .../commands/player/PlayerCommandsMap.java | 104 +++++++------- 4 files changed, 127 insertions(+), 146 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java index 3abc6e861e..e750290612 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java @@ -86,7 +86,13 @@ public void loadData() { @Override public void registerCommand(SuperiorCommand superiorCommand) { Preconditions.checkNotNull(superiorCommand, "superiorCommand parameter cannot be null."); - registerCommand(superiorCommand, true); + + if (pendingCommands != null) { + pendingCommands.add(() -> registerCommand(superiorCommand)); + return; + } + + playerCommandsMap.registerCommand(superiorCommand); } @Override @@ -102,7 +108,7 @@ public void registerAdminCommand(SuperiorCommand superiorCommand) { } Preconditions.checkNotNull(superiorCommand, "superiorCommand parameter cannot be null."); - adminCommandsMap.registerCommand(superiorCommand, true); + adminCommandsMap.registerCommand(superiorCommand); } @Override @@ -170,15 +176,6 @@ public String getLabel() { return label; } - public void registerCommand(SuperiorCommand superiorCommand, boolean sort) { - if (pendingCommands != null) { - pendingCommands.add(() -> registerCommand(superiorCommand, sort)); - return; - } - - playerCommandsMap.registerCommand(superiorCommand, sort); - } - @SuppressWarnings("ResultOfMethodCallIgnored") private void loadCommands() { File commandsFolder = new File(plugin.getDataFolder(), "commands"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java index f8f6c78981..4e0c52ad6a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java @@ -10,15 +10,14 @@ import com.google.common.base.Preconditions; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.TreeMap; public abstract class CommandsMap { @@ -38,7 +37,7 @@ public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CommandsMap::onSettingsUpdate); } - private final Map subCommands = new LinkedHashMap<>(); + private final Map subCommands = new TreeMap<>(); private final Map> aliasesToCommand = new HashMap<>(); protected final SuperiorSkyblockPlugin plugin; @@ -49,7 +48,7 @@ protected CommandsMap(SuperiorSkyblockPlugin plugin) { public abstract void loadDefaultCommands(); - public void registerCommand(SuperiorCommand superiorCommand, boolean sort) { + public void registerCommand(SuperiorCommand superiorCommand) { List aliases = new LinkedList<>(superiorCommand.getAliases()); String label = aliases.remove(0).toLowerCase(Locale.ENGLISH); aliases.addAll(plugin.getSettings().getCommandAliases().getOrDefault(label, Collections.emptyList())); @@ -61,20 +60,9 @@ public void registerCommand(SuperiorCommand superiorCommand, boolean sort) { aliasesToCommand.computeIfAbsent(alias.toLowerCase(Locale.ENGLISH), a -> new LinkedList<>()).add(superiorCommand); } - if (sort) { - sortCommands(); - } - PluginEventsFactory.callCommandsUpdateEvent(); } - public void sortCommands() { - List superiorCommands = new LinkedList<>(subCommands.values()); - superiorCommands.sort(Comparator.comparing(o -> o.getAliases().get(0))); - subCommands.clear(); - superiorCommands.forEach(s -> subCommands.put(s.getAliases().get(0), s)); - } - public void unregisterCommand(SuperiorCommand superiorCommand) { Preconditions.checkNotNull(superiorCommand, "superiorCommand parameter cannot be null."); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java index c7c7741a56..972b525db7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java @@ -11,75 +11,73 @@ public AdminCommandsMap(SuperiorSkyblockPlugin plugin) { @Override public void loadDefaultCommands() { - registerCommand(new CmdAdminAdd(), false); - registerCommand(new CmdAdminAddBlockLimit(), false); - registerCommand(new CmdAdminAddBonus(), false); + registerCommand(new CmdAdminAdd()); + registerCommand(new CmdAdminAddBlockLimit()); + registerCommand(new CmdAdminAddBonus()); if (plugin.getSettings().isCoopMembers()) - registerCommand(new CmdAdminAddCoopLimit(), false); - registerCommand(new CmdAdminAddDisbands(), false); - registerCommand(new CmdAdminAddEntityLimit(), false); - registerCommand(new CmdAdminAddSize(), false); - registerCommand(new CmdAdminAddTeamLimit(), false); - registerCommand(new CmdAdminAddWarpsLimit(), false); - registerCommand(new CmdAdminBypass(), false); - registerCommand(new CmdAdminChest(), false); - registerCommand(new CmdAdminClose(), false); - registerCommand(new CmdAdminCmdAll(), false); - registerCommand(new CmdAdminCount(), false); - registerCommand(new CmdAdminData(), false); - registerCommand(new CmdAdminDebug(), false); - registerCommand(new CmdAdminDelWarp(), false); - registerCommand(new CmdAdminDemote(), false); - registerCommand(new CmdAdminDisband(), false); - registerCommand(new CmdAdminIgnore(), false); - registerCommand(new CmdAdminJoin(), false); - registerCommand(new CmdAdminKick(), false); - registerCommand(new CmdAdminModules(), false); - registerCommand(new CmdAdminMsg(), false); - registerCommand(new CmdAdminMsgAll(), false); - registerCommand(new CmdAdminName(), false); - registerCommand(new CmdAdminOpen(), false); - registerCommand(new CmdAdminOpenMenu(), false); - registerCommand(new CmdAdminPromote(), false); - registerCommand(new CmdAdminPurge(), false); - registerCommand(new CmdAdminRecalc(), false); - registerCommand(new CmdAdminReload(), false); - registerCommand(new CmdAdminRemoveBlockLimit(), false); - registerCommand(new CmdAdminRemoveRatings(), false); - registerCommand(new CmdAdminResetWorld(), false); - registerCommand(new CmdAdminSchematic(), false); - registerCommand(new CmdAdminSetBankLimit(), false); - registerCommand(new CmdAdminSetBiome(), false); - registerCommand(new CmdAdminSetBlockAmount(), false); - registerCommand(new CmdAdminSetBlockLimit(), false); - registerCommand(new CmdAdminSetBonus(), false); - registerCommand(new CmdAdminSetChestRow(), false); + registerCommand(new CmdAdminAddCoopLimit()); + registerCommand(new CmdAdminAddDisbands()); + registerCommand(new CmdAdminAddEntityLimit()); + registerCommand(new CmdAdminAddSize()); + registerCommand(new CmdAdminAddTeamLimit()); + registerCommand(new CmdAdminAddWarpsLimit()); + registerCommand(new CmdAdminBypass()); + registerCommand(new CmdAdminChest()); + registerCommand(new CmdAdminClose()); + registerCommand(new CmdAdminCmdAll()); + registerCommand(new CmdAdminCount()); + registerCommand(new CmdAdminData()); + registerCommand(new CmdAdminDebug()); + registerCommand(new CmdAdminDelWarp()); + registerCommand(new CmdAdminDemote()); + registerCommand(new CmdAdminDisband()); + registerCommand(new CmdAdminIgnore()); + registerCommand(new CmdAdminJoin()); + registerCommand(new CmdAdminKick()); + registerCommand(new CmdAdminModules()); + registerCommand(new CmdAdminMsg()); + registerCommand(new CmdAdminMsgAll()); + registerCommand(new CmdAdminName()); + registerCommand(new CmdAdminOpen()); + registerCommand(new CmdAdminOpenMenu()); + registerCommand(new CmdAdminPromote()); + registerCommand(new CmdAdminPurge()); + registerCommand(new CmdAdminRecalc()); + registerCommand(new CmdAdminReload()); + registerCommand(new CmdAdminRemoveBlockLimit()); + registerCommand(new CmdAdminRemoveRatings()); + registerCommand(new CmdAdminResetWorld()); + registerCommand(new CmdAdminSchematic()); + registerCommand(new CmdAdminSetBankLimit()); + registerCommand(new CmdAdminSetBiome()); + registerCommand(new CmdAdminSetBlockAmount()); + registerCommand(new CmdAdminSetBlockLimit()); + registerCommand(new CmdAdminSetBonus()); + registerCommand(new CmdAdminSetChestRow()); if (plugin.getSettings().isCoopMembers()) - registerCommand(new CmdAdminSetCoopLimit(), false); - registerCommand(new CmdAdminSetDisbands(), false); - registerCommand(new CmdAdminSetEntityLimit(), false); - registerCommand(new CmdAdminSetLeader(), false); - registerCommand(new CmdAdminSetPermission(), false); - registerCommand(new CmdAdminSetRate(), false); - registerCommand(new CmdAdminSetRoleLimit(), false); - registerCommand(new CmdAdminSetSettings(), false); - registerCommand(new CmdAdminSetSize(), false); - registerCommand(new CmdAdminSetSpawn(), false); - registerCommand(new CmdAdminSetTeamLimit(), false); - registerCommand(new CmdAdminSettings(), false); - registerCommand(new CmdAdminSetWarpsLimit(), false); - registerCommand(new CmdAdminShow(), false); - registerCommand(new CmdAdminSpawn(), false); - registerCommand(new CmdAdminSpy(), false); - registerCommand(new CmdAdminStats(), false); - registerCommand(new CmdAdminSyncBonus(), false); - registerCommand(new CmdAdminTeleport(), false); - registerCommand(new CmdAdminTitle(), false); - registerCommand(new CmdAdminTitleAll(), false); - registerCommand(new CmdAdminUnignore(), false); - registerCommand(new CmdAdminUnlockWorld(), false); - - sortCommands(); + registerCommand(new CmdAdminSetCoopLimit()); + registerCommand(new CmdAdminSetDisbands()); + registerCommand(new CmdAdminSetEntityLimit()); + registerCommand(new CmdAdminSetLeader()); + registerCommand(new CmdAdminSetPermission()); + registerCommand(new CmdAdminSetRate()); + registerCommand(new CmdAdminSetRoleLimit()); + registerCommand(new CmdAdminSetSettings()); + registerCommand(new CmdAdminSetSize()); + registerCommand(new CmdAdminSetSpawn()); + registerCommand(new CmdAdminSetTeamLimit()); + registerCommand(new CmdAdminSettings()); + registerCommand(new CmdAdminSetWarpsLimit()); + registerCommand(new CmdAdminShow()); + registerCommand(new CmdAdminSpawn()); + registerCommand(new CmdAdminSpy()); + registerCommand(new CmdAdminStats()); + registerCommand(new CmdAdminSyncBonus()); + registerCommand(new CmdAdminTeleport()); + registerCommand(new CmdAdminTitle()); + registerCommand(new CmdAdminTitleAll()); + registerCommand(new CmdAdminUnignore()); + registerCommand(new CmdAdminUnlockWorld()); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java index 4dca66018b..e32abd21ab 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java @@ -11,62 +11,60 @@ public PlayerCommandsMap(SuperiorSkyblockPlugin plugin) { @Override public void loadDefaultCommands() { - registerCommand(new CmdAccept(), false); - registerCommand(new CmdAdmin(), false); - registerCommand(new CmdBan(), false); - registerCommand(new CmdBiome(), false); - registerCommand(new CmdBorder(), false); - registerCommand(new CmdChest(), false); - registerCommand(new CmdClose(), false); + registerCommand(new CmdAccept()); + registerCommand(new CmdAdmin()); + registerCommand(new CmdBan()); + registerCommand(new CmdBiome()); + registerCommand(new CmdBorder()); + registerCommand(new CmdChest()); + registerCommand(new CmdClose()); if (plugin.getSettings().isCoopMembers()) { - registerCommand(new CmdCoop(), false); - registerCommand(new CmdCoops(), false); + registerCommand(new CmdCoop()); + registerCommand(new CmdCoops()); } - registerCommand(new CmdCounts(), false); - registerCommand(new CmdCreate(), false); - registerCommand(new CmdDelWarp(), false); - registerCommand(new CmdDemote(), false); - registerCommand(new CmdDisband(), false); - registerCommand(new CmdExpel(), false); - registerCommand(new CmdFly(), false); - registerCommand(new CmdHelp(), false); - registerCommand(new CmdInvite(), false); - registerCommand(new CmdKick(), false); - registerCommand(new CmdLang(), false); - registerCommand(new CmdLeave(), false); - registerCommand(new CmdMembers(), false); - registerCommand(new CmdName(), false); - registerCommand(new CmdOpen(), false); - registerCommand(new CmdPanel(), false); - registerCommand(new CmdPardon(), false); - registerCommand(new CmdPermissions(), false); - registerCommand(new CmdPromote(), false); - registerCommand(new CmdRate(), false); - registerCommand(new CmdRatings(), false); - registerCommand(new CmdRecalc(), false); - registerCommand(new CmdSetDiscord(), false); - registerCommand(new CmdSetPaypal(), false); - registerCommand(new CmdSetRole(), false); - registerCommand(new CmdSetTeleport(), false); - registerCommand(new CmdSettings(), false); - registerCommand(new CmdSetWarp(), false); - registerCommand(new CmdShow(), false); - registerCommand(new CmdTeam(), false); - registerCommand(new CmdTeamChat(), false); - registerCommand(new CmdTeleport(), false); - registerCommand(new CmdToggle(), false); - registerCommand(new CmdTop(), false); - registerCommand(new CmdTransfer(), false); + registerCommand(new CmdCounts()); + registerCommand(new CmdCreate()); + registerCommand(new CmdDelWarp()); + registerCommand(new CmdDemote()); + registerCommand(new CmdDisband()); + registerCommand(new CmdExpel()); + registerCommand(new CmdFly()); + registerCommand(new CmdHelp()); + registerCommand(new CmdInvite()); + registerCommand(new CmdKick()); + registerCommand(new CmdLang()); + registerCommand(new CmdLeave()); + registerCommand(new CmdMembers()); + registerCommand(new CmdName()); + registerCommand(new CmdOpen()); + registerCommand(new CmdPanel()); + registerCommand(new CmdPardon()); + registerCommand(new CmdPermissions()); + registerCommand(new CmdPromote()); + registerCommand(new CmdRate()); + registerCommand(new CmdRatings()); + registerCommand(new CmdRecalc()); + registerCommand(new CmdSetDiscord()); + registerCommand(new CmdSetPaypal()); + registerCommand(new CmdSetRole()); + registerCommand(new CmdSetTeleport()); + registerCommand(new CmdSettings()); + registerCommand(new CmdSetWarp()); + registerCommand(new CmdShow()); + registerCommand(new CmdTeam()); + registerCommand(new CmdTeamChat()); + registerCommand(new CmdTeleport()); + registerCommand(new CmdToggle()); + registerCommand(new CmdTop()); + registerCommand(new CmdTransfer()); if (plugin.getSettings().isCoopMembers()) - registerCommand(new CmdUncoop(), false); - registerCommand(new CmdValue(), false); - registerCommand(new CmdValues(), false); - registerCommand(new CmdVisit(), false); - registerCommand(new CmdVisitors(), false); - registerCommand(new CmdWarp(), false); - registerCommand(new CmdWarps(), false); - - sortCommands(); + registerCommand(new CmdUncoop()); + registerCommand(new CmdValue()); + registerCommand(new CmdValues()); + registerCommand(new CmdVisit()); + registerCommand(new CmdVisitors()); + registerCommand(new CmdWarp()); + registerCommand(new CmdWarps()); } } From 0703a56ea584479c67c3be89dcace3ac4fe7c2da Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 4 May 2025 20:26:52 +0300 Subject: [PATCH 160/600] Do not cache hard references to PlayerRole (#2448) --- .../collections/view/Int2ObjectMapView.java | 10 +++ .../menu/button/impl/MemberRoleButton.java | 14 +-- .../superiorskyblock/island/SIsland.java | 88 +++++++++++++------ .../island/builder/IslandBuilderImpl.java | 29 ++++-- .../island/role/RolesManagerImpl.java | 2 + .../role/container/DefaultRolesContainer.java | 6 ++ .../island/role/container/RolesContainer.java | 2 + .../player/SSuperiorPlayer.java | 33 +++++-- 8 files changed, 137 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Int2ObjectMapView.java b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Int2ObjectMapView.java index 4f1db62d58..b4312ca323 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Int2ObjectMapView.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Int2ObjectMapView.java @@ -44,6 +44,16 @@ default V computeIfAbsent(int key, AbsentConsumer consumer) { return value; } + default void putAll(Int2ObjectMapView other) { + if (!other.isEmpty()) { + Iterator> iterator = other.entryIterator(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + put(entry.getKey(), entry.getValue()); + } + } + } + interface AbsentConsumer { V accept(int key); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberRoleButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberRoleButton.java index 3b697a05e0..22229184c1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberRoleButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberRoleButton.java @@ -32,7 +32,7 @@ public Template getTemplate() { public void onButtonClick(InventoryClickEvent clickEvent) { Player inventoryViewer = menuView.getInventoryViewer().asPlayer(); SuperiorPlayer targetPlayer = menuView.getSuperiorPlayer(); - PlayerRole playerRole = getTemplate().playerRole; + PlayerRole playerRole = plugin.getRoles().getPlayerRoleFromId(getTemplate().playerRoleId); if (playerRole.isLastRole()) { plugin.getCommands().dispatchSubCommand(inventoryViewer, "transfer", @@ -45,29 +45,29 @@ public void onButtonClick(InventoryClickEvent clickEvent) { public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { - private PlayerRole playerRole; + private int playerRoleId; public Builder setPlayerRole(PlayerRole playerRole) { - this.playerRole = playerRole; + this.playerRoleId = Objects.requireNonNull(playerRole, "playerRole cannot be null").getId(); return this; } @Override public MenuTemplateButton build() { - return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, playerRole); + return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, playerRoleId); } } public static class Template extends MenuTemplateButtonImpl { - private final PlayerRole playerRole; + private final int playerRoleId; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, - @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, PlayerRole playerRole) { + @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, int playerRoleId) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, MemberRoleButton.class, MemberRoleButton::new); - this.playerRole = Objects.requireNonNull(playerRole, "playerRole cannot be null"); + this.playerRoleId = playerRoleId; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 1d27d7b570..7c617815d1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -50,8 +50,10 @@ import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; +import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; @@ -123,6 +125,7 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -192,7 +195,7 @@ protected PlaceholdersService create() { private final Synchronized spawnerRates = Synchronized.of(DoubleValue.syncedFixed(-1D)); private final Synchronized mobDrops = Synchronized.of(DoubleValue.syncedFixed(-1D)); private final Synchronized> bankLimit = Synchronized.of(Value.syncedFixed(SYNCED_BANK_LIMIT_VALUE)); - private final Map roleLimits = new ConcurrentHashMap<>(); + private final Synchronized> roleLimits = Synchronized.of(CollectionsFactory.createInt2ObjectArrayMap()); private final Synchronized>> cobbleGeneratorValues = Synchronized.of(new EnumerateMap<>(Dimension.values())); private final Map islandEffects = new ConcurrentHashMap<>(); private final KeyMap blockLimits = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL); @@ -219,7 +222,7 @@ protected PlaceholdersService create() { */ private final Synchronized> islandHomes = Synchronized.of(new EnumerateMap<>(Dimension.values())); private final Synchronized> visitorHomes = Synchronized.of(new EnumerateMap<>(Dimension.values())); - private final Map rolePermissions = new ConcurrentHashMap<>(); + private final Map rolePermissions = new ConcurrentHashMap<>(); private final Map islandFlags = new ConcurrentHashMap<>(); private final IslandUpgrades upgrades = new IslandUpgrades(); private final AtomicReference islandWorth = new AtomicReference<>(BigDecimal.ZERO); @@ -305,7 +308,7 @@ public SIsland(IslandBuilderImpl builder) { islandChests[index] = SIslandChest.createChest(this, index, builder.islandChests.get(index)); } this.islandChests.set(islandChests); - this.roleLimits.putAll(builder.roleLimits); + this.roleLimits.write(roleLimits -> roleLimits.putAll(builder.roleLimits)); this.visitorHomes.set(builder.visitorHomes); this.islandSize.set(builder.islandSize); this.teamLimit.set(builder.teamLimit); @@ -1590,9 +1593,9 @@ public void setPermission(PlayerRole playerRole, IslandPrivilege islandPrivilege Log.debug(Debug.SET_PERMISSION, owner.getName(), playerRole, islandPrivilege); - PlayerRole oldRole = rolePermissions.put(islandPrivilege, playerRole); + Integer oldRoleId = rolePermissions.put(islandPrivilege, playerRole.getId()); - if (oldRole == playerRole) + if (oldRoleId != null && oldRoleId == playerRole.getId()) return; if (islandPrivilege == IslandPrivileges.FLY) { @@ -1684,10 +1687,10 @@ public PrivilegeNodeAbstract getPermissionNode(SuperiorPlayer superiorPlayer) { public PlayerRole getRequiredPlayerRole(IslandPrivilege islandPrivilege) { Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); - PlayerRole playerRole = rolePermissions.get(islandPrivilege); + Integer playerRoleId = rolePermissions.get(islandPrivilege); - if (playerRole != null) - return playerRole; + if (playerRoleId != null) + return plugin.getRoles().getPlayerRoleFromId(playerRoleId); return plugin.getRoles().getRoles().stream() .filter(_playerRole -> { @@ -1710,7 +1713,10 @@ public Map getPlayerPermissions() { @Override public Map getRolePermissions() { - return Collections.unmodifiableMap(rolePermissions); + return Collections.unmodifiableMap(this.rolePermissions.entrySet().stream().collect(Collectors.toMap( + Map.Entry::getKey, + entry -> plugin.getRoles().getPlayerRoleFromId(entry.getValue()) + ))); } @Override @@ -3473,7 +3479,8 @@ public void setRoleLimit(PlayerRole playerRole, int limit) { Log.debug(Debug.SET_ROLE_LIMIT, owner.getName(), playerRole.getName(), limit); - IntValue oldRoleLimit = roleLimits.put(playerRole, IntValue.fixed(limit)); + IntValue oldRoleLimit = roleLimits.writeAndGet(roleLimits -> + roleLimits.put(playerRole.getId(), IntValue.fixed(limit))); if (limit == IntValue.getNonSynced(oldRoleLimit, -1)) return; @@ -3487,7 +3494,7 @@ public void removeRoleLimit(PlayerRole playerRole) { Log.debug(Debug.REMOVE_ROLE_LIMIT, owner.getName(), playerRole.getName()); - IntValue oldRoleLimit = roleLimits.remove(playerRole); + IntValue oldRoleLimit = roleLimits.writeAndGet(roleLimits -> roleLimits.remove(playerRole.getId())); if (oldRoleLimit == null) return; @@ -3498,27 +3505,49 @@ public void removeRoleLimit(PlayerRole playerRole) { @Override public int getRoleLimit(PlayerRole playerRole) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); - IntValue roleLimit = roleLimits.get(playerRole); + IntValue roleLimit = roleLimits.readAndGet(roleLimits -> roleLimits.get(playerRole.getId())); return roleLimit == null ? -1 : roleLimit.get(); } @Override public int getRoleLimitRaw(PlayerRole playerRole) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); - return IntValue.getNonSynced(roleLimits.get(playerRole), -1); + return IntValue.getNonSynced(roleLimits.readAndGet(roleLimits -> roleLimits.get(playerRole.getId())), -1); } @Override public Map getRoleLimits() { - return roleLimits.entrySet().stream().collect( - Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().get())); + if (this.roleLimits.readAndGet(Int2ObjectMapView::isEmpty)) + return Collections.emptyMap(); + + Map roleLimits = new HashMap<>(); + this.roleLimits.read(roleLimitsMap -> { + Iterator> iterator = roleLimitsMap.entryIterator(); + while (iterator.hasNext()) { + Int2ObjectMapView.Entry entry = iterator.next(); + roleLimits.put(plugin.getRoles().getPlayerRoleFromId(entry.getKey()), entry.getValue().get()); + } + }); + + return Collections.unmodifiableMap(roleLimits); } @Override public Map getCustomRoleLimits() { - return this.roleLimits.entrySet().stream() - .filter(entry -> !entry.getValue().isSynced()) - .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().get())); + if (this.roleLimits.readAndGet(Int2ObjectMapView::isEmpty)) + return Collections.emptyMap(); + + Map roleLimits = new HashMap<>(); + this.roleLimits.read(roleLimitsMap -> { + Iterator> iterator = roleLimitsMap.entryIterator(); + while (iterator.hasNext()) { + Int2ObjectMapView.Entry entry = iterator.next(); + if (!entry.getValue().isSynced()) + roleLimits.put(plugin.getRoles().getPlayerRoleFromId(entry.getKey()), entry.getValue().get()); + } + }); + + return Collections.unmodifiableMap(roleLimits); } @Override @@ -4995,9 +5024,14 @@ private void clearUpgrades(boolean overrideCustom) { .filter(entry -> overrideCustom || entry.getValue().isSynced()) .forEach(entry -> entry.setValue(IntValue.syncedFixed(-1))); - roleLimits.entrySet().stream() - .filter(entry -> overrideCustom || entry.getValue().isSynced()) - .forEach(entry -> entry.setValue(IntValue.syncedFixed(-1))); + roleLimits.write(roleLimits -> { + Iterator> iterator = roleLimits.entryIterator(); + while (iterator.hasNext()) { + Int2ObjectMapView.Entry entry = iterator.next(); + if (overrideCustom || entry.getValue().isSynced()) + entry.setValue(IntValue.syncedFixed(-1)); + } + }); if (overrideCustom) IslandsDatabaseBridge.clearIslandSettings(this); @@ -5114,11 +5148,13 @@ private void syncUpgrade(SUpgradeLevel upgradeLevel, boolean overrideCustom) { applyEffects(); } - for (Map.Entry entry : upgradeLevel.getRoleLimitsUpgradeValue().entrySet()) { - IntValue currentValue = roleLimits.get(entry.getKey()); - if (currentValue == null || ((overrideCustom || currentValue.isSynced()) && currentValue.get() < entry.getValue().get())) - roleLimits.put(entry.getKey(), entry.getValue()); - } + roleLimits.write(roleLimits -> { + for (Map.Entry entry : upgradeLevel.getRoleLimitsUpgradeValue().entrySet()) { + IntValue currentValue = roleLimits.get(entry.getKey().getId()); + if (currentValue == null || ((overrideCustom || currentValue.isSynced()) && currentValue.get() < entry.getValue().get())) + roleLimits.put(entry.getKey().getId(), entry.getValue()); + } + }); } private void updateIslandChests() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java index a2657beebe..6f8da343cc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java @@ -20,8 +20,10 @@ import com.bgsoftware.superiorskyblock.core.DirtyChunk; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.LegacyMasks; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; +import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.value.DoubleValue; @@ -42,7 +44,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.EnumMap; +import java.util.HashMap; import java.util.IdentityHashMap; +import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; @@ -82,7 +86,7 @@ public class IslandBuilderImpl implements Island.Builder { public final List members = new LinkedList<>(); public final List bannedPlayers = new LinkedList<>(); public final Map playerPermissions = new LinkedHashMap<>(); - public final Map rolePermissions = new LinkedHashMap<>(); + public final Map rolePermissions = new LinkedHashMap<>(); public final Map upgrades = new LinkedHashMap<>(); public final KeyMap blockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); public final Map ratings = new LinkedHashMap<>(); @@ -93,7 +97,7 @@ public class IslandBuilderImpl implements Island.Builder { public final KeyMap entityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); public final Map islandEffects = new LinkedHashMap<>(); public final List islandChests = new ArrayList<>(plugin.getSettings().getIslandChests().getDefaultPages()); - public final Map roleLimits = new LinkedHashMap<>(); + public final Int2ObjectMapView roleLimits = CollectionsFactory.createInt2ObjectArrayMap(); public final EnumerateMap visitorHomes = new EnumerateMap<>(Dimension.values()); public IntValue islandSize = IntValue.syncedFixed(-1); public IntValue warpsLimit = IntValue.syncedFixed(-1); @@ -446,13 +450,16 @@ public Map getPlayerPermissions() { public Island.Builder setRolePermission(IslandPrivilege islandPrivilege, PlayerRole requiredRole) { Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); Preconditions.checkNotNull(requiredRole, "requiredRole parameter cannot be null."); - this.rolePermissions.put(islandPrivilege, requiredRole); + this.rolePermissions.put(islandPrivilege, requiredRole.getId()); return this; } @Override public Map getRolePermissions() { - return Collections.unmodifiableMap(this.rolePermissions); + return Collections.unmodifiableMap(this.rolePermissions.entrySet().stream().collect(Collectors.toMap( + Map.Entry::getKey, + entry -> plugin.getRoles().getPlayerRoleFromId(entry.getValue()) + ))); } @Override @@ -648,13 +655,23 @@ public List getIslandChests() { @Override public Island.Builder setRoleLimit(PlayerRole playerRole, int limit) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); - this.roleLimits.put(playerRole, limit < 0 ? IntValue.syncedFixed(limit) : IntValue.fixed(limit)); + this.roleLimits.put(playerRole.getId(), limit < 0 ? IntValue.syncedFixed(limit) : IntValue.fixed(limit)); return this; } @Override public Map getRoleLimits() { - return Collections.unmodifiableMap(IntValue.unboxMap(this.roleLimits)); + if (this.roleLimits.isEmpty()) + return Collections.emptyMap(); + + Map roleLimits = new HashMap<>(); + Iterator> iterator = this.roleLimits.entryIterator(); + while (iterator.hasNext()) { + Int2ObjectMapView.Entry entry = iterator.next(); + roleLimits.put(plugin.getRoles().getPlayerRoleFromId(entry.getKey()), entry.getValue().get()); + } + + return Collections.unmodifiableMap(roleLimits); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/role/RolesManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/role/RolesManagerImpl.java index 97772da624..92546d683a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/role/RolesManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/role/RolesManagerImpl.java @@ -28,6 +28,8 @@ public RolesManagerImpl(SuperiorSkyblockPlugin plugin, RolesContainer rolesConta @Override public void loadData() throws ManagerLoadException { + this.rolesContainer.clearRoles(); + ConfigurationSection rolesSection = plugin.getSettings().getIslandRoles().getSection(); ConfigurationSection guestSection = rolesSection.getConfigurationSection("guest"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/role/container/DefaultRolesContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/role/container/DefaultRolesContainer.java index 4e09fadb54..487a75e3fc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/role/container/DefaultRolesContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/role/container/DefaultRolesContainer.java @@ -54,4 +54,10 @@ public void addPlayerRole(PlayerRole playerRole) { this.rolesByName.put(playerRole.getName().toUpperCase(Locale.ENGLISH), playerRole); } + @Override + public void clearRoles() { + this.rolesByWeight.clear(); + this.rolesById.clear(); + this.rolesByName.clear(); + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/role/container/RolesContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/role/container/RolesContainer.java index 0bfa2ef84b..52a964ac43 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/role/container/RolesContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/role/container/RolesContainer.java @@ -19,4 +19,6 @@ public interface RolesContainer { void addPlayerRole(PlayerRole playerRole); + void clearRoles(); + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index 3951f5ce5a..a35beecee1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -25,7 +25,6 @@ import com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.bgsoftware.superiorskyblock.mission.MissionData; @@ -44,6 +43,7 @@ import org.bukkit.inventory.InventoryView; import org.bukkit.scheduler.BukkitTask; +import java.lang.ref.WeakReference; import java.util.Collections; import java.util.EnumSet; import java.util.LinkedHashMap; @@ -74,7 +74,8 @@ public class SSuperiorPlayer implements SuperiorPlayer { private Island playerIsland = null; private String name; private String textureValue; - private PlayerRole playerRole; + private WeakReference playerRole; + private int playerRoleId; private java.util.Locale userLocale; private boolean worldBorderEnabled; @@ -98,7 +99,7 @@ public class SSuperiorPlayer implements SuperiorPlayer { public SSuperiorPlayer(SuperiorPlayerBuilderImpl builder) { this.uuid = builder.uuid; this.name = builder.name; - this.playerRole = builder.playerRole; + setPlayerRoleInternal(builder.playerRole); this.disbands = builder.disbands; this.userLocale = builder.locale; this.textureValue = builder.textureValue; @@ -503,7 +504,7 @@ public void setIsland(Island island) { this.playerIsland = island; if (this.playerIsland == null) { - this.playerRole = SPlayerRole.guestRole(); + setPlayerRoleInternal(null); } } @@ -531,8 +532,18 @@ public List getInvites() { @Override public PlayerRole getPlayerRole() { - if (playerRole == null || (this.playerIsland == null && this.playerRole != SPlayerRole.guestRole())) - setPlayerRole(SPlayerRole.guestRole()); + PlayerRole playerRole = this.playerRole.get(); + + if (playerRole == null) { + // Reference doesn't exist anymore, let's get it from roles manager again + playerRole = plugin.getRoles().getPlayerRoleFromId(this.playerRoleId); + this.playerRole = new WeakReference<>(playerRole); + } + + if (this.playerIsland == null && playerRole != SPlayerRole.guestRole()) { + setPlayerRoleInternal(null); + playerRole = this.playerRole.get(); + } return playerRole; } @@ -543,7 +554,7 @@ public void setPlayerRole(PlayerRole playerRole) { Log.debug(Debug.SET_PLAYER_ROLE, getName(), playerRole.getName()); - this.playerRole = playerRole; + setPlayerRoleInternal(playerRole); Island island = getIsland(); if (island != null && island.getOwner() != this) @@ -916,7 +927,7 @@ public void merge(SuperiorPlayer otherPlayer) { this.name = otherPlayer.getName(); this.playerIsland = otherPlayer.getIsland(); - this.playerRole = otherPlayer.getPlayerRole(); + setPlayerRoleInternal(otherPlayer.getPlayerRole()); this.userLocale = otherPlayer.getUserLocale(); this.worldBorderEnabled |= otherPlayer.hasWorldBorderEnabled(); this.blocksStackerEnabled |= otherPlayer.hasBlocksStackerEnabled(); @@ -1082,6 +1093,12 @@ public String toString() { "}"; } + private void setPlayerRoleInternal(@Nullable PlayerRole playerRole) { + PlayerRole newRole = playerRole == null ? SPlayerRole.guestRole() : playerRole; + this.playerRole = new WeakReference<>(newRole); + this.playerRoleId = newRole.getId(); + } + private static String removeTextureValueTimeStamp(@Nullable String textureValue) { // The texture value string is a json containing a timestamp value. // However, when we compare texture values, we want to emit the timestamp value. From 1efe1e17af96829a0d8ad0823f5708649398cee4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 4 May 2025 21:09:07 +0300 Subject: [PATCH 161/600] Fixed protected message delay not updated upon reloading of the plugin (#2443) --- .../events/plugin/PluginEventsDispatcher.java | 2 ++ .../core/messages/Message.java | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java index cd3b5d228e..4ebd5e101d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.SpawnIsland; import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; @@ -37,6 +38,7 @@ public void registerDefaultListeners() { RegionManagerServiceImpl.registerCallbacks(this); CmdHelp.registerListeners(this); CmdAdmin.registerCallbacks(this); + Message.registerListeners(this); } public void registerCallback(PluginEventType type, Runnable callback) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 8481372009..bded3d9fd0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -14,6 +14,8 @@ import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.io.Files; @@ -30,11 +32,9 @@ import java.io.File; import java.io.InputStream; -import java.math.BigDecimal; import java.util.Collection; import java.util.Locale; import java.util.Map; -import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -790,10 +790,6 @@ public void send(CommandSender sender, Locale locale, Object... objects) { }, PROTECTION(true) { - - @Nullable - private Collection noInteractMessages; - @Override public void send(CommandSender sender, Locale locale, Object... args) { if (!(sender instanceof Player)) @@ -836,6 +832,9 @@ protected MessagesService create() { } }; + @Nullable + private static Collection noInteractMessages; + private final String defaultMessage; private final boolean isCustom; private final Map messages = new ArrayMap<>(); @@ -999,4 +998,12 @@ private static void convertOldFile() { } } + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, Message::onSettingsUpdate); + } + + private static void onSettingsUpdate() { + noInteractMessages = null; + } + } From 275a9257dd67bc94689a5362fc610f4603cf8e84 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 4 May 2025 21:12:51 +0300 Subject: [PATCH 162/600] Updated the comment for default-blocks-stacker in config (#2441) --- src/main/resources/config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 6fb648803e..6fc023a6ba 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -711,7 +711,8 @@ default-language: 'en-US' # Should world borders be enabled by default for new players? default-world-border: true -# Should blocks stacking be enabled by default for new players? +# Should blocks stacking be enabled by default for players? +# The blocks stacking will reset every restart for all players to this value. default-blocks-stacker: true # Should panels be toggled by default for new players? From 79f93ccb20153a4e65c98cb0833344406ca290b1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 May 2025 12:38:20 +0300 Subject: [PATCH 163/600] Potential fix for ghost generator blocks (#2373) --- .../nms/v1_21_3/NMSUtils.java | 28 +++++++++++++------ .../nms/v1_21_4/NMSUtils.java | 28 +++++++++++++------ .../nms/v1_21_5/NMSUtils.java | 28 +++++++++++++------ 3 files changed, 60 insertions(+), 24 deletions(-) diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java index 9954abb664..dcdf787282 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java @@ -27,6 +27,7 @@ import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.tags.BlockTags; import net.minecraft.world.entity.Entity; @@ -57,6 +58,7 @@ import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.io.IOException; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Collections; @@ -67,13 +69,22 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; +import java.util.function.Supplier; public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectMethod SEND_PACKETS_TO_RELEVANT_PLAYERS = new ReflectMethod<>( - ChunkHolder.class, 1, Packet.class, boolean.class); + private static final boolean MOONRISE_SUPPORT = ((Supplier) () -> { + for (Method method : ChunkHolder.class.getDeclaredMethods()) { + if (method.getName().contains("moonrise$")) { + return true; + } + } + + return false; + }).get(); + private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( @@ -326,19 +337,20 @@ public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chun ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); ChunkHolder chunkHolder; - try { + if (MOONRISE_SUPPORT) { chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); - } catch (Throwable ex) { + } else { chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); } if (chunkHolder != null) { - if (SEND_PACKETS_TO_RELEVANT_PLAYERS.isValid()) { - SEND_PACKETS_TO_RELEVANT_PLAYERS.invoke(chunkHolder, packet, false); + List relevantPlayers; + if (MOONRISE_SUPPORT) { + relevantPlayers = chunkHolder.moonrise$getPlayers(false); } else { - chunkHolder.playerProvider.getPlayers(chunkPos, false).forEach(serverPlayer -> - serverPlayer.connection.send(packet)); + relevantPlayers = chunkHolder.playerProvider.getPlayers(chunkPos, false); } + relevantPlayers.forEach(serverPlayer -> serverPlayer.connection.send(packet)); } } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java index ba96213ca7..430df64841 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java @@ -27,6 +27,7 @@ import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.tags.BlockTags; import net.minecraft.world.entity.Entity; @@ -57,6 +58,7 @@ import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.io.IOException; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Collections; @@ -67,13 +69,22 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; +import java.util.function.Supplier; public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectMethod SEND_PACKETS_TO_RELEVANT_PLAYERS = new ReflectMethod<>( - ChunkHolder.class, 1, Packet.class, boolean.class); + private static final boolean MOONRISE_SUPPORT = ((Supplier) () -> { + for (Method method : ChunkHolder.class.getDeclaredMethods()) { + if (method.getName().contains("moonrise$")) { + return true; + } + } + + return false; + }).get(); + private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( @@ -326,19 +337,20 @@ public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chun ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); ChunkHolder chunkHolder; - try { + if (MOONRISE_SUPPORT) { chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); - } catch (Throwable ex) { + } else { chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); } if (chunkHolder != null) { - if (SEND_PACKETS_TO_RELEVANT_PLAYERS.isValid()) { - SEND_PACKETS_TO_RELEVANT_PLAYERS.invoke(chunkHolder, packet, false); + List relevantPlayers; + if (MOONRISE_SUPPORT) { + relevantPlayers = chunkHolder.moonrise$getPlayers(false); } else { - chunkHolder.playerProvider.getPlayers(chunkPos, false).forEach(serverPlayer -> - serverPlayer.connection.send(packet)); + relevantPlayers = chunkHolder.playerProvider.getPlayers(chunkPos, false); } + relevantPlayers.forEach(serverPlayer -> serverPlayer.connection.send(packet)); } } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java index e65fcc3a0a..121fd079e7 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java @@ -27,6 +27,7 @@ import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.tags.BlockTags; import net.minecraft.world.entity.Entity; @@ -57,6 +58,7 @@ import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.io.IOException; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Collections; @@ -67,13 +69,22 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; +import java.util.function.Supplier; public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectMethod SEND_PACKETS_TO_RELEVANT_PLAYERS = new ReflectMethod<>( - ChunkHolder.class, 1, Packet.class, boolean.class); + private static final boolean MOONRISE_SUPPORT = ((Supplier) () -> { + for (Method method : ChunkHolder.class.getDeclaredMethods()) { + if (method.getName().contains("moonrise$")) { + return true; + } + } + + return false; + }).get(); + private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( @@ -326,19 +337,20 @@ public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chun ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); ChunkHolder chunkHolder; - try { + if (MOONRISE_SUPPORT) { chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); - } catch (Throwable ex) { + } else { chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); } if (chunkHolder != null) { - if (SEND_PACKETS_TO_RELEVANT_PLAYERS.isValid()) { - SEND_PACKETS_TO_RELEVANT_PLAYERS.invoke(chunkHolder, packet, false); + List relevantPlayers; + if (MOONRISE_SUPPORT) { + relevantPlayers = chunkHolder.moonrise$getPlayers(false); } else { - chunkHolder.playerProvider.getPlayers(chunkPos, false).forEach(serverPlayer -> - serverPlayer.connection.send(packet)); + relevantPlayers = chunkHolder.playerProvider.getPlayers(chunkPos, false); } + relevantPlayers.forEach(serverPlayer -> serverPlayer.connection.send(packet)); } } From a47e4bb49b405d6221c3818d4a0aad8935129c39 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 May 2025 12:52:03 +0300 Subject: [PATCH 164/600] Fix empty messages are sent to players (#2453) --- .../bgsoftware/superiorskyblock/external/MiniMessageHook.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java index c619e5a32a..dd6c50dcfa 100644 --- a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java +++ b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java @@ -3,8 +3,10 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.service.message.MessagesService; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.MessageContent; +import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; @@ -43,6 +45,8 @@ private static Optional parseMiniMessage(YamlConfiguration co return Optional.empty(); String content = config.getString(path); + if (Text.isBlank(content)) + return Optional.of(EmptyMessageComponent.getInstance()); try { Component component = MINI_MESSAGE.deserialize(Formatters.COLOR_FORMATTER.format(content)); From eff15c92a7654a01592ed5ad5b11f01d89fb6cfe Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 May 2025 12:52:37 +0300 Subject: [PATCH 165/600] Fix empty messages are sent to players (#2453) --- .../bgsoftware/superiorskyblock/external/MiniMessageHook.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java index dd6c50dcfa..c71946f831 100644 --- a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java +++ b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java @@ -6,7 +6,6 @@ import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.MessageContent; -import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.TextComponent; @@ -46,7 +45,7 @@ private static Optional parseMiniMessage(YamlConfiguration co String content = config.getString(path); if (Text.isBlank(content)) - return Optional.of(EmptyMessageComponent.getInstance()); + return Optional.empty(); try { Component component = MINI_MESSAGE.deserialize(Formatters.COLOR_FORMATTER.format(content)); From 680cf2c8301cb7641bce94fc250ac72dfa2979d8 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 May 2025 13:34:07 +0300 Subject: [PATCH 166/600] Fixed visit location is not removed properly when signs break (#2413) --- .../superiorskyblock/listener/SignsListener.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java index c0a8fc51e2..43d180104e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java @@ -3,6 +3,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; @@ -89,7 +90,7 @@ private void onSignBreak(GameEvent e) { island = plugin.getGrid().getIslandAt(e.getArgs().block.getLocation(wrapper.getHandle())); } - if (island == null || island.getIslandWarps().isEmpty()) + if (!isValidIsland(island)) return; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); @@ -108,7 +109,7 @@ private void onSignExplode(GameEvent e) { island = plugin.getGrid().getIslandAt(e.getArgs().entity.getLocation(wrapper.getHandle())); } - if (island == null || island.getIslandWarps().isEmpty()) + if (!isValidIsland(island)) return; Iterator iterator = e.getArgs().blocks.iterator(); @@ -172,4 +173,8 @@ private void registerListeners() { registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.MONITOR, this::onSignExplode); } + private static boolean isValidIsland(Island island) { + return island == null || (island.getIslandWarps().isEmpty() && island.getVisitorsLocation((Dimension) null) == null); + } + } From 18a8826b842bf4ba6c7f986d88f0c3a053b65af2 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 May 2025 14:07:06 +0300 Subject: [PATCH 167/600] Fixed detection of warps by their location (#2424) --- .../core/collections/AutoRemovalMap.java | 6 ++- .../superiorskyblock/island/SIsland.java | 37 ++++++++++--------- .../listener/SignsListener.java | 2 +- .../type/UpgradeTypeEntityLimits.java | 24 ++++-------- 4 files changed, 34 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/AutoRemovalMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/AutoRemovalMap.java index c6fec2f46e..49d3bc70cc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/AutoRemovalMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/AutoRemovalMap.java @@ -21,7 +21,11 @@ public class AutoRemovalMap implements Map { private final Cache elementsLifeTime; public static AutoRemovalMap newHashMap(long removalDelay, TimeUnit timeUnit) { - return new AutoRemovalMap<>(removalDelay, timeUnit, HashMap::new); + return newMap(removalDelay, timeUnit, HashMap::new); + } + + public static AutoRemovalMap newMap(long removalDelay, TimeUnit timeUnit, Supplier> mapSupplier) { + return new AutoRemovalMap<>(removalDelay, timeUnit, mapSupplier); } private AutoRemovalMap(long removalDelay, TimeUnit timeUnit, Supplier> mapSupplier) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 7c617815d1..bef5e50ae0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -53,6 +53,7 @@ import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; +import com.bgsoftware.superiorskyblock.core.collections.Location2ObjectMap; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; @@ -125,7 +126,6 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; -import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -215,7 +215,7 @@ protected PlaceholdersService create() { * Island Warps */ private final Map warpsByName = new ConcurrentHashMap<>(); - private final Map warpsByLocation = new ConcurrentHashMap<>(); + private final Synchronized> warpsByLocation = Synchronized.of(new Location2ObjectMap<>()); private final Map warpCategories = new ConcurrentHashMap<>(); /* * General Settings @@ -3668,9 +3668,8 @@ public void renameWarp(IslandWarp islandWarp, String newName) { @Override public IslandWarp getWarp(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); - try (LocationKey locationKey = LocationKey.of(location)) { - return warpsByLocation.get(locationKey); - } + Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); + return this.warpsByLocation.readAndGet(warpsByLocation -> warpsByLocation.get(location)); } @Override @@ -3714,17 +3713,18 @@ public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean f @Override public void deleteWarp(@Nullable SuperiorPlayer superiorPlayer, Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); + Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); - IslandWarp islandWarp; - try (LocationKey locationKey = LocationKey.of(location)) { - islandWarp = warpsByLocation.remove(locationKey); - } + IslandWarp islandWarp = this.warpsByLocation.writeAndGet( + warpsByLocation -> warpsByLocation.remove(location)); - if (islandWarp != null) { - deleteWarp(islandWarp.getName()); - if (superiorPlayer != null) - Message.DELETE_WARP.send(superiorPlayer, islandWarp.getName()); - } + if (islandWarp == null) + return; + + deleteWarp(islandWarp.getName()); + + if (superiorPlayer != null) + Message.DELETE_WARP.send(superiorPlayer, islandWarp.getName()); } @Override @@ -3737,9 +3737,11 @@ public void deleteWarp(String name) { WarpCategory warpCategory = islandWarp == null ? null : islandWarp.getCategory(); if (islandWarp != null) { - try (LocationKey locationKey = LocationKey.of(islandWarp)) { - warpsByLocation.remove(locationKey); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = islandWarp.getLocation(wrapper.getHandle()); + this.warpsByLocation.write(warpsByLocation -> warpsByLocation.remove(location)); } + warpCategory.getWarps().remove(islandWarp); IslandsDatabaseBridge.removeWarp(this, islandWarp); @@ -4569,7 +4571,8 @@ public IslandWarp loadIslandWarp(String name, LazyWorldLocation location, @Nulla warpsByName.put(warpName, islandWarp); - warpsByLocation.put(LocationKey.of(location, false), islandWarp); + this.warpsByLocation.write(warpsByLocation -> + warpsByLocation.put(location, islandWarp)); return islandWarp; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java index 43d180104e..9d1b677e1c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java @@ -174,7 +174,7 @@ private void registerListeners() { } private static boolean isValidIsland(Island island) { - return island == null || (island.getIslandWarps().isEmpty() && island.getVisitorsLocation((Dimension) null) == null); + return island != null && (!island.getIslandWarps().isEmpty() || island.getVisitorsLocation((Dimension) null) != null); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java index 2563ae6d37..3dbb1bd0a3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java @@ -4,12 +4,12 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; -import com.bgsoftware.superiorskyblock.core.LocationKey; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalMap; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.Location2ObjectMap; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; @@ -47,7 +47,7 @@ public class UpgradeTypeEntityLimits implements IUpgradeType { private final Map entityBreederPlayers = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS); - private final Map vehiclesOwners = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS); + private final Map vehiclesOwners = AutoRemovalMap.newMap(2, TimeUnit.SECONDS, Location2ObjectMap::new); private final Map spawnEggPlayers = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS); private final SuperiorSkyblockPlugin plugin; @@ -163,7 +163,6 @@ public void onVehicleSpawn(PlayerInteractEvent e) { if (!isMinecart && !isBoat) return; - LocationKey futureEntitySpawnLocation; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = e.getClickedBlock().getLocation(wrapper.getHandle()); Island island = plugin.getGrid().getIslandAt(blockLocation); @@ -171,12 +170,11 @@ public void onVehicleSpawn(PlayerInteractEvent e) { if (island == null) return; - futureEntitySpawnLocation = isMinecart ? LocationKey.of(blockLocation, false) : - LocationKey.of(blockLocation.getWorld().getName(), blockLocation.getX(), - blockLocation.getY() + 1, blockLocation.getZ(), false); - } + Location futureEntitySpawnLocation = isMinecart ? blockLocation : + blockLocation.add(0, 1, 0); - vehiclesOwners.put(futureEntitySpawnLocation, new SpawningPlayerData(e.getPlayer())); + vehiclesOwners.put(futureEntitySpawnLocation, new SpawningPlayerData(e.getPlayer())); + } } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) @@ -188,7 +186,7 @@ public void onVehicleSpawn(VehicleCreateEvent e) { return; Island island; - LocationKey entityBlockLocation; + SpawningPlayerData vehicleOwnerData; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); @@ -197,15 +195,9 @@ public void onVehicleSpawn(VehicleCreateEvent e) { if (island == null) return; - entityBlockLocation = LocationKey.of( - entityLocation.getWorld().getName(), - entityLocation.getBlockX(), - entityLocation.getBlockY(), - entityLocation.getBlockZ() - ); + vehicleOwnerData = vehiclesOwners.remove(entityLocation); } - SpawningPlayerData vehicleOwnerData = vehiclesOwners.remove(entityBlockLocation); Player vehicleOwner = vehicleOwnerData == null ? null : vehicleOwnerData.player.get(); boolean hasReachedLimit = island.hasReachedEntityLimit(Keys.of(entity)).join(); From 78502886a18ba2c2c70a7e57be50f1819124fe43 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 10 May 2025 10:57:50 +0300 Subject: [PATCH 168/600] Fixed schematics not removed after reload (#2458) --- .../superiorskyblock/SuperiorSkyblockPlugin.java | 3 ++- .../world/schematic/SchematicsManagerImpl.java | 8 ++++++++ .../schematic/container/DefaultSchematicsContainer.java | 5 +++++ .../world/schematic/container/SchematicsContainer.java | 2 ++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index 6a48661b9f..26bf8c54fd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -471,12 +471,13 @@ public void reloadPlugin(PluginReloadReason reloadReason) throws ManagerLoadExce if (reloadReason == PluginReloadReason.STARTUP) { playersHandler.loadData(); gridHandler.loadData(); + schematicsHandler.loadData(); } else { BukkitExecutor.sync(gridHandler::updateSpawn, 1L); gridHandler.syncUpgrades(); + schematicsHandler.loadSchematics(); } - schematicsHandler.loadData(); menusHandler.loadData(); missionsHandler.loadData(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index 777a41e61b..12702b4a53 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -85,6 +85,14 @@ public void loadData() throws ManagerLoadException { loadDefaultSchematicParsers(); + loadSchematics(); + } + + public void loadSchematics() throws ManagerLoadException { + this.schematicsContainer.clearSchematics(); + + File schematicsFolder = new File(plugin.getDataFolder(), "schematics"); + for (File schemFile : Files.listFolderFiles(schematicsFolder, false)) { String schemName = Files.getFileName(schemFile).toLowerCase(Locale.ENGLISH); Schematic schematic = loadFromFile(schemName, schemFile); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/DefaultSchematicsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/DefaultSchematicsContainer.java index 080055aa85..27ae003676 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/DefaultSchematicsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/DefaultSchematicsContainer.java @@ -43,4 +43,9 @@ public List getSchematicParsers() { return Collections.unmodifiableList(this.schematicParsers); } + @Override + public void clearSchematics() { + this.schematicMap.clear(); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/SchematicsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/SchematicsContainer.java index 13eab8bde9..1c76e4b9f8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/SchematicsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/SchematicsContainer.java @@ -19,4 +19,6 @@ public interface SchematicsContainer { List getSchematicParsers(); + void clearSchematics(); + } From 2404554aeaf66e4c661fc2eb72019da0bf5f6627 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 10 May 2025 11:04:09 +0300 Subject: [PATCH 169/600] Adds INVALID_MENU message to the openmenu command (#2459) --- .../commands/admin/CmdAdminOpenMenu.java | 13 ++++++++++--- .../superiorskyblock/core/messages/Message.java | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + 12 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpenMenu.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpenMenu.java index 4a5ef4a228..5fa79f1790 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpenMenu.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpenMenu.java @@ -62,9 +62,16 @@ public boolean supportMultiplePlayers() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { - Menu menu = plugin.getMenus().getMenu(MenuIdentifiers.MENU_CUSTOM_PREFIX + args[3]); - if (menu instanceof MenuCustom) - menu.createView(targetPlayer, EmptyViewArgs.INSTANCE); + String menuIdentifier = MenuIdentifiers.MENU_CUSTOM_PREFIX + args[3]; + + Menu menu = plugin.getMenus().getMenu(menuIdentifier); + + if (!(menu instanceof MenuCustom)) { + Message.INVALID_MENU.send(sender, menuIdentifier); + return; + } + + menu.createView(targetPlayer, EmptyViewArgs.INSTANCE); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index bded3d9fd0..cb1bbccede 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -430,6 +430,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { INVALID_LIMIT, INVALID_MATERIAL, INVALID_MATERIAL_DATA, + INVALID_MENU, INVALID_MISSION, INVALID_MODULE, INVALID_MULTIPLIER, diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 99b25beaf1..fc210bc53f 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -378,6 +378,7 @@ INVALID_LEVEL: '&c&lError | &7Invalid level {0}.' INVALID_LIMIT: '&c&lError | &7Invalid limit {0}.' INVALID_MATERIAL: '&c&lError | &7Invalid material {0}.' INVALID_MATERIAL_DATA: '&c&lError | &7Invalid material-data {0}.' +INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lError | &7Invalid mission {0}.' INVALID_MODULE: '&c&lError | &7Invalid module {0}.' INVALID_MULTIPLIER: '&c&lError | &7Invalid multiplier {0}.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index a76fd8429b..743d16e1b4 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -378,6 +378,7 @@ INVALID_LEVEL: '&c&lError | &7Nivel {0} no válido.' INVALID_LIMIT: '&c&lError | &7Límite no válido {0}.' INVALID_MATERIAL: '&c&lError | &7Material no válido {0}.' INVALID_MATERIAL_DATA: '&c&lError | &7Invalid material-data {0}.' +INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lError | &7Misión no válida {0}.' INVALID_MODULE: '&c&lError | &7Invalid module {0}.' INVALID_MULTIPLIER: '&c&lError | &7Multiplicador no válido {0}.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index cef5a8f95f..988cd9287d 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -379,6 +379,7 @@ INVALID_LEVEL: '&c&lErreur | &7Niveau invalide: {0}.' INVALID_LIMIT: '&c&lErreur | &7Limite invalide: {0}.' INVALID_MATERIAL: '&c&lErreur | &7Matériau invalide: {0}.' INVALID_MATERIAL_DATA: '&c&lErreur | &7Donnée de matériau {0} invalide.' +INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lErreur | &7Mission {0} invalide.' INVALID_MODULE: '&c&lErreur | &7Module {0} invalide.' INVALID_MULTIPLIER: '&c&lErreur | &7Multiplicateur invalide: {0}.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index abdf1e21f1..3d5886aaba 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -382,6 +382,7 @@ INVALID_LEVEL: '&c&lErrore | &7Livello non valido {0}.' INVALID_LIMIT: '&c&lErrore | &7Limite non valido {0}.' INVALID_MATERIAL: '&c&lErrore | &7Materiale non valido {0}.' INVALID_MATERIAL_DATA: '&c&lErrore | &7Il material-data non è corretto {0}.' +INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lErrore | &7La missione {0} non è corretta.' INVALID_MODULE: '&c&lError | &7Modulo non valido: {0}' INVALID_MULTIPLIER: '&c&lErrore | &7Il moltiplicatore {0} non è corretto.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 8bc8a99a7b..c7b1c207e8 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -394,6 +394,7 @@ INVALID_LEVEL: '&c&lהאיגש | &7{0} תיקוח אל המר.' INVALID_LIMIT: '&c&lהאיגש | &7{0} תיקוח אל הלבגמ.' INVALID_MATERIAL: '&c&lהאיגש | &7{0} תיקוח אל רמוח.' INVALID_MATERIAL_DATA: '&c&lError | &7Invalid material-data {0}.' +INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lהאיגש | &7{0} תיקוח אל המישמ.' INVALID_MODULE: '&c&lError | &7Invalid module {0}.' INVALID_MULTIPLIER: '&c&lהאיגש | &7{0} יקוח אל סונוב.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 64dc7b9512..01b9e2463c 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -380,6 +380,7 @@ INVALID_LEVEL: '&c&lBlad | &7Nieprawidlowy poziom {0}.' INVALID_LIMIT: '&c&lBlad | &7Nieprawidlowy limit {0}.' INVALID_MATERIAL: '&c&lBlad | &7Nieprawidlowy material {0}.' INVALID_MATERIAL_DATA: '&c&lBlad | &7Nieprawidlowe dane materialu {0}.' +INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lBlad | &7Nieprawidlowa misja {0}.' INVALID_MODULE: '&c&lBlad | &7Nieprawidlowy modul {0}.' INVALID_MULTIPLIER: '&c&lBlad | &7Nieprawidlowy mnoznik {0}.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 54deb19ee7..32d3964763 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -378,6 +378,7 @@ INVALID_LEVEL: '&c&lErro | &7Nível inválido {0}.' INVALID_LIMIT: '&c&lErro | &7Limite inválido {0}.' INVALID_MATERIAL: '&c&lErro | &7Material inválido {0}.' INVALID_MATERIAL_DATA: '&c&lErro | &7Material-dados inválido {0}.' +INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lErro | &7Missão inválida {0}.' INVALID_MODULE: '&c&lErro | &7Módulo inválido {0}.' INVALID_MULTIPLIER: '&c&lErro | &7Multiplicador inválido {0}.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 88ce4dad59..74b470da07 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -378,6 +378,7 @@ INVALID_LEVEL: '&c&lОшибка | &7Недопустимый уровень {0} INVALID_LIMIT: '&c&lОшибка | &7Недопустимый лимит {0}.' INVALID_MATERIAL: '&c&lОшибка | &7Недопустимый материал {0}.' INVALID_MATERIAL_DATA: '&c&lОшибка | &7Недопустимые данные материала {0}.' +INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lОшибка | &7Недопустимая миссия {0}.' INVALID_MODULE: '&c&lОшибка | &7Недопустимый модуль {0}.' INVALID_MULTIPLIER: '&c&lОшибка | &7Недопустимый множитель {0}.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index b5fc6ea4b0..4289f8cb19 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -430,6 +430,7 @@ INVALID_LEVEL: '&c&lLỗi | &7Cấp độ không hợp lệ {0}.' INVALID_LIMIT: '&c&lLỗi | &7Giới hạn không hợp lệ {0}.' INVALID_MATERIAL: '&c&lLỗi | &7Vật liệu không hợp lệ {0}.' INVALID_MATERIAL_DATA: '&c&lLỗi | &7Dữ liệu-vật liệu không hợp lệ {0}.' +INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lLỗi | &7Nhiệm vụ không hợp lệ {0}.' INVALID_MODULE: '&c&lLỗi | &7Module không hợp lệ {0}.' INVALID_MULTIPLIER: '&c&lLỗi | &7Hệ số không hợp lệ {0}.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 90c4ffbe0f..ac798c5174 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -378,6 +378,7 @@ INVALID_LEVEL: '&c&l错误 | &7无效等级 {0}.' INVALID_LIMIT: '&c&l错误 | &7无效限制 {0}.' INVALID_MATERIAL: '&c&l错误 | &7无效材料名 {0}.' INVALID_MATERIAL_DATA: '&c&l错误 | &7无效材料数据 {0}.' +INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&l错误 | &7无效任务 {0}.' INVALID_MODULE: '&c&l错误 | &7无效模块 {0}.' INVALID_MULTIPLIER: '&c&l错误 | &7无效翻倍 {0}.' From bfa2f0f886a04e1aa61b793ce835549606156051 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 10 May 2025 11:23:15 +0300 Subject: [PATCH 170/600] Cache names of privileges, flags and others for messages & fix privileges not formatted correctly (#2460) --- .../superiorskyblock/api/enums/Rating.java | 14 ++++++++++---- .../commands/admin/CmdAdminSetPermission.java | 2 +- .../commands/admin/CmdAdminSetRoleLimit.java | 2 +- .../commands/arguments/CommandArguments.java | 17 ++++++----------- .../commands/player/CmdSetRole.java | 2 +- .../island/flag/IslandFlags.java | 18 ++++++++++++++++++ .../island/privilege/IslandPrivileges.java | 17 +++++++++++++++++ .../island/role/RolesManagerImpl.java | 2 ++ .../island/role/SPlayerRole.java | 18 ++++++++++++++---- .../island/upgrade/UpgradesManagerImpl.java | 14 ++++++++++++++ 10 files changed, 84 insertions(+), 22 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/Rating.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/Rating.java index 529f6d1f76..bda245f461 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/Rating.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/Rating.java @@ -1,6 +1,5 @@ package com.bgsoftware.superiorskyblock.api.enums; -import java.util.Arrays; import java.util.Locale; /** @@ -16,13 +15,20 @@ public enum Rating { FOUR_STARS, FIVE_STARS; + private static String ALL_RATING_NAMES; + /** * Get a string of all the rating names. */ public static String getValuesString() { - StringBuilder stringBuilder = new StringBuilder(); - Arrays.stream(values()).forEach(rating -> stringBuilder.append(", ").append(rating.toString().toLowerCase(Locale.ENGLISH))); - return stringBuilder.substring(2); + if (ALL_RATING_NAMES == null) { + StringBuilder namesBuilder = new StringBuilder(); + for (Rating rating : Rating.values()) + namesBuilder.append(", ").append(rating.toString().toLowerCase(Locale.ENGLISH)); + ALL_RATING_NAMES = namesBuilder.length() == 0 ? "" : namesBuilder.substring(2); + } + + return ALL_RATING_NAMES; } /** diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java index a452d08cc4..e66ed786e3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java @@ -79,7 +79,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; if (islandPrivilege.getType() == IslandPrivilege.Type.COMMAND && !playerRole.isRoleLadder()) { - Message.INVALID_ROLE.send(sender, args[4], SPlayerRole.getValuesString()); + Message.INVALID_ROLE.send(sender, args[4], SPlayerRole.getRolesNames()); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java index 06d5605756..312105fc74 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java @@ -75,7 +75,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; if (!IslandUtils.isValidRoleForLimit(playerRole)) { - Message.INVALID_ROLE.send(sender, args[3], SPlayerRole.getValuesString()); + Message.INVALID_ROLE.send(sender, args[3], SPlayerRole.getRolesNames()); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java index bf2510a49b..1c9d100cad 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java @@ -15,6 +15,8 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -27,7 +29,6 @@ import java.math.BigDecimal; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -165,8 +166,7 @@ public static Upgrade getUpgrade(SuperiorSkyblockPlugin plugin, CommandSender se Upgrade upgrade = plugin.getUpgrades().getUpgrade(argument); if (upgrade == null) { - Message.INVALID_UPGRADE.send(sender, argument, Formatters.COMMA_FORMATTER.format( - plugin.getUpgrades().getUpgrades().stream().map(Upgrade::getName))); + Message.INVALID_UPGRADE.send(sender, argument, plugin.getUpgrades().getUpgradesNames()); } return upgrade; @@ -190,7 +190,7 @@ public static PlayerRole getPlayerRole(CommandSender sender, String argument) { } if (playerRole == null) - Message.INVALID_ROLE.send(sender, argument, SPlayerRole.getValuesString()); + Message.INVALID_ROLE.send(sender, argument, SPlayerRole.getRolesNames()); return playerRole; } @@ -320,10 +320,7 @@ public static IslandPrivilege getIslandPrivilege(CommandSender sender, String ar } if (islandPrivilege == null) { - Message.INVALID_ISLAND_PERMISSION.send(sender, argument, Formatters.COMMA_FORMATTER.format( - IslandPrivilege.values().stream() - .sorted(Comparator.comparing(IslandPrivilege::getName)) - .map(_islandPrivilege -> _islandPrivilege.toString().toLowerCase(Locale.ENGLISH)))); + Message.INVALID_ISLAND_PERMISSION.send(sender, argument, IslandPrivileges.getPrivilegesNames()); } return islandPrivilege; @@ -350,9 +347,7 @@ public static IslandFlag getIslandFlag(CommandSender sender, String argument) { } if (islandFlag == null) { - Message.INVALID_SETTINGS.send(sender, argument, Formatters.COMMA_FORMATTER.format(IslandFlag.values().stream() - .sorted(Comparator.comparing(IslandFlag::getName)) - .map(_islandFlag -> _islandFlag.getName().toLowerCase(Locale.ENGLISH)))); + Message.INVALID_SETTINGS.send(sender, argument, IslandFlags.getFlagsNames()); } return islandFlag; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java index e9ae24515e..3cf05490ca 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java @@ -86,7 +86,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer return; if (!playerRole.isRoleLadder()) { - Message.INVALID_ROLE.send(sender, args[2], SPlayerRole.getValuesString()); + Message.INVALID_ROLE.send(sender, args[2], SPlayerRole.getRolesNames()); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/flag/IslandFlags.java b/src/main/java/com/bgsoftware/superiorskyblock/island/flag/IslandFlags.java index c4dd204f71..851a8bbc29 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/flag/IslandFlags.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/flag/IslandFlags.java @@ -1,6 +1,10 @@ package com.bgsoftware.superiorskyblock.island.flag; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; + +import java.util.Comparator; +import java.util.Locale; public class IslandFlags { @@ -27,6 +31,9 @@ public class IslandFlags { public static final IslandFlag WATER_FLOW = register("WATER_FLOW"); public static final IslandFlag WITHER_EXPLOSION = register("WITHER_EXPLOSION"); + private static String ALL_FLAG_NAMES; + private static int KNOWN_FLAGS_COUNT; + private IslandFlags() { } @@ -35,6 +42,17 @@ public static void registerFlags() { // Do nothing, only trigger all the register calls } + public static String getFlagsNames() { + if (ALL_FLAG_NAMES == null || KNOWN_FLAGS_COUNT != IslandFlag.values().size()) { + ALL_FLAG_NAMES = Formatters.COMMA_FORMATTER.format(IslandFlag.values().stream() + .sorted(Comparator.comparing(IslandFlag::getName)) + .map(islandFlag -> islandFlag.getName().toLowerCase(Locale.ENGLISH))); + KNOWN_FLAGS_COUNT = IslandFlag.values().size(); + } + + return ALL_FLAG_NAMES; + } + private static IslandFlag register(String name) { IslandFlag.register(name); return IslandFlag.getByName(name); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index e7946c271c..c16f0a2d5f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -4,7 +4,10 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.core.ServerVersion; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import java.util.Comparator; +import java.util.Locale; import java.util.Objects; public class IslandPrivileges { @@ -89,6 +92,9 @@ public class IslandPrivileges { public static final IslandPrivilege WIND_CHARGE = register("WIND_CHARGE", ServerVersion.isAtLeast(ServerVersion.v1_21)); public static final IslandPrivilege WITHDRAW_MONEY = register("WITHDRAW_MONEY", IslandPrivilege.Type.COMMAND); + private static String ALL_PRIVILEGE_NAMES; + private static int KNOWN_PRIVILEGES_COUNT; + private IslandPrivileges() { } @@ -97,6 +103,17 @@ public static void registerPrivileges() { // Do nothing, only trigger all the register calls } + public static String getPrivilegesNames() { + if (ALL_PRIVILEGE_NAMES == null || KNOWN_PRIVILEGES_COUNT != IslandPrivilege.values().size()) { + ALL_PRIVILEGE_NAMES = Formatters.COMMA_FORMATTER.format(IslandPrivilege.values().stream() + .sorted(Comparator.comparing(IslandPrivilege::getName)) + .map(islandPrivilege -> islandPrivilege.getName().toLowerCase(Locale.ENGLISH))); + KNOWN_PRIVILEGES_COUNT = IslandPrivilege.values().size(); + } + + return ALL_PRIVILEGE_NAMES; + } + @NotNull private static IslandPrivilege register(String name) { return Objects.requireNonNull(register(name, true)); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/role/RolesManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/role/RolesManagerImpl.java index 92546d683a..8f0b0eb64e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/role/RolesManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/role/RolesManagerImpl.java @@ -58,6 +58,8 @@ public void loadData() throws ManagerLoadException { SPlayerRole previousRole = coopRole; for (ConfigurationSection roleSection : rolesByWeight) previousRole = loadRole(roleSection, previousRole.getWeight() + 1, previousRole); + + SPlayerRole.refreshRoles(); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java b/src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java index eaf783ce95..a1b1ef2910 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java @@ -3,6 +3,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.island.privilege.RolePrivilegeNode; import com.google.common.base.Preconditions; @@ -14,6 +15,8 @@ public class SPlayerRole implements PlayerRole { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static String ALL_ROLE_NAMES; + private final String name; private final String displayName; private final int id; @@ -62,10 +65,17 @@ public static PlayerRole of(String name) { return plugin.getRoles().getPlayerRole(name); } - public static String getValuesString() { - StringBuilder stringBuilder = new StringBuilder(); - plugin.getRoles().getRoles().forEach(playerRole -> stringBuilder.append(", ").append(playerRole.toString().toLowerCase(Locale.ENGLISH))); - return stringBuilder.substring(2); + public static String getRolesNames() { + if (ALL_ROLE_NAMES == null) { + ALL_ROLE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getRoles().getRoles().stream() + .map(playerRole -> playerRole.getName().toLowerCase(Locale.ENGLISH))); + } + + return ALL_ROLE_NAMES; + } + + public static void refreshRoles() { + ALL_ROLE_NAMES = null; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/UpgradesManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/UpgradesManagerImpl.java index a7aca2ad1a..49b177c8d9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/UpgradesManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/UpgradesManagerImpl.java @@ -6,15 +6,19 @@ import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.cost.UpgradeCostLoader; import com.bgsoftware.superiorskyblock.core.Manager; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.island.upgrade.container.UpgradesContainer; import com.google.common.base.Preconditions; import java.util.Collection; +import java.util.Locale; public class UpgradesManagerImpl extends Manager implements UpgradesManager { private final UpgradesContainer upgradesContainer; + private String ALL_UPGRADE_NAMES; + public UpgradesManagerImpl(SuperiorSkyblockPlugin plugin, UpgradesContainer upgradesContainer) { super(plugin); this.upgradesContainer = upgradesContainer; @@ -39,6 +43,7 @@ public Upgrade getUpgrade(int slot) { @Override public void addUpgrade(Upgrade upgrade) { this.upgradesContainer.addUpgrade(upgrade); + ALL_UPGRADE_NAMES = null; } @Override @@ -80,4 +85,13 @@ public void clearUpgrades() { this.upgradesContainer.clearUpgrades(); } + public String getUpgradesNames() { + if (ALL_UPGRADE_NAMES == null) { + ALL_UPGRADE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getUpgrades().getUpgrades().stream() + .map(upgrade -> upgrade.getName().toLowerCase(Locale.ENGLISH))); + } + + return ALL_UPGRADE_NAMES; + } + } From d101ce649af920588c57aa6ff6c5ae3a7b7e46a1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 10 May 2025 12:59:23 +0300 Subject: [PATCH 171/600] Fixed errors when using /is admin setbiome (#2461) --- .../nms/v1_21_4/NMSAlgorithmsImpl.java | 18 +++++++++++++ .../nms/v1_21_5/NMSAlgorithmsImpl.java | 18 +++++++++++++ .../commands/CommandTabCompletes.java | 13 +++++++++- .../core/SequentialListBuilder.java | 13 ++++++++-- .../superiorskyblock/nms/NMSAlgorithms.java | 26 +++++++++++++++++++ 5 files changed, 85 insertions(+), 3 deletions(-) diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index 2688da1993..9bb69d1835 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -38,6 +38,7 @@ import org.bukkit.Material; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; +import org.bukkit.block.Biome; import org.bukkit.block.data.Ageable; import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; @@ -69,6 +70,18 @@ public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final Multimap EMPTY_ATTRIBUTES_MAP = MultimapBuilder.hashKeys().hashSetValues().build(); + private static final EnumBridge BIOME_ENUM_BRIDGE = new EnumBridge<>() { + @Override + public Biome[] getValues() { + return Biome.values(); + } + + @Override + public String getName(Biome enumValue) { + return enumValue.name(); + } + }; + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { @@ -258,6 +271,11 @@ public void hideAttributes(ItemMeta itemMeta) { itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); } + @Override + public EnumBridge getBiomeBridge() { + return BIOME_ENUM_BRIDGE; + } + private interface MenuCreator extends BiFunction { } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java index cbdcd661f9..57f2ba6172 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java @@ -38,6 +38,7 @@ import org.bukkit.Material; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; +import org.bukkit.block.Biome; import org.bukkit.block.data.Ageable; import org.bukkit.block.data.BlockData; import org.bukkit.command.defaults.BukkitCommand; @@ -69,6 +70,18 @@ public class NMSAlgorithmsImpl implements NMSAlgorithms { private static final Multimap EMPTY_ATTRIBUTES_MAP = MultimapBuilder.hashKeys().hashSetValues().build(); + private static final EnumBridge BIOME_ENUM_BRIDGE = new EnumBridge<>() { + @Override + public Biome[] getValues() { + return Biome.values(); + } + + @Override + public String getName(Biome enumValue) { + return enumValue.name(); + } + }; + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { @@ -258,6 +271,11 @@ public void hideAttributes(ItemMeta itemMeta) { itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); } + @Override + public EnumBridge getBiomeBridge() { + return BIOME_ENUM_BRIDGE; + } + private interface MenuCreator extends BiFunction { } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index 852f38ddef..8f42fb4ff0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -13,9 +13,11 @@ import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; +import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import org.bukkit.Bukkit; import org.bukkit.World; @@ -39,6 +41,8 @@ public class CommandTabCompletes { + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private CommandTabCompletes() { } @@ -215,7 +219,8 @@ public static List getCustomMenus(SuperiorSkyblockPlugin plugin, String } public static List getBiomes(String argument) { - return getFromEnum(Arrays.asList(Biome.values()), argument.toLowerCase(Locale.ENGLISH)); + NMSAlgorithms.EnumBridge biomeEnumBridge = plugin.getNMSAlgorithms().getBiomeBridge(); + return filterByArgument(biomeEnumBridge.getValues(), biomeEnumBridge::getName, argument.toLowerCase(Locale.ENGLISH)); } public static List getWorlds(String argument) { @@ -289,6 +294,12 @@ private static List filterByArgument(Collection collection, Funct .build(collection, mapper); } + private static List filterByArgument(E[] collection, Function mapper, String argument) { + return new SequentialListBuilder() + .filter(name -> name.toLowerCase(Locale.ENGLISH).contains(argument)) + .build(collection, mapper); + } + private static List getFromEnum(Collection> enums, String argument) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/SequentialListBuilder.java b/src/main/java/com/bgsoftware/superiorskyblock/core/SequentialListBuilder.java index c42c7e1602..ca10be0f6d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/SequentialListBuilder.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/SequentialListBuilder.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.core; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; import java.util.Collection; import java.util.Collections; @@ -10,7 +9,6 @@ import java.util.LinkedList; import java.util.List; import java.util.function.Function; -import java.util.function.LongFunction; import java.util.function.Predicate; import java.util.stream.Stream; @@ -49,6 +47,17 @@ public List build(Collection collection, Function mapper) { return completeBuild(sequentialList); } + public List build(O[] collection, Function mapper) { + LinkedList sequentialList = new LinkedList<>(); + + for (O element : collection) { + E mappedElement = mapper.apply(element); + if (predicate == null || predicate.test(mappedElement)) + sequentialList.add(mappedElement); + } + + return completeBuild(sequentialList); + } public List map(Collection collection, Function mapper) { LinkedList sequentialList = new LinkedList<>(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java index 40698e0b77..84d736f7fc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.command.defaults.BukkitCommand; @@ -21,6 +22,18 @@ public interface NMSAlgorithms { + EnumBridge BIOME_ENUM_BRIDGE = new EnumBridge() { + @Override + public Biome[] getValues() { + return Biome.values(); + } + + @Override + public String getName(Biome enumValue) { + return enumValue.name(); + } + }; + void registerCommand(BukkitCommand command); String parseSignLine(String original); @@ -73,4 +86,17 @@ default void handlePaperChatRenderer(Object event) { default void hideAttributes(ItemMeta itemMeta) { } + + default EnumBridge getBiomeBridge() { + return BIOME_ENUM_BRIDGE; + } + + interface EnumBridge { + + T[] getValues(); + + String getName(T enumValue); + + } + } From c7c372616d25f3b54a28ce7cea853d62450349f7 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 10 May 2025 13:08:40 +0300 Subject: [PATCH 172/600] Fixed Island#getPotionEffectLevel returns -1 if effect is not active for the island (#2464) --- .../java/com/bgsoftware/superiorskyblock/island/SIsland.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index bef5e50ae0..5fc212a832 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -44,7 +44,6 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.LegacyMasks; -import com.bgsoftware.superiorskyblock.core.LocationKey; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; @@ -3395,7 +3394,7 @@ public void removePotionEffect(PotionEffectType type) { public int getPotionEffectLevel(PotionEffectType type) { Preconditions.checkNotNull(type, "potionEffectType parameter cannot be null."); IntValue islandEffect = islandEffects.get(type); - return islandEffect == null ? -1 : islandEffect.get(); + return islandEffect == null ? 0 : islandEffect.get(); } @Override From 602dade6c8bf9b2edb5292341ebad395fe9cecbf Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 10 May 2025 13:14:52 +0300 Subject: [PATCH 173/600] Fixed tab completes for potion effect types (#2464) --- .../commands/CommandTabCompletes.java | 11 +++++++++-- .../superiorskyblock/core/SequentialListBuilder.java | 11 +++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index 8f42fb4ff0..c15c4b2e4b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -13,7 +13,6 @@ import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; @@ -185,7 +184,15 @@ public static List getPotionEffects(String argument) { return false; } }) - .map(Arrays.asList(PotionEffectType.values()), PotionEffectType::getName); + .map(PotionEffectType.values(), potionEffectType -> { + String name = potionEffectType.getName(); + if (name.startsWith("minecraft:")) { + name = name.substring("minecraft:".length()).toLowerCase(Locale.ENGLISH); + } else { + name = name.toLowerCase(Locale.ENGLISH); + } + return name; + }); } public static List getEntitiesForLimit(String argument) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/SequentialListBuilder.java b/src/main/java/com/bgsoftware/superiorskyblock/core/SequentialListBuilder.java index ca10be0f6d..221074c8e1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/SequentialListBuilder.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/SequentialListBuilder.java @@ -70,6 +70,17 @@ public List map(Collection collection, Function mapper) { return completeBuild(sequentialList, null, this.mutable); } + public List map(E[] collection, Function mapper) { + LinkedList sequentialList = new LinkedList<>(); + + for (E element : collection) { + if (predicate == null || predicate.test(element)) + sequentialList.add(mapper.apply(element)); + } + + return completeBuild(sequentialList, null, this.mutable); + } + public List map(Iterator iterator, Function mapper) { LinkedList sequentialList = new LinkedList<>(); From 34f70b44b42f847498795fbbc9a4f75faf2bf077 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 10 May 2025 13:18:41 +0300 Subject: [PATCH 174/600] Fixed addblocklimit command does not have tab complete for island names (#2465) --- .../commands/admin/CmdAdminAddBlockLimit.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBlockLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBlockLimit.java index 138c1a02fa..dd9788e701 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBlockLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBlockLimit.java @@ -62,11 +62,6 @@ public boolean canBeExecutedByConsole() { return true; } - @Override - public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { - return args.length == 4 ? CommandTabCompletes.getMaterials(args[3]) : Collections.emptyList(); - } - @Override public boolean supportMultipleIslands() { return true; @@ -105,4 +100,8 @@ else if (targetPlayer == null) Message.CHANGED_BLOCK_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), targetPlayer.getName()); } + @Override + public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { + return args.length == 4 ? CommandTabCompletes.getMaterials(args[3]) : Collections.emptyList(); + } } From dc78d422b49f5172e133a00dd7cc78dce83574af Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 10 May 2025 13:37:19 +0300 Subject: [PATCH 175/600] Fixed tab completes for add and setrate admin commands (#2466) --- .../commands/admin/CmdAdminAdd.java | 2 +- .../commands/admin/CmdAdminSetRate.java | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java index 3e85542d6f..84ca2b6c97 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java @@ -97,7 +97,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { - return args.length == 4 ? CommandTabCompletes.getOnlinePlayers(plugin, args[2], false, + return args.length == 4 ? CommandTabCompletes.getOnlinePlayers(plugin, args[3], false, superiorPlayer -> superiorPlayer.getIsland() == null) : Collections.emptyList(); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRate.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRate.java index e2f61df570..670a783e38 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRate.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRate.java @@ -14,6 +14,7 @@ import org.bukkit.command.CommandSender; import java.util.Collections; +import java.util.LinkedList; import java.util.List; public class CmdAdminSetRate implements IAdminIslandCommand { @@ -86,8 +87,18 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { - return args.length == 4 ? CommandTabCompletes.getRatedPlayers(plugin, island, args[3]) : - args.length == 5 ? CommandTabCompletes.getRatings(args[4]) : Collections.emptyList(); + switch (args.length) { + case 4: { + List tabCompletes = new LinkedList<>(); + tabCompletes.addAll(CommandTabCompletes.getRatedPlayers(plugin, island, args[3])); + tabCompletes.addAll(CommandTabCompletes.getOnlinePlayers(plugin, args[3], false)); + return tabCompletes.isEmpty() ? Collections.emptyList() : tabCompletes; + } + case 5: + return CommandTabCompletes.getRatings(args[4]); + default: + return Collections.emptyList(); + } } } From 0273f7c738d153bd240bc6a7aa9678268cdee0c6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 10 May 2025 13:40:09 +0300 Subject: [PATCH 176/600] Fixed tab completes for cleargenerator command (#2467) --- .../module/generators/commands/CmdAdminClearGenerator.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java index 9ebbad8b1d..2005e923b5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; @@ -12,6 +13,7 @@ import org.bukkit.command.CommandSender; import java.util.Arrays; +import java.util.Collections; import java.util.List; public class CmdAdminClearGenerator implements IAdminIslandCommand { @@ -90,4 +92,8 @@ else if (targetPlayer == null) Message.GENERATOR_CLEARED.send(sender, targetPlayer.getName()); } + @Override + public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { + return args.length == 4 ? CommandTabCompletes.getDimensions(args[3]) : Collections.emptyList(); + } } From 88d12e85d9cb1045f046f8a6f1f674f70dd18f08 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 10 May 2025 13:43:53 +0300 Subject: [PATCH 177/600] Fixed tab completes for unlockworld command (#2468) --- .../superiorskyblock/commands/admin/CmdAdminUnlockWorld.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java index a63369787e..e22987c1ee 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java @@ -94,7 +94,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { if (args.length == 5) - return CommandTabCompletes.getCustomComplete(args[3], "true", "false"); + return CommandTabCompletes.getCustomComplete(args[4], "true", "false"); if (args.length != 4) return Collections.emptyList(); From 5c5c6c2a5b6441b4e287d1dab2685d7a34cfb96f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 10 May 2025 14:05:50 +0300 Subject: [PATCH 178/600] Fixed tab completes for commands related to roles (#2469) --- .../commands/CommandTabCompletes.java | 7 ----- .../commands/admin/CmdAdminSetPermission.java | 23 +++++++-------- .../commands/admin/CmdAdminSetRoleLimit.java | 9 +----- .../commands/arguments/CommandArguments.java | 28 ++++++++++++++++--- .../commands/player/CmdSetRole.java | 8 +----- .../island/role/SPlayerRole.java | 26 +++++++++++++---- 6 files changed, 58 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index c15c4b2e4b..bd3f9a0a96 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -152,13 +152,6 @@ public static List getUpgrades(SuperiorSkyblockPlugin plugin, String arg return filterByArgument(plugin.getUpgrades().getUpgrades(), Upgrade::getName, argument.toLowerCase(Locale.ENGLISH)); } - public static List getPlayerRoles(SuperiorSkyblockPlugin plugin, @Nullable IslandPrivilege islandPrivilege, String argument) { - return new SequentialListBuilder() - .filter(playerRole -> playerRole.getName().toLowerCase(Locale.ENGLISH).contains(argument) && - (islandPrivilege == null || islandPrivilege.getType() != IslandPrivilege.Type.COMMAND || playerRole.isRoleLadder())) - .map(plugin.getRoles().getRoles(), PlayerRole::getName); - } - public static List getPlayerRoles(SuperiorSkyblockPlugin plugin, String argument, Predicate predicate) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java index e66ed786e3..078c4e06eb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java @@ -12,7 +12,6 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.command.CommandSender; import java.util.Arrays; @@ -69,20 +68,13 @@ public boolean supportMultipleIslands() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { IslandPrivilege islandPrivilege = CommandArguments.getIslandPrivilege(sender, args[3]); - if (islandPrivilege == null) return; - PlayerRole playerRole = CommandArguments.getPlayerRole(sender, args[4]); - + PlayerRole playerRole = CommandArguments.getPlayerRoleFromLadder(sender, args[4]); if (playerRole == null) return; - if (islandPrivilege.getType() == IslandPrivilege.Type.COMMAND && !playerRole.isRoleLadder()) { - Message.INVALID_ROLE.send(sender, args[4], SPlayerRole.getRolesNames()); - return; - } - int islandsChangedCount = 0; for (Island island : islands) { @@ -105,8 +97,17 @@ else if (targetPlayer == null) @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { - return args.length == 4 ? CommandTabCompletes.getIslandPrivileges(args[3]) : - args.length == 5 ? CommandTabCompletes.getPlayerRoles(plugin, getIslandPrivilegeSafe(args[3]), args[4]) : Collections.emptyList(); + switch (args.length) { + case 4: + return CommandTabCompletes.getIslandPrivileges(args[3]); + case 5: { + IslandPrivilege islandPrivilege = getIslandPrivilegeSafe(args[3]); + return islandPrivilege == null || islandPrivilege.getType() == IslandPrivilege.Type.COMMAND ? + Collections.emptyList() : CommandTabCompletes.getPlayerRoles(plugin, args[4], PlayerRole::isRoleLadder); + } + default: + return Collections.emptyList(); + } } @Nullable diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java index 312105fc74..9d3be49dee 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetRoleLimit.java @@ -14,7 +14,6 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.command.CommandSender; import java.util.Collections; @@ -69,16 +68,10 @@ public boolean supportMultipleIslands() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { - PlayerRole playerRole = CommandArguments.getPlayerRole(sender, args[3]); - + PlayerRole playerRole = CommandArguments.getPlayerRoleForLimit(sender, args[3]); if (playerRole == null) return; - if (!IslandUtils.isValidRoleForLimit(playerRole)) { - Message.INVALID_ROLE.send(sender, args[3], SPlayerRole.getRolesNames()); - return; - } - NumberArgument arguments = CommandArguments.getLimit(sender, args[4]); if (!arguments.isSucceed()) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java index 1c9d100cad..7c78d49136 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java @@ -15,6 +15,7 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; @@ -181,7 +182,7 @@ public static String buildLongString(String[] args, int start, boolean colorize) return colorize ? Formatters.COLOR_FORMATTER.format(stringBuilder.substring(1)) : stringBuilder.substring(1); } - public static PlayerRole getPlayerRole(CommandSender sender, String argument) { + public static PlayerRole getPlayerRoleFromLadder(CommandSender sender, String argument) { PlayerRole playerRole = null; try { @@ -189,8 +190,26 @@ public static PlayerRole getPlayerRole(CommandSender sender, String argument) { } catch (IllegalArgumentException ignored) { } - if (playerRole == null) - Message.INVALID_ROLE.send(sender, argument, SPlayerRole.getRolesNames()); + if (playerRole == null || !playerRole.isRoleLadder()) { + Message.INVALID_ROLE.send(sender, argument, SPlayerRole.getRolesLadderNames()); + playerRole = null; + } + + return playerRole; + } + + public static PlayerRole getPlayerRoleForLimit(CommandSender sender, String argument) { + PlayerRole playerRole = null; + + try { + playerRole = SPlayerRole.of(argument); + } catch (IllegalArgumentException ignored) { + } + + if (playerRole == null || !IslandUtils.isValidRoleForLimit(playerRole)) { + Message.INVALID_ROLE.send(sender, argument, SPlayerRole.getRoleLimitsNames()); + playerRole = null; + } return playerRole; } @@ -319,8 +338,9 @@ public static IslandPrivilege getIslandPrivilege(CommandSender sender, String ar } catch (NullPointerException ignored) { } - if (islandPrivilege == null) { + if (islandPrivilege == null || islandPrivilege.getType() == IslandPrivilege.Type.COMMAND) { Message.INVALID_ISLAND_PERMISSION.send(sender, argument, IslandPrivileges.getPrivilegesNames()); + islandPrivilege = null; } return islandPrivilege; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java index 3cf05490ca..6f4c2ceed1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetRole.java @@ -80,16 +80,10 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer return; } - PlayerRole playerRole = CommandArguments.getPlayerRole(sender, args[2]); - + PlayerRole playerRole = CommandArguments.getPlayerRoleFromLadder(sender, args[2]); if (playerRole == null) return; - if (!playerRole.isRoleLadder()) { - Message.INVALID_ROLE.send(sender, args[2], SPlayerRole.getRolesNames()); - return; - } - Island targetIsland = targetPlayer.getIsland(); // Checking requirements for players diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java b/src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java index a1b1ef2910..a5e165d1e3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.RolePrivilegeNode; import com.google.common.base.Preconditions; @@ -15,7 +16,8 @@ public class SPlayerRole implements PlayerRole { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static String ALL_ROLE_NAMES; + private static String LIMIT_ROLE_NAMES; + private static String LADDER_ROLE_NAMES; private final String name; private final String displayName; @@ -65,17 +67,29 @@ public static PlayerRole of(String name) { return plugin.getRoles().getPlayerRole(name); } - public static String getRolesNames() { - if (ALL_ROLE_NAMES == null) { - ALL_ROLE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getRoles().getRoles().stream() + public static String getRoleLimitsNames() { + if (LIMIT_ROLE_NAMES == null) { + LIMIT_ROLE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getRoles().getRoles().stream() + .filter(IslandUtils::isValidRoleForLimit) .map(playerRole -> playerRole.getName().toLowerCase(Locale.ENGLISH))); } - return ALL_ROLE_NAMES; + return LIMIT_ROLE_NAMES; + } + + public static String getRolesLadderNames() { + if (LADDER_ROLE_NAMES == null) { + LADDER_ROLE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getRoles().getRoles().stream() + .filter(PlayerRole::isRoleLadder) + .map(playerRole -> playerRole.getName().toLowerCase(Locale.ENGLISH))); + } + + return LADDER_ROLE_NAMES; } public static void refreshRoles() { - ALL_ROLE_NAMES = null; + LIMIT_ROLE_NAMES = null; + LADDER_ROLE_NAMES = null; } @Override From 06d00e3abae20f940f2b21216f1031773ad663a8 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 18 May 2025 12:35:15 +0300 Subject: [PATCH 179/600] Fixed admin unlockworld messages (#2489) --- .../commands/admin/CmdAdminUnlockWorld.java | 60 +++++++++++++++---- .../core/messages/Message.java | 5 ++ src/main/resources/lang/de-DE.yml | 7 ++- src/main/resources/lang/en-US.yml | 7 ++- src/main/resources/lang/es-ES.yml | 7 ++- src/main/resources/lang/fr-FR.yml | 7 ++- src/main/resources/lang/it-IT.yml | 7 ++- src/main/resources/lang/iw-IL.yml | 7 ++- src/main/resources/lang/pl-PL.yml | 7 ++- src/main/resources/lang/pt-BR.yml | 7 ++- src/main/resources/lang/ru-RU.yml | 7 ++- src/main/resources/lang/vi-VN.yml | 7 ++- src/main/resources/lang/zh-CN.yml | 7 ++- 13 files changed, 118 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java index e22987c1ee..2ee5e2ab30 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java @@ -74,21 +74,13 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; } - boolean enable = Boolean.parseBoolean(args[4]); + boolean unlockWorld = Boolean.parseBoolean(args[4]); - int islandsChangedCount = 0; - - for (Island island : islands) { - if (enable ? !PluginEventsFactory.callIslandUnlockWorldEvent(island, sender, dimension) : - !PluginEventsFactory.callIslandLockWorldEvent(island, sender, dimension)) - continue; - - island.setDimensionEnabled(dimension, enable); - ++islandsChangedCount; + if (unlockWorld) { + handleWorldUnlock(sender, islands, dimension, targetPlayer, args[3]); + } else { + handleWorldLock(sender, islands, dimension, targetPlayer, args[3]); } - - if (islandsChangedCount > 0) - Message.UNLOCK_WORLD_ANNOUNCEMENT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3])); } @Override @@ -102,4 +94,46 @@ public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSende return CommandTabCompletes.getDimensions(args[3]); } + private void handleWorldUnlock(CommandSender sender, List islands, Dimension dimension, + @Nullable SuperiorPlayer targetPlayer, String worldType) { + int islandsChangedCount = 0; + + for (Island island : islands) { + if (!PluginEventsFactory.callIslandUnlockWorldEvent(island, sender, dimension)) + continue; + + island.setDimensionEnabled(dimension, true); + ++islandsChangedCount; + } + + if (islandsChangedCount > 1) + Message.UNLOCK_WORLD_ANNOUNCEMENT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType)); + else if (targetPlayer == null) + Message.UNLOCK_WORLD_ANNOUNCEMENT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType), islands.get(0).getName()); + else + Message.UNLOCK_WORLD_ANNOUNCEMENT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType), targetPlayer.getName()); + + } + + private void handleWorldLock(CommandSender sender, List islands, Dimension dimension, + @Nullable SuperiorPlayer targetPlayer, String worldType) { + int islandsChangedCount = 0; + + for (Island island : islands) { + if (!PluginEventsFactory.callIslandLockWorldEvent(island, sender, dimension)) + continue; + + island.setDimensionEnabled(dimension, false); + ++islandsChangedCount; + } + + if (islandsChangedCount > 1) + Message.LOCK_WORLD_ANNOUNCEMENT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType)); + else if (targetPlayer == null) + Message.LOCK_WORLD_ANNOUNCEMENT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType), islands.get(0).getName()); + else + Message.LOCK_WORLD_ANNOUNCEMENT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(worldType), targetPlayer.getName()); + + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index cb1bbccede..c3f7fd33d9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -560,6 +560,9 @@ public void send(CommandSender sender, Locale locale, Object... args) { LEFT_ISLAND, LEFT_ISLAND_COOP, LEFT_ISLAND_COOP_NAME, + LOCK_WORLD_ANNOUNCEMENT_ALL, + LOCK_WORLD_ANNOUNCEMENT_NAME, + LOCK_WORLD_ANNOUNCEMENT, MATERIAL_NOT_SOLID, MAXIMUM_LEVEL, MESSAGE_SENT, @@ -733,6 +736,8 @@ public void send(CommandSender sender, Locale locale, Object... args) { UNCOOP_LEFT_ANNOUNCEMENT, UNIGNORED_ISLAND, UNIGNORED_ISLAND_NAME, + UNLOCK_WORLD_ANNOUNCEMENT_ALL, + UNLOCK_WORLD_ANNOUNCEMENT_NAME, UNLOCK_WORLD_ANNOUNCEMENT, UNSAFE_WARP, UPDATED_PERMISSION, diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index cd71d6e928..331f85e60d 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -665,6 +665,9 @@ LEFT_ISLAND_COOP: '&e&lInsel | &7Du bist kein Koop-Mitglied mehr auf der Insel v {0}.' LEFT_ISLAND_COOP_NAME: '&e&lInsel | &7Du bist kein Genossenschaftsmitglied der Insel {0} mehr.' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lError | &7Du musst festes Material bereitstellen.' MAXIMUM_LEVEL: '&c&lError | &7Die maximale Stufe für dieses Upgrade ist {0}.' MESSAGE_SENT: '&e&lIsland | &7Die Nachricht wurde erfolgreich an {0} gesendet!' @@ -920,7 +923,9 @@ UNIGNORED_ISLAND: '&e&lInsel | Die Insel von &7{0} wird jetzt nicht mehr von den ignoriert.' UNIGNORED_ISLAND_NAME: '&e&lInsel | &7Die Insel {0} wird jetzt von den Top-Inseln nicht mehr ignoriert.' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7Ihre {0} Welt ist jetzt freigeschaltet!' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lInsel | &7&oAnscheinend ist dieser Warp unsicher. Bitte versuche es mit einem anderen Warp.' UPDATED_PERMISSION: '&e&lInsel | &7Aktualisierte Berechtigungen für {0}.' diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index fc210bc53f..52dc58a6aa 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -535,6 +535,9 @@ LEAVE_ISLAND_AS_LEADER: |- LEFT_ISLAND: '&e&lIsland | &7You left your island.' LEFT_ISLAND_COOP: '&e&lIsland | &7You are no longer a co-op member of {0}''s island.' LEFT_ISLAND_COOP_NAME: '&e&lIsland | &7You are no longer a co-op member of the island {0}.' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lError | &7You must provide a solid material.' MAXIMUM_LEVEL: '&c&lError | &7The maximum level for this upgrade is {0}.' MESSAGE_SENT: '&e&lIsland | &7Successfully sent {0} the message!' @@ -721,7 +724,9 @@ UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and UNCOOP_LEFT_ANNOUNCEMENT: '&e&lIsland | &7{0} left the game and is no longer a co-op member.' UNIGNORED_ISLAND: '&e&lIsland | &7{0}''s island is now un-ignored from top islands.' UNIGNORED_ISLAND_NAME: '&e&lIsland | &7The island {0} is now un-ignored from top islands.' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7Your {0} world is now unlocked!' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lIsland | &7&oLooks like this warp is unsafe. Please try another warp.' UPDATED_PERMISSION: '&e&lIsland | &7Updated permissions for {0}.' UPDATED_SETTINGS: '&e&lIsland | &7Updated the island settings {0}.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 743d16e1b4..39e4efd653 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -535,6 +535,9 @@ LEAVE_ISLAND_AS_LEADER: |- LEFT_ISLAND: '&e&lIsla | &7Dejaste tu isla.' LEFT_ISLAND_COOP: '&e&lIsla | &7Ya no eres miembro cooperativo de la isla de {0}.' LEFT_ISLAND_COOP_NAME: '&e&lIsla | &7Ya no eres miembro cooperativo de la isla de {0}.' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lError | &7Debe proporcionar un material sólido.' MAXIMUM_LEVEL: '&c&lError | &7El nivel máximo para esta actualización es {0}.' MESSAGE_SENT: '&e&lIsla | &7Se envió correctamente {0} el mensaje.!' @@ -721,7 +724,9 @@ UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and UNCOOP_LEFT_ANNOUNCEMENT: '&e&lIsla | &7{0} abandonó el juego y ya no es miembro cooperativo.' UNIGNORED_ISLAND: '&e&lIsla | &7La isla {0} dejo de ser ingnorada del TOP Islas' UNIGNORED_ISLAND_NAME: '&e&lIsla | &7La isla {0} dejo de ser ingnorada del TOP Islas' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&lMundos | &7¡Tu mundo {0} ahora está desbloqueado!' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lIsla | &7&oParece que este warp no es seguro. Intente con otro warp.' UPDATED_PERMISSION: '&e&lIsla | &7Permisos actualizados para {0}.' UPDATED_SETTINGS: '&e&lIsla | &7Se actualizó la configuración de la isla {0}.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 988cd9287d..cd14322b38 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -537,6 +537,9 @@ LEAVE_ISLAND_AS_LEADER: |- LEFT_ISLAND: '&e&lIle | &7Vous avez quitté votre île.' LEFT_ISLAND_COOP: '&e&lIle | &7Vous n''êtes plus un coopérateur de l''île de {0}.' LEFT_ISLAND_COOP_NAME: '&e&lIle | &7Vous n''êtes plus un coopérateur de l''île {0}.' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lErreur | &7Vous devez fournir un matériau solide.' MAXIMUM_LEVEL: '&c&lErreur | &7Le niveau maximal pour cette amélioration est de {0}.' MESSAGE_SENT: '&e&lIle | &7Message envoyé a {0} !' @@ -723,7 +726,9 @@ UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and UNCOOP_LEFT_ANNOUNCEMENT: '&e&lIle | &7{0} a quitté le jeu et n''est désormais plus un coopérateur.' UNIGNORED_ISLAND: '&e&lIle | &7L''île de {0} est désormais visible dans le top des îles.' UNIGNORED_ISLAND_NAME: '&e&lIle | &7L''île {0} n''est plus masquée dans le top des îles.' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&lMondes | &7Votre monde {0} est désormais dévérouillé !' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lIle | &7&oIl semblerait que ce warp ne soit pas sécurisé. Veuillez en essayer un autre.' UPDATED_PERMISSION: '&e&lIle | &7Permission mise à jour pour {0}.' UPDATED_SETTINGS: '&e&lIle | &7Paramètre de l''île mit à jour {0}.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 3d5886aaba..bfd1bd4fd0 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -543,6 +543,9 @@ LEAVE_ISLAND_AS_LEADER: | LEFT_ISLAND: '&e&lIsola | &7Hai lasciato la tua isola.' LEFT_ISLAND_COOP: '&e&lIsola | &7Non sei più un membro coop dell''isola di {0}.' LEFT_ISLAND_COOP_NAME: '&e&lIsola | &7Non sei più un membro coop dell''isola {0}.' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lErrore | &7È necessario fornire un materiale solido.' MAXIMUM_LEVEL: '&c&lErrore | &7Il livello massimo per questo aggiornamento è {0}.' MESSAGE_SENT: '&e&lIsola | &7{0} inviato correttamente il messaggio!' @@ -729,7 +732,9 @@ UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsola | &7Non ci sono membri dell''isola online e UNCOOP_LEFT_ANNOUNCEMENT: '&e&lIsola | &7{0} è uscito dal server, non è più un membro coop.' UNIGNORED_ISLAND: '&e&lIsola | &7L''isola di {0} ora NON È PIÙ IGNORATA dalle isole migliori(/is top).' UNIGNORED_ISLAND_NAME: '&e&lIsola | &7L''isola {0} ora NON È PIÙ IGNORATA dalle isole migliori(/is top).' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&lMondi | &7Il tuo {0} mondo è stato sbloccato!' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lIsola | &7&oSembra che questa warp non sia sicura. Per favore, prova un altra warp.' UPDATED_PERMISSION: '&e&lIsola | &7Autorizzazioni aggiornate per {0}.' UPDATED_SETTINGS: '&e&lIsola | &7Aggiornate le impostazioni dell''isola {0}.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index c7b1c207e8..484ae20301 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -555,6 +555,9 @@ LEAVE_ISLAND_AS_LEADER: |- LEFT_ISLAND: '&e&lיא | &7ךלש יאה תא תבזע.' LEFT_ISLAND_COOP: '&e&lיא | &7{0} לש יאה לש הלועפ ףתשמ אל התא.' LEFT_ISLAND_COOP_NAME: '&e&lיא | &7רמוע יאה לש הלועפ ףתשמ אל התא.' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lהאיגש | &7חישק רמוח סינכהל ביוחמ התא.' MAXIMUM_LEVEL: '&c&lהאיגש | &7{0} איה גורדשה לש תילמיסקמה המרה.' MESSAGE_SENT: '&e&lיא | &7החלצהב {0} לא החלשנ העדוהה!' @@ -743,7 +746,9 @@ UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and UNCOOP_LEFT_ANNOUNCEMENT: '&e&lיא | &7דוע יאה לש הלועפ ףתשמ וניא ןכלו תרשה תא בזע {0}.' UNIGNORED_ISLAND: '&e&lיא | &7החלצהב םיבוטה םייאה תמישרל ףסוותה {0} לש יאה.' UNIGNORED_ISLAND_NAME: '&e&lיא | &7החלצהב םיבוטה םייאה תמישרל ףסוותה {0} יאה.' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&lתומלוע | &7יאב וישכעמ חותפ {0} םלועה!' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lיא | &7&oרחא םוקימ הסנ אנא .חוטב וניא םוקימה יכ הארנ.' UPDATED_PERMISSION: '&e&lיא | &7{0} ל תואשרהה ונכדוע.' UPDATED_SETTINGS: '&e&lיא | &7{0} תורדגהה ונכדוע.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 01b9e2463c..724bdf8937 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -537,6 +537,9 @@ LEAVE_ISLAND_AS_LEADER: |- LEFT_ISLAND: '&e&lWyspa | &7Opusciles swoja wyspe.' LEFT_ISLAND_COOP: '&e&lWyspa | &7Nie jestes juz czlonkiem trybu wspólpracy na wyspie {0}.' LEFT_ISLAND_COOP_NAME: '&e&lWyspa | &7Nie jestes juz czlonkiem spóldzielni na wyspie {0}.' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lBlad | &7Musisz dostarczyc solidny material.' MAXIMUM_LEVEL: '&c&lBlad | &7Maksymalny poziom tego uaktualnienia to {0}.' MESSAGE_SENT: '&e&lWyspa | &7Pomyslnie wyslano {0} wiadomosc!' @@ -723,7 +726,9 @@ UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and UNCOOP_LEFT_ANNOUNCEMENT: '&e&lWyspa | &7{0} opuscil gre i nie jest juz czlonkiem trybu wspólpracy.' UNIGNORED_ISLAND: '&e&lWyspa | Wyspa &7{0} nie jest teraz ignorowana wsród najlepszych wysp.' UNIGNORED_ISLAND_NAME: '&e&lWyspa | &7Wyspa {0} nie jest teraz ignorowana wsród najlepszych wysp.' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&lSwiaty | &7Twój {0} swiat jest teraz odblokowany!' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lWyspa | &7&oWyglada na to, ze to wypaczenie jest niebezpieczne. Prosze spróbowac innego wypaczenia.' UPDATED_PERMISSION: '&e&lWyspa | &7Zaktualizowano uprawnienia dla {0}.' UPDATED_SETTINGS: '&e&lWyspa | &7Zaktualizowano ustawienia wyspy {0}.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 32d3964763..fd22246410 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -535,6 +535,9 @@ LEAVE_ISLAND_AS_LEADER: |- LEFT_ISLAND: '&e&lIlha | &7Você saiu da sua ilha.' LEFT_ISLAND_COOP: '&e&lIlha | &7Você não é mais um membro cooperativo da ilha de {0}.' LEFT_ISLAND_COOP_NAME: '&e&lIlha | &7Você não é mais um membro cooperativo da ilha {0}.' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lErro | &7Você deve fornecer um material sólido.' MAXIMUM_LEVEL: '&c&lErro | &7O nível máximo para esta atualização é {0}.' MESSAGE_SENT: '&e&lIlha | &7A mensagem foi enviada com sucesso para {0}!' @@ -721,7 +724,9 @@ UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIlha | &7Não há membros da ilha online e, porta UNCOOP_LEFT_ANNOUNCEMENT: '&e&lIlha | &7{0} saiu do jogo e não é mais um membro cooperativo.' UNIGNORED_ISLAND: A ilha de '&e&lIlha | &7{0}' agora não é mais ignorada das ilhas principais.' UNIGNORED_ISLAND_NAME: '&e&lIlha | &7A ilha {0} agora não é mais ignorada das ilhas principais.' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&lMundos | &7Seu mundo {0} agora está desbloqueado!' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lIlha | &7&oParece que este warp não é seguro. Tente outro warp.' UPDATED_PERMISSION: '&e&lIlha | &7Permissões atualizadas para {0}.' UPDATED_SETTINGS: '&e&lIlha | &7Configurações da ilha [{0}] atualizado.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 74b470da07..0442ab89ed 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -535,6 +535,9 @@ LEAVE_ISLAND_AS_LEADER: |- LEFT_ISLAND: '&e&lОстров | &7Вы покинули свой остров.' LEFT_ISLAND_COOP: '&e&lОстров | &7Вы больше не являетесь соучастником острова {0}.' LEFT_ISLAND_COOP_NAME: '&e&lОстров | &7Вы больше не являетесь соучастником острова {0}.' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lОшибка | &7Вы должны предоставить твердый материал.' MAXIMUM_LEVEL: '&c&lОшибка | &7Максимальный уровень для этого улучшения - {0}.' MESSAGE_SENT: '&e&lОстров | &7Сообщение успешно отправлено {0}!' @@ -721,7 +724,9 @@ UNCOOP_AUTO_ANNOUNCEMENT: '&e&lОстров | &7Игроков в коопера UNCOOP_LEFT_ANNOUNCEMENT: '&e&lОстров | &7{0} покинул игру и больше не является членом кооперации.' UNIGNORED_ISLAND: '&e&lОстров | &7Остров {0} больше не игнорируется в топах.' UNIGNORED_ISLAND_NAME: '&e&lОстров | &7Остров {0} больше не игнорируется в топах.' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&lМиры | &7Ваш мир {0} теперь разблокирован!' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lОстров | &7&oПохоже, этот варп небезопасен. Попробуйте другой варп.' UPDATED_PERMISSION: '&e&lОстров | &7Обновлены права для {0}.' UPDATED_SETTINGS: '&e&lОстров | &7Обновлены настройки острова {0}.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 4289f8cb19..0c01b932fe 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -597,6 +597,9 @@ LEFT_ISLAND_COOP: '&e&lĐảo | &7Bạn không còn là thành viên co-op đả nữa.' LEFT_ISLAND_COOP_NAME: '&e&lĐảo | &7Bạn không còn là thành viên co-op đảo {0} nữa.' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&lLỗi | &7Bạn phải cung cấp một vật liệu rắn.' MAXIMUM_LEVEL: '&c&lLỗi | &7Mức tối đa cho việc nâng cấp này là {0}.' MESSAGE_SENT: '&e&lĐảo | &7Gửi thành công {0} tin nhắn!' @@ -818,7 +821,9 @@ UNIGNORED_ISLAND: '&e&lĐảo | &7Đảo của {0} bây giờ không được b đảo hàng đầu.' UNIGNORED_ISLAND_NAME: '&e&lĐảo | &7Đảo {0} bây giờ không được bỏ qua từ các đảo hàng đầu.' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&lThế Giới | &7Thế giới {0} của bạn hiện đã được mở khóa!' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&lĐảo | &7&oCó vẻ như khu vực này không an toàn. Vui lòng thử lại với khu vực khác.' UPDATED_PERMISSION: '&e&lĐảo | &7Đã cập nhật quyền cho {0}.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index ac798c5174..4004bc4a37 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -535,6 +535,9 @@ LEAVE_ISLAND_AS_LEADER: |- LEFT_ISLAND: '&e&l岛屿 | &7你离开了你的岛屿.' LEFT_ISLAND_COOP: '&e&l岛屿 | &7你不再是玩家 {0} 的岛屿合作成员.' LEFT_ISLAND_COOP_NAME: '&e&l岛屿 | &7你不再是岛屿 {0} 的合作成员.' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' MATERIAL_NOT_SOLID: '&c&l错误 | &7你必须提供一个固体方块材料名.' MAXIMUM_LEVEL: '&c&l错误 | &7该功能的最大等级为 {0}.' MESSAGE_SENT: '&e&l岛屿 | &7成功将消息发送给了 {0}!' @@ -721,7 +724,9 @@ UNCOOP_AUTO_ANNOUNCEMENT: '&e&l岛屿 | &7没有岛屿成员在线, 你已被自 UNCOOP_LEFT_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 离开了游戏, 自动取消其成员关系.' UNIGNORED_ISLAND: '&e&l岛屿 | &7{0} 的岛屿现在已重新参与岛屿排行榜计算.' UNIGNORED_ISLAND_NAME: '&e&l岛屿 | &7岛屿 {0} 现在已重新参与岛屿排行榜计算.' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&l世界 | &7你的 {0} 世界现已解锁!' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' UNSAFE_WARP: '&e&l岛屿 | &7&o看起来该传送点不安全. 请尝试使用其他传送点.' UPDATED_PERMISSION: '&e&l岛屿 | &7更新了 {0} 的权限.' UPDATED_SETTINGS: '&e&l岛屿 | &7更新了岛屿设置 {0}.' From fb31a961fab7fbe20a9322ee94f153af8192376f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 18 May 2025 12:55:39 +0300 Subject: [PATCH 180/600] Fixed a NPE when going through portals in 1.8 (#2488) --- .../superiorskyblock/listener/BukkitEventsListener.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index c4a17f0d1d..351d8f6cd0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -734,9 +734,10 @@ private GameEvent createGameEvent(GameEvent private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerPortalEvent e) { GameEventArgs.EntityPortalEvent entityPortalEvent = new GameEventArgs.EntityPortalEvent(); entityPortalEvent.entity = e.getPlayer(); - entityPortalEvent.cause = e.getTo().getWorld().getEnvironment() == World.Environment.THE_END || - e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ? - PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL; + entityPortalEvent.cause = e.getTo() == null ? e.getCause() : + e.getTo().getWorld().getEnvironment() == World.Environment.THE_END || + e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ? + PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL; entityPortalEvent.from = e.getFrom(); entityPortalEvent.to = e.getTo(); return eventType.createEvent(entityPortalEvent); From f57e6e3e9c000724d5300acbc07e56c5537bf133 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 18 May 2025 13:00:05 +0300 Subject: [PATCH 181/600] Fixed a NPE when crops growth multiplier is used in 1.8 (#2487) --- .../bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java index b61d42f7f2..e6ec0c543a 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java @@ -56,6 +56,7 @@ public class NMSChunksImpl implements NMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; KeyBlocksCache.cacheAllBlocks(); + CropsTickingTileEntity.register(); } @Override From 78f0fbbc2b5b7e8c9098097564230482c29492d1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 18 May 2025 13:09:04 +0300 Subject: [PATCH 182/600] Fixed errors when reloading plugin in 1.8 (#2485) --- .../bgsoftware/superiorskyblock/core/collections/ArrayMap.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/ArrayMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/ArrayMap.java index 3ca6c1adcb..e22bc09b62 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/ArrayMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/ArrayMap.java @@ -64,6 +64,7 @@ public void clear() { this.values = EMPTY_ARRAY; this.keys = EMPTY_ARRAY; this.size = 0; + this.capacity = 0; } @Override From a119440b87936656f2e21a1652a9cd160357dd85 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 18 May 2025 13:29:00 +0300 Subject: [PATCH 183/600] Fixed sounds of menus in 1.8 (#2486) --- src/main/resources/menus/bank-logs.yml | 2 +- src/main/resources/menus/bank-logs1_12.yml | 64 + src/main/resources/menus/banned-players.yml | 2 +- .../resources/menus/banned-players1_12.yml | 51 + src/main/resources/menus/biomes.yml | 28 +- src/main/resources/menus/biomes1_12.yml | 205 +++ src/main/resources/menus/border-color.yml | 8 +- src/main/resources/menus/border-color1_12.yml | 67 + src/main/resources/menus/confirm-ban.yml | 4 +- src/main/resources/menus/confirm-ban1_12.yml | 44 + src/main/resources/menus/confirm-disband.yml | 4 +- .../resources/menus/confirm-disband1_12.yml | 44 + src/main/resources/menus/confirm-kick.yml | 4 +- src/main/resources/menus/confirm-kick1_12.yml | 44 + src/main/resources/menus/confirm-leave.yml | 4 +- .../resources/menus/confirm-leave1_12.yml | 44 + src/main/resources/menus/control-panel.yml | 26 +- .../resources/menus/control-panel1_12.yml | 169 +++ src/main/resources/menus/coops.yml | 2 +- src/main/resources/menus/coops1_12.yml | 51 + src/main/resources/menus/counts.yml | 2 +- src/main/resources/menus/counts1_12.yml | 52 + src/main/resources/menus/global-warps.yml | 2 +- src/main/resources/menus/global-warps1_12.yml | 56 + src/main/resources/menus/island-bank.yml | 26 +- src/main/resources/menus/island-bank1_12.yml | 142 ++ src/main/resources/menus/island-chest.yml | 2 +- src/main/resources/menus/island-chest1_12.yml | 53 + src/main/resources/menus/island-creation.yml | 12 +- .../resources/menus/island-creation1_12.yml | 115 ++ src/main/resources/menus/island-rate.yml | 12 +- src/main/resources/menus/island-rate1_12.yml | 77 ++ src/main/resources/menus/member-manage.yml | 6 +- .../resources/menus/member-manage1_12.yml | 57 + src/main/resources/menus/member-role.yml | 8 +- src/main/resources/menus/member-role1_12.yml | 72 + src/main/resources/menus/members.yml | 2 +- src/main/resources/menus/members1_12.yml | 51 + .../resources/menus/missions-category.yml | 6 +- .../resources/menus/missions-category1_12.yml | 47 + src/main/resources/menus/missions.yml | 10 +- src/main/resources/menus/missions1_12.yml | 71 + src/main/resources/menus/permissions.yml | 260 ++-- src/main/resources/menus/player-language.yml | 4 +- .../resources/menus/player-language1_12.yml | 115 ++ src/main/resources/menus/settings.yml | 44 +- src/main/resources/menus/settings1_12.yml | 451 +++++++ src/main/resources/menus/top-islands.yml | 2 +- src/main/resources/menus/top-islands1_12.yml | 88 ++ src/main/resources/menus/unique-visitors.yml | 2 +- .../resources/menus/unique-visitors1_12.yml | 52 + src/main/resources/menus/upgrades.yml | 130 +- src/main/resources/menus/upgrades1_12.yml | 1200 +++++++++++++++++ src/main/resources/menus/visitors.yml | 2 +- src/main/resources/menus/visitors1_12.yml | 57 + .../menus/warp-category-icon-edit.yml | 2 +- .../menus/warp-category-icon-edit1_12.yml | 60 + .../resources/menus/warp-category-manage.yml | 2 +- .../menus/warp-category-manage1_12.yml | 50 + src/main/resources/menus/warp-icon-edit.yml | 2 +- .../resources/menus/warp-icon-edit1_12.yml | 60 + src/main/resources/menus/warp-manage.yml | 2 +- src/main/resources/menus/warp-manage1_12.yml | 58 + src/main/resources/menus/warps.yml | 2 +- src/main/resources/menus/warps1_12.yml | 57 + 65 files changed, 4137 insertions(+), 313 deletions(-) create mode 100644 src/main/resources/menus/bank-logs1_12.yml create mode 100644 src/main/resources/menus/banned-players1_12.yml create mode 100644 src/main/resources/menus/biomes1_12.yml create mode 100644 src/main/resources/menus/border-color1_12.yml create mode 100644 src/main/resources/menus/confirm-ban1_12.yml create mode 100644 src/main/resources/menus/confirm-disband1_12.yml create mode 100644 src/main/resources/menus/confirm-kick1_12.yml create mode 100644 src/main/resources/menus/confirm-leave1_12.yml create mode 100644 src/main/resources/menus/control-panel1_12.yml create mode 100644 src/main/resources/menus/coops1_12.yml create mode 100644 src/main/resources/menus/counts1_12.yml create mode 100644 src/main/resources/menus/global-warps1_12.yml create mode 100644 src/main/resources/menus/island-bank1_12.yml create mode 100644 src/main/resources/menus/island-chest1_12.yml create mode 100644 src/main/resources/menus/island-creation1_12.yml create mode 100644 src/main/resources/menus/island-rate1_12.yml create mode 100644 src/main/resources/menus/member-manage1_12.yml create mode 100644 src/main/resources/menus/member-role1_12.yml create mode 100644 src/main/resources/menus/members1_12.yml create mode 100644 src/main/resources/menus/missions-category1_12.yml create mode 100644 src/main/resources/menus/missions1_12.yml create mode 100644 src/main/resources/menus/player-language1_12.yml create mode 100644 src/main/resources/menus/settings1_12.yml create mode 100644 src/main/resources/menus/top-islands1_12.yml create mode 100644 src/main/resources/menus/unique-visitors1_12.yml create mode 100644 src/main/resources/menus/upgrades1_12.yml create mode 100644 src/main/resources/menus/visitors1_12.yml create mode 100644 src/main/resources/menus/warp-category-icon-edit1_12.yml create mode 100644 src/main/resources/menus/warp-category-manage1_12.yml create mode 100644 src/main/resources/menus/warp-icon-edit1_12.yml create mode 100644 src/main/resources/menus/warp-manage1_12.yml create mode 100644 src/main/resources/menus/warps1_12.yml diff --git a/src/main/resources/menus/bank-logs.yml b/src/main/resources/menus/bank-logs.yml index aebddb2681..decbda174c 100644 --- a/src/main/resources/menus/bank-logs.yml +++ b/src/main/resources/menus/bank-logs.yml @@ -59,6 +59,6 @@ items: sounds: '@': - type: BLOCK_CHEST_OPEN + type: CHEST_OPEN volume: 0.8 pitch: 1 \ No newline at end of file diff --git a/src/main/resources/menus/bank-logs1_12.yml b/src/main/resources/menus/bank-logs1_12.yml new file mode 100644 index 0000000000..aebddb2681 --- /dev/null +++ b/src/main/resources/menus/bank-logs1_12.yml @@ -0,0 +1,64 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lTransaction Logs &r{0}' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '$ $ $ ! $ - $ $ $' + - '# # % # * # ^ # #' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +time-sort: '!' +money-sort: '-' + +items: + '@': + type: PAPER + name: '&e#{0}' + lore: + - '&7Player: {1}' + - '&7Status: {2}' + - '&7Time: {3}' + - '&7Amount: {4}' + - '&7 ' + - '&7&o(( &f&oRight-Click &7&oto filter transactions by this player. ))' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: DOUBLE_PLANT + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + '$': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + '!': + type: WATCH + name: '&6Sort by creation time' + '-': + type: EMERALD + name: '&6Sort by money' + +sounds: + '@': + type: BLOCK_CHEST_OPEN + volume: 0.8 + pitch: 1 \ No newline at end of file diff --git a/src/main/resources/menus/banned-players.yml b/src/main/resources/menus/banned-players.yml index c40187a181..b304f4c567 100644 --- a/src/main/resources/menus/banned-players.yml +++ b/src/main/resources/menus/banned-players.yml @@ -46,6 +46,6 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/banned-players1_12.yml b/src/main/resources/menus/banned-players1_12.yml new file mode 100644 index 0000000000..c40187a181 --- /dev/null +++ b/src/main/resources/menus/banned-players1_12.yml @@ -0,0 +1,51 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Banned Players' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '$ $ $ $ $ $ $ $ $' + - '# # % # * # ^ # #' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +items: + '@': + type: SKULL_ITEM + data: 3 + name: '&e{0}' + lore: + - '&7Click to unban the player.' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: DOUBLE_PLANT + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + '$': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/biomes.yml b/src/main/resources/menus/biomes.yml index fd2a023d2b..24bba9d05d 100644 --- a/src/main/resources/menus/biomes.yml +++ b/src/main/resources/menus/biomes.yml @@ -142,64 +142,64 @@ items: sounds: '!': access: - type: ENTITY_ENDERMAN_TELEPORT + type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '@': access: - type: ENTITY_ENDERMAN_TELEPORT + type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '%': access: - type: ENTITY_ENDERMAN_TELEPORT + type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '^': access: - type: ENTITY_ENDERMAN_TELEPORT + type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '&': access: - type: ENTITY_ENDERMAN_TELEPORT + type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '*': access: - type: ENTITY_ENDERMAN_TELEPORT + type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '~': access: - type: ENTITY_ENDERMAN_TELEPORT + type: ENDERMAN_TELEPORT volume: 0.8 pitch: 0.2 no-access: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/biomes1_12.yml b/src/main/resources/menus/biomes1_12.yml new file mode 100644 index 0000000000..fd2a023d2b --- /dev/null +++ b/src/main/resources/menus/biomes1_12.yml @@ -0,0 +1,205 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lSelect a biome' +previous-menu: true + +pattern: + - '$ $ $ $ $ $ $ $ $' + - '# ! # % # & # ~ #' + - '# # @ # ^ # * # #' + - '$ $ $ $ $ $ $ $ $' + +# Should the current biome be glowing? +current-biome-glow: false + +items: + '$': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + '!': + biome: PLAINS + access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' + name: '&ePlains Biome &a(Available)' + lore: + - '&7Change your island biome to plains.' + no-access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' + name: '&ePlains Biome &c(Unavailable)' + lore: + - '&7Change your island biome to plains.' + '@': + biome: JUNGLE + access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0=' + name: '&eJungle Biome &a(Available)' + lore: + - '&7Change your island biome to jungle.' + no-access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODQ0OWI5MzE4ZTMzMTU4ZTY0YTQ2YWIwZGUxMjFjM2Q0MDAwMGUzMzMyYzE1NzQ5MzJiM2M4NDlkOGZhMGRjMiJ9fX0=' + name: '&eJungle Biome &c(Unavailable)' + lore: + - '&7Change your island biome to jungle.' + '%': + biome: TAIGA + access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ==' + name: '&eTaiga Biome &a(Available)' + lore: + - '&7Change your island biome to taiga.' + no-access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDNjNTJlYWU3NDdjYWQ1YjRmZDE5YjFhMjNiMzlhMzM2YjYyZWQ0MjI3OTdhNjIyZDA0NWY0M2U1ZDM4In19fQ==' + name: '&eTaiga Biome &c(Unavailable)' + lore: + - '&7Change your island biome to taiga.' + '^': + biome: DESERT + access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0=' + name: '&eDesert Biome &a(Available)' + lore: + - '&7Change your island biome to desert.' + - '&cWarning ice and snow must go!' + no-access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTMxOTkzZTRjZmRhMTUzZWFmN2RjMTM4ZDUyYmJhNWMyODNkMDE2MzI2MDIyNjIxNjE3NzZmMGY0Yjg2YSJ9fX0=' + name: '&eDesert Biome &c(Unavailable)' + lore: + - '&7Change your island biome to desert.' + - '&cWarning ice and snow must go!' + '&': + biome: HELL + access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19' + name: '&eNether Biome &a(Available)' + lore: + - '&7Change your island biome to nether.' + - '&cWarning ice, snow and water must go!' + no-access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTU2Y2E1YzY3OTMzNmRkNGYzMjYyZjRmYmMyM2MxYTJlZTBkODJhN2ZkODFlNmU2MjMzN2U1ZmQ1YzcifX19' + name: '&eNether Biome &c(Unavailable)' + lore: + - '&7Change your island biome to nether.' + - '&cWarning ice snow, and water must go!' + '*': + biome: SWAMPLAND + access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0=' + name: '&eSwamp Biome &a(Available)' + lore: + - '&7Change your island biome to swamp.' + no-access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzdlOGNiNTdmZTc5MGU5NjVlM2NmYTZjNGZiYzE2ZTMyMjYyMTBkNjVmNTYxNGU4ODUzZmE5ZmI4NDA3NDQ0MSJ9fX0=' + name: '&eSwamp Biome &c(Unavailable)' + lore: + - '&7Change your island biome to swamp.' + '~': + biome: MESA + access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19' + name: '&eMesa Biome &a(Available)' + lore: + - '&7Change your island biome to Mesa.' + no-access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODJkNWZlZmUyMGRhZjMxYzIzOGVlMjI3ZGQxNDE4MjdhZGE1ZWY4NDgyZDhkMzU3YmJlNWE3Y2Y0MGFmODUifX19' + name: '&eMesa Biome &c(Unavailable)' + lore: + - '&7Change your island biome to Mesa.' + +sounds: + '!': + access: + type: ENTITY_ENDERMAN_TELEPORT + volume: 0.8 + pitch: 0.2 + no-access: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '@': + access: + type: ENTITY_ENDERMAN_TELEPORT + volume: 0.8 + pitch: 0.2 + no-access: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '%': + access: + type: ENTITY_ENDERMAN_TELEPORT + volume: 0.8 + pitch: 0.2 + no-access: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '^': + access: + type: ENTITY_ENDERMAN_TELEPORT + volume: 0.8 + pitch: 0.2 + no-access: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '&': + access: + type: ENTITY_ENDERMAN_TELEPORT + volume: 0.8 + pitch: 0.2 + no-access: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '*': + access: + type: ENTITY_ENDERMAN_TELEPORT + volume: 0.8 + pitch: 0.2 + no-access: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '~': + access: + type: ENTITY_ENDERMAN_TELEPORT + volume: 0.8 + pitch: 0.2 + no-access: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/border-color.yml b/src/main/resources/menus/border-color.yml index 22ec82f8e8..52dc549e7b 100644 --- a/src/main/resources/menus/border-color.yml +++ b/src/main/resources/menus/border-color.yml @@ -50,18 +50,18 @@ items: sounds: '~': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '$': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/border-color1_12.yml b/src/main/resources/menus/border-color1_12.yml new file mode 100644 index 0000000000..22ec82f8e8 --- /dev/null +++ b/src/main/resources/menus/border-color1_12.yml @@ -0,0 +1,67 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&l Border Color' +previous-menu: true +type: HOPPER + +pattern: + - '~ # @ ^ $' + +green-color: '@' +red-color: '^' +blue-color: '$' + +items: + '~': + enable-border: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0=' + name: '&aEnable Border' + disable-border: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvM2ZhZjRjMjlmMWU3NDA1ZjQ2ODBjNWMyYjAzZWY5Mzg0ZjFhZWNmZTI5ODZhZDUwMTM4YzYwNWZlZmZmMmYxNSJ9fX0=' + name: '&cDisable Border' + '#': + type: STAINED_GLASS_PANE + data: 15 + name: '&f ' + '@': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' + name: '&aGreen Color' + '^': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' + name: '&cRed Color' + '$': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzZTY2NDZmMWMwZDQxZmQzYmY1NTg0YTFjZTA0NGY1YzQ2ZDU5ODI1OGRiNDYyMTYxMTc4NTlmNTdhZjE5NyJ9fX0=' + name: '&bBlue Color' + +sounds: + '~': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '^': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '$': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/confirm-ban.yml b/src/main/resources/menus/confirm-ban.yml index 181015313e..2b339fcbcd 100644 --- a/src/main/resources/menus/confirm-ban.yml +++ b/src/main/resources/menus/confirm-ban.yml @@ -35,10 +35,10 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/confirm-ban1_12.yml b/src/main/resources/menus/confirm-ban1_12.yml new file mode 100644 index 0000000000..181015313e --- /dev/null +++ b/src/main/resources/menus/confirm-ban1_12.yml @@ -0,0 +1,44 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&l Confirm Ban' +previous-menu: true +type: HOPPER + +pattern: + - '# @ # ^ #' + +confirm: '@' +cancel: '^' + +items: + '#': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + '@': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' + name: '&aConfirm' + lore: + - '&7Are you sure you want to ban that player?' + '^': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' + name: '&4Cancel' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '^': + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/confirm-disband.yml b/src/main/resources/menus/confirm-disband.yml index 286b95f7d2..c8703d918c 100644 --- a/src/main/resources/menus/confirm-disband.yml +++ b/src/main/resources/menus/confirm-disband.yml @@ -35,10 +35,10 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/confirm-disband1_12.yml b/src/main/resources/menus/confirm-disband1_12.yml new file mode 100644 index 0000000000..286b95f7d2 --- /dev/null +++ b/src/main/resources/menus/confirm-disband1_12.yml @@ -0,0 +1,44 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&l Confirm Disband' +previous-menu: true +type: HOPPER + +pattern: + - '# @ # ^ #' + +confirm: '@' +cancel: '^' + +items: + '#': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + '@': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' + name: '&aConfirm' + lore: + - '&7Are you sure you want to delete your island?' + '^': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' + name: '&4Cancel' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '^': + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/confirm-kick.yml b/src/main/resources/menus/confirm-kick.yml index 21ea5b1b8a..86a66a8675 100644 --- a/src/main/resources/menus/confirm-kick.yml +++ b/src/main/resources/menus/confirm-kick.yml @@ -35,10 +35,10 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/confirm-kick1_12.yml b/src/main/resources/menus/confirm-kick1_12.yml new file mode 100644 index 0000000000..21ea5b1b8a --- /dev/null +++ b/src/main/resources/menus/confirm-kick1_12.yml @@ -0,0 +1,44 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&l Confirm Kick' +previous-menu: true +type: HOPPER + +pattern: + - '# @ # ^ #' + +confirm: '@' +cancel: '^' + +items: + '#': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + '@': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' + name: '&aConfirm' + lore: + - '&7Are you sure you want to kick that player?' + '^': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' + name: '&4Cancel' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '^': + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/confirm-leave.yml b/src/main/resources/menus/confirm-leave.yml index 49a41970b0..acee76b40e 100644 --- a/src/main/resources/menus/confirm-leave.yml +++ b/src/main/resources/menus/confirm-leave.yml @@ -35,10 +35,10 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/confirm-leave1_12.yml b/src/main/resources/menus/confirm-leave1_12.yml new file mode 100644 index 0000000000..49a41970b0 --- /dev/null +++ b/src/main/resources/menus/confirm-leave1_12.yml @@ -0,0 +1,44 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&l Confirm Leave' +previous-menu: true +type: HOPPER + +pattern: + - '# @ # ^ #' + +confirm: '@' +cancel: '^' + +items: + '#': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + '@': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' + name: '&aConfirm' + lore: + - '&7Are you sure you want to leave your island?' + '^': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' + name: '&4Cancel' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '^': + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/control-panel.yml b/src/main/resources/menus/control-panel.yml index 41fc26163f..2ac826ecfc 100644 --- a/src/main/resources/menus/control-panel.yml +++ b/src/main/resources/menus/control-panel.yml @@ -94,55 +94,55 @@ items: sounds: '!': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '$': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '%': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '_': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '&': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '*': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '1': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '~': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '-': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '=': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '+': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 diff --git a/src/main/resources/menus/control-panel1_12.yml b/src/main/resources/menus/control-panel1_12.yml new file mode 100644 index 0000000000..41fc26163f --- /dev/null +++ b/src/main/resources/menus/control-panel1_12.yml @@ -0,0 +1,169 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Panel' +previous-menu: true + +pattern: + - '2 2 2 2 2 2 2 2 2' + - '# ! # @ # $ # % #' + - '_ # ^ # & # * # 1' + - '# ~ # = # - # + #' + - '2 2 2 2 2 2 2 2 2' + +members: '+' +settings: '@' +visitors: '-' + +items: + '!': + type: SIGN + name: '&eTeleport' + lore: + - '&7Teleport back to your island.' + '@': + type: DIODE + name: '&eIsland Settings' + lore: + - '&7Manage settings regarding your island.' + '$': + type: ENDER_PEARL + name: '&eIsland Permissions' + lore: + - '&7Manage permissions in your island.' + '%': + type: GRASS + name: '&eIsland Biomes' + lore: + - '&7Change the biome of your island.' + '_': + type: EMERALD + name: '&eIsland Bank' + lore: + - '&7Open the bank of your island.' + '^': + type: GOLD_INGOT + name: '&eIsland Upgrades' + lore: + - '&7Upgrade your island statistics!' + '&': + type: BEACON + name: '&eTop Islands' + lore: + - '&7Check which island is the best on the server!' + '*': + type: PAPER + name: '&eIsland Missions' + lore: + - '&7Complete missions and get rewarded!' + '1': + type: SMOOTH_BRICK + name: '&eIsland Counts' + lore: + - '&7See all the blocks on your island!' + '~': + type: BARRIER + name: '&eIsland Disband' + lore: + - '&7Disband your island.' + - '&cThis action cannot be restored!' + '=': + type: CHEST + name: '&eIsland Chest' + lore: + - '&7Open the community chest of the island.' + '-': + type: SKULL_ITEM + name: '&eIsland Visitors' + lore: + - '&7Check all the visitors of the island.' + '+': + type: SKULL_ITEM + data: 3 + name: '&eIsland Members' + lore: + - '&7Manage the members of the island.' + '2': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + +sounds: + '!': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '$': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '%': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '_': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '^': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '&': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '*': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '1': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '~': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '-': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '=': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '+': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + +commands: + '!': + - '[player] is tp' + '$': + - '[player] is permissions' + '%': + - '[player] is biome' + '_': + - '[player] is bank' + '^': + - '[player] is upgrade' + '&': + - '[player] is top' + '*': + - '[player] is missions' + '1': + - '[player] is counts' + '~': + - '[player] is disband' + '=': + - '[player] is chest' \ No newline at end of file diff --git a/src/main/resources/menus/coops.yml b/src/main/resources/menus/coops.yml index e572e7f9d4..12850e1743 100644 --- a/src/main/resources/menus/coops.yml +++ b/src/main/resources/menus/coops.yml @@ -46,6 +46,6 @@ items: sounds: '@': - type: BLOCK_CHEST_OPEN + type: CHEST_OPEN volume: 0.8 pitch: 1 \ No newline at end of file diff --git a/src/main/resources/menus/coops1_12.yml b/src/main/resources/menus/coops1_12.yml new file mode 100644 index 0000000000..e572e7f9d4 --- /dev/null +++ b/src/main/resources/menus/coops1_12.yml @@ -0,0 +1,51 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Coop Players ({0}/{1})' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '$ $ $ $ $ $ $ $ $' + - '# # % # * # ^ # #' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +items: + '@': + type: SKULL_ITEM + data: 3 + name: '&e{0}' + lore: + - '&7Click to uncoop the player.' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: DOUBLE_PLANT + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + '$': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + +sounds: + '@': + type: BLOCK_CHEST_OPEN + volume: 0.8 + pitch: 1 \ No newline at end of file diff --git a/src/main/resources/menus/counts.yml b/src/main/resources/menus/counts.yml index 5c16235e55..a7685903d8 100644 --- a/src/main/resources/menus/counts.yml +++ b/src/main/resources/menus/counts.yml @@ -47,6 +47,6 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/counts1_12.yml b/src/main/resources/menus/counts1_12.yml new file mode 100644 index 0000000000..5c16235e55 --- /dev/null +++ b/src/main/resources/menus/counts1_12.yml @@ -0,0 +1,52 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Block Counts' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '$ $ $ $ $ $ $ $ $' + - '# # % # * # ^ # #' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +items: + '@': + type: STONE + name: '&e{0}' + lore: + - '&6&l* &e&lQuantity &fx{1}' + - '&6&l* &e&lWorth: &f${2}' + - '&6&l* &e&lLevel: &f${3}' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: DOUBLE_PLANT + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + '$': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/global-warps.yml b/src/main/resources/menus/global-warps.yml index de31a6c8e3..f93874e01d 100644 --- a/src/main/resources/menus/global-warps.yml +++ b/src/main/resources/menus/global-warps.yml @@ -51,6 +51,6 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/global-warps1_12.yml b/src/main/resources/menus/global-warps1_12.yml new file mode 100644 index 0000000000..de31a6c8e3 --- /dev/null +++ b/src/main/resources/menus/global-warps1_12.yml @@ -0,0 +1,56 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Warps' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '$ $ $ $ $ $ $ $ $' + - '# # % # * # ^ # #' + +warps: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +# When enabled, instead of showing warps, the visitor warp locations will be shown. +# To show the description, use the {1} placeholder. +visitor-warps: false + +items: + '@': + type: SKULL_ITEM + data: 3 + name: '&e{0}''s Island' + lore: + - '&7Click to see all warps of this island.' + - '&8>> &7This island has {2} warps.' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: DOUBLE_PLANT + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + '$': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/island-bank.yml b/src/main/resources/menus/island-bank.yml index 77aac7b961..68581eef87 100644 --- a/src/main/resources/menus/island-bank.yml +++ b/src/main/resources/menus/island-bank.yml @@ -84,59 +84,59 @@ items: sounds: '!': success-sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '#': success-sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '$': success-sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '%': success-sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '^': success-sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '&': success-sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 fail-sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '~': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/island-bank1_12.yml b/src/main/resources/menus/island-bank1_12.yml new file mode 100644 index 0000000000..77aac7b961 --- /dev/null +++ b/src/main/resources/menus/island-bank1_12.yml @@ -0,0 +1,142 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Bank' +previous-menu: true + +pattern: + - '= - @ @ @ @ @ - =' + - '- @ ! @ @ @ % @ -' + - '@ # @ @ * @ @ ^ @' + - '- @ $ @ @ @ & @ -' + - '= - @ @ ~ @ @ - =' + +logs: '~' + +items: + '!': + type: STAINED_GLASS_PANE + data: 5 + name: '&aDeposit Half Money' + lore: + - '&7Deposit half of your money into the bank.' + bank-action: + deposit: 50.0 + '#': + type: STAINED_GLASS_PANE + data: 5 + name: '&aDeposit Money' + lore: + - '&7Deposit money into the bank.' + bank-action: + deposit: 0.0 + '$': + type: STAINED_GLASS_PANE + data: 5 + name: '&aDeposit All Money' + lore: + - '&7Deposit all of your money into the bank.' + bank-action: + deposit: 100.0 + '%': + type: STAINED_GLASS_PANE + data: 14 + name: '&aWithdraw Half Money' + lore: + - '&7Withdraw half of the money from the bank.' + bank-action: + withdraw: 50.0 + '^': + type: STAINED_GLASS_PANE + data: 14 + name: '&aWithdraw Money' + lore: + - '&7Withdraw money from the bank.' + bank-action: + withdraw: 0.0 + '&': + type: STAINED_GLASS_PANE + data: 14 + name: '&aWithdraw All Money' + lore: + - '&7Withdraw all of the money from the bank.' + bank-action: + withdraw: 100.0 + '*': + type: PAPER + name: '&6Balance' + lore: + - '&7Your bank currently has $%superior_island_bank_format%' + '=': + type: EMERALD_BLOCK + name: '&f ' + '-': + type: EMERALD + name: '&f ' + '~': + type: EXP_BOTTLE + name: '&6Transaction Logs' + +sounds: + '!': + success-sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + fail-sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '#': + success-sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + fail-sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '$': + success-sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + fail-sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '%': + success-sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + fail-sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '^': + success-sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + fail-sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '&': + success-sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + fail-sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '~': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/island-chest.yml b/src/main/resources/menus/island-chest.yml index f50f6c5b90..112584f604 100644 --- a/src/main/resources/menus/island-chest.yml +++ b/src/main/resources/menus/island-chest.yml @@ -48,6 +48,6 @@ items: sounds: '@': - type: BLOCK_CHEST_OPEN + type: CHEST_OPEN volume: 0.8 pitch: 1 \ No newline at end of file diff --git a/src/main/resources/menus/island-chest1_12.yml b/src/main/resources/menus/island-chest1_12.yml new file mode 100644 index 0000000000..f50f6c5b90 --- /dev/null +++ b/src/main/resources/menus/island-chest1_12.yml @@ -0,0 +1,53 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Chest' +previous-menu: true + +pattern: + - '# # # # # # # # #' + - '# $ @ @ @ @ @ $ #' + - '# $ @ @ @ @ @ $ #' + - '# $ @ @ @ @ @ $ #' + - '# $ @ @ @ @ @ $ #' + - '# # % # * # ^ # #' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +items: + '@': + valid-page: + type: STORAGE_MINECART + name: '&ePage #{0}' + lore: + - '&eSize: &7{1}' + invalid-page: + type: MINECART + name: '&f ' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: DOUBLE_PLANT + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + '#': + type: RAILS + name: '&f ' + +sounds: + '@': + type: BLOCK_CHEST_OPEN + volume: 0.8 + pitch: 1 \ No newline at end of file diff --git a/src/main/resources/menus/island-creation.yml b/src/main/resources/menus/island-creation.yml index 242a0849c3..2bb54ce78c 100644 --- a/src/main/resources/menus/island-creation.yml +++ b/src/main/resources/menus/island-creation.yml @@ -88,28 +88,28 @@ items: sounds: '@': access: - type: BLOCK_PORTAL_AMBIENT + type: PORTAL_TRIGGER volume: 1 pitch: 0.2 no-access: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '^': access: - type: BLOCK_PORTAL_AMBIENT + type: PORTAL_TRIGGER volume: 1 pitch: 0.2 no-access: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 '$': access: - type: BLOCK_PORTAL_AMBIENT + type: PORTAL_TRIGGER volume: 1 pitch: 0.2 no-access: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/island-creation1_12.yml b/src/main/resources/menus/island-creation1_12.yml new file mode 100644 index 0000000000..242a0849c3 --- /dev/null +++ b/src/main/resources/menus/island-creation1_12.yml @@ -0,0 +1,115 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lCreate a new island...' +previous-menu: true + +pattern: + - '~ ~ ~ ~ ~ ~ ~ ~ ~' + - '# @ # # ^ # # $ #' + - '~ ~ ~ ~ ~ ~ ~ ~ ~' + +items: + '@': + schematic: 'normal' + biome: PLAINS + spawn-offset: '0, 0, 0' + access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' + name: '&eNormal Island &a(Available)' + lore: + - '&7Simple island with trees and a mining area!' + - '&7 ' + - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' + no-access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzk1ZDM3OTkzZTU5NDA4MjY3ODQ3MmJmOWQ4NjgyMzQxM2MyNTBkNDMzMmEyYzdkOGM1MmRlNDk3NmIzNjIifX19' + name: '&eNormal Island &c(Unavailable)' + lore: + - '&7Simple island with trees and a mining area!' + - '&7 ' + - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' + '^': + schematic: 'mycel' + biome: MUSHROOM_ISLAND + spawn-offset: '0, 0, 0' + access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19' + name: '&eMycelium Island &a(Available)' + lore: + - '&7Customized island with lots of mycelium!' + - '&7 ' + - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' + no-access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZWE0NWQxYjQxN2NiZGRjMjE3NjdiMDYwNDRlODk5YjI2NmJmNzhhNjZlMjE4NzZiZTNjMDUxNWFiNTVkNzEifX19' + name: '&eMycelium Island &c(Unavailable)' + lore: + - '&7Customized island with lots of mycelium!' + - '&7 ' + - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' + '$': + schematic: 'desert' + biome: DESERT + spawn-offset: '0, 0, 0' + access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0=' + name: '&eDesert Island &a(Available)' + lore: + - '&7Customized island with lots of sand!' + - '&7 ' + - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' + no-access: + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjVkYjMxMjA2N2JlMWQ1YzRmMTQ3OGFmM2NhMmY2Y2Y4MTA0YWI0Y2NiZmY1NzkxN2M4NTc4ZGFhMTUwMDJjMiJ9fX0=' + name: '&eDesert Island &c(Unavailable)' + lore: + - '&7Customized island with lots of sand!' + - '&7 ' + - '&7&o(( &f&oRight-Click &7&oto preview the island. ))' + '~': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + +sounds: + '@': + access: + type: BLOCK_PORTAL_AMBIENT + volume: 1 + pitch: 0.2 + no-access: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '^': + access: + type: BLOCK_PORTAL_AMBIENT + volume: 1 + pitch: 0.2 + no-access: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '$': + access: + type: BLOCK_PORTAL_AMBIENT + volume: 1 + pitch: 0.2 + no-access: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/island-rate.yml b/src/main/resources/menus/island-rate.yml index d34d46878f..598ab075a0 100644 --- a/src/main/resources/menus/island-rate.yml +++ b/src/main/resources/menus/island-rate.yml @@ -52,26 +52,26 @@ items: sounds: '~': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '%': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '*': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '&': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/island-rate1_12.yml b/src/main/resources/menus/island-rate1_12.yml new file mode 100644 index 0000000000..d34d46878f --- /dev/null +++ b/src/main/resources/menus/island-rate1_12.yml @@ -0,0 +1,77 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lRate Island' +previous-menu: true + +pattern: + - '# ~ @ % # * ^ & #' + +zero-stars: '~' +one-star: '@' +two-stars: '%' +three-stars: '*' +four-stars: '^' +five-stars: '&' + +items: + '~': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODViZDFlNjEzZmYzMmI1MjNjY2Y5ZTU3NGNjMzExYjc5OGMyYjNhNjgyOGYwZjcxYTI1NGM5OTVlNmRiOGU1In19fQ==' + name: '&4Horrible (0/5)' + '@': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmNmYWZmYThjNmM3ZjYyNjIxNjgyZmU1NjcxMWRjM2I4OTQ0NjVmZGY3YTYyZjQzYjMxYTBkMzQwM2YzNGU3In19fQ==' + name: '&6Ugly (1/5)' + '%': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNThjY2ExZTBmYjVkOWJmNzdmNTI3MzU2ZThiZjRlNTNjYjRhNGM1NmYxMWU3NzlhYmFkYWU1NDFiYmVkYzYifX19' + name: '&eNice (2/5)' + '*': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYzQyMjZmMmViNjRhYmM4NmIzOGI2MWQxNDk3NzY0Y2JhMDNkMTc4YWZjMzNiN2I4MDIzY2Y0OGI0OTMxMSJ9fX0=' + name: '&aGood (3/5)' + '^': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI1MjdiMjRiNWQyYmNkYzc1NmY5OTVkMzRlYWU1NzlkNzQxNGIwYTVmMjZjNGZmYTRhNTU4ZWNhZjZiNyJ9fX0=' + name: '&2Beautiful (4/5)' + '&': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDkzNTdjYjQ2NjQ0MjZhOWFlMGY5Yzc3MjVlYTQzNTFkYzY5ZjE1YTgwNjJjMDM1OTFlMjZhYzExYmJjNWEifX19' + name: '&5Fabulous (5/5)' + +sounds: + '~': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '%': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '*': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '^': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '&': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/member-manage.yml b/src/main/resources/menus/member-manage.yml index 225ed9f75f..687a0f227c 100644 --- a/src/main/resources/menus/member-manage.yml +++ b/src/main/resources/menus/member-manage.yml @@ -44,14 +44,14 @@ items: sounds: '@': - type: BLOCK_CHEST_OPEN + type: CHEST_OPEN volume: 0.8 pitch: 1 '%': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/member-manage1_12.yml b/src/main/resources/menus/member-manage1_12.yml new file mode 100644 index 0000000000..225ed9f75f --- /dev/null +++ b/src/main/resources/menus/member-manage1_12.yml @@ -0,0 +1,57 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&8&l{}' +previous-menu: true + +pattern: + - '$ $ $ $ $ $ $ $ $' + - '$ # # # # # # # $' + - '$ # @ # % # ^ # $' + - '$ # # # # # # # $' + - '$ $ $ $ $ $ $ $ $' + +roles: '@' +ban: '%' +kick: '^' + +items: + '$': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + '@': + type: DIAMOND_CHESTPLATE + name: '&ePlayer Role' + lore: + - '&7Click to edit player''s role.' + flags: + - HIDE_ATTRIBUTES + '%': + type: BARRIER + name: '&eBan Player' + lore: + - '&7Click to ban the player from the island.' + '^': + type: SKULL_ITEM + name: '&eKick Player' + lore: + - '&7Click to kick the player from the island.' + +sounds: + '@': + type: BLOCK_CHEST_OPEN + volume: 0.8 + pitch: 1 + '%': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '^': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/member-role.yml b/src/main/resources/menus/member-role.yml index 592621da9b..8b8374048b 100644 --- a/src/main/resources/menus/member-role.yml +++ b/src/main/resources/menus/member-role.yml @@ -55,18 +55,18 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '%': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '&': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '*': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/member-role1_12.yml b/src/main/resources/menus/member-role1_12.yml new file mode 100644 index 0000000000..592621da9b --- /dev/null +++ b/src/main/resources/menus/member-role1_12.yml @@ -0,0 +1,72 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&8&l{}' +previous-menu: true + +pattern: + - '$ $ $ $ $ $ $ $ $' + - '$ # # # # # # # $' + - '$ @ # % # & # * $' + - '$ # # # # # # # $' + - '$ $ $ $ $ $ $ $ $' + +items: + '$': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + '@': + role: Member + type: LEATHER_CHESTPLATE + name: '&eMember' + lore: + - '&7Click to set player''s role to member.' + flags: + - HIDE_ATTRIBUTES + '%': + role: Moderator + type: GOLD_CHESTPLATE + name: '&eModerator' + lore: + - '&7Click to set player''s role to moderator.' + flags: + - HIDE_ATTRIBUTES + '&': + role: Admin + type: IRON_CHESTPLATE + name: '&eAdmin' + lore: + - '&7Click to set player''s role to admin.' + flags: + - HIDE_ATTRIBUTES + '*': + role: Leader + type: DIAMOND_CHESTPLATE + name: '&eLeader' + lore: + - '&7Click to transfer leadership to player.' + flags: + - HIDE_ATTRIBUTES + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '%': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '&': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '*': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/members.yml b/src/main/resources/menus/members.yml index 2756fbca86..ddcbfe16c8 100644 --- a/src/main/resources/menus/members.yml +++ b/src/main/resources/menus/members.yml @@ -46,6 +46,6 @@ items: sounds: '@': - type: BLOCK_CHEST_OPEN + type: CHEST_OPEN volume: 0.8 pitch: 1 \ No newline at end of file diff --git a/src/main/resources/menus/members1_12.yml b/src/main/resources/menus/members1_12.yml new file mode 100644 index 0000000000..2756fbca86 --- /dev/null +++ b/src/main/resources/menus/members1_12.yml @@ -0,0 +1,51 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Members' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '$ $ $ $ $ $ $ $ $' + - '# # % # * # ^ # #' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +items: + '@': + type: SKULL_ITEM + data: 3 + name: '&e{0}' + lore: + - '&eRole: &7{1}' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: DOUBLE_PLANT + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + '$': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + +sounds: + '@': + type: BLOCK_CHEST_OPEN + volume: 0.8 + pitch: 1 \ No newline at end of file diff --git a/src/main/resources/menus/missions-category.yml b/src/main/resources/menus/missions-category.yml index d93cd3b3eb..dcc6755c0f 100644 --- a/src/main/resources/menus/missions-category.yml +++ b/src/main/resources/menus/missions-category.yml @@ -34,14 +34,14 @@ items: sounds: '@': completed: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 not-completed: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 can-complete: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/missions-category1_12.yml b/src/main/resources/menus/missions-category1_12.yml new file mode 100644 index 0000000000..d93cd3b3eb --- /dev/null +++ b/src/main/resources/menus/missions-category1_12.yml @@ -0,0 +1,47 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&l{0} Missions' +previous-menu: true + +pattern: + - '# # # # # # # # #' + - '# # @ @ @ @ @ # #' + - '# # # # # # # # #' + +slots: '@' +previous-page: '*' +current-page: '*' +next-page: '*' + +# Should missions be sorted by their completion status? +# Not completed -> Can complete -> Completed +sort-by-completion: false + +# Should completed missions not be displayed in the menu? +remove-completed: false + +items: + '#': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + +sounds: + '@': + completed: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + not-completed: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + can-complete: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/missions.yml b/src/main/resources/menus/missions.yml index ecad82af88..c49b60fc39 100644 --- a/src/main/resources/menus/missions.yml +++ b/src/main/resources/menus/missions.yml @@ -50,22 +50,22 @@ items: sounds: '#': - type: BLOCK_CHEST_OPEN + type: CHEST_OPEN volume: 0.8 pitch: 1 '@': - type: BLOCK_CHEST_OPEN + type: CHEST_OPEN volume: 0.8 pitch: 1 '%': - type: BLOCK_CHEST_OPEN + type: CHEST_OPEN volume: 0.8 pitch: 1 '^': - type: BLOCK_CHEST_OPEN + type: CHEST_OPEN volume: 0.8 pitch: 1 '&': - type: BLOCK_CHEST_OPEN + type: CHEST_OPEN volume: 0.8 pitch: 1 \ No newline at end of file diff --git a/src/main/resources/menus/missions1_12.yml b/src/main/resources/menus/missions1_12.yml new file mode 100644 index 0000000000..ecad82af88 --- /dev/null +++ b/src/main/resources/menus/missions1_12.yml @@ -0,0 +1,71 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lMissions' +previous-menu: true + +pattern: + - '$ $ $ $ $ $ $ $ $' + - '$ * * * * * * * $' + - '$ * # @ % ^ & * $' + - '$ * * * * * * * $' + - '$ $ $ $ $ $ $ $ $' + +items: + '$': + type: STAINED_GLASS_PANE + data: 15 + '#': + type: DIAMOND_PICKAXE + name: '&eMiner Missions' + lore: + - '&7Click to start your adventure as a Miner.' + flags: + - HIDE_ATTRIBUTES + '@': + type: SKULL_ITEM + data: 2 + name: '&eSlayer Missions' + lore: + - '&7Click to start your adventure as a Slayer.' + '%': + type: WHEAT + name: '&eFarmer Missions' + lore: + - '&7Click to start your adventure as a Farmer.' + '^': + type: FISHING_ROD + name: '&eFisherman Missions' + lore: + - '&7Click to start your adventure as a Fisherman.' + '&': + type: MAP + name: '&eExplorer Missions' + lore: + - '&7Click to start your adventure as an Explorer.' + +sounds: + '#': + type: BLOCK_CHEST_OPEN + volume: 0.8 + pitch: 1 + '@': + type: BLOCK_CHEST_OPEN + volume: 0.8 + pitch: 1 + '%': + type: BLOCK_CHEST_OPEN + volume: 0.8 + pitch: 1 + '^': + type: BLOCK_CHEST_OPEN + volume: 0.8 + pitch: 1 + '&': + type: BLOCK_CHEST_OPEN + volume: 0.8 + pitch: 1 \ No newline at end of file diff --git a/src/main/resources/menus/permissions.yml b/src/main/resources/menus/permissions.yml index 006e244ebd..bb0b4e4e1a 100644 --- a/src/main/resources/menus/permissions.yml +++ b/src/main/resources/menus/permissions.yml @@ -67,12 +67,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -100,12 +100,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -133,12 +133,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -166,12 +166,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -202,12 +202,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -235,12 +235,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -268,12 +268,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -301,12 +301,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -334,12 +334,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -367,12 +367,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -400,12 +400,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -433,12 +433,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -466,12 +466,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -499,12 +499,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -532,12 +532,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -565,12 +565,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -598,12 +598,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -634,12 +634,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -667,12 +667,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -703,12 +703,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -736,12 +736,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -769,12 +769,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -802,12 +802,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -835,12 +835,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -868,12 +868,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -904,12 +904,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -937,12 +937,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -970,12 +970,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1006,12 +1006,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1042,12 +1042,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1075,12 +1075,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1111,12 +1111,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1144,12 +1144,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1177,12 +1177,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1210,12 +1210,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1243,12 +1243,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1276,12 +1276,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1309,12 +1309,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1342,12 +1342,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1378,12 +1378,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1414,12 +1414,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1447,12 +1447,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1480,12 +1480,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1513,12 +1513,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1549,12 +1549,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1582,12 +1582,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1615,12 +1615,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1648,12 +1648,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1681,12 +1681,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1714,12 +1714,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1747,12 +1747,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1783,12 +1783,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1816,12 +1816,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1852,12 +1852,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1885,12 +1885,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1918,12 +1918,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1951,12 +1951,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -1984,12 +1984,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -2017,12 +2017,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -2050,12 +2050,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -2083,12 +2083,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -2116,12 +2116,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -2149,12 +2149,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -2188,12 +2188,12 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 @@ -2221,11 +2221,11 @@ permissions: - '{0}' has-access: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 no-access: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/player-language.yml b/src/main/resources/menus/player-language.yml index 98182f3de5..045aca59be 100644 --- a/src/main/resources/menus/player-language.yml +++ b/src/main/resources/menus/player-language.yml @@ -106,10 +106,10 @@ items: sounds: '#': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 '^': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/player-language1_12.yml b/src/main/resources/menus/player-language1_12.yml new file mode 100644 index 0000000000..98182f3de5 --- /dev/null +++ b/src/main/resources/menus/player-language1_12.yml @@ -0,0 +1,115 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lSelect Language...' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ # % * + ^ ~ 1 @' + - '@ @ - = @ ! 2 @ @' + - '@ @ @ @ @ @ @ @ @' + +items: + '#': + language: 'en-US' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNGNhYzk3NzRkYTEyMTcyNDg1MzJjZTE0N2Y3ODMxZjY3YTEyZmRjY2ExY2YwY2I0YjM4NDhkZTZiYzk0YjQifX19' + name: '&eEnglish' + lore: + - '&7Change language to English.' + '%': + language: 'iw-IL' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMWJhMDg2YTJjYzcyNzJjZjViYTQ5YzgwMjQ4NTQ2YzIyZTVlZjFiYWI1NDEyMGU4YThlNWQ5ZTc1YjZhIn19fQ==' + name: '&eHebrew' + lore: + - '&7Change language to Hebrew.' + '*': + language: 'vi-VN' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGE1N2I5ZDdkZDA0MTY5NDc4Y2ZkYjhkMGI2ZmQwYjhjODJiNjU2NmJiMjgzNzFlZTlhN2M3YzE2NzFhZDBiYiJ9fX0=' + name: '&eVietnamese' + lore: + - '&7Change language to Vietnamese.' + '+': + language: 'pl-PL' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTIxYjJhZjhkMjMyMjI4MmZjZTRhMWFhNGYyNTdhNTJiNjhlMjdlYjMzNGY0YTE4MWZkOTc2YmFlNmQ4ZWIifX19' + name: '&ePolish' + lore: + - '&7Change language to Polish.' + '2': + language: 'pt-BR' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOWE0NjQ3NWQ1ZGNjODE1ZjZjNWYyODU5ZWRiYjEwNjExZjNlODYxYzBlYjE0ZjA4ODE2MWIzYzBjY2IyYjBkOSJ9fX0=' + name: '&eBrazilian Portuguese' + lore: + - '&7Change language to Brazilian Portuguese.' + '^': + language: 'it-IT' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODVjZTg5MjIzZmE0MmZlMDZhZDY1ZDhkNDRjYTQxMmFlODk5YzgzMTMwOWQ2ODkyNGRmZTBkMTQyZmRiZWVhNCJ9fX0=' + name: '&eItalian' + lore: + - '&7Change language to Italian.' + '~': + language: 'zh-CN' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2Y5YmMwMzVjZGM4MGYxYWI1ZTExOThmMjlmM2FkM2ZkZDJiNDJkOWE2OWFlYjY0ZGU5OTA2ODE4MDBiOThkYyJ9fX0=' + name: '&eSimplified Chinese' + lore: + - '&7Change language to Simplified Chinese.' + '1': + language: 'ru-RU' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZlYWZlZjk4MGQ2MTE3ZGFiZTg5ODJhYzRiNDUwOTg4N2UyYzQ2MjFmNmE4ZmU1YzliNzM1YTgzZDc3NWFkIn19fQ==' + name: '&eRussian' + lore: + - '&7Change language to Russian.' + '-': + language: 'fr-FR' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTEyNjlhMDY3ZWUzN2U2MzYzNWNhMWU3MjNiNjc2ZjEzOWRjMmRiZGRmZjk2YmJmZWY5OWQ4YjM1Yzk5NmJjIn19fQ==' + name: '&eFrench' + lore: + - '&7Change language to French.' + '=': + language: 'es-ES' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzJiZDQ1MjE5ODMzMDllMGFkNzZjMWVlMjk4NzQyODc5NTdlYzNkOTZmOGQ4ODkzMjRkYThjODg3ZTQ4NWVhOCJ9fX0=' + name: '&eSpanish' + lore: + - '&7Change language to Spanish.' + '!': + language: 'de-DE' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWU3ODk5YjQ4MDY4NTg2OTdlMjgzZjA4NGQ5MTczZmU0ODc4ODY0NTM3NzQ2MjZiMjRiZDhjZmVjYzc3YjNmIn19fQ==' + name: '&eGerman' + lore: + - '&7Change language to German.' + +sounds: + '#': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '^': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/settings.yml b/src/main/resources/menus/settings.yml index 7a63dad0a8..41123e3fce 100644 --- a/src/main/resources/menus/settings.yml +++ b/src/main/resources/menus/settings.yml @@ -54,7 +54,7 @@ settings: - '&7Set a day time on your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -74,7 +74,7 @@ settings: - '&7Set a middle day time on your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -94,7 +94,7 @@ settings: - '&7Set a night time on your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -114,7 +114,7 @@ settings: - '&7Set a middle night day time on your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -132,7 +132,7 @@ settings: - '&7Set a rainy weather on your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -150,7 +150,7 @@ settings: - '&7Set a shiny weather on your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -170,7 +170,7 @@ settings: - '&7Allow creepers to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -188,7 +188,7 @@ settings: - '&7Allow growth of crops inside your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -206,7 +206,7 @@ settings: - '&7Allow chickens to lay eggs inside your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -224,7 +224,7 @@ settings: - '&7Allow enderman to grief blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -242,7 +242,7 @@ settings: - '&7Allow fire to spread inside your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -260,7 +260,7 @@ settings: - '&7Allow fireballs to break blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -278,7 +278,7 @@ settings: - '&7Allow lava to flow inside your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -298,7 +298,7 @@ settings: - '&7Allow natural spawning of animals inside the island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -318,7 +318,7 @@ settings: - '&7Allow natural spawning of monsters inside the island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -336,7 +336,7 @@ settings: - '&7Allow players to pvp inside the island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -354,7 +354,7 @@ settings: - '&7Allow spawner spawning of animals inside the island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -372,7 +372,7 @@ settings: - '&7Allow spawner spawning of monsters inside the island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -390,7 +390,7 @@ settings: - '&7Allow TNT to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -408,7 +408,7 @@ settings: - '&7Allow growth of trees inside your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -426,7 +426,7 @@ settings: - '&7Allow water to flow inside your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -446,6 +446,6 @@ settings: - '&7Allow withers to explode blocks inside your island.' - '&7Currently &cDISABLED&7.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/settings1_12.yml b/src/main/resources/menus/settings1_12.yml new file mode 100644 index 0000000000..7a63dad0a8 --- /dev/null +++ b/src/main/resources/menus/settings1_12.yml @@ -0,0 +1,451 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Settings' +previous-menu: true + +pattern: + - '$ $ $ $ $ $ $ $ $' + - '$ @ @ @ @ @ @ @ $' + - '$ @ @ @ @ @ @ @ $' + - '$ @ @ @ @ @ @ @ $' + - '$ $ % $ * $ ^ $ $' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +items: + '$': + type: STAINED_GLASS_PANE + data: 3 + name: '&f' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: DOUBLE_PLANT + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + +settings: + always_day: + settings-enabled: + type: STAINED_CLAY + data: 4 + name: '&6Always Day' + lore: + - '&7Set a day time on your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: STAINED_CLAY + data: 4 + name: '&6Always Day' + lore: + - '&7Set a day time on your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + always_middle_day: + settings-enabled: + type: STAINED_CLAY + data: 1 + name: '&6Always Middle Day' + lore: + - '&7Set a middle day time on your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: STAINED_CLAY + data: 1 + name: '&6Always Middle Day' + lore: + - '&7Set a middle day time on your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + always_night: + settings-enabled: + type: STAINED_CLAY + data: 3 + name: '&6Always Night' + lore: + - '&7Set a night time on your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: STAINED_CLAY + data: 3 + name: '&6Always Night' + lore: + - '&7Set a night time on your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + always_middle_night: + settings-enabled: + type: STAINED_CLAY + data: 11 + name: '&6Always Middle Night' + lore: + - '&7Set a middle night day time on your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: STAINED_CLAY + data: 11 + name: '&6Always Middle Night' + lore: + - '&7Set a middle night day time on your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + always_rain: + settings-enabled: + type: WATER_LILY + name: '&6Always Rain' + lore: + - '&7Set a rainy weather on your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: WATER_LILY + name: '&6Always Rain' + lore: + - '&7Set a rainy weather on your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + always_shiny: + settings-enabled: + type: DEAD_BUSH + name: '&6Always Shiny' + lore: + - '&7Set a shiny weather on your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: DEAD_BUSH + name: '&6Always Shiny' + lore: + - '&7Set a shiny weather on your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + creeper_explosion: + settings-enabled: + type: SKULL_ITEM + data: 4 + name: '&6Creeper Explosion' + lore: + - '&7Allow creepers to explode blocks inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: SKULL_ITEM + data: 4 + name: '&6Creeper Explosion' + lore: + - '&7Allow creepers to explode blocks inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + crops_growth: + settings-enabled: + type: SEEDS + name: '&6Crops Growth' + lore: + - '&7Allow growth of crops inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: SEEDS + name: '&6Crops Growth' + lore: + - '&7Allow growth of crops inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + egg_lay: + settings-enabled: + type: EGG + name: '&6Egg Lay' + lore: + - '&7Allow chickens to lay eggs inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: EGG + name: '&6Egg Lay' + lore: + - '&7Allow chickens to lay eggs inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + enderman_grief: + settings-enabled: + type: ENDER_PEARL + name: '&6Enderman Grief' + lore: + - '&7Allow enderman to grief blocks inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: ENDER_PEARL + name: '&6Enderman Grief' + lore: + - '&7Allow enderman to grief blocks inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + fire_spread: + settings-enabled: + type: FLINT_AND_STEEL + name: '&6Fire Spread' + lore: + - '&7Allow fire to spread inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: FLINT_AND_STEEL + name: '&6Fire Spread' + lore: + - '&7Allow fire to spread inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + ghast_fireball: + settings-enabled: + type: FIREBALL + name: '&6Ghast Fireball' + lore: + - '&7Allow fireballs to break blocks inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: FIREBALL + name: '&6Ghast Fireball' + lore: + - '&7Allow fireballs to break blocks inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + lava_flow: + settings-enabled: + type: LAVA_BUCKET + name: '&6Lava Flow' + lore: + - '&7Allow lava to flow inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: LAVA_BUCKET + name: '&6Lava Flow' + lore: + - '&7Allow lava to flow inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + natural_animals_spawn: + settings-enabled: + type: MONSTER_EGG + data: 90 + name: '&6Natural Animals Spawn' + lore: + - '&7Allow natural spawning of animals inside the island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: MONSTER_EGG + data: 90 + name: '&6Natural Animals Spawn' + lore: + - '&7Allow natural spawning of animals inside the island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + natural_monster_spawn: + settings-enabled: + type: MONSTER_EGG + data: 54 + name: '&6Natural Monster Spawn' + lore: + - '&7Allow natural spawning of monsters inside the island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: MONSTER_EGG + data: 54 + name: '&6Natural Monster Spawn' + lore: + - '&7Allow natural spawning of monsters inside the island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + pvp: + settings-enabled: + type: DIAMOND_SWORD + name: '&6PvP' + lore: + - '&7Allow players to pvp inside the island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: DIAMOND_SWORD + name: '&6PvP' + lore: + - '&7Allow players to pvp inside the island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + spawner_animals_spawn: + settings-enabled: + type: MOB_SPAWNER + name: '&6Spawner Animals Spawn' + lore: + - '&7Allow spawner spawning of animals inside the island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: MOB_SPAWNER + name: '&6Spawner Animals Spawn' + lore: + - '&7Allow spawner spawning of animals inside the island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + spawner_monster_spawn: + settings-enabled: + type: MOB_SPAWNER + name: '&6Spawner Monster Spawn' + lore: + - '&7Allow spawner spawning of monsters inside the island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: MOB_SPAWNER + name: '&6Spawner Monster Spawn' + lore: + - '&7Allow spawner spawning of monsters inside the island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + tnt_explosion: + settings-enabled: + type: TNT + name: '&6TNT Explosion' + lore: + - '&7Allow TNT to explode blocks inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: TNT + name: '&6TNT Explosion' + lore: + - '&7Allow TNT to explode blocks inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + tree_growth: + settings-enabled: + type: SAPLING + name: '&6Tree Growth' + lore: + - '&7Allow growth of trees inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: SAPLING + name: '&6Tree Growth' + lore: + - '&7Allow growth of trees inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + water_flow: + settings-enabled: + type: WATER_BUCKET + name: '&6Water Flow' + lore: + - '&7Allow water to flow inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: WATER_BUCKET + name: '&6Water Flow' + lore: + - '&7Allow water to flow inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + wither_explosion: + settings-enabled: + type: SKULL_ITEM + data: 1 + name: '&6Wither Explosion' + lore: + - '&7Allow withers to explode blocks inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: SKULL_ITEM + data: 1 + name: '&6Wither Explosion' + lore: + - '&7Allow withers to explode blocks inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/top-islands.yml b/src/main/resources/menus/top-islands.yml index 17d7d7253f..3740b853c1 100644 --- a/src/main/resources/menus/top-islands.yml +++ b/src/main/resources/menus/top-islands.yml @@ -83,6 +83,6 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/top-islands1_12.yml b/src/main/resources/menus/top-islands1_12.yml new file mode 100644 index 0000000000..17d7d7253f --- /dev/null +++ b/src/main/resources/menus/top-islands1_12.yml @@ -0,0 +1,88 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lTop Islands' +previous-menu: true + +pattern: + - '~ ~ ~ ~ ~ ~ ~ ~ ~' + - '@ % @ @ @ # @ @ @' + - '@ * @ @ # # # @ @' + - '@ ^ @ # # # # # @' + - '@ & @ @ @ $ @ @ @' + - '~ ~ ! ~ - ~ + ~ ~' + +slots: '#' +previous-page: '!' +current-page: '-' +next-page: '+' + +player-island: '$' +sort-glow-when-selected: true + +items: + '#': + island: + type: SKULL_ITEM + data: 3 + name: '&e&l[!] Island: &6&n{0}&7 (#{1})' + lore: + - '&7' + - '&6&l* &e&lIsland Level &7{2}' + - '&7' + - '&6&l* &e&lPlace &7#{1}' + - '&6&l* &e&lWorth &7${3}' + - '&6&l* &e&lRating {8} &7({9})' + - '&6&l* &e&lPlayers &7{10}' + - '&7' + - '&6&l* &e&lMembers:' + - '{4}:&f - &7{}' + - '&7' + - '&7&o(( &f&oLeft-Click &7&oto view their items. ))' + - '&7&o(( &f&oRight-Click &7&oto teleport to island warp. ))' + no-island: + type: SKULL_ITEM + data: 3 + name: '&cInvalid Island' + '%': + type: DIAMOND + sorting-type: 'WORTH' + name: '&6Sort by Worth' + '*': + type: GOLD_INGOT + sorting-type: 'LEVEL' + name: '&6Sort by Level' + '^': + type: EMERALD + sorting-type: 'RATING' + name: '&6Sort by Rating' + '&': + type: SKULL_ITEM + data: 3 + sorting-type: 'PLAYERS' + name: '&6Sort by Players' + '!': + type: PAPER + name: '{0}Previous Page' + '-': + type: DOUBLE_PLANT + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '+': + type: PAPER + name: '{0}Next Page' + '~': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/unique-visitors.yml b/src/main/resources/menus/unique-visitors.yml index d3272e3409..e2d60ab557 100644 --- a/src/main/resources/menus/unique-visitors.yml +++ b/src/main/resources/menus/unique-visitors.yml @@ -47,6 +47,6 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/unique-visitors1_12.yml b/src/main/resources/menus/unique-visitors1_12.yml new file mode 100644 index 0000000000..d3272e3409 --- /dev/null +++ b/src/main/resources/menus/unique-visitors1_12.yml @@ -0,0 +1,52 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Visitors ({0})' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '$ $ $ $ $ $ $ $ $' + - '# # % # * # ^ # #' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +items: + '@': + type: SKULL_ITEM + data: 3 + name: '&e{0}' + lore: + - '&7Island Owner: {1}' + - '&7Last Time Joined: {3}' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: DOUBLE_PLANT + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + '$': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/upgrades.yml b/src/main/resources/menus/upgrades.yml index 596cce7021..57e511c450 100644 --- a/src/main/resources/menus/upgrades.yml +++ b/src/main/resources/menus/upgrades.yml @@ -27,7 +27,7 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 @@ -37,7 +37,7 @@ upgrades: '1': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: HOPPER @@ -56,7 +56,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: HOPPER @@ -76,7 +76,7 @@ upgrades: '2': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: HOPPER @@ -95,7 +95,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: HOPPER @@ -115,7 +115,7 @@ upgrades: '3': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: HOPPER @@ -134,7 +134,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: HOPPER @@ -154,7 +154,7 @@ upgrades: '4': has-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: HOPPER @@ -164,7 +164,7 @@ upgrades: - '&7level of the hoppers limit!' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: HOPPER @@ -177,7 +177,7 @@ upgrades: '1': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: DIAMOND_HOE @@ -196,7 +196,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: DIAMOND_HOE @@ -216,7 +216,7 @@ upgrades: '2': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: DIAMOND_HOE @@ -235,7 +235,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: DIAMOND_HOE @@ -255,7 +255,7 @@ upgrades: '3': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: DIAMOND_HOE @@ -274,7 +274,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: DIAMOND_HOE @@ -294,7 +294,7 @@ upgrades: '4': has-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: DIAMOND_HOE @@ -304,7 +304,7 @@ upgrades: - '&7level of the crop growth!' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: DIAMOND_HOE @@ -317,7 +317,7 @@ upgrades: '1': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: MOB_SPAWNER @@ -336,7 +336,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: MOB_SPAWNER @@ -356,7 +356,7 @@ upgrades: '2': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: MOB_SPAWNER @@ -375,7 +375,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: MOB_SPAWNER @@ -395,7 +395,7 @@ upgrades: '3': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: MOB_SPAWNER @@ -414,7 +414,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: MOB_SPAWNER @@ -434,7 +434,7 @@ upgrades: '4': has-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: MOB_SPAWNER @@ -444,7 +444,7 @@ upgrades: - '&7level of the spawner rates!' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: MOB_SPAWNER @@ -457,7 +457,7 @@ upgrades: '1': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: ROTTEN_FLESH @@ -476,7 +476,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: ROTTEN_FLESH @@ -496,7 +496,7 @@ upgrades: '2': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: ROTTEN_FLESH @@ -515,7 +515,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: ROTTEN_FLESH @@ -535,7 +535,7 @@ upgrades: '3': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: ROTTEN_FLESH @@ -554,7 +554,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: ROTTEN_FLESH @@ -574,7 +574,7 @@ upgrades: '4': has-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: ROTTEN_FLESH @@ -584,7 +584,7 @@ upgrades: - '&7level of the mob drops!' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: ROTTEN_FLESH @@ -597,7 +597,7 @@ upgrades: '1': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: SKULL_ITEM @@ -617,7 +617,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: SKULL_ITEM @@ -638,7 +638,7 @@ upgrades: '2': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: SKULL_ITEM @@ -658,7 +658,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: SKULL_ITEM @@ -679,7 +679,7 @@ upgrades: '3': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: SKULL_ITEM @@ -699,7 +699,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: SKULL_ITEM @@ -720,7 +720,7 @@ upgrades: '4': has-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: SKULL_ITEM @@ -731,7 +731,7 @@ upgrades: - '&7level of the members limit!' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: SKULL_ITEM @@ -745,7 +745,7 @@ upgrades: '1': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: BARRIER @@ -764,7 +764,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: BARRIER @@ -784,7 +784,7 @@ upgrades: '2': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: BARRIER @@ -803,7 +803,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: BARRIER @@ -823,7 +823,7 @@ upgrades: '3': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: BARRIER @@ -842,7 +842,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: BARRIER @@ -862,7 +862,7 @@ upgrades: '4': has-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: BARRIER @@ -872,7 +872,7 @@ upgrades: - '&7level of the border size!' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: BARRIER @@ -885,7 +885,7 @@ upgrades: '1': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: COBBLESTONE @@ -908,7 +908,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: COBBLESTONE @@ -932,7 +932,7 @@ upgrades: '2': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: COBBLESTONE @@ -957,7 +957,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: COBBLESTONE @@ -983,7 +983,7 @@ upgrades: '3': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: COBBLESTONE @@ -1011,7 +1011,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: COBBLESTONE @@ -1040,7 +1040,7 @@ upgrades: '4': has-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: COBBLESTONE @@ -1050,7 +1050,7 @@ upgrades: - '&7level of the generator rates!' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: COBBLESTONE @@ -1063,7 +1063,7 @@ upgrades: '1': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: MINECART @@ -1082,7 +1082,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: MINECART @@ -1102,7 +1102,7 @@ upgrades: '2': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: MINECART @@ -1121,7 +1121,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: MINECART @@ -1141,7 +1141,7 @@ upgrades: '3': has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 type: MINECART @@ -1160,7 +1160,7 @@ upgrades: - '&aLeft-click to purchase upgrade.' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: MINECART @@ -1180,7 +1180,7 @@ upgrades: '4': has-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: MINECART @@ -1190,7 +1190,7 @@ upgrades: - '&7level of the minecarts limit!' no-next-level: sound: - type: BLOCK_ANVIL_PLACE + type: ANVIL_LAND volume: 0.2 pitch: 0.2 type: MINECART diff --git a/src/main/resources/menus/upgrades1_12.yml b/src/main/resources/menus/upgrades1_12.yml new file mode 100644 index 0000000000..596cce7021 --- /dev/null +++ b/src/main/resources/menus/upgrades1_12.yml @@ -0,0 +1,1200 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Upgrades' +previous-menu: true + +pattern: + - '$ $ $ $ $ $ $ $ $' + - '% % @ % # % ^ % %' + - '% % % ! % + % % %' + - '% % * % ~ % & % %' + - '$ $ $ $ $ $ $ $ $' + +items: + '$': + type: STAINED_GLASS_PANE + data: 9 + name: '&f' + '%': + type: STAINED_GLASS_PANE + data: 11 + name: '&f' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + +upgrades: + hoppers-limit: + item: '@' + '1': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: HOPPER + name: '&d&lHopper Increase &a(Available)' + lore: + - '&7' + - '&dNext Level: &e2' + - '&7' + - '&7Purchasing the hopper upgrade' + - '&7will increase your island''s' + - '&7max hoppers limit.' + - '&7' + - '&dAmount: &f16x Hoppers' + - '&dPrice: &f$1,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: HOPPER + name: '&d&lHopper Increase &c(Unavailable)' + lore: + - '&7' + - '&dNext Level: &e2' + - '&7' + - '&7Purchasing the hopper upgrade' + - '&7will increase your island''s' + - '&7max hoppers limit.' + - '&7' + - '&dAmount: &f16x Hoppers' + - '&dPrice: &f$1,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '2': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: HOPPER + name: '&d&lHopper Increase &a(Available)' + lore: + - '&7' + - '&dNext Level: &e3' + - '&7' + - '&7Purchasing the hopper upgrade' + - '&7will increase your island''s' + - '&7max hoppers limit.' + - '&7' + - '&dAmount: &f32x Hoppers' + - '&dPrice: &f$3,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: HOPPER + name: '&d&lHopper Increase &c(Unavailable)' + lore: + - '&7' + - '&dNext Level: &e3' + - '&7' + - '&7Purchasing the hopper upgrade' + - '&7will increase your island''s' + - '&7max hoppers limit.' + - '&7' + - '&dAmount: &f32x Hoppers' + - '&dPrice: &f$3,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '3': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: HOPPER + name: '&d&lHopper Increase &a(Available)' + lore: + - '&7' + - '&dNext Level: &e4' + - '&7' + - '&7Purchasing the hopper upgrade' + - '&7will increase your island''s' + - '&7max hoppers limit.' + - '&7' + - '&dAmount: &f64x Hoppers' + - '&dPrice: &f$9,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: HOPPER + name: '&d&lHopper Increase &c(Unavailable)' + lore: + - '&7' + - '&dNext Level: &e2' + - '&7' + - '&7Purchasing the hopper upgrade' + - '&7will increase your island''s' + - '&7max hoppers limit.' + - '&7' + - '&dAmount: &f64x Hoppers' + - '&dPrice: &f$9,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '4': + has-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: HOPPER + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the hoppers limit!' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: HOPPER + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the hoppers limit!' + crop-growth: + item: '#' + '1': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: DIAMOND_HOE + name: '&e&lCrop Growth &a(Available)' + lore: + - '&7' + - '&eNext Level: 2' + - '&7' + - '&7Purchasing the growth upgrade' + - '&7gives all crops within your island' + - '&7increased growth speed.' + - '&7' + - '&eGrowth: &fx2 Speed' + - '&ePrice: &f$100,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: DIAMOND_HOE + name: '&e&lCrop Growth &c(Unavailable)' + lore: + - '&7' + - '&eNext Level: 2' + - '&7' + - '&7Purchasing the growth upgrade' + - '&7gives all crops within your island' + - '&7increased growth speed.' + - '&7' + - '&eGrowth: &fx2 Speed' + - '&ePrice: &f$100,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '2': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: DIAMOND_HOE + name: '&e&lCrop Growth &a(Available)' + lore: + - '&7' + - '&eNext Level: 3' + - '&7' + - '&7Purchasing the growth upgrade' + - '&7gives all crops within your island' + - '&7increased growth speed.' + - '&7' + - '&eGrowth: &fx3 Speed' + - '&ePrice: &f$500,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: DIAMOND_HOE + name: '&e&lCrop Growth &c(Unavailable)' + lore: + - '&7' + - '&eNext Level: 3' + - '&7' + - '&7Purchasing the growth upgrade' + - '&7gives all crops within your island' + - '&7increased growth speed.' + - '&7' + - '&eGrowth: &fx3 Speed' + - '&ePrice: &f$500,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '3': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: DIAMOND_HOE + name: '&e&lCrop Growth &a(Available)' + lore: + - '&7' + - '&eNext Level: 4' + - '&7' + - '&7Purchasing the growth upgrade' + - '&7gives all crops within your island' + - '&7increased growth speed.' + - '&7' + - '&eGrowth: &fx4 Speed' + - '&ePrice: &f$1,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: DIAMOND_HOE + name: '&e&lCrop Growth &c(Unavailable)' + lore: + - '&7' + - '&eNext Level: 4' + - '&7' + - '&7Purchasing the growth upgrade' + - '&7gives all crops within your island' + - '&7increased growth speed.' + - '&7' + - '&eGrowth: &fx4 Speed' + - '&ePrice: &f$1,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '4': + has-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: DIAMOND_HOE + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the crop growth!' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: DIAMOND_HOE + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the crop growth!' + spawner-rates: + item: '^' + '1': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: MOB_SPAWNER + name: '&b&lSpawner Boost &a(Available)' + lore: + - '&7' + - '&bNext Level: &e2' + - '&7' + - '&7Purchasing the spawner upgrade' + - '&7gives all spawners within your island' + - '&7increased spawn speed.' + - '&7' + - '&bBoost: &fx2 Speed' + - '&bPrice: &f$500,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: MOB_SPAWNER + name: '&b&lSpawner Boost &c(Unavailable)' + lore: + - '&7' + - '&bNext Level: &e2' + - '&7' + - '&7Purchasing the spawner upgrade' + - '&7gives all spawners within your island' + - '&7increased spawn speed.' + - '&7' + - '&bBoost: &fx2 Speed' + - '&bPrice: &f$500,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '2': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: MOB_SPAWNER + name: '&b&lSpawner Boost &a(Available)' + lore: + - '&7' + - '&bNext Level: &e3' + - '&7' + - '&7Purchasing the spawner upgrade' + - '&7gives all spawners within your island' + - '&7increased spawn speed.' + - '&7' + - '&bBoost: &fx3 Speed' + - '&bPrice: &f$1,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: MOB_SPAWNER + name: '&b&lSpawner Boost &c(Unavailable)' + lore: + - '&7' + - '&bNext Level: &e3' + - '&7' + - '&7Purchasing the spawner upgrade' + - '&7gives all spawners within your island' + - '&7increased spawn speed.' + - '&7' + - '&bBoost: &fx3 Speed' + - '&bPrice: &f$1,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '3': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: MOB_SPAWNER + name: '&b&lSpawner Boost &a(Available)' + lore: + - '&7' + - '&bNext Level: &e4' + - '&7' + - '&7Purchasing the spawner upgrade' + - '&7gives all spawners within your island' + - '&7increased spawn speed.' + - '&7' + - '&bBoost: &fx4 Speed' + - '&bPrice: &f$2,500,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: MOB_SPAWNER + name: '&b&lSpawner Boost &c(Unavailable)' + lore: + - '&7' + - '&bNext Level: &e4' + - '&7' + - '&7Purchasing the spawner upgrade' + - '&7gives all spawners within your island' + - '&7increased spawn speed.' + - '&7' + - '&bBoost: &fx4 Speed' + - '&bPrice: &f$2,500,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '4': + has-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: MOB_SPAWNER + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the spawner rates!' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: MOB_SPAWNER + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the spawner rates!' + mob-drops: + item: '*' + '1': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: ROTTEN_FLESH + name: '&4&lPremium Drops &a(Available)' + lore: + - '&7' + - '&4Next Level: &e2' + - '&7' + - '&7Purchasing the drops upgrade' + - '&7gives all mobs within your island' + - '&7increased loot drops.' + - '&7' + - '&4Amount: &fx2 Drops' + - '&4Price: &f$1,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: ROTTEN_FLESH + name: '&4&lPremium Drops &c(Unavailable)' + lore: + - '&7' + - '&4Next Level: &e2' + - '&7' + - '&7Purchasing the drops upgrade' + - '&7gives all mobs within your island' + - '&7increased loot drops.' + - '&7' + - '&4Amount: &fx2 Drops' + - '&4Price: &f$1,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '2': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: ROTTEN_FLESH + name: '&4&lPremium Drops &a(Available)' + lore: + - '&7' + - '&4Next Level: &e3' + - '&7' + - '&7Purchasing the drops upgrade' + - '&7gives all mobs within your island' + - '&7increased loot drops.' + - '&7' + - '&4Amount: &fx3 Drops' + - '&4Price: &f$2,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: ROTTEN_FLESH + name: '&4&lPremium Drops &c(Unavailable)' + lore: + - '&7' + - '&4Next Level: &e3' + - '&7' + - '&7Purchasing the drops upgrade' + - '&7gives all mobs within your island' + - '&7increased loot drops.' + - '&7' + - '&4Amount: &fx3 Drops' + - '&4Price: &f$2,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '3': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: ROTTEN_FLESH + name: '&4&lPremium Drops &a(Available)' + lore: + - '&7' + - '&4Next Level: &e4' + - '&7' + - '&7Purchasing the drops upgrade' + - '&7gives all mobs within your island' + - '&7increased loot drops.' + - '&7' + - '&4Amount: &fx5 Drops' + - '&4Price: &f$5,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: ROTTEN_FLESH + name: '&4&lPremium Drops &c(Unavailable)' + lore: + - '&7' + - '&4Next Level: &e4' + - '&7' + - '&7Purchasing the drops upgrade' + - '&7gives all mobs within your island' + - '&7increased loot drops.' + - '&7' + - '&4Amount: &fx5 Drops' + - '&4Price: &f$5,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '4': + has-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: ROTTEN_FLESH + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the mob drops!' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: ROTTEN_FLESH + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the mob drops!' + members-limit: + item: '~' + '1': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: SKULL_ITEM + data: 3 + name: '&2&lMembers Size &a(Available)' + lore: + - '&7' + - '&2Next Level: &e2' + - '&7' + - '&7Purchasing the members upgrade' + - '&7will increase the maximum allowed' + - '&7members in your island.' + - '&7' + - '&2Amount: &f8 Members' + - '&2Price: &f$100,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: SKULL_ITEM + data: 3 + name: '&2&lMembers Size &c(Unavailable)' + lore: + - '&7' + - '&2Next Level: &e2' + - '&7' + - '&7Purchasing the members upgrade' + - '&7will increase the maximum allowed' + - '&7members in your island.' + - '&7' + - '&2Amount: &f8 Members' + - '&2Price: &f$100,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '2': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: SKULL_ITEM + data: 3 + name: '&2&lMembers Size &a(Available)' + lore: + - '&7' + - '&2Next Level: &e3' + - '&7' + - '&7Purchasing the members upgrade' + - '&7will increase the maximum allowed' + - '&7members in your island.' + - '&7' + - '&2Amount: &f16 Members' + - '&2Price: &f$300,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: SKULL_ITEM + data: 3 + name: '&2&lMembers Size &c(Unavailable)' + lore: + - '&7' + - '&2Next Level: &e3' + - '&7' + - '&7Purchasing the members upgrade' + - '&7will increase the maximum allowed' + - '&7members in your island.' + - '&7' + - '&2Amount: &f16 Members' + - '&2Price: &f$300,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '3': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: SKULL_ITEM + data: 3 + name: '&2&lMembers Size &a(Available)' + lore: + - '&7' + - '&2Next Level: &e4' + - '&7' + - '&7Purchasing the members upgrade' + - '&7will increase the maximum allowed' + - '&7members in your island.' + - '&7' + - '&2Amount: &f32 Members' + - '&2Price: &f$500,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: SKULL_ITEM + data: 3 + name: '&2&lMembers Size &c(Unavailable)' + lore: + - '&7' + - '&2Next Level: &e4' + - '&7' + - '&7Purchasing the members upgrade' + - '&7will increase the maximum allowed' + - '&7members in your island.' + - '&7' + - '&2Amount: &f32 Members' + - '&2Price: &f$500,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '4': + has-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: SKULL_ITEM + data: 3 + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the members limit!' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: SKULL_ITEM + data: 3 + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the members limit!' + border-size: + item: '!' + '1': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: BARRIER + name: '&9&lBorder Size &a(Available)' + lore: + - '&7' + - '&9Next Level: &e2' + - '&7' + - '&7Purchasing the border upgrade' + - '&7will increase the radius' + - '&7of your island.' + - '&7' + - '&9Radius: &f50 Blocks' + - '&9Price: &f$30,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: BARRIER + name: '&9&lBorder Size &c(Unavailable)' + lore: + - '&7' + - '&9Next Level: &e2' + - '&7' + - '&7Purchasing the border upgrade' + - '&7will increase the radius' + - '&7of your island.' + - '&7' + - '&9Radius: &f50 Blocks' + - '&9Price: &f$30,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '2': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: BARRIER + name: '&9&lBorder Size &a(Available)' + lore: + - '&7' + - '&9Next Level: &e3' + - '&7' + - '&7Purchasing the border upgrade' + - '&7will increase the radius' + - '&7of your island.' + - '&7' + - '&9Radius: &f75 Blocks' + - '&9Price: &f$80,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: BARRIER + name: '&9&lBorder Size &c(Unavailable)' + lore: + - '&7' + - '&9Next Level: &e3' + - '&7' + - '&7Purchasing the border upgrade' + - '&7will increase the radius' + - '&7of your island.' + - '&7' + - '&9Radius: &f75 Blocks' + - '&9Price: &f$80,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '3': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: BARRIER + name: '&9&lBorder Size &a(Available)' + lore: + - '&7' + - '&9Next Level: &e4' + - '&7' + - '&7Purchasing the border upgrade' + - '&7will increase the radius' + - '&7of your island.' + - '&7' + - '&9Radius: &f125 Blocks' + - '&9Price: &f$150,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: BARRIER + name: '&9&lBorder Size &c(Unavailable)' + lore: + - '&7' + - '&9Next Level: &e4' + - '&7' + - '&7Purchasing the border upgrade' + - '&7will increase the radius' + - '&7of your island.' + - '&7' + - '&9Radius: &f125 Blocks' + - '&9Price: &f$150,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '4': + has-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: BARRIER + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the border size!' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: BARRIER + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the border size!' + generator-rates: + item: '+' + '1': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: COBBLESTONE + name: '&3&lGenerator Boost &a(Available)' + lore: + - '&7' + - '&3Next Level: &e2' + - '&7' + - '&7Purchasing the generator upgrade' + - '&7will increase rates of ores from' + - '&7cobblestone generators in your island.' + - '&7' + - '&3Rates:' + - ' &7 - &f92% Stone' + - ' &7 - &f5% Coal Ore' + - ' &7 - &f3% Redstone Ore' + - '&7' + - '&3Price: &f$25,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: COBBLESTONE + name: '&3&lGenerator Boost &c(Unavailable)' + lore: + - '&7' + - '&3Next Level: &e2' + - '&7' + - '&7Purchasing the generator upgrade' + - '&7will increase rates of ores from' + - '&7cobblestone generators in your island.' + - '&7' + - '&3Rates:' + - ' &7 - &f92% Stone' + - ' &7 - &f5% Coal Ore' + - ' &7 - &f3% Redstone Ore' + - '&7' + - '&3Price: &f$25,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '2': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: COBBLESTONE + name: '&3&lGenerator Boost &a(Available)' + lore: + - '&7' + - '&3Next Level: &e3' + - '&7' + - '&7Purchasing the generator upgrade' + - '&7will increase rates of ores from' + - '&7cobblestone generators in your island.' + - '&7' + - '&3Rates:' + - ' &7 - &f80% Stone' + - ' &7 - &f8% Coal Ore' + - ' &7 - &f6% Redstone Ore' + - ' &7 - &f4% Lapis Ore' + - ' &7 - &f2% Iron Ore' + - '&7' + - '&3Price: &f$75,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: COBBLESTONE + name: '&3&lGenerator Boost &c(Unavailable)' + lore: + - '&7' + - '&3Next Level: &e3' + - '&7' + - '&7Purchasing the generator upgrade' + - '&7will increase rates of ores from' + - '&7cobblestone generators in your island.' + - '&7' + - '&3Rates:' + - ' &7 - &f80% Stone' + - ' &7 - &f8% Coal Ore' + - ' &7 - &f6% Redstone Ore' + - ' &7 - &f4% Lapis Ore' + - ' &7 - &f2% Iron Ore' + - '&7' + - '&3Price: &f$75,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '3': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: COBBLESTONE + name: '&3&lGenerator Boost &a(Available)' + lore: + - '&7' + - '&3Next Level: &e4' + - '&7' + - '&7Purchasing the generator upgrade' + - '&7will increase rates of ores from' + - '&7cobblestone generators in your island.' + - '&7' + - '&3Rates:' + - ' &7 - &f65% Stone' + - ' &7 - &f10% Coal Ore' + - ' &7 - &f9% Redstone Ore' + - ' &7 - &f6% Lapis Ore' + - ' &7 - &f4% Iron Ore' + - ' &7 - &f3% Gold Ore' + - ' &7 - &f2% Diamond Ore' + - ' &7 - &f1% Emerald Ore' + - '&7' + - '&3Price: &f$150,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: COBBLESTONE + name: '&3&lGenerator Boost &c(Unavailable)' + lore: + - '&7' + - '&3Next Level: &e4' + - '&7' + - '&7Purchasing the generator upgrade' + - '&7will increase rates of ores from' + - '&7cobblestone generators in your island.' + - '&7' + - '&3Rates:' + - ' &7 - &f65% Stone' + - ' &7 - &f10% Coal Ore' + - ' &7 - &f9% Redstone Ore' + - ' &7 - &f6% Lapis Ore' + - ' &7 - &f4% Iron Ore' + - ' &7 - &f3% Gold Ore' + - ' &7 - &f2% Diamond Ore' + - ' &7 - &f1% Emerald Ore' + - '&7' + - '&3Price: &f$150,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '4': + has-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: COBBLESTONE + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the generator rates!' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: COBBLESTONE + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the generator rates!' + minecarts-limit: + item: '&' + '1': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: MINECART + name: '&d&lMinecart Increase &a(Available)' + lore: + - '&7' + - '&dNext Level: &e2' + - '&7' + - '&7Purchasing the minecart upgrade' + - '&7will increase your island''s' + - '&7max minecarts limit.' + - '&7' + - '&dAmount: &f8x Minecarts' + - '&dPrice: &f$1,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: MINECART + name: '&d&lHopper Increase &c(Unavailable)' + lore: + - '&7' + - '&dNext Level: &e2' + - '&7' + - '&7Purchasing the minecart upgrade' + - '&7will increase your island''s' + - '&7max minecarts limit.' + - '&7' + - '&dAmount: &f8x Minecarts' + - '&dPrice: &f$1,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '2': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: MINECART + name: '&d&lHopper Increase &a(Available)' + lore: + - '&7' + - '&dNext Level: &e3' + - '&7' + - '&7Purchasing the minecart upgrade' + - '&7will increase your island''s' + - '&7max minecarts limit.' + - '&7' + - '&dAmount: &f16x Minecarts' + - '&dPrice: &f$3,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: MINECART + name: '&d&lHopper Increase &c(Unavailable)' + lore: + - '&7' + - '&dNext Level: &e3' + - '&7' + - '&7Purchasing the minecart upgrade' + - '&7will increase your island''s' + - '&7max minecarts limit.' + - '&7' + - '&dAmount: &f16x Minecarts' + - '&dPrice: &f$3,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '3': + has-next-level: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + type: MINECART + name: '&d&lHopper Increase &a(Available)' + lore: + - '&7' + - '&dNext Level: &e4' + - '&7' + - '&7Purchasing the minecart upgrade' + - '&7will increase your island''s' + - '&7max minecarts limit.' + - '&7' + - '&dAmount: &f32x Minecarts' + - '&dPrice: &f$9,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: MINECART + name: '&d&lHopper Increase &c(Unavailable)' + lore: + - '&7' + - '&dNext Level: &e4' + - '&7' + - '&7Purchasing the minecart upgrade' + - '&7will increase your island''s' + - '&7max minecarts limit.' + - '&7' + - '&dAmount: &f32x Minecarts' + - '&dPrice: &f$9,000,000' + - '&7' + - '&aLeft-click to purchase upgrade.' + '4': + has-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: MINECART + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the minecarts limit!' + no-next-level: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + type: MINECART + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maxmimum' + - '&7level of the minecarts limit!' \ No newline at end of file diff --git a/src/main/resources/menus/visitors.yml b/src/main/resources/menus/visitors.yml index d47d6c278f..23043e6146 100644 --- a/src/main/resources/menus/visitors.yml +++ b/src/main/resources/menus/visitors.yml @@ -52,6 +52,6 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/visitors1_12.yml b/src/main/resources/menus/visitors1_12.yml new file mode 100644 index 0000000000..d47d6c278f --- /dev/null +++ b/src/main/resources/menus/visitors1_12.yml @@ -0,0 +1,57 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Visitors' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '$ $ $ $ ~ $ $ $ $' + - '# # % # * # ^ # #' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' +unique-visitors: '~' + +items: + '@': + type: SKULL_ITEM + data: 3 + name: '&e{0}' + lore: + - '&7Island Owner: {1}' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: DOUBLE_PLANT + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + '~': + type: SKULL_ITEM + name: '&eUnique Visitors' + lore: + - '&7Click to open all-time visitors menu.' + '$': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/warp-category-icon-edit.yml b/src/main/resources/menus/warp-category-icon-edit.yml index f70f4c1370..28b3f17277 100644 --- a/src/main/resources/menus/warp-category-icon-edit.yml +++ b/src/main/resources/menus/warp-category-icon-edit.yml @@ -55,6 +55,6 @@ items: sounds: '%': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/warp-category-icon-edit1_12.yml b/src/main/resources/menus/warp-category-icon-edit1_12.yml new file mode 100644 index 0000000000..f70f4c1370 --- /dev/null +++ b/src/main/resources/menus/warp-category-icon-edit1_12.yml @@ -0,0 +1,60 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lCategory: {0}' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ ! @ @ @ @ @ ~ @' + - '@ @ @ @ ^ @ @ @ @' + - '@ $ @ @ @ @ @ % @' + - '@ @ @ @ @ @ @ @ @' + +icon-type: '!' +icon-rename: '~' +icon-relore: '$' +icon-confirm: '%' +icon-slots: '^' + +items: + '!': + type: DIAMOND + name: '&6Set Type' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto edit the item type. ))' + '~': + type: ANVIL + name: '&6Set Name' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto edit the item name. ))' + '$': + type: PAPER + name: '&6Set Lore' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto edit the item lore. ))' + '%': + type: EMERALD + name: '&6Confirm Changes' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto confirm all changes. ))' + '^': + type: STONE + +sounds: + '%': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/warp-category-manage.yml b/src/main/resources/menus/warp-category-manage.yml index ff43ee33aa..8e16fc2b4e 100644 --- a/src/main/resources/menus/warp-category-manage.yml +++ b/src/main/resources/menus/warp-category-manage.yml @@ -14,7 +14,7 @@ pattern: - '@ @ @ @ @ @ @ @ @' success-update-sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 diff --git a/src/main/resources/menus/warp-category-manage1_12.yml b/src/main/resources/menus/warp-category-manage1_12.yml new file mode 100644 index 0000000000..ff43ee33aa --- /dev/null +++ b/src/main/resources/menus/warp-category-manage1_12.yml @@ -0,0 +1,50 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lCategory: {0}' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ ! @ @ ~ @ @ $ @' + - '@ @ @ @ @ @ @ @ @' + +success-update-sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + +category-rename: '!' +category-icon: '~' +category-warps: '$' + +items: + '!': + type: BOOK + name: '&6Rename Category' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto rename the category. ))' + '~': + type: STONE + lore: + - '&f ' + - '&f ' + - '&7&oYou can use the following placeholders:' + - '&7&o{0} is used for the warp''s name.' + - '&7&o{1} is used for the warp''s location.' + - '&7&o{2} is used for the warp''s public status.' + - '&7&o(( &f&oRight-Click &7&oto edit the icon. ))' + - '&7&o(( &f&oLeft-Click &7&oto edit the category''s slot. ))' + '$': + type: ENDER_PEARL + name: '&6Island Warps' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto edit the category warps. ))' \ No newline at end of file diff --git a/src/main/resources/menus/warp-icon-edit.yml b/src/main/resources/menus/warp-icon-edit.yml index 4349c0ce73..4e18bb32bb 100644 --- a/src/main/resources/menus/warp-icon-edit.yml +++ b/src/main/resources/menus/warp-icon-edit.yml @@ -55,6 +55,6 @@ items: sounds: '%': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/warp-icon-edit1_12.yml b/src/main/resources/menus/warp-icon-edit1_12.yml new file mode 100644 index 0000000000..4349c0ce73 --- /dev/null +++ b/src/main/resources/menus/warp-icon-edit1_12.yml @@ -0,0 +1,60 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lWarp: {0}' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ ! @ @ @ @ @ ~ @' + - '@ @ @ @ ^ @ @ @ @' + - '@ $ @ @ @ @ @ % @' + - '@ @ @ @ @ @ @ @ @' + +icon-type: '!' +icon-rename: '~' +icon-relore: '$' +icon-confirm: '%' +icon-slots: '^' + +items: + '!': + type: DIAMOND + name: '&6Set Type' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto edit the item type. ))' + '~': + type: ANVIL + name: '&6Set Name' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto edit the item name. ))' + '$': + type: PAPER + name: '&6Set Lore' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto edit the item lore. ))' + '%': + type: EMERALD + name: '&6Confirm Changes' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto confirm all changes. ))' + '^': + type: STONE + +sounds: + '%': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/warp-manage.yml b/src/main/resources/menus/warp-manage.yml index 15b1b9dea9..33d9f7397f 100644 --- a/src/main/resources/menus/warp-manage.yml +++ b/src/main/resources/menus/warp-manage.yml @@ -15,7 +15,7 @@ pattern: - '@ @ @ @ @ @ @ @ @' success-update-sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 diff --git a/src/main/resources/menus/warp-manage1_12.yml b/src/main/resources/menus/warp-manage1_12.yml new file mode 100644 index 0000000000..15b1b9dea9 --- /dev/null +++ b/src/main/resources/menus/warp-manage1_12.yml @@ -0,0 +1,58 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lWarp: {0}' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ @ ! @ % @ $ @ @' + - '@ @ @ @ ~ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + +success-update-sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + +warp-rename: '!' +warp-icon: '~' +warp-location: '$' +warp-private: '%' + +items: + '!': + type: BOOK + name: '&6Rename Warp' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto rename the warp. ))' + '~': + type: STONE + lore: + - '&f ' + - '&f ' + - '&7&oYou can use the following placeholders:' + - '&7&o{0} is used for the warp''s name.' + - '&7&o{1} is used for the warp''s location.' + - '&7&o{2} is used for the warp''s public status.' + - '&7&o(( &f&oClick &7&oto edit the icon. ))' + '$': + type: ENDER_PEARL + name: '&6Warp Location' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto update the warp location. ))' + '%': + type: FEATHER + name: '&6Private Warp' + lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oClick &7&oto toggle warp to the public. ))' \ No newline at end of file diff --git a/src/main/resources/menus/warps.yml b/src/main/resources/menus/warps.yml index 8feed930d0..83700db9da 100644 --- a/src/main/resources/menus/warps.yml +++ b/src/main/resources/menus/warps.yml @@ -52,6 +52,6 @@ items: sounds: '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: ORB_PICKUP volume: 0.2 pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/warps1_12.yml b/src/main/resources/menus/warps1_12.yml new file mode 100644 index 0000000000..8feed930d0 --- /dev/null +++ b/src/main/resources/menus/warps1_12.yml @@ -0,0 +1,57 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Warps' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '$ $ $ $ $ $ $ $ $' + - '# # % # * # ^ # #' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +# This lore is added to warp icons. +edit-lore: + - '&f ' + - '&f ' + - '&7&o(( &f&oLeft-Click &7&oto warp to the location. ))' + - '&7&o(( &f&oRight-Click &7&oto edit warp. ))' + +items: + '@': + type: BOOK + name: '&e{0} {2}' + lore: + - '&7Located at {1}.' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: DOUBLE_PLANT + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + '$': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file From 0e9a65d18b82f3e144ecb5b96e73922a5f7549f5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 18 May 2025 13:32:35 +0300 Subject: [PATCH 184/600] Adds world not enabled message when going through portals of disabled worlds (#2490) --- .../service/portals/PortalsManagerServiceImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java index ad9105510b..e1d3bb69fe 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java @@ -135,6 +135,10 @@ private EntityPortalResult handlePlayerPortalInternal(SuperiorPlayer superiorPla superiorPlayer.getUserLocale(), Formatters.CAPITALIZED_FORMATTER.format(originalDestination.getName()))); } + if (portalResult == EntityPortalResult.DESTINATION_WORLD_DISABLED && !Message.WORLD_NOT_ENABLED.isEmpty(superiorPlayer.getUserLocale())) { + Message.SCHEMATICS.send(superiorPlayer, Message.WORLD_NOT_ENABLED.getMessage(superiorPlayer.getUserLocale())); + } + return portalResult; } From 0f8e4bf4d1850dd13af0eae2a299c5fd6ded2dad Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 1 Jun 2025 17:02:51 +0300 Subject: [PATCH 185/600] [CI SKIP] Updated gradle and paperweight --- NMS/Paper-1_20_3/build.gradle | 2 +- NMS/v1_17/build.gradle | 2 +- NMS/v1_18/build.gradle | 2 +- NMS/v1_19/build.gradle | 2 +- NMS/v1_20_3/build.gradle | 2 +- NMS/v1_20_4/build.gradle | 2 +- NMS/v1_21/build.gradle | 2 +- NMS/v1_21_3/build.gradle | 2 +- NMS/v1_21_4/build.gradle | 2 +- NMS/v1_21_5/build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/NMS/Paper-1_20_3/build.gradle b/NMS/Paper-1_20_3/build.gradle index 6dc5afd0de..7446737715 100644 --- a/NMS/Paper-1_20_3/build.gradle +++ b/NMS/Paper-1_20_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } group 'NMS:Paper-1_20_3' diff --git a/NMS/v1_17/build.gradle b/NMS/v1_17/build.gradle index 627e339389..bf5f5d8352 100644 --- a/NMS/v1_17/build.gradle +++ b/NMS/v1_17/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_18/build.gradle b/NMS/v1_18/build.gradle index 94104dbd12..bdcf38c1ca 100644 --- a/NMS/v1_18/build.gradle +++ b/NMS/v1_18/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_19/build.gradle b/NMS/v1_19/build.gradle index 5642e98ee6..39cf25b853 100644 --- a/NMS/v1_19/build.gradle +++ b/NMS/v1_19/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_20_3/build.gradle b/NMS/v1_20_3/build.gradle index 40ff4eaede..94cd254e76 100644 --- a/NMS/v1_20_3/build.gradle +++ b/NMS/v1_20_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_20_4/build.gradle b/NMS/v1_20_4/build.gradle index 4fd3c1b8f5..808202fdbe 100644 --- a/NMS/v1_20_4/build.gradle +++ b/NMS/v1_20_4/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_21/build.gradle b/NMS/v1_21/build.gradle index 8a98614ad7..fcc7b15fe0 100644 --- a/NMS/v1_21/build.gradle +++ b/NMS/v1_21/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_21_3/build.gradle b/NMS/v1_21_3/build.gradle index f551333bc2..4c164d66eb 100644 --- a/NMS/v1_21_3/build.gradle +++ b/NMS/v1_21_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_21_4/build.gradle b/NMS/v1_21_4/build.gradle index f5199ecaec..b868b25a2d 100644 --- a/NMS/v1_21_4/build.gradle +++ b/NMS/v1_21_4/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_21_5/build.gradle b/NMS/v1_21_5/build.gradle index b4f455cdc5..00638de249 100644 --- a/NMS/v1_21_5/build.gradle +++ b/NMS/v1_21_5/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d6e308a637..260504c0cb 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From e82e46f7eb500a7d51dbe9931fc403083b76ea65 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 1 Jun 2025 17:33:26 +0300 Subject: [PATCH 186/600] Fixed NPE when using custom schematics using the API (#2496) --- .../core/database/bridge/IslandsDatabaseBridge.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index b626a70c30..704188518a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.core.database.bridge; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; @@ -623,7 +624,7 @@ public static void clearIslandSettings(Island island) { )); } - public static void insertIsland(Island island, List dirtyChunks) { + public static void insertIsland(Island island, @Nullable List dirtyChunks) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { BlockPosition centerPosition = island.getCenterPosition(); WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, Dimensions.NORMAL); @@ -644,7 +645,7 @@ public static void insertIsland(Island island, List dirtyChunks) new Pair<>("generated_schematics", LegacyMasks.convertGeneratedSchematicsMask(island.getGeneratedSchematics())), new Pair<>("unlocked_worlds", LegacyMasks.convertUnlockedWorldsMask(island.getUnlockedWorlds())), new Pair<>("last_time_updated", System.currentTimeMillis() / 1000L), - new Pair<>("dirty_chunks", IslandsSerializer.serializeDirtyChunkPositions(dirtyChunks)), + new Pair<>("dirty_chunks", dirtyChunks == null ? "" : IslandsSerializer.serializeDirtyChunkPositions(dirtyChunks)), new Pair<>("block_counts", IslandsSerializer.serializeBlockCounts(island.getBlockCountsAsBigInteger())), new Pair<>("entity_counts", IslandsSerializer.serializeEntityCounts(island.getEntitiesTracker().getEntitiesCounts())) ); From c2f647ec704986f607edb76c5cc48d070002771b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 1 Jun 2025 17:41:13 +0300 Subject: [PATCH 187/600] Fixed errors when running Leaf (#2480) --- .../nms/v1_20_3/NMSWorldImpl.java | 22 ++++++++++-------- .../nms/v1_20_4/NMSWorldImpl.java | 22 ++++++++++-------- .../nms/v1_21/NMSWorldImpl.java | 23 +++++++++++-------- .../nms/v1_21_3/NMSWorldImpl.java | 23 +++++++++++-------- .../nms/v1_21_4/NMSWorldImpl.java | 23 +++++++++++-------- .../nms/v1_21_5/NMSWorldImpl.java | 23 +++++++++++-------- 6 files changed, 82 insertions(+), 54 deletions(-) diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index 0a479c365f..b92359c803 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -69,8 +69,7 @@ public class NMSWorldImpl implements NMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); @@ -101,13 +100,8 @@ public void listenSpawner(Location location, IntFunction delayChangeCal ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - List blockEntityTickers; - - if (LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.isValid()) { - blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.get(serverLevel); - } else { - blockEntityTickers = serverLevel.blockEntityTickers; - } + List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? + LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); List tickersToAdd = new LinkedList<>(); @@ -360,4 +354,14 @@ public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } + private static ReflectField> initializeLevelBlockEntityTickersField() { + ReflectField> field = new ReflectField<>( + Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + + if (!field.isValid()) + field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + + return field; + } + } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index 48830d1098..e4d5b85d4f 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -69,8 +69,7 @@ public class NMSWorldImpl implements NMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); @@ -101,13 +100,8 @@ public void listenSpawner(Location location, IntFunction delayChangeCal ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - List blockEntityTickers; - - if (LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.isValid()) { - blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.get(serverLevel); - } else { - blockEntityTickers = serverLevel.blockEntityTickers; - } + List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? + LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); List tickersToAdd = new LinkedList<>(); @@ -360,4 +354,14 @@ public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } + private static ReflectField> initializeLevelBlockEntityTickersField() { + ReflectField> field = new ReflectField<>( + Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + + if (!field.isValid()) + field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + + return field; + } + } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index 997cdb8d4f..17521dcf5f 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -76,8 +76,7 @@ public class NMSWorldImpl implements NMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); @@ -108,13 +107,8 @@ public void listenSpawner(Location location, IntFunction delayChangeCal ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - List blockEntityTickers; - - if (LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.isValid()) { - blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.get(serverLevel); - } else { - blockEntityTickers = serverLevel.blockEntityTickers; - } + List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? + LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); List tickersToAdd = new LinkedList<>(); @@ -410,4 +404,15 @@ public WorldEditSession createEditSession(World world) { public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } + + private static ReflectField> initializeLevelBlockEntityTickersField() { + ReflectField> field = new ReflectField<>( + Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + + if (!field.isValid()) + field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + + return field; + } + } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index b0d1355dbe..2a8304d09c 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -76,8 +76,7 @@ public class NMSWorldImpl implements NMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); @@ -108,13 +107,8 @@ public void listenSpawner(Location location, IntFunction delayChangeCal ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - List blockEntityTickers; - - if (LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.isValid()) { - blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.get(serverLevel); - } else { - blockEntityTickers = serverLevel.blockEntityTickers; - } + List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? + LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); List tickersToAdd = new LinkedList<>(); @@ -410,4 +404,15 @@ public WorldEditSession createEditSession(World world) { public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } + + private static ReflectField> initializeLevelBlockEntityTickersField() { + ReflectField> field = new ReflectField<>( + Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + + if (!field.isValid()) + field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + + return field; + } + } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index 73bb7f1555..a58bbbda00 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -76,8 +76,7 @@ public class NMSWorldImpl implements NMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); @@ -108,13 +107,8 @@ public void listenSpawner(Location location, IntFunction delayChangeCal ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - List blockEntityTickers; - - if (LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.isValid()) { - blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.get(serverLevel); - } else { - blockEntityTickers = serverLevel.blockEntityTickers; - } + List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? + LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); List tickersToAdd = new LinkedList<>(); @@ -410,4 +404,15 @@ public WorldEditSession createEditSession(World world) { public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } + + private static ReflectField> initializeLevelBlockEntityTickersField() { + ReflectField> field = new ReflectField<>( + Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + + if (!field.isValid()) + field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + + return field; + } + } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java index 0d24386c24..9a26f90cc3 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java @@ -76,8 +76,7 @@ public class NMSWorldImpl implements NMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); @@ -108,13 +107,8 @@ public void listenSpawner(Location location, IntFunction delayChangeCal ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - List blockEntityTickers; - - if (LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.isValid()) { - blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS_PROTECTED.get(serverLevel); - } else { - blockEntityTickers = serverLevel.blockEntityTickers; - } + List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? + LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); List tickersToAdd = new LinkedList<>(); @@ -410,4 +404,15 @@ public WorldEditSession createEditSession(World world) { public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } + + private static ReflectField> initializeLevelBlockEntityTickersField() { + ReflectField> field = new ReflectField<>( + Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + + if (!field.isValid()) + field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + + return field; + } + } From 5803d6ad01ff00bc7d04352fd18f82d246e4f6a4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 2 Jun 2025 14:12:12 +0300 Subject: [PATCH 188/600] Better detection to stacked blocks placed with RoseStacker (#2502) --- .../StackedBlocksProvider_RoseStacker.java | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java b/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java index c55fd83a57..126b52219d 100644 --- a/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java +++ b/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java @@ -10,7 +10,10 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.google.common.base.Preconditions; import dev.rosewood.rosestacker.api.RoseStackerAPI; @@ -83,9 +86,21 @@ private class StackerListener implements Listener { public void onBlockStack(BlockStackEvent e) { Location location = e.getStack().getLocation(); Island island = plugin.getGrid().getIslandAt(location); - if (island != null) { - int placedBlocksAmount = e.isNew() ? Math.max(1, e.getIncreaseAmount() - 1) : e.getIncreaseAmount(); - island.handleBlockPlace(e.getStack().getBlock(), placedBlocksAmount); + + if (island == null) + return; + + Key blockKey = Keys.of(e.getStack().getBlock()); + + int increaseAmount = e.getStack().getStackSize() + e.getIncreaseAmount() > e.getStack().getStackSettings().getMaxStackSize() ? + e.getStack().getStackSettings().getMaxStackSize() - e.getStack().getStackSize() : e.getIncreaseAmount(); + int newBlocksCount = e.isNew() ? Math.max(1, increaseAmount - 1) : increaseAmount; + + if (island.hasReachedBlockLimit(blockKey, newBlocksCount)) { + e.setCancelled(true); + Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); + } else { + island.handleBlockPlace(blockKey, newBlocksCount); } } From 032021f03843dc1db01f433d4e41efefe41e01b8 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 2 Jun 2025 14:34:03 +0300 Subject: [PATCH 189/600] Disable MiniMessage hook in versions below 1.18 (#2498) --- .../superiorskyblock/external/MiniMessageHook.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java index c71946f831..65a962d593 100644 --- a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java +++ b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.service.message.MessagesService; +import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.MessageContent; @@ -31,6 +32,10 @@ public class MiniMessageHook { private static boolean registered = false; + public static boolean isCompatible() { + return ServerVersion.isAtLeast(ServerVersion.v1_18); + } + public static void register(SuperiorSkyblockPlugin plugin) { if (!registered) { MessagesServiceImpl messagesService = (MessagesServiceImpl) plugin.getServices().getService(MessagesService.class); From 6ba0dff56faf3487237d559a10b7477652266544 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 2 Jun 2025 14:44:22 +0300 Subject: [PATCH 190/600] Clear Slimefun data asynchronous on chunk wipe (#2474) --- .../bgsoftware/superiorskyblock/external/SlimefunHook.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java b/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java index b554138035..cd685c0853 100644 --- a/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java +++ b/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java @@ -14,6 +14,7 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.external.slimefun.ProtectionModule_Dev999; import com.bgsoftware.superiorskyblock.external.slimefun.ProtectionModule_RC13; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; @@ -149,7 +150,11 @@ private static class ChunkWipeListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onChunkWipe(IslandChunkResetEvent e) { - BLOCK_STORAGE_CLEAR_ALL_BLOCK_INFO_AT_CHUNK_METHOD.invoke(null, e.getWorld(), e.getChunkX(), e.getChunkZ(), true); + BukkitExecutor.async(() -> { + // Might be unsafe to call async. Should fix: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2474 + BLOCK_STORAGE_CLEAR_ALL_BLOCK_INFO_AT_CHUNK_METHOD.invoke(null, e.getWorld(), e.getChunkX(), e.getChunkZ(), true); + }); } } From facc62ae05ae383ca250c7232b0dd440c14ed201 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 2 Jun 2025 15:05:43 +0300 Subject: [PATCH 191/600] Do not use BlockPosition#setValues in 1.16 or below (#2475) --- .../superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java | 2 +- .../superiorskyblock/nms/v1_12_R1/NMSUtils.java | 2 +- .../superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java | 6 +++--- .../nms/v1_12_R1/world/ChunkReaderImpl.java | 2 +- .../superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java | 2 +- .../superiorskyblock/nms/v1_16_R3/NMSUtils.java | 2 +- .../superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java | 8 ++++---- .../nms/v1_16_R3/crops/CropsTickingMethod.java | 4 ++-- .../nms/v1_16_R3/dragon/IslandEnderDragonBattle.java | 2 +- .../nms/v1_16_R3/world/ChunkReaderImpl.java | 2 +- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java index 1450dca54b..06acd1a35b 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java @@ -66,7 +66,7 @@ public int getCombinedId(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); IBlockData blockData; try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - wrapper.getHandle().setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + wrapper.getHandle().c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); blockData = world.getType(wrapper.getHandle()); } return Block.getCombinedId(blockData); diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java index 5f0f117e70..b01dbc77e6 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java @@ -71,7 +71,7 @@ public static T getTileEntityAt(Location location, Class< try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); TileEntity tileEntity = worldServer.getTileEntity(blockPosition); return !type.isInstance(tileEntity) ? null : type.cast(tileEntity); } diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java index f95e6c4f6d..345b58aa60 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java @@ -163,7 +163,7 @@ public void setBlock(Location location, int combinedId) { try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null); NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4, @@ -283,7 +283,7 @@ public void playBreakAnimation(org.bukkit.block.Block block) { WorldServer worldServer = ((CraftWorld) block.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues(block.getX(), block.getY(), block.getZ()); + blockPosition.c(block.getX(), block.getY(), block.getZ()); worldServer.a(null, 2001, blockPosition, Block.getCombinedId(worldServer.getType(blockPosition))); } } @@ -294,7 +294,7 @@ public void playPlaceSound(Location location) { try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockPosition.c(location.getBlockX(), location.getBlockY(), location.getBlockZ()); SoundEffectType soundEffectType = worldServer.getType(blockPosition).getBlock().getStepSound(); worldServer.a(null, blockPosition, soundEffectType.e(), SoundCategory.BLOCKS, diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java index a2008976a8..f6ead4df34 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java @@ -120,7 +120,7 @@ public short getData(int x, int y, int z) { public CompoundTag getTileEntity(int x, int y, int z) { try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues((this.x << 4) + x, y, (this.z << 4) + z); + blockPosition.c((this.x << 4) + x, y, (this.z << 4) + z); return this.tileEntities.get(blockPosition); } } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java index 7f71177317..430dd24571 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java @@ -102,7 +102,7 @@ public int getCombinedId(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); IBlockData blockData; try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - wrapper.getHandle().setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + wrapper.getHandle().d(location.getBlockX(), location.getBlockY(), location.getBlockZ()); blockData = world.getType(wrapper.getHandle()); } return Block.getCombinedId(blockData); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java index 10104ccf75..e542a2acf9 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java @@ -78,7 +78,7 @@ public static T getTileEntityAt(Location location, Class< try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockPosition.d(location.getBlockX(), location.getBlockY(), location.getBlockZ()); TileEntity tileEntity = worldServer.getTileEntity(blockPosition); return !type.isInstance(tileEntity) ? null : type.cast(tileEntity); } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java index b0306a70fe..d51e6e15e5 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java @@ -167,7 +167,7 @@ public void setBlock(Location location, int combinedId) { WorldServer world = ((CraftWorld) location.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockPosition.d(location.getBlockX(), location.getBlockY(), location.getBlockZ()); NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null, null); NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4, @@ -263,7 +263,7 @@ public void playGeneratorSound(Location location) { World world = ((CraftWorld) location.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues(location.getX(), location.getY(), location.getZ()); + blockPosition.c(location.getX(), location.getY(), location.getZ()); world.triggerEffect(1501, blockPosition, 0); } } @@ -273,7 +273,7 @@ public void playBreakAnimation(org.bukkit.block.Block block) { World world = ((CraftWorld) block.getWorld()).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues(block.getX(), block.getY(), block.getZ()); + blockPosition.c(block.getX(), block.getY(), block.getZ()); world.a(null, 2001, blockPosition, Block.getCombinedId(world.getType(blockPosition))); } } @@ -284,7 +284,7 @@ public void playPlaceSound(Location location) { try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockPosition.d(location.getBlockX(), location.getBlockY(), location.getBlockZ()); SoundEffectType soundEffectType = world.getType(blockPosition).getStepSound(); float volume = SOUND_VOLUME.isValid() ? SOUND_VOLUME.invoke(soundEffectType) : soundEffectType.getVolume(); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java index 244e8157a3..93e73d0a8c 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingMethod.java @@ -99,7 +99,7 @@ protected void doTick(Chunk chunk, int tickSpeed) { if (!CROPS_TO_GROW_CACHE.contains(blockData.getBlock())) continue; - chunkTickMutablePosition.setValues((location & 15) | chunkOffsetX, + chunkTickMutablePosition.d((location & 15) | chunkOffsetX, ((location >>> 8) & 255) | offsetY, ((location >>> 4) & 15) | chunkOffsetZ); @@ -134,7 +134,7 @@ protected void doTick(Chunk chunk, int tickSpeed) { int y = factor >> 16 & 15; IBlockData blockData = chunkSection.getType(x, y, z); if (blockData.isTicking() && CROPS_TO_GROW_CACHE.contains(blockData.getBlock())) { - chunkTickMutablePosition.setValues(x + chunkOffsetX, y + chunkSection.getYPosition(), z + chunkOffsetZ); + chunkTickMutablePosition.d(x + chunkOffsetX, y + chunkSection.getYPosition(), z + chunkOffsetZ); blockData.b(worldServer, chunkTickMutablePosition, worldServer.random); } } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java index a74de54409..cd0f9be5b0 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java @@ -131,7 +131,7 @@ public ShapeDetector.ShapeDetectorCollection getExitPortalShape() { try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition currentPosition = wrapper.getHandle(); - currentPosition.setValues(this.islandBlockPosition.getX(), 0, this.islandBlockPosition.getZ()); + currentPosition.d(this.islandBlockPosition.getX(), 0, this.islandBlockPosition.getZ()); for (int y = highestBlock; y >= 0; --y) { currentPosition.setY(y); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java index cc0ba844cd..c0e22ff399 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java @@ -139,7 +139,7 @@ public short getData(int x, int y, int z) { public CompoundTag getTileEntity(int x, int y, int z) { try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); - blockPosition.setValues((this.x << 4) + x, y, (this.z << 4) + z); + blockPosition.d((this.x << 4) + x, y, (this.z << 4) + z); return this.tileEntities.get(blockPosition); } } From 3d091e40bea023fe0972d36894c5c82a26e74209 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 2 Jun 2025 15:11:21 +0300 Subject: [PATCH 192/600] Adds `NETHER_WARTS` to the default crops-to-grow list --- src/main/resources/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 6fc023a6ba..a094d5852f 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -684,6 +684,7 @@ crops-to-grow: - 'CAVE_VINES' - 'SWEET_BERRY_BUSH' - 'NETHER_WART' + - 'NETHER_WARTS' - 'KELP' - 'CARROT' - 'CARROTS' From ede519fa3c615529be2a33218d08c3ddf8539a63 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 7 Jun 2025 13:19:14 +0300 Subject: [PATCH 193/600] Fixed placeholders in commands not working properly (#2506) --- .../core/menu/MenuCommandsImpl.java | 6 +-- .../core/menu/button/impl/BanButton.java | 2 +- .../button/impl/BankCustomDepositButton.java | 2 +- .../button/impl/BankCustomWithdrawButton.java | 2 +- .../menu/button/impl/BankDepositButton.java | 2 +- .../menu/button/impl/BankWithdrawButton.java | 2 +- .../core/menu/button/impl/BiomeButton.java | 2 +- .../menu/button/impl/ControlPanelButton.java | 2 +- .../core/menu/button/impl/DisbandButton.java | 2 +- .../core/menu/button/impl/KickButton.java | 2 +- .../menu/button/impl/MemberManageButton.java | 20 +++++----- .../menu/button/impl/MemberRoleButton.java | 13 +++---- .../menu/button/impl/OpenBankLogsButton.java | 2 +- .../menu/button/impl/RateIslandButton.java | 2 +- .../core/menu/button/impl/UpgradeButton.java | 2 +- .../core/menu/impl/MenuBankLogs.java | 15 +++++++- .../core/menu/impl/MenuBiomes.java | 2 +- .../core/menu/impl/MenuConfirmBan.java | 14 ++++--- .../core/menu/impl/MenuConfirmDisband.java | 2 +- .../core/menu/impl/MenuConfirmKick.java | 14 ++++--- .../core/menu/impl/MenuControlPanel.java | 2 +- .../core/menu/impl/MenuCoops.java | 8 +++- .../core/menu/impl/MenuCounts.java | 8 +++- .../core/menu/impl/MenuIslandBank.java | 2 +- .../menu/impl/MenuIslandBannedPlayers.java | 8 +++- .../core/menu/impl/MenuIslandChest.java | 8 +++- .../core/menu/impl/MenuIslandFlags.java | 4 +- .../core/menu/impl/MenuIslandMembers.java | 8 +++- .../core/menu/impl/MenuIslandPrivileges.java | 11 +++++- .../core/menu/impl/MenuIslandRate.java | 2 +- .../core/menu/impl/MenuIslandRatings.java | 8 +++- .../menu/impl/MenuIslandUniqueVisitors.java | 8 +++- .../core/menu/impl/MenuIslandUpgrades.java | 2 +- .../core/menu/impl/MenuIslandValues.java | 16 +++++--- .../core/menu/impl/MenuIslandVisitors.java | 4 +- .../core/menu/impl/MenuMemberManage.java | 37 ++++--------------- .../core/menu/impl/MenuMemberRole.java | 37 ++++--------------- .../core/menu/impl/MenuWarpCategories.java | 12 +++--- .../menu/impl/MenuWarpCategoryIconEdit.java | 6 +++ .../menu/impl/MenuWarpCategoryManage.java | 9 ++++- .../core/menu/impl/MenuWarpIconEdit.java | 6 +++ .../core/menu/impl/MenuWarpManage.java | 9 ++++- .../core/menu/impl/MenuWarps.java | 12 +++--- .../menu/view/AbstractIconProviderMenu.java | 6 ++- .../core/menu/view/IIslandMenuView.java | 9 +++++ .../core/menu/view/IPlayerMenuView.java | 11 ++++++ .../menu/view/{ => impl}/IslandMenuView.java | 12 +++++- .../menu/view/{ => impl}/PlayerMenuView.java | 14 +++++-- 48 files changed, 248 insertions(+), 141 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IIslandMenuView.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IPlayerMenuView.java rename src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/{ => impl}/IslandMenuView.java (67%) rename src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/{ => impl}/PlayerMenuView.java (64%) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuCommandsImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuCommandsImpl.java index 464fc11c66..555d14b4bb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuCommandsImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuCommandsImpl.java @@ -7,7 +7,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; -import com.bgsoftware.superiorskyblock.core.menu.view.PlayerMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -62,8 +62,8 @@ private void runCommand(MenuView menuView, String command, InventoryClickE setClickedCloseButton(menuView); clickEvent.getWhoClicked().closeInventory(); } else { - SuperiorPlayer targetPlayer = menuView instanceof PlayerMenuView ? - ((PlayerMenuView) menuView).getSuperiorPlayer() : null; + SuperiorPlayer targetPlayer = menuView instanceof IPlayerMenuView ? + ((IPlayerMenuView) menuView).getSuperiorPlayer() : null; if (targetPlayer != null) command = placeholdersService.get().parsePlaceholders(targetPlayer.asOfflinePlayer(), command); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BanButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BanButton.java index aa0f630305..f919f87a94 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BanButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BanButton.java @@ -31,7 +31,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); if (getTemplate().banPlayer) - IslandUtils.handleBanPlayer(clickedPlayer, menuView.getIsland(), menuView.getTargetPlayer()); + IslandUtils.handleBanPlayer(clickedPlayer, menuView.getIsland(), menuView.getSuperiorPlayer()); BukkitExecutor.sync(menuView::closeView, 1L); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java index 66d5f6972b..3bfca38fb2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import org.bukkit.entity.Player; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java index 65a356e7a7..fcd7260c11 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import org.bukkit.entity.Player; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java index b4ead2a699..bd89a0df66 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import org.bukkit.event.inventory.InventoryClickEvent; import java.math.BigDecimal; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java index eea8fc6f17..4e6b744f54 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import org.bukkit.event.inventory.InventoryClickEvent; import java.math.BigDecimal; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java index 960523095e..02923f3a55 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BiomeButton.java @@ -16,7 +16,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.Bukkit; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ControlPanelButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ControlPanelButton.java index 41bc94cec4..89b4965981 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ControlPanelButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ControlPanelButton.java @@ -9,7 +9,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java index 286b57d7a5..5086ab2221 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/KickButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/KickButton.java index a3cce84c94..03ace0a6f7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/KickButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/KickButton.java @@ -31,7 +31,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); if (getTemplate().kickPlayer) - IslandUtils.handleKickPlayer(clickedPlayer, menuView.getIsland(), menuView.getTargetPlayer()); + IslandUtils.handleKickPlayer(clickedPlayer, menuView.getIsland(), menuView.getSuperiorPlayer()); BukkitExecutor.sync(menuView::closeView, 1L); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberManageButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberManageButton.java index 3d17c96c9a..bde3ac8ddf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberManageButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberManageButton.java @@ -9,17 +9,17 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; -import com.bgsoftware.superiorskyblock.core.menu.impl.MenuMemberManage; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.PlayerMenuView; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; import java.util.Objects; -public class MemberManageButton extends AbstractMenuViewButton { +public class MemberManageButton extends AbstractMenuViewButton { - private MemberManageButton(AbstractMenuTemplateButton templateButton, MenuMemberManage.View menuView) { + private MemberManageButton(AbstractMenuTemplateButton templateButton, PlayerMenuView menuView) { super(templateButton, menuView); } @@ -37,14 +37,14 @@ public enum ManageAction { SET_ROLE { @Override - void onButtonClick(MenuMemberManage.View menuView, InventoryClickEvent clickEvent) { + void onButtonClick(PlayerMenuView menuView, InventoryClickEvent clickEvent) { menuView.setPreviousMove(false); plugin.getMenus().openMemberRole(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), menuView.getSuperiorPlayer()); } }, BAN_MEMBER { @Override - void onButtonClick(MenuMemberManage.View menuView, InventoryClickEvent clickEvent) { + void onButtonClick(PlayerMenuView menuView, InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); if (plugin.getSettings().isBanConfirm()) { Island island = inventoryViewer.getIsland(); @@ -59,7 +59,7 @@ void onButtonClick(MenuMemberManage.View menuView, InventoryClickEvent clickEven }, KICK_MEMBER { @Override - void onButtonClick(MenuMemberManage.View menuView, InventoryClickEvent clickEvent) { + void onButtonClick(PlayerMenuView menuView, InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); if (plugin.getSettings().isKickConfirm()) { Island island = inventoryViewer.getIsland(); @@ -81,11 +81,11 @@ void onButtonClick(MenuMemberManage.View menuView, InventoryClickEvent clickEven } - abstract void onButtonClick(MenuMemberManage.View menuView, InventoryClickEvent clickEvent); + abstract void onButtonClick(PlayerMenuView menuView, InventoryClickEvent clickEvent); } - public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { + public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private ManageAction manageAction; @@ -95,13 +95,13 @@ public Builder setManageAction(ManageAction manageAction) { } @Override - public MenuTemplateButton build() { + public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, manageAction); } } - public static class Template extends MenuTemplateButtonImpl { + public static class Template extends MenuTemplateButtonImpl { private final ManageAction manageAction; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberRoleButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberRoleButton.java index 22229184c1..cc5a5fd50f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberRoleButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MemberRoleButton.java @@ -9,17 +9,16 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; -import com.bgsoftware.superiorskyblock.core.menu.impl.MenuMemberRole; -import com.bgsoftware.superiorskyblock.core.menu.view.PlayerMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.PlayerMenuView; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; import java.util.Objects; -public class MemberRoleButton extends AbstractMenuViewButton { +public class MemberRoleButton extends AbstractMenuViewButton { - private MemberRoleButton(AbstractMenuTemplateButton templateButton, MenuMemberRole.View menuView) { + private MemberRoleButton(AbstractMenuTemplateButton templateButton, PlayerMenuView menuView) { super(templateButton, menuView); } @@ -43,7 +42,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { } } - public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { + public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { private int playerRoleId; @@ -53,13 +52,13 @@ public Builder setPlayerRole(PlayerRole playerRole) { } @Override - public MenuTemplateButton build() { + public MenuTemplateButton build() { return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, playerRoleId); } } - public static class Template extends MenuTemplateButtonImpl { + public static class Template extends MenuTemplateButtonImpl { private final int playerRoleId; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenBankLogsButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenBankLogsButton.java index b4507f141f..6071475248 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenBankLogsButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenBankLogsButton.java @@ -4,7 +4,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import org.bukkit.event.inventory.InventoryClickEvent; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/RateIslandButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/RateIslandButton.java index d2efa79dd1..ae75a34843 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/RateIslandButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/RateIslandButton.java @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/UpgradeButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/UpgradeButton.java index 8233fb199d..2b50a46f59 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/UpgradeButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/UpgradeButton.java @@ -13,7 +13,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; import org.bukkit.Material; import org.bukkit.event.inventory.InventoryClickEvent; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java index 974adc79dc..33812bf616 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java @@ -18,6 +18,8 @@ import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -69,7 +71,7 @@ public static MenuBankLogs createInstance() { return new MenuBankLogs(menuParseResult); } - public static class View extends AbstractPagedMenuView { + public static class View extends AbstractPagedMenuView implements IIslandMenuView, IPlayerMenuView { private final Island island; @@ -82,6 +84,17 @@ public static class View extends AbstractPagedMenuView sorting) { this.sorting = sorting; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java index b8e293e147..f082bd1cd3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java @@ -14,7 +14,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.impl.BiomeButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.block.Biome; import org.bukkit.configuration.ConfigurationSection; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmBan.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmBan.java index e4c1551262..fb189d7f2b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmBan.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmBan.java @@ -13,6 +13,8 @@ import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BanButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.file.YamlConfiguration; @@ -58,7 +60,7 @@ public Args(Island island, SuperiorPlayer targetPlayer) { } - public static class View extends AbstractMenuView { + public static class View extends AbstractMenuView implements IIslandMenuView, IPlayerMenuView { private final Island island; private SuperiorPlayer targetPlayer; @@ -70,16 +72,18 @@ protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previous this.targetPlayer = args.targetPlayer; } + @Override public Island getIsland() { return island; } - public void setTargetPlayer(SuperiorPlayer targetPlayer) { - this.targetPlayer = targetPlayer; + @Override + public SuperiorPlayer getSuperiorPlayer() { + return targetPlayer; } - public SuperiorPlayer getTargetPlayer() { - return targetPlayer; + public void setTargetPlayer(SuperiorPlayer targetPlayer) { + this.targetPlayer = targetPlayer; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmDisband.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmDisband.java index 08a014f44f..d30ccfdf79 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmDisband.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmDisband.java @@ -13,7 +13,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.impl.DisbandButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmKick.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmKick.java index 9a3739736d..9e02c1af28 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmKick.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmKick.java @@ -13,6 +13,8 @@ import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.button.impl.KickButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.file.YamlConfiguration; @@ -60,7 +62,7 @@ public Args(Island island, SuperiorPlayer targetPlayer) { } - public static class View extends AbstractMenuView { + public static class View extends AbstractMenuView implements IIslandMenuView, IPlayerMenuView { private final Island island; private SuperiorPlayer targetPlayer; @@ -72,16 +74,18 @@ protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previous this.targetPlayer = args.targetPlayer; } + @Override public Island getIsland() { return island; } - public void setTargetPlayer(SuperiorPlayer targetPlayer) { - this.targetPlayer = targetPlayer; + @Override + public SuperiorPlayer getSuperiorPlayer() { + return targetPlayer; } - public SuperiorPlayer getTargetPlayer() { - return targetPlayer; + public void setTargetPlayer(SuperiorPlayer targetPlayer) { + this.targetPlayer = targetPlayer; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuControlPanel.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuControlPanel.java index 8fc9ebb823..9ec77849a0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuControlPanel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuControlPanel.java @@ -13,7 +13,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.impl.ControlPanelButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuCoops.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuCoops.java index 4afc5a61c3..eaa7f1cf04 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuCoops.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuCoops.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.button.impl.CoopsPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import java.util.List; @@ -38,7 +39,7 @@ public static MenuCoops createInstance() { return menuParseResult == null ? null : new MenuCoops(menuParseResult); } - public static class View extends AbstractPagedMenuView { + public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; @@ -48,6 +49,11 @@ public static class View extends AbstractPagedMenuView { + public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; @@ -66,6 +67,11 @@ public static class View extends AbstractPagedMenuView requestObjects() { return new SequentialListBuilder() diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java index e9da2a0f46..62d4bd7382 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java @@ -16,7 +16,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankDepositButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankWithdrawButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.OpenBankLogsButton; -import com.bgsoftware.superiorskyblock.core.menu.view.IslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.file.YamlConfiguration; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBannedPlayers.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBannedPlayers.java index 3e97cddd79..d3efe852e4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBannedPlayers.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBannedPlayers.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BannedPlayersPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import java.util.List; @@ -38,7 +39,7 @@ public static MenuIslandBannedPlayers createInstance() { return menuParseResult == null ? null : new MenuIslandBannedPlayers(menuParseResult); } - public static class View extends AbstractPagedMenuView { + public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; @@ -48,6 +49,11 @@ public static class View extends AbstractPagedMenuView requestObjects() { return island.getBannedPlayers(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandChest.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandChest.java index 5fb2aad6c9..67b3fed95f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandChest.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandChest.java @@ -16,6 +16,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandChestPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.layout.PagedMenuLayoutImpl; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -80,7 +81,7 @@ public static MenuIslandChest createInstance() { return new MenuIslandChest(menuParseResult); } - public static class View extends AbstractPagedMenuView { + public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; @@ -90,6 +91,11 @@ public static class View extends AbstractPagedMenuView requestObjects() { return new SequentialListBuilder() diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java index c93017788e..6a06b18d1c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java @@ -20,6 +20,7 @@ import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -91,7 +92,7 @@ private static IslandFlagInfo loadIslandFlagInfo(ConfigurationSection islandFlag disabledIslandFlagItem, clickSound, position); } - public class View extends AbstractPagedMenuView { + public class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; @@ -101,6 +102,7 @@ public class View extends AbstractPagedMenuView { + public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; @@ -55,6 +56,11 @@ public static class View extends AbstractPagedMenuView requestObjects() { return island.getIslandMembers(true); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java index 1e786f7894..cf53f48759 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java @@ -21,6 +21,8 @@ import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -143,7 +145,7 @@ public Args(Island island, Object permissionHolder) { } - public class View extends AbstractPagedMenuView { + public class View extends AbstractPagedMenuView implements IIslandMenuView, IPlayerMenuView { private final Island island; private final Object permissionHolder; @@ -155,10 +157,17 @@ public class View extends AbstractPagedMenuView { + public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; @@ -63,6 +64,11 @@ public static class View extends AbstractPagedMenuView requestObjects() { return new SequentialListBuilder() diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandUniqueVisitors.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandUniqueVisitors.java index 0463da5975..b64e0f9dc8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandUniqueVisitors.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandUniqueVisitors.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.button.impl.UniqueVisitorPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import java.util.List; @@ -44,7 +45,7 @@ public static MenuIslandUniqueVisitors createInstance() { return menuParseResult == null ? null : new MenuIslandUniqueVisitors(menuParseResult); } - public static class View extends AbstractPagedMenuView { + public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; @@ -54,6 +55,11 @@ public static class View extends AbstractPagedMenuView { + public static class View extends AbstractMenuView implements IIslandMenuView, IPlayerMenuView { private final Island island; private SuperiorPlayer targetPlayer; @@ -98,16 +100,18 @@ protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previous this.targetPlayer = args.getIsland().getOwner(); } + @Override public Island getIsland() { return island; } - public void setTargetPlayer(SuperiorPlayer targetPlayer) { - this.targetPlayer = targetPlayer; + @Override + public SuperiorPlayer getSuperiorPlayer() { + return targetPlayer; } - public SuperiorPlayer getTargetPlayer() { - return targetPlayer; + public void setTargetPlayer(SuperiorPlayer targetPlayer) { + this.targetPlayer = targetPlayer; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java index 82f7fc009a..7861a6a9ca 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java @@ -17,6 +17,7 @@ import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -60,7 +61,7 @@ public static MenuIslandVisitors createInstance() { return new MenuIslandVisitors(menuParseResult); } - public static class View extends AbstractPagedMenuView { + public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; @@ -70,6 +71,7 @@ public static class View extends AbstractPagedMenuView { +public class MenuMemberManage extends AbstractMenu { - private MenuMemberManage(MenuParseResult parseResult) { + private MenuMemberManage(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_MEMBER_MANAGE, parseResult); } @Override - protected MenuMemberManage.View createViewInternal(SuperiorPlayer superiorPlayer, PlayerViewArgs args, - @Nullable MenuView previousMenuView) { - return new MenuMemberManage.View(superiorPlayer, previousMenuView, this, args); + protected PlayerMenuView createViewInternal(SuperiorPlayer superiorPlayer, PlayerViewArgs args, + @Nullable MenuView previousMenuView) { + return new PlayerMenuView(superiorPlayer, previousMenuView, this, args); } public void closeViews(SuperiorPlayer islandMember) { @@ -39,7 +39,7 @@ public void closeViews(SuperiorPlayer islandMember) { @Nullable public static MenuMemberManage createInstance() { - MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("member-manage.yml", + MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("member-manage.yml", MenuMemberManage::convertOldGUI); if (menuParseResult == null) { @@ -48,7 +48,7 @@ public static MenuMemberManage createInstance() { MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); - MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); + MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "roles", menuPatternSlots), new MemberManageButton.Builder().setManageAction(MemberManageButton.ManageAction.SET_ROLE)); @@ -60,27 +60,6 @@ public static MenuMemberManage createInstance() { return new MenuMemberManage(menuParseResult); } - public static class View extends AbstractMenuView { - - private final SuperiorPlayer superiorPlayer; - - View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, - MenuMemberManage menu, PlayerViewArgs args) { - super(inventoryViewer, previousMenuView, menu); - this.superiorPlayer = args.getSuperiorPlayer(); - } - - public SuperiorPlayer getSuperiorPlayer() { - return this.superiorPlayer; - } - - @Override - public String replaceTitle(String title) { - return title.replace("{}", getSuperiorPlayer().getName()); - } - - } - private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/panel-gui.yml"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberRole.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberRole.java index 544b8ad48b..fd21d019a4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberRole.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberRole.java @@ -17,8 +17,8 @@ import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; -import com.bgsoftware.superiorskyblock.core.menu.view.PlayerMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.PlayerViewArgs; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.PlayerMenuView; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -26,16 +26,16 @@ import java.io.File; import java.util.Arrays; -public class MenuMemberRole extends AbstractMenu { +public class MenuMemberRole extends AbstractMenu { - private MenuMemberRole(MenuParseResult parseResult) { + private MenuMemberRole(MenuParseResult parseResult) { super(MenuIdentifiers.MENU_MEMBER_ROLE, parseResult); } @Override - protected MenuMemberRole.View createViewInternal(SuperiorPlayer superiorPlayer, PlayerViewArgs args, - @Nullable MenuView previousMenuView) { - return new MenuMemberRole.View(superiorPlayer, previousMenuView, this, args); + protected PlayerMenuView createViewInternal(SuperiorPlayer superiorPlayer, PlayerViewArgs args, + @Nullable MenuView previousMenuView) { + return new PlayerMenuView(superiorPlayer, previousMenuView, this, args); } public void closeViews(SuperiorPlayer islandMember) { @@ -44,7 +44,7 @@ public void closeViews(SuperiorPlayer islandMember) { @Nullable public static MenuMemberRole createInstance() { - MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("member-role.yml", + MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("member-role.yml", MenuMemberRole::convertOldGUI); if (menuParseResult == null) { @@ -53,7 +53,7 @@ public static MenuMemberRole createInstance() { MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); YamlConfiguration cfg = menuParseResult.getConfig(); - MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); + MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); if (cfg.isConfigurationSection("items")) { for (String itemsSectionName : cfg.getConfigurationSection("items").getKeys(false)) { @@ -89,27 +89,6 @@ public static MenuMemberRole createInstance() { return new MenuMemberRole(menuParseResult); } - public static class View extends AbstractMenuView { - - private final SuperiorPlayer superiorPlayer; - - View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, - MenuMemberRole menu, PlayerViewArgs args) { - super(inventoryViewer, previousMenuView, menu); - this.superiorPlayer = args.getSuperiorPlayer(); - } - - public SuperiorPlayer getSuperiorPlayer() { - return this.superiorPlayer; - } - - @Override - public String replaceTitle(String title) { - return title.replace("{}", getSuperiorPlayer().getName()); - } - - } - private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { File oldFile = new File(plugin.getDataFolder(), "guis/panel-gui.yml"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java index 669e353ede..fdc171a79e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java @@ -14,6 +14,7 @@ import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryPagedObjectButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.configuration.file.YamlConfiguration; @@ -69,7 +70,7 @@ public static MenuWarpCategories createInstance() { return new MenuWarpCategories(menuParseResult, editLore, rowsSize); } - public static class View extends AbstractPagedMenuView { + public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; private final boolean hasManagePerms; @@ -81,6 +82,11 @@ protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previous this.hasManagePerms = island.hasPermission(inventoryViewer, IslandPrivileges.SET_WARP); } + @Override + public Island getIsland() { + return island; + } + @Override protected List requestObjects() { DynamicArray warpCategories = new DynamicArray<>(); @@ -94,10 +100,6 @@ protected List requestObjects() { return warpCategories.toList(); } - public Island getIsland() { - return island; - } - public boolean hasManagePerms() { return hasManagePerms; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategoryIconEdit.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategoryIconEdit.java index c1ec089ff8..c5f62625ed 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategoryIconEdit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategoryIconEdit.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; @@ -77,6 +78,11 @@ public static class View extends AbstractIconProviderMenu.View { super(inventoryViewer, previousMenuView, menu, args); } + @Override + public Island getIsland() { + return getIconProvider().getIsland(); + } + @Override public String replaceTitle(String title) { return title.replace("{0}", getIconProvider().getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategoryManage.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategoryManage.java index 2c726cf61d..511e40b2e3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategoryManage.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategoryManage.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; @@ -17,6 +18,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryManageRenameButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpCategoryManageWarpsButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import org.bukkit.configuration.file.YamlConfiguration; public class MenuWarpCategoryManage extends AbstractMenu { @@ -79,7 +81,7 @@ public Args(WarpCategory warpCategory) { } - public static class View extends AbstractMenuView { + public static class View extends AbstractMenuView implements IIslandMenuView { private final WarpCategory warpCategory; @@ -89,6 +91,11 @@ protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previous this.warpCategory = args.warpCategory; } + @Override + public Island getIsland() { + return this.warpCategory.getIsland(); + } + public WarpCategory getWarpCategory() { return warpCategory; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpIconEdit.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpIconEdit.java index bed57038c7..9117d81229 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpIconEdit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpIconEdit.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; @@ -79,6 +80,11 @@ public static class View extends AbstractIconProviderMenu.View { super(inventoryViewer, previousMenuView, menu, args); } + @Override + public Island getIsland() { + return getIconProvider().getIsland(); + } + @Override public String replaceTitle(String title) { return title.replace("{0}", getIconProvider().getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpManage.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpManage.java index 321b8ecd26..2f4138f2e4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpManage.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpManage.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.core.menu.impl; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; @@ -18,6 +19,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpManagePrivateButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.WarpManageRenameButton; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import org.bukkit.configuration.file.YamlConfiguration; public class MenuWarpManage extends AbstractMenu { @@ -80,7 +82,7 @@ public Args(IslandWarp islandWarp) { } - public static class View extends AbstractMenuView { + public static class View extends AbstractMenuView implements IIslandMenuView { private final IslandWarp islandWarp; @@ -89,6 +91,11 @@ protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previous this.islandWarp = args.islandWarp; } + @Override + public Island getIsland() { + return this.islandWarp.getIsland(); + } + public IslandWarp getIslandWarp() { return islandWarp; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java index 750f1331ab..7e776d94be 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java @@ -20,6 +20,7 @@ import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.warp.WarpIcons; @@ -91,7 +92,7 @@ public Args(WarpCategory warpCategory) { } - public static class View extends AbstractPagedMenuView { + public static class View extends AbstractPagedMenuView implements IIslandMenuView { private final Island island; private final WarpCategory warpCategory; @@ -105,6 +106,11 @@ protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previous this.hasManagePerms = warpCategory.getIsland().hasPermission(inventoryViewer, IslandPrivileges.SET_WARP); } + @Override + public Island getIsland() { + return island; + } + @Override protected List requestObjects() { boolean isMember = warpCategory.getIsland().isMember(getInventoryViewer()); @@ -113,10 +119,6 @@ protected List requestObjects() { .build(warpCategory.getWarps()); } - public Island getIsland() { - return island; - } - public WarpCategory getWarpCategory() { return warpCategory; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractIconProviderMenu.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractIconProviderMenu.java index dc47b7a1e1..7e43495ce3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractIconProviderMenu.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractIconProviderMenu.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.core.menu.view; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.menu.view.ViewArgs; @@ -21,7 +22,7 @@ public Args(E iconProvider, TemplateItem iconTemplate) { } - public abstract static class View extends AbstractMenuView, Args> { + public abstract static class View extends AbstractMenuView, Args> implements IIslandMenuView { private final E iconProvider; private final TemplateItem iconTemplate; @@ -41,6 +42,9 @@ public TemplateItem getIconTemplate() { return iconTemplate; } + @Override + public abstract Island getIsland(); + @Override public abstract String replaceTitle(String title); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IIslandMenuView.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IIslandMenuView.java new file mode 100644 index 0000000000..58e4d38d2c --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IIslandMenuView.java @@ -0,0 +1,9 @@ +package com.bgsoftware.superiorskyblock.core.menu.view; + +import com.bgsoftware.superiorskyblock.api.island.Island; + +public interface IIslandMenuView { + + Island getIsland(); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IPlayerMenuView.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IPlayerMenuView.java new file mode 100644 index 0000000000..7f0ca08061 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IPlayerMenuView.java @@ -0,0 +1,11 @@ +package com.bgsoftware.superiorskyblock.core.menu.view; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; + +public interface IPlayerMenuView { + + @Nullable + SuperiorPlayer getSuperiorPlayer(); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IslandMenuView.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/impl/IslandMenuView.java similarity index 67% rename from src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IslandMenuView.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/impl/IslandMenuView.java index 0ebe06039f..39873a4e85 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/IslandMenuView.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/impl/IslandMenuView.java @@ -1,13 +1,15 @@ -package com.bgsoftware.superiorskyblock.core.menu.view; +package com.bgsoftware.superiorskyblock.core.menu.view.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; -public class IslandMenuView extends AbstractMenuView { +public class IslandMenuView extends AbstractMenuView implements IIslandMenuView { private final Island island; @@ -17,8 +19,14 @@ public IslandMenuView(SuperiorPlayer inventoryViewer, @Nullable MenuView p this.island = args.getIsland(); } + @Override public Island getIsland() { return island; } + @Override + public String replaceTitle(String title) { + return title.replace("{}", this.island.getName()); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/PlayerMenuView.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/impl/PlayerMenuView.java similarity index 64% rename from src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/PlayerMenuView.java rename to src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/impl/PlayerMenuView.java index 483d01bf43..dbaca020ec 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/PlayerMenuView.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/impl/PlayerMenuView.java @@ -1,12 +1,14 @@ -package com.bgsoftware.superiorskyblock.core.menu.view; +package com.bgsoftware.superiorskyblock.core.menu.view.impl; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.PlayerViewArgs; -public class PlayerMenuView extends AbstractMenuView { +public class PlayerMenuView extends AbstractMenuView implements IPlayerMenuView { private final SuperiorPlayer superiorPlayer; @@ -16,8 +18,14 @@ public PlayerMenuView(SuperiorPlayer inventoryViewer, @Nullable MenuView p this.superiorPlayer = args.getSuperiorPlayer(); } + @Override public SuperiorPlayer getSuperiorPlayer() { - return superiorPlayer; + return this.superiorPlayer; + } + + @Override + public String replaceTitle(String title) { + return title.replace("{}", this.superiorPlayer.getName()); } } From 7cb65e6362285ff74ea0f269444ff1b0559393c0 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 7 Jun 2025 13:46:40 +0300 Subject: [PATCH 194/600] Fix detection of MiniMessage support (#2498) --- .../superiorskyblock/external/MiniMessageHook.java | 5 ----- .../superiorskyblock/external/ProvidersManagerImpl.java | 3 ++- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java index 65a962d593..c71946f831 100644 --- a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java +++ b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java @@ -3,7 +3,6 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.service.message.MessagesService; -import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.MessageContent; @@ -32,10 +31,6 @@ public class MiniMessageHook { private static boolean registered = false; - public static boolean isCompatible() { - return ServerVersion.isAtLeast(ServerVersion.v1_18); - } - public static void register(SuperiorSkyblockPlugin plugin) { if (!registered) { MessagesServiceImpl messagesService = (MessagesServiceImpl) plugin.getServices().getService(MessagesService.class); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java index 7dd30f893b..013daafe43 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java @@ -28,6 +28,7 @@ import com.bgsoftware.superiorskyblock.core.JavaVersion; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Manager; +import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.SpawnerKey; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -701,7 +702,7 @@ private static boolean isOldSlimeWorldManager() { private static boolean hasMiniMessageSupport() { try { Class.forName("net.kyori.adventure.text.minimessage.MiniMessage"); - return true; + return ServerVersion.isAtLeast(ServerVersion.v1_18); } catch (ClassNotFoundException error) { return false; } From e5b4b81c5a822238ee44b680cb5b0e5390760e96 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 7 Jun 2025 14:01:24 +0300 Subject: [PATCH 195/600] Fix issues when installing CraftEngine alongside of SuperiorSkyblock (#2504) --- .../superiorskyblock/nms/v1_12_R1/world/KeyBlocksCache.java | 2 ++ .../superiorskyblock/nms/v1_16_R3/world/KeyBlocksCache.java | 2 +- .../superiorskyblock/nms/v1_17/world/KeyBlocksCache.java | 2 +- .../superiorskyblock/nms/v1_18/world/KeyBlocksCache.java | 2 +- .../superiorskyblock/nms/v1_19/world/KeyBlocksCache.java | 2 +- .../superiorskyblock/nms/v1_20_3/world/KeyBlocksCache.java | 2 +- .../superiorskyblock/nms/v1_20_4/world/KeyBlocksCache.java | 2 +- .../superiorskyblock/nms/v1_21/world/KeyBlocksCache.java | 2 +- .../superiorskyblock/nms/v1_21_3/world/KeyBlocksCache.java | 2 +- .../superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java | 2 +- .../superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java | 2 +- .../superiorskyblock/nms/v1_8_R3/world/KeyBlocksCache.java | 2 ++ 12 files changed, 14 insertions(+), 10 deletions(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/KeyBlocksCache.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/KeyBlocksCache.java index 5afa14c9c5..a50caad861 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/KeyBlocksCache.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/KeyBlocksCache.java @@ -22,6 +22,8 @@ public static Key getBlockKey(IBlockData blockData) { return BLOCK_TO_KEY.computeIfAbsent(blockData, unused -> { Block block = blockData.getBlock(); Material blockType = CraftMagicNumbers.getMaterial(block); + if (blockType == null) + return null; byte data = (byte) block.toLegacyData(blockData); return Keys.of(blockType, data); }); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/KeyBlocksCache.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/KeyBlocksCache.java index 24b69bb794..f60d81e595 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/KeyBlocksCache.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/KeyBlocksCache.java @@ -21,7 +21,7 @@ private KeyBlocksCache() { public static Key getBlockKey(Block block) { return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { Material blockType = CraftMagicNumbers.getMaterial(block); - return Keys.of(blockType, (short) 0); + return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); }); } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/KeyBlocksCache.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/KeyBlocksCache.java index cc272f3e93..ad05e2fc18 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/KeyBlocksCache.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/KeyBlocksCache.java @@ -21,7 +21,7 @@ private KeyBlocksCache() { public static Key getBlockKey(Block block) { return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { Material blockType = CraftMagicNumbers.getMaterial(block); - return Keys.of(blockType, (short) 0); + return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); }); } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/KeyBlocksCache.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/KeyBlocksCache.java index 022cd377f5..07c8a76549 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/KeyBlocksCache.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/KeyBlocksCache.java @@ -21,7 +21,7 @@ private KeyBlocksCache() { public static Key getBlockKey(Block block) { return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { Material blockType = CraftMagicNumbers.getMaterial(block); - return Keys.of(blockType, (short) 0); + return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); }); } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/KeyBlocksCache.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/KeyBlocksCache.java index 985b611627..772a984ce0 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/KeyBlocksCache.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/KeyBlocksCache.java @@ -21,7 +21,7 @@ private KeyBlocksCache() { public static Key getBlockKey(Block block) { return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { Material blockType = CraftMagicNumbers.getMaterial(block); - return Keys.of(blockType, (short) 0); + return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); }); } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/KeyBlocksCache.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/KeyBlocksCache.java index 633efc4359..9f87ed3a19 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/KeyBlocksCache.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/KeyBlocksCache.java @@ -21,7 +21,7 @@ private KeyBlocksCache() { public static Key getBlockKey(Block block) { return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { Material blockType = CraftMagicNumbers.getMaterial(block); - return Keys.of(blockType, (short) 0); + return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); }); } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/KeyBlocksCache.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/KeyBlocksCache.java index f9ff7bff3c..df45d7b9d2 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/KeyBlocksCache.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/KeyBlocksCache.java @@ -21,7 +21,7 @@ private KeyBlocksCache() { public static Key getBlockKey(Block block) { return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { Material blockType = CraftMagicNumbers.getMaterial(block); - return Keys.of(blockType, (short) 0); + return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); }); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/KeyBlocksCache.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/KeyBlocksCache.java index 4220a1e1b2..b21ffec0cb 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/KeyBlocksCache.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/KeyBlocksCache.java @@ -21,7 +21,7 @@ private KeyBlocksCache() { public static Key getBlockKey(Block block) { return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); + return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); }); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/KeyBlocksCache.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/KeyBlocksCache.java index 3d735a430d..4fa1124aac 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/KeyBlocksCache.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/KeyBlocksCache.java @@ -21,7 +21,7 @@ private KeyBlocksCache() { public static Key getBlockKey(Block block) { return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); + return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); }); } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java index 613b7b40b1..c9eeb0ea83 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java @@ -21,7 +21,7 @@ private KeyBlocksCache() { public static Key getBlockKey(Block block) { return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); + return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); }); } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java index 9d44c3b036..671c6f9800 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java @@ -21,7 +21,7 @@ private KeyBlocksCache() { public static Key getBlockKey(Block block) { return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); + return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); }); } diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/KeyBlocksCache.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/KeyBlocksCache.java index 3d43c7fc8f..32a5474d14 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/KeyBlocksCache.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/KeyBlocksCache.java @@ -22,6 +22,8 @@ public static Key getBlockKey(IBlockData blockData) { return BLOCK_TO_KEY.computeIfAbsent(blockData, unused -> { Block block = blockData.getBlock(); Material blockType = CraftMagicNumbers.getMaterial(block); + if (blockType == null) + return null; byte data = (byte) block.toLegacyData(blockData); return Keys.of(blockType, data); }); From d4b0ee472e359965b989406909a3e526b62933e6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 7 Jun 2025 15:57:02 +0300 Subject: [PATCH 196/600] Adds support to custom blocks by CraftEngine (#2507) --- Hooks/CraftEngine/build.gradle | 24 +++ .../external/CraftEngineHook.java | 154 ++++++++++++++++++ settings.gradle | 1 + .../external/ProvidersManagerImpl.java | 4 + 4 files changed, 183 insertions(+) create mode 100644 Hooks/CraftEngine/build.gradle create mode 100644 Hooks/CraftEngine/src/main/java/com/bgsoftware/superiorskyblock/external/CraftEngineHook.java diff --git a/Hooks/CraftEngine/build.gradle b/Hooks/CraftEngine/build.gradle new file mode 100644 index 0000000000..7d665809a3 --- /dev/null +++ b/Hooks/CraftEngine/build.gradle @@ -0,0 +1,24 @@ +group 'Hooks:CraftEngine' + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } +} + +repositories { + maven { url "https://repo.momirealms.net/releases/" } +} + +dependencies { + compileOnly "net.momirealms:craft-engine-core:0.0.56" + compileOnly "net.momirealms:craft-engine-bukkit:0.0.56" + compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" + compileOnly project(":API") + compileOnly rootProject +} + +if (project.hasProperty('hook.compile_craftengine') && + !Boolean.valueOf(project.findProperty("hook.compile_craftengine").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/Hooks/CraftEngine/src/main/java/com/bgsoftware/superiorskyblock/external/CraftEngineHook.java b/Hooks/CraftEngine/src/main/java/com/bgsoftware/superiorskyblock/external/CraftEngineHook.java new file mode 100644 index 0000000000..64ff12df03 --- /dev/null +++ b/Hooks/CraftEngine/src/main/java/com/bgsoftware/superiorskyblock/external/CraftEngineHook.java @@ -0,0 +1,154 @@ +package com.bgsoftware.superiorskyblock.external; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; +import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.set.KeySets; +import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; +import net.momirealms.craftengine.bukkit.api.CraftEngineItems; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; + +import java.util.Locale; + +public class CraftEngineHook { + + private static final String CRAFTENGINE_PREFIX = "CRAFTENGINE"; + private static final KeySet CUSTOM_ITEM_KEYS = collectCustomItemKeys(); + private static final KeySet CUSTOM_BLOCK_KEYS = collectCustomBlockKeys(); + private static final KeyMap CUSTOM_ITEM_CACHE = collectCustomItemsCache(); + private static final KeyMap CUSTOM_ITEM_TO_BLOCK_CACHE = collectCustomItemToBlocksCache(); + + public static void register(SuperiorSkyblockPlugin plugin) { + plugin.getBlockValues().registerKeyParser(new CraftEngineKeyParser(), collectCustomKeys()); + plugin.getServer().getPluginManager().registerEvents(new ListenerImpl(), plugin); + } + + private static KeySet collectCustomItemKeys() { + KeySet customItemKeys = KeySets.createHashSet(KeyIndicator.MATERIAL); + for (net.momirealms.craftengine.core.util.Key itemKey : CraftEngine.instance().itemManager().items()) { + CustomItem customItem = CraftEngineItems.byId(itemKey); + if (customItem != null) { + ItemStack itemStack = customItem.buildItemStack(); + customItemKeys.add(Keys.of(itemStack.getType())); + } + } + return customItemKeys; + } + + private static KeySet collectCustomBlockKeys() { + KeySet customBlockKeys = KeySets.createHashSet(KeyIndicator.MATERIAL); + for (CustomBlock customBlock : CraftEngine.instance().blockManager().blocks().values()) { + BlockData blockData = CraftEngineBlocks.getBukkitBlockData(customBlock.defaultState()); + customBlockKeys.add(Keys.of(blockData.getMaterial())); + } + return customBlockKeys; + } + + private static KeyMap collectCustomItemsCache() { + KeyMap customItemsCache = KeyMaps.createHashMap(KeyIndicator.CUSTOM); + + for (net.momirealms.craftengine.core.util.Key itemKey : CraftEngine.instance().itemManager().items()) { + CustomItem customItem = CraftEngineItems.byId(itemKey); + if (customItem != null) { + ItemStack itemStack = customItem.buildItemStack(); + Key ssbItemKey = Keys.of(CRAFTENGINE_PREFIX, itemKey.value().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + customItemsCache.put(ssbItemKey, itemStack); + } + } + + return customItemsCache; + } + + private static KeyMap collectCustomItemToBlocksCache() { + KeyMap customItemToBlocksCache = KeyMaps.createHashMap(KeyIndicator.CUSTOM); + + CraftEngine.instance().blockManager().blocks().forEach((blockKey, customBlock) -> { + Key ssbBlockKey = Keys.of(CRAFTENGINE_PREFIX, blockKey.value().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + customItemToBlocksCache.put(ssbBlockKey, customBlock); + }); + + return customItemToBlocksCache; + } + + private static Key[] collectCustomKeys() { + KeySet customKeys = KeySets.createHashSet(KeyIndicator.MATERIAL); + customKeys.addAll(CUSTOM_ITEM_KEYS); + customKeys.addAll(CUSTOM_BLOCK_KEYS); + return customKeys.toArray(new Key[0]); + } + + private static class ListenerImpl implements Listener { + + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onIslandGenerateBlock(IslandGenerateBlockEvent event) { + if (!event.getBlock().getGlobalKey().equals(CRAFTENGINE_PREFIX)) + return; + + CustomBlock customBlock = CUSTOM_ITEM_TO_BLOCK_CACHE.get(event.getBlock()); + if (customBlock == null) { + event.setCancelled(true); + return; + } + + event.setPlaceBlock(false); + CraftEngineBlocks.place(event.getLocation(), customBlock.defaultState(), false); + } + + } + + private static class CraftEngineKeyParser implements CustomKeyParser { + + @Override + public Key getCustomKey(Location location) { + Block block = location.getBlock(); + ImmutableBlockState customBlockState = CraftEngineBlocks.getCustomBlockState(block); + if (customBlockState == null || customBlockState.isEmpty()) + return null; + + net.momirealms.craftengine.core.util.Key blockKey = customBlockState.owner().value().id(); + + return Keys.of(CRAFTENGINE_PREFIX, blockKey.value().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + } + + @Override + public Key getCustomKey(ItemStack itemStack, Key def) { + CustomItem customItem = CraftEngineItems.byItemStack(itemStack); + if (customItem == null) + return def; + + net.momirealms.craftengine.core.util.Key itemKey = customItem.id(); + + return Keys.of(CRAFTENGINE_PREFIX, itemKey.value().toUpperCase(Locale.ENGLISH), KeyIndicator.CUSTOM); + } + + @Override + public boolean isCustomKey(Key key) { + return key.getGlobalKey().equals(CRAFTENGINE_PREFIX); + } + + @Override + @Nullable + public ItemStack getCustomKeyItem(Key key) { + return key.getGlobalKey().equals(CRAFTENGINE_PREFIX) ? CUSTOM_ITEM_CACHE.get(key) : null; + } + + } + +} diff --git a/settings.gradle b/settings.gradle index d5fea00496..d72fde2f43 100644 --- a/settings.gradle +++ b/settings.gradle @@ -15,6 +15,7 @@ include 'Hooks:CandcSilkSpawners' include 'Hooks:ChangeSkin' include 'Hooks:CMI' include 'Hooks:CoreProtect' +include 'Hooks:CraftEngine' include 'Hooks:EpicSpawners6' include 'Hooks:EpicSpawners7' include 'Hooks:EpicSpawners8' diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java index 013daafe43..e30bcea607 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java @@ -468,6 +468,10 @@ private void registerGeneralHooks() { if (Bukkit.getPluginManager().isPluginEnabled("ItemsAdder")) registerHook("ItemsAdderHook"); + if (Bukkit.getPluginManager().isPluginEnabled("CraftEngine")) + // We load the hook with an extra delay to let CraftEngine load its data first + BukkitExecutor.sync(() -> registerHook("CraftEngineHook"), 5L); + if (canRegisterHook("SmoothTimber")) registerHook("SmoothTimberHook"); From d755636696bce2fc2deb45247c226740b036b78b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 14 Jun 2025 21:14:10 +0300 Subject: [PATCH 197/600] Adds support to EpicSpawners 9 (#2511) --- Hooks/EpicSpawners9/build.gradle | 13 ++ .../SpawnersProvider_EpicSpawners9.java | 138 ++++++++++++++++++ settings.gradle | 1 + .../external/ProvidersManagerImpl.java | 4 +- 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 Hooks/EpicSpawners9/build.gradle create mode 100644 Hooks/EpicSpawners9/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners9.java diff --git a/Hooks/EpicSpawners9/build.gradle b/Hooks/EpicSpawners9/build.gradle new file mode 100644 index 0000000000..6fbe56ab49 --- /dev/null +++ b/Hooks/EpicSpawners9/build.gradle @@ -0,0 +1,13 @@ +group 'Hooks:EpicSpawners8' + +dependencies { + compileOnly "com.songoda:EpicSpawners:9.1.1" + compileOnly "org.spigotmc:v1_8_R3-Taco:latest" + compileOnly project(":API") + compileOnly rootProject +} + +if (project.hasProperty('hook.compile_epicspawners9') && + !Boolean.valueOf(project.findProperty("hook.compile_epicspawners9").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/Hooks/EpicSpawners9/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners9.java b/Hooks/EpicSpawners9/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners9.java new file mode 100644 index 0000000000..937dc75ab7 --- /dev/null +++ b/Hooks/EpicSpawners9/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners9.java @@ -0,0 +1,138 @@ +package com.bgsoftware.superiorskyblock.external.spawners; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.hooks.SpawnersProvider; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.google.common.base.Preconditions; +import com.songoda.epicspawners.api.EpicSpawnersApi; +import com.songoda.epicspawners.api.events.SpawnerBreakEvent; +import com.songoda.epicspawners.api.events.SpawnerChangeEvent; +import com.songoda.epicspawners.api.events.SpawnerPlaceEvent; +import com.songoda.epicspawners.api.spawners.spawner.SpawnerData; +import com.songoda.epicspawners.api.spawners.spawner.SpawnerStack; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; + +@SuppressWarnings("unused") +public class SpawnersProvider_EpicSpawners9 implements SpawnersProvider { + + private static boolean registered = false; + + private final SuperiorSkyblockPlugin plugin; + + public SpawnersProvider_EpicSpawners9(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + if (!registered) { + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + registered = true; + Log.info("Using EpicSpawners as a spawners provider."); + } + } + + @Override + public Pair getSpawner(Location location) { + Preconditions.checkNotNull(location, "location parameter cannot be null."); + + int blockCount = -1; + String entityType = null; + + if (Bukkit.isPrimaryThread()) { + SpawnerStack spawnerStack = EpicSpawnersApi.getSpawnerManager().getSpawnerFromWorld(location).getFirstStack(); + if (spawnerStack != null) { + blockCount = spawnerStack.getStackSize(); + entityType = spawnerStack.getCurrentTier().getIdentifyingName(); + } + } + + return new Pair<>(blockCount, entityType); + } + + @Override + public String getSpawnerType(ItemStack itemStack) { + Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null."); + return EpicSpawnersApi.getSpawnerManager().getSpawnerTier(itemStack).getSpawnerData().getIdentifyingName(); + } + + private class StackerListener implements Listener { + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onSpawnerStack(SpawnerPlaceEvent e) { + Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); + + if (island == null) + return; + + SpawnerData spawnerData = e.getSpawner().getFirstStack().getSpawnerData(); + + Key spawnerKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); + int increaseAmount = e.getSpawner().getFirstStack().getStackSize(); + + if (spawnerData.isCustom()) { + // Custom spawners are egg spawners. Therefore, we want to remove one egg spawner from the counts and + // replace it with the custom spawner. We subtract the spawner 1 tick later, so it will be registered + // before removing it. + BukkitExecutor.sync(() -> island.handleBlockBreak(ConstantKeys.EGG_MOB_SPAWNER, 1), 1L); + } else { + // Vanilla spawners are listened in the vanilla listeners as well, and therefore 1 spawner is already + // being counted by the other listeners. We need to subtract 1 so the counts will be adjusted correctly. + increaseAmount--; + } + + if (increaseAmount <= 0) + return; + + if (island.hasReachedBlockLimit(spawnerKey, increaseAmount)) { + e.setCancelled(true); + Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(spawnerKey.toString())); + } else { + island.handleBlockPlace(spawnerKey, increaseAmount); + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onSpawnerStack(SpawnerChangeEvent e) { + Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); + + if (island == null) + return; + + Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); + + int increaseAmount = e.getStackSize() - e.getOldStackSize(); + + if (increaseAmount < 0) { + island.handleBlockBreak(blockKey, -increaseAmount); + } else if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { + e.setCancelled(true); + Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); + } else { + island.handleBlockPlace(blockKey, increaseAmount); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onSpawnerUnstack(SpawnerBreakEvent e) { + Island island = plugin.getGrid().getIslandAt(e.getSpawner().getLocation()); + + if (island == null) + return; + + Key blockKey = Key.ofSpawner(e.getSpawner().getIdentifyingName()); + + island.handleBlockBreak(blockKey, e.getSpawner().getFirstStack().getStackSize()); + } + + } + +} diff --git a/settings.gradle b/settings.gradle index d72fde2f43..6e23229032 100644 --- a/settings.gradle +++ b/settings.gradle @@ -19,6 +19,7 @@ include 'Hooks:CraftEngine' include 'Hooks:EpicSpawners6' include 'Hooks:EpicSpawners7' include 'Hooks:EpicSpawners8' +include 'Hooks:EpicSpawners9' include 'Hooks:Essentials' include 'Hooks:FastAsyncWorldEdit' include 'Hooks:ItemsAdder' diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java index e30bcea607..4631aed1a4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java @@ -523,7 +523,9 @@ private void registerSpawnersProvider() { } else if (canRegisterHook("EpicSpawners") && (auto || configSpawnersProvider.equalsIgnoreCase("EpicSpawners"))) { String version = Bukkit.getPluginManager().getPlugin("EpicSpawners").getDescription().getVersion(); - if (version.startsWith("8")) { + if (version.startsWith("9")) { + spawnersProvider = createInstance("spawners.SpawnersProvider_EpicSpawners9"); + } else if (version.startsWith("8")) { spawnersProvider = createInstance("spawners.SpawnersProvider_EpicSpawners8"); } else if (version.startsWith("7")) { spawnersProvider = createInstance("spawners.SpawnersProvider_EpicSpawners7"); From 8f286ccdcf28e929988f9332d7be15713486e63a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 20 Jun 2025 19:55:13 +0300 Subject: [PATCH 198/600] Add debug messages to generate ghost block bug (#2373) --- .../com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java | 2 ++ .../com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java index 430df64841..e82fe4f401 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; +import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.PropertiesMapper; @@ -350,6 +351,7 @@ public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chun } else { relevantPlayers = chunkHolder.playerProvider.getPlayers(chunkPos, false); } + Log.debug(Debug.GENERATE_BLOCK, "Relevant Players", relevantPlayers); relevantPlayers.forEach(serverPlayer -> serverPlayer.connection.send(packet)); } } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java index 121fd079e7..fcd9976f93 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; +import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.PropertiesMapper; @@ -350,6 +351,7 @@ public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chun } else { relevantPlayers = chunkHolder.playerProvider.getPlayers(chunkPos, false); } + Log.debug(Debug.GENERATE_BLOCK, "Relevant Players", relevantPlayers); relevantPlayers.forEach(serverPlayer -> serverPlayer.connection.send(packet)); } } From 3500d73d154396cc28595a69542319b601b3eace Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 20 Jun 2025 20:22:40 +0300 Subject: [PATCH 199/600] Fixed errors when creating schematics in Spigot (#2512) --- .../nms/v1_17/world/ChunkReaderImpl.java | 8 +++++--- .../nms/v1_18/world/ChunkReaderImpl.java | 10 ++++++---- .../nms/v1_19/world/ChunkReaderImpl.java | 10 ++++++---- .../nms/v1_20_3/world/ChunkReaderImpl.java | 11 +++++++---- .../nms/v1_20_4/world/ChunkReaderImpl.java | 11 +++++++---- .../nms/v1_21/world/ChunkReaderImpl.java | 11 +++++++---- .../nms/v1_21_3/world/ChunkReaderImpl.java | 11 +++++++---- .../nms/v1_21_4/world/ChunkReaderImpl.java | 11 +++++++---- .../nms/v1_21_5/world/ChunkReaderImpl.java | 12 +++++++----- 9 files changed, 59 insertions(+), 36 deletions(-) diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java index eb42169b4b..9e152be105 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java @@ -10,6 +10,7 @@ import net.minecraft.nbt.NbtUtils; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -56,8 +57,9 @@ public ChunkReaderImpl(Chunk bukkitChunk) { LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); this.serverLevel = levelChunk.level; - this.x = levelChunk.locX; - this.z = levelChunk.locZ; + ChunkPos chunkPos = levelChunk.getPos(); + this.x = chunkPos.x; + this.z = chunkPos.z; LevelChunkSection[] levelChunkSections = levelChunk.getSections(); this.blockids = new PalettedContainer[levelChunkSections.length]; @@ -126,7 +128,7 @@ public int getZ() { @Override public Material getType(int x, int y, int z) { - return getBlockState(x, y, z).getBukkitMaterial(); + return CraftMagicNumbers.getMaterial(getBlockState(x, y, z).getBlock()); } @Override diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java index 4cdc5c5610..19e588d294 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java @@ -9,6 +9,7 @@ import net.minecraft.core.SectionPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -38,7 +39,7 @@ public class ChunkReaderImpl implements ChunkReader { private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); private static final byte[] EMPTY_LIGHT = new byte[2048]; private final ServerLevel serverLevel; @@ -55,8 +56,9 @@ public ChunkReaderImpl(Chunk bukkitChunk) { LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); this.serverLevel = levelChunk.level; - this.x = levelChunk.locX; - this.z = levelChunk.locZ; + ChunkPos chunkPos = levelChunk.getPos(); + this.x = chunkPos.x; + this.z = chunkPos.z; LevelChunkSection[] levelChunkSections = levelChunk.getSections(); this.blockids = new PalettedContainer[levelChunkSections.length]; @@ -119,7 +121,7 @@ public int getZ() { @Override public Material getType(int x, int y, int z) { - return getBlockState(x, y, z).getBukkitMaterial(); + return CraftMagicNumbers.getMaterial(getBlockState(x, y, z).getBlock()); } @Override diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java index 906f8d88b6..06dceae8a3 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java @@ -9,6 +9,7 @@ import net.minecraft.core.SectionPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -39,7 +40,7 @@ public class ChunkReaderImpl implements ChunkReader { private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); private static final byte[] EMPTY_LIGHT = new byte[2048]; private final ServerLevel serverLevel; @@ -56,8 +57,9 @@ public ChunkReaderImpl(Chunk bukkitChunk) { LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); this.serverLevel = levelChunk.level; - this.x = levelChunk.locX; - this.z = levelChunk.locZ; + ChunkPos chunkPos = levelChunk.getPos(); + this.x = chunkPos.x; + this.z = chunkPos.z; LevelChunkSection[] levelChunkSections = levelChunk.getSections(); this.blockids = new PalettedContainerRO[levelChunkSections.length]; @@ -120,7 +122,7 @@ public int getZ() { @Override public Material getType(int x, int y, int z) { - return getBlockState(x, y, z).getBukkitMaterial(); + return CraftMagicNumbers.getMaterial(getBlockState(x, y, z).getBlock()); } @Override diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java index fcd68078e8..ba9173424c 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java @@ -9,6 +9,7 @@ import net.minecraft.core.SectionPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -26,6 +27,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockType; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; @@ -40,7 +42,7 @@ public class ChunkReaderImpl implements ChunkReader { private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); private static final byte[] FULL_LIGHT = new byte[2048]; private static final byte[] EMPTY_LIGHT = new byte[2048]; @@ -62,8 +64,9 @@ public ChunkReaderImpl(Chunk bukkitChunk) { LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); this.serverLevel = levelChunk.level; - this.x = levelChunk.locX; - this.z = levelChunk.locZ; + ChunkPos chunkPos = levelChunk.getPos(); + this.x = chunkPos.x; + this.z = chunkPos.z; LevelChunkSection[] levelChunkSections = levelChunk.getSections(); this.blockids = new PalettedContainerRO[levelChunkSections.length]; @@ -126,7 +129,7 @@ public int getZ() { @Override public Material getType(int x, int y, int z) { - return getBlockState(x, y, z).getBukkitMaterial(); + return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); } @Override diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java index 2576de2480..b9156b44df 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java @@ -10,6 +10,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -27,6 +28,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.block.CraftBlockType; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; @@ -41,7 +43,7 @@ public class ChunkReaderImpl implements ChunkReader { private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); private static final byte[] FULL_LIGHT = new byte[2048]; private static final byte[] EMPTY_LIGHT = new byte[2048]; @@ -63,8 +65,9 @@ public ChunkReaderImpl(Chunk bukkitChunk) { LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); this.serverLevel = levelChunk.level; - this.x = levelChunk.locX; - this.z = levelChunk.locZ; + ChunkPos chunkPos = levelChunk.getPos(); + this.x = chunkPos.x; + this.z = chunkPos.z; LevelChunkSection[] levelChunkSections = levelChunk.getSections(); this.blockids = new PalettedContainerRO[levelChunkSections.length]; @@ -127,7 +130,7 @@ public int getZ() { @Override public Material getType(int x, int y, int z) { - return getBlockState(x, y, z).getBukkitMaterial(); + return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); } @Override diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java index caef562acf..7dd5afc8d2 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java @@ -10,6 +10,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -27,6 +28,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.block.CraftBlockType; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; @@ -41,7 +43,7 @@ public class ChunkReaderImpl implements ChunkReader { private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); private static final byte[] FULL_LIGHT = new byte[2048]; private static final byte[] EMPTY_LIGHT = new byte[2048]; @@ -63,8 +65,9 @@ public ChunkReaderImpl(Chunk bukkitChunk) { LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); this.serverLevel = levelChunk.level; - this.x = levelChunk.locX; - this.z = levelChunk.locZ; + ChunkPos chunkPos = levelChunk.getPos(); + this.x = chunkPos.x; + this.z = chunkPos.z; LevelChunkSection[] levelChunkSections = levelChunk.getSections(); this.blockids = new PalettedContainerRO[levelChunkSections.length]; @@ -127,7 +130,7 @@ public int getZ() { @Override public Material getType(int x, int y, int z) { - return getBlockState(x, y, z).getBukkitMaterial(); + return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); } @Override diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java index d294b442f4..f415010496 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java @@ -10,6 +10,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -27,6 +28,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.block.CraftBlockType; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; @@ -41,7 +43,7 @@ public class ChunkReaderImpl implements ChunkReader { private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); private static final byte[] FULL_LIGHT = new byte[2048]; private static final byte[] EMPTY_LIGHT = new byte[2048]; @@ -63,8 +65,9 @@ public ChunkReaderImpl(Chunk bukkitChunk) { LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); this.serverLevel = levelChunk.level; - this.x = levelChunk.locX; - this.z = levelChunk.locZ; + ChunkPos chunkPos = levelChunk.getPos(); + this.x = chunkPos.x; + this.z = chunkPos.z; LevelChunkSection[] levelChunkSections = levelChunk.getSections(); this.blockids = new PalettedContainerRO[levelChunkSections.length]; @@ -127,7 +130,7 @@ public int getZ() { @Override public Material getType(int x, int y, int z) { - return getBlockState(x, y, z).getBukkitMaterial(); + return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); } @Override diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java index b345f6e3be..8d18c1d5cc 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java @@ -10,6 +10,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -27,6 +28,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.block.CraftBlockType; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; @@ -41,7 +43,7 @@ public class ChunkReaderImpl implements ChunkReader { private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); private static final byte[] FULL_LIGHT = new byte[2048]; private static final byte[] EMPTY_LIGHT = new byte[2048]; @@ -63,8 +65,9 @@ public ChunkReaderImpl(Chunk bukkitChunk) { LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); this.serverLevel = levelChunk.level; - this.x = levelChunk.locX; - this.z = levelChunk.locZ; + ChunkPos chunkPos = levelChunk.getPos(); + this.x = chunkPos.x; + this.z = chunkPos.z; LevelChunkSection[] levelChunkSections = levelChunk.getSections(); this.blockids = new PalettedContainerRO[levelChunkSections.length]; @@ -127,7 +130,7 @@ public int getZ() { @Override public Material getType(int x, int y, int z) { - return getBlockState(x, y, z).getBukkitMaterial(); + return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); } @Override diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java index 805cf48057..f08e37e3a1 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java @@ -3,7 +3,6 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.core.BlockPos; @@ -11,6 +10,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -28,6 +28,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.block.CraftBlockType; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; @@ -42,7 +43,7 @@ public class ChunkReaderImpl implements ChunkReader { private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES, null); + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); private static final byte[] FULL_LIGHT = new byte[2048]; private static final byte[] EMPTY_LIGHT = new byte[2048]; @@ -64,8 +65,9 @@ public ChunkReaderImpl(Chunk bukkitChunk) { LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); this.serverLevel = levelChunk.level; - this.x = levelChunk.locX; - this.z = levelChunk.locZ; + ChunkPos chunkPos = levelChunk.getPos(); + this.x = chunkPos.x; + this.z = chunkPos.z; LevelChunkSection[] levelChunkSections = levelChunk.getSections(); this.blockids = new PalettedContainerRO[levelChunkSections.length]; @@ -128,7 +130,7 @@ public int getZ() { @Override public Material getType(int x, int y, int z) { - return getBlockState(x, y, z).getBukkitMaterial(); + return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); } @Override From b729fac682ad2df5a846ca1a3033509a8ffdc389 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 20 Jun 2025 21:06:11 +0300 Subject: [PATCH 200/600] Potential fix for generator ghost blocks (#2373) --- .../nms/v1_16_R3/NMSUtils.java | 37 +++----------- .../nms/v1_16_R3/NMSWorldImpl.java | 12 +++-- .../superiorskyblock/nms/v1_17/NMSUtils.java | 36 +++---------- .../nms/v1_17/NMSWorldImpl.java | 13 +++-- .../superiorskyblock/nms/v1_18/NMSUtils.java | 32 +++--------- .../nms/v1_18/NMSWorldImpl.java | 13 +++-- .../superiorskyblock/nms/v1_19/NMSUtils.java | 32 +++--------- .../nms/v1_19/NMSWorldImpl.java | 12 +++-- .../nms/v1_20_3/NMSUtils.java | 39 +++----------- .../nms/v1_20_3/NMSWorldImpl.java | 13 +++-- .../nms/v1_20_4/NMSUtils.java | 37 +++----------- .../nms/v1_20_4/NMSWorldImpl.java | 12 +++-- .../superiorskyblock/nms/v1_21/NMSUtils.java | 31 +++-------- .../nms/v1_21/NMSWorldImpl.java | 12 +++-- .../nms/v1_21_3/NMSUtils.java | 49 +++--------------- .../nms/v1_21_3/NMSWorldImpl.java | 12 +++-- .../nms/v1_21_4/NMSUtils.java | 51 +++---------------- .../nms/v1_21_4/NMSWorldImpl.java | 12 +++-- .../nms/v1_21_5/NMSUtils.java | 51 +++---------------- .../nms/v1_21_5/NMSWorldImpl.java | 13 +++-- 20 files changed, 140 insertions(+), 379 deletions(-) diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java index e542a2acf9..3ee0a2ae1d 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_16_R3; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.ChunkPosition; @@ -29,8 +28,6 @@ import net.minecraft.server.v1_16_R3.IBlockState; import net.minecraft.server.v1_16_R3.IChunkAccess; import net.minecraft.server.v1_16_R3.NBTTagCompound; -import net.minecraft.server.v1_16_R3.Packet; -import net.minecraft.server.v1_16_R3.PlayerChunk; import net.minecraft.server.v1_16_R3.PlayerChunkMap; import net.minecraft.server.v1_16_R3.ProtoChunk; import net.minecraft.server.v1_16_R3.TileEntity; @@ -51,10 +48,6 @@ public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( - PlayerChunkMap.class, Map.class, "visibleChunks"); - private static final ReflectMethod SEND_PACKETS_TO_RELEVANT_PLAYERS = new ReflectMethod<>( - PlayerChunk.class, "a", Packet.class, boolean.class); private static final ReflectMethod CHUNK_PROVIDER_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ChunkProviderServer.class, "getChunkAtIfCachedImmediately", int.class, int.class); @@ -202,30 +195,10 @@ public static ProtoChunk createProtoChunk(ChunkCoordIntPair chunkCoord, World wo } } - public static void sendPacketToRelevantPlayers(WorldServer worldServer, int chunkX, int chunkZ, Packet packet) { - PlayerChunkMap playerChunkMap = worldServer.getChunkProvider().playerChunkMap; - ChunkCoordIntPair chunkCoordIntPair = new ChunkCoordIntPair(chunkX, chunkZ); - PlayerChunk playerChunk; - - try { - playerChunk = playerChunkMap.getVisibleChunk(chunkCoordIntPair.pair()); - } catch (Throwable ex) { - playerChunk = VISIBLE_CHUNKS.get(playerChunkMap).get(chunkCoordIntPair.pair()); - } - - if (playerChunk != null) { - try { - playerChunk.sendPacketToTrackedPlayers(packet, false); - } catch (Throwable ex) { - SEND_PACKETS_TO_RELEVANT_PLAYERS.invoke(playerChunk, packet, false); - } - } - } - - public static void setBlock(Chunk chunk, BlockPosition blockPosition, int combinedId, CompoundTag statesTag, - CompoundTag tileEntity) { + public static IBlockData setBlock(Chunk chunk, BlockPosition blockPosition, int combinedId, CompoundTag statesTag, + CompoundTag tileEntity) { if (!isValidPosition(chunk.getWorld(), blockPosition)) - return; + return null; IBlockData blockData = Block.getByCombinedId(combinedId); @@ -255,7 +228,7 @@ public static void setBlock(Chunk chunk, BlockPosition blockPosition, int combin if ((blockData.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || blockData.getBlock() instanceof BlockBed) { chunk.world.setTypeAndData(blockPosition, blockData, 3); - return; + return blockData; } int indexY = blockPosition.getY() >> 4; @@ -307,6 +280,8 @@ public static void setBlock(Chunk chunk, BlockPosition blockPosition, int combin worldTileEntity.load(blockData, tileEntityCompound); } } + + return blockData; } private static boolean isValidPosition(World world, BlockPosition blockPosition) { diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java index d51e6e15e5..c0879e1c78 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java @@ -30,9 +30,9 @@ import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.BlockPropertySlabType; import net.minecraft.server.v1_16_R3.BlockStepAbstract; +import net.minecraft.server.v1_16_R3.Blocks; import net.minecraft.server.v1_16_R3.IBlockData; import net.minecraft.server.v1_16_R3.IChatBaseComponent; -import net.minecraft.server.v1_16_R3.PacketPlayOutBlockChange; import net.minecraft.server.v1_16_R3.PacketPlayOutWorldBorder; import net.minecraft.server.v1_16_R3.SoundCategory; import net.minecraft.server.v1_16_R3.SoundEffectType; @@ -169,9 +169,13 @@ public void setBlock(Location location, int combinedId) { BlockPosition.MutableBlockPosition blockPosition = wrapper.getHandle(); blockPosition.d(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null, null); - NMSUtils.sendPacketToRelevantPlayers(world, blockPosition.getX() >> 4, blockPosition.getZ() >> 4, - new PacketPlayOutBlockChange(world, blockPosition)); + IBlockData blockData = + NMSUtils.setBlock(world.getChunkAtWorldCoords(blockPosition), blockPosition, combinedId, null, null); + + if (blockData != null) { + world.getChunkProvider().flagDirty(blockPosition); + world.chunkPacketBlockController.onBlockChange(world, blockPosition, blockData, Blocks.AIR.getBlockData(), 530); + } } } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java index 24e8947f33..b9cdadd88a 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java @@ -19,8 +19,6 @@ import com.google.common.base.Suppliers; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; -import net.minecraft.network.protocol.Packet; -import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; @@ -59,10 +57,6 @@ public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectMethod SEND_PACKETS_TO_RELEVANT_PLAYERS = new ReflectMethod<>( - ChunkHolder.class, 1, Packet.class, boolean.class); - private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( - ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( @@ -255,32 +249,12 @@ public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverL } } - public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chunkX, int chunkZ, Packet packet) { - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - ChunkHolder chunkHolder; - - try { - chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); - } catch (Throwable ex) { - chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); - } - - if (chunkHolder != null) { - try { - chunkHolder.broadcast(packet, false); - } catch (Throwable ex) { - SEND_PACKETS_TO_RELEVANT_PLAYERS.invoke(chunkHolder, packet, false); - } - } - } - - public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { + public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, + CompoundTag statesTag, CompoundTag tileEntity) { ServerLevel serverLevel = levelChunk.level; if (!isValidPosition(serverLevel, blockPos)) - return; + return null; BlockState blockState = Block.stateById(combinedId); @@ -311,7 +285,7 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin if ((blockState.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || blockState.getBlock() instanceof BedBlock) { serverLevel.setBlock(blockPos, blockState, 3); - return; + return blockState; } int indexY = serverLevel.getSectionIndex(blockPos.getY()); @@ -363,6 +337,8 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin worldBlockEntity.load(tileEntityCompound); } } + + return blockState; } public static boolean isDoubleBlock(Block block, BlockState blockState) { diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index a4c77f9220..e99ad2a932 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -28,12 +28,12 @@ import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -195,12 +195,15 @@ public void setBlock(Location location, int combinedId) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + BlockState blockState = + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + if (blockState != null) { + serverLevel.getChunkSource().blockChanged(blockPos); + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java index 0d979ab932..0389237f75 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java @@ -21,8 +21,6 @@ import net.minecraft.core.Registry; import net.minecraft.core.SectionPos; import net.minecraft.nbt.ListTag; -import net.minecraft.network.protocol.Packet; -import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; @@ -63,10 +61,6 @@ public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectMethod SEND_PACKETS_TO_RELEVANT_PLAYERS = new ReflectMethod<>( - ChunkHolder.class, 1, Packet.class, boolean.class); - private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( - ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( @@ -276,28 +270,12 @@ public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverL null); } - public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chunkX, int chunkZ, Packet packet) { - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - ChunkHolder chunkHolder; - - try { - chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); - } catch (Throwable ex) { - chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); - } - - if (chunkHolder != null) { - SEND_PACKETS_TO_RELEVANT_PLAYERS.invoke(chunkHolder, packet, false); - } - } - - public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { + public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, + CompoundTag statesTag, CompoundTag tileEntity) { ServerLevel serverLevel = levelChunk.level; if (!isValidPosition(serverLevel, blockPos)) - return; + return null; BlockState blockState = Block.stateById(combinedId); @@ -328,7 +306,7 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin if ((blockState.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || blockState.getBlock() instanceof BedBlock) { serverLevel.setBlock(blockPos, blockState, 3); - return; + return blockState; } int indexY = serverLevel.getSectionIndex(blockPos.getY()); @@ -374,6 +352,8 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin worldBlockEntity.load(tileEntityCompound); } } + + return blockState; } public static boolean isDoubleBlock(Block block, BlockState blockState) { diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index 4fe75b3490..8379d9e5d4 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -28,12 +28,12 @@ import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -196,12 +196,15 @@ public void setBlock(Location location, int combinedId) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + BlockState blockState = + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + if (blockState != null) { + serverLevel.getChunkSource().blockChanged(blockPos); + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java index e7e0381337..4ab18cb078 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java @@ -21,8 +21,6 @@ import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; -import net.minecraft.network.protocol.Packet; -import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; @@ -67,10 +65,6 @@ public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectMethod SEND_PACKETS_TO_RELEVANT_PLAYERS = new ReflectMethod<>( - ChunkHolder.class, 1, Packet.class, boolean.class); - private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( - ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( @@ -305,28 +299,12 @@ public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverL null); } - public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chunkX, int chunkZ, Packet packet) { - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - ChunkHolder chunkHolder; - - try { - chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); - } catch (Throwable ex) { - chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); - } - - if (chunkHolder != null) { - SEND_PACKETS_TO_RELEVANT_PLAYERS.invoke(chunkHolder, packet, false); - } - } - - public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { + public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, + CompoundTag statesTag, CompoundTag tileEntity) { ServerLevel serverLevel = levelChunk.level; if (!isValidPosition(serverLevel, blockPos)) - return; + return null; BlockState blockState = Block.stateById(combinedId); @@ -357,7 +335,7 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin if ((blockState.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || blockState.getBlock() instanceof BedBlock) { serverLevel.setBlock(blockPos, blockState, 3); - return; + return blockState; } int indexY = serverLevel.getSectionIndex(blockPos.getY()); @@ -403,6 +381,8 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin worldBlockEntity.load(tileEntityCompound); } } + + return blockState; } public static boolean isDoubleBlock(Block block, BlockState blockState) { diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index f302716e49..9d0fb80fba 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -34,6 +34,7 @@ import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -198,12 +199,15 @@ public void setBlock(Location location, int combinedId) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + BlockState blockState = + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + if (blockState != null) { + serverLevel.getChunkSource().blockChanged(blockPos); + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java index 34c4f3860b..02be14144c 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java @@ -20,8 +20,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; -import net.minecraft.network.protocol.Packet; -import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; @@ -66,14 +64,8 @@ public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectMethod SEND_PACKETS_TO_RELEVANT_PLAYERS = new ReflectMethod<>( - ChunkHolder.class, 1, Packet.class, boolean.class); - private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( - ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); - private static final ReflectMethod CRAFT_CHUNK_GET_HANDLE = new ReflectMethod<>( - CraftChunk.class, LevelChunk.class, "getHandle"); private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( @@ -304,33 +296,12 @@ public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverL null); } - public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chunkX, int chunkZ, Packet packet) { - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - ChunkHolder chunkHolder; - - try { - chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); - } catch (Throwable ex) { - chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); - } - - if (chunkHolder != null) { - if (SEND_PACKETS_TO_RELEVANT_PLAYERS.isValid()) { - SEND_PACKETS_TO_RELEVANT_PLAYERS.invoke(chunkHolder, packet, false); - } else { - chunkHolder.playerProvider.getPlayers(chunkPos, false).forEach(serverPlayer -> - serverPlayer.connection.send(packet)); - } - } - } - - public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { + public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, + CompoundTag statesTag, CompoundTag tileEntity) { ServerLevel serverLevel = levelChunk.level; if (!isValidPosition(serverLevel, blockPos)) - return; + return null; BlockState blockState = Block.stateById(combinedId); @@ -361,7 +332,7 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || blockState.getBlock() instanceof BedBlock) { serverLevel.setBlock(blockPos, blockState, 3); - return; + return blockState; } int indexY = serverLevel.getSectionIndex(blockPos.getY()); @@ -401,6 +372,8 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin worldBlockEntity.load(tileEntityCompound); } } + + return blockState; } public static boolean isDoubleBlock(Block block, BlockState blockState) { diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index b92359c803..9f0e47dbd5 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -27,12 +27,12 @@ import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -195,12 +195,15 @@ public void setBlock(Location location, int combinedId) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + BlockState blockState = + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + if (blockState != null) { + serverLevel.getChunkSource().blockChanged(blockPos); + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java index ff893d7bd4..5c36d5caf1 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java @@ -20,9 +20,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; -import net.minecraft.network.protocol.Packet; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; @@ -67,10 +65,6 @@ public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectMethod SEND_PACKETS_TO_RELEVANT_PLAYERS = new ReflectMethod<>( - ChunkHolder.class, 1, Packet.class, boolean.class); - private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( - ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( @@ -304,33 +298,12 @@ public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverL null); } - public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chunkX, int chunkZ, Packet packet) { - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - ChunkHolder chunkHolder; - - try { - chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); - } catch (Throwable ex) { - chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); - } - - if (chunkHolder != null) { - if (SEND_PACKETS_TO_RELEVANT_PLAYERS.isValid()) { - SEND_PACKETS_TO_RELEVANT_PLAYERS.invoke(chunkHolder, packet, false); - } else { - chunkHolder.playerProvider.getPlayers(chunkPos, false).forEach(serverPlayer -> - serverPlayer.connection.send(packet)); - } - } - } - - public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { + public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, + CompoundTag statesTag, CompoundTag tileEntity) { ServerLevel serverLevel = levelChunk.level; if (!isValidPosition(serverLevel, blockPos)) - return; + return null; BlockState blockState = Block.stateById(combinedId); @@ -361,7 +334,7 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || blockState.getBlock() instanceof BedBlock) { serverLevel.setBlock(blockPos, blockState, 3); - return; + return blockState; } int indexY = serverLevel.getSectionIndex(blockPos.getY()); @@ -401,6 +374,8 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin worldBlockEntity.loadWithComponents(tileEntityCompound, MinecraftServer.getServer().registryAccess()); } } + + return blockState; } public static boolean isDoubleBlock(Block block, BlockState blockState) { diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index e4d5b85d4f..49c62747e6 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -33,6 +33,7 @@ import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -195,12 +196,15 @@ public void setBlock(Location location, int combinedId) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + BlockState blockState = + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + if (blockState != null) { + serverLevel.getChunkSource().blockChanged(blockPos); + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java index 9387e5a661..257ef5c0a3 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java @@ -312,33 +312,12 @@ public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverL null); } - public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chunkX, int chunkZ, Packet packet) { - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - ChunkHolder chunkHolder; - - try { - chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); - } catch (Throwable ex) { - chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); - } - - if (chunkHolder != null) { - if (SEND_PACKETS_TO_RELEVANT_PLAYERS.isValid()) { - SEND_PACKETS_TO_RELEVANT_PLAYERS.invoke(chunkHolder, packet, false); - } else { - chunkHolder.playerProvider.getPlayers(chunkPos, false).forEach(serverPlayer -> - serverPlayer.connection.send(packet)); - } - } - } - - public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { + public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, + CompoundTag statesTag, CompoundTag tileEntity) { ServerLevel serverLevel = levelChunk.level; if (!isValidPosition(serverLevel, blockPos)) - return; + return null; BlockState blockState = Block.stateById(combinedId); @@ -369,7 +348,7 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || blockState.getBlock() instanceof BedBlock) { serverLevel.setBlock(blockPos, blockState, 3); - return; + return blockState; } int indexY = serverLevel.getSectionIndex(blockPos.getY()); @@ -409,6 +388,8 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin worldBlockEntity.loadWithComponents(tileEntityCompound, MinecraftServer.getServer().registryAccess()); } } + + return blockState; } public static boolean isDoubleBlock(Block block, BlockState blockState) { diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index 17521dcf5f..7afe76772b 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -34,6 +34,7 @@ import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; @@ -246,12 +247,15 @@ public void setBlock(Location location, int combinedId) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + BlockState blockState = + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + if (blockState != null) { + serverLevel.getChunkSource().blockChanged(blockPos); + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java index dcdf787282..142419a8d5 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java @@ -21,13 +21,10 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; -import net.minecraft.network.protocol.Packet; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.tags.BlockTags; import net.minecraft.world.entity.Entity; @@ -58,7 +55,6 @@ import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.io.IOException; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Collections; @@ -69,24 +65,11 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; -import java.util.function.Supplier; public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final boolean MOONRISE_SUPPORT = ((Supplier) () -> { - for (Method method : ChunkHolder.class.getDeclaredMethods()) { - if (method.getName().contains("moonrise$")) { - return true; - } - } - - return false; - }).get(); - - private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( - ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( @@ -332,34 +315,12 @@ public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverL null); } - public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chunkX, int chunkZ, Packet packet) { - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - ChunkHolder chunkHolder; - - if (MOONRISE_SUPPORT) { - chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); - } else { - chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); - } - - if (chunkHolder != null) { - List relevantPlayers; - if (MOONRISE_SUPPORT) { - relevantPlayers = chunkHolder.moonrise$getPlayers(false); - } else { - relevantPlayers = chunkHolder.playerProvider.getPlayers(chunkPos, false); - } - relevantPlayers.forEach(serverPlayer -> serverPlayer.connection.send(packet)); - } - } - - public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { + public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, + CompoundTag statesTag, CompoundTag tileEntity) { ServerLevel serverLevel = levelChunk.level; if (!isValidPosition(serverLevel, blockPos)) - return; + return null; BlockState blockState = Block.stateById(combinedId); @@ -390,7 +351,7 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || blockState.getBlock() instanceof BedBlock) { serverLevel.setBlock(blockPos, blockState, 3); - return; + return blockState; } int indexY = serverLevel.getSectionIndex(blockPos.getY()); @@ -430,6 +391,8 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin worldBlockEntity.loadWithComponents(tileEntityCompound, MinecraftServer.getServer().registryAccess()); } } + + return blockState; } public static boolean isDoubleBlock(Block block, BlockState blockState) { diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index 2a8304d09c..b9ba397682 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -34,6 +34,7 @@ import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; @@ -246,12 +247,15 @@ public void setBlock(Location location, int combinedId) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + BlockState blockState = + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + if (blockState != null) { + serverLevel.getChunkSource().blockChanged(blockPos); + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java index e82fe4f401..c4b5bad6a7 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java @@ -9,7 +9,6 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; -import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.PropertiesMapper; @@ -22,13 +21,10 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; -import net.minecraft.network.protocol.Packet; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.tags.BlockTags; import net.minecraft.world.entity.Entity; @@ -59,7 +55,6 @@ import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.io.IOException; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Collections; @@ -70,24 +65,11 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; -import java.util.function.Supplier; public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final boolean MOONRISE_SUPPORT = ((Supplier) () -> { - for (Method method : ChunkHolder.class.getDeclaredMethods()) { - if (method.getName().contains("moonrise$")) { - return true; - } - } - - return false; - }).get(); - - private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( - ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( @@ -333,35 +315,12 @@ public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverL null); } - public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chunkX, int chunkZ, Packet packet) { - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - ChunkHolder chunkHolder; - - if (MOONRISE_SUPPORT) { - chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); - } else { - chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); - } - - if (chunkHolder != null) { - List relevantPlayers; - if (MOONRISE_SUPPORT) { - relevantPlayers = chunkHolder.moonrise$getPlayers(false); - } else { - relevantPlayers = chunkHolder.playerProvider.getPlayers(chunkPos, false); - } - Log.debug(Debug.GENERATE_BLOCK, "Relevant Players", relevantPlayers); - relevantPlayers.forEach(serverPlayer -> serverPlayer.connection.send(packet)); - } - } - - public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { + public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, + CompoundTag statesTag, CompoundTag tileEntity) { ServerLevel serverLevel = levelChunk.level; if (!isValidPosition(serverLevel, blockPos)) - return; + return null; BlockState blockState = Block.stateById(combinedId); @@ -392,7 +351,7 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || blockState.getBlock() instanceof BedBlock) { serverLevel.setBlock(blockPos, blockState, 3); - return; + return blockState; } int indexY = serverLevel.getSectionIndex(blockPos.getY()); @@ -432,6 +391,8 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin worldBlockEntity.loadWithComponents(tileEntityCompound, MinecraftServer.getServer().registryAccess()); } } + + return blockState; } public static boolean isDoubleBlock(Block block, BlockState blockState) { diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index a58bbbda00..7af243029f 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -34,6 +34,7 @@ import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; @@ -246,12 +247,15 @@ public void setBlock(Location location, int combinedId) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + BlockState blockState = + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + if (blockState != null) { + serverLevel.getChunkSource().blockChanged(blockPos); + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java index fcd9976f93..e5cbc58f53 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java @@ -9,7 +9,6 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; -import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.PropertiesMapper; @@ -22,13 +21,10 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; -import net.minecraft.network.protocol.Packet; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.tags.BlockTags; import net.minecraft.world.entity.Entity; @@ -59,7 +55,6 @@ import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.io.IOException; -import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Collections; @@ -70,24 +65,11 @@ import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; -import java.util.function.Supplier; public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final boolean MOONRISE_SUPPORT = ((Supplier) () -> { - for (Method method : ChunkHolder.class.getDeclaredMethods()) { - if (method.getName().contains("moonrise$")) { - return true; - } - } - - return false; - }).get(); - - private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( - ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( @@ -333,35 +315,12 @@ public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverL null); } - public static void sendPacketToRelevantPlayers(ServerLevel serverLevel, int chunkX, int chunkZ, Packet packet) { - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - ChunkHolder chunkHolder; - - if (MOONRISE_SUPPORT) { - chunkHolder = chunkMap.getVisibleChunkIfPresent(chunkPos.toLong()); - } else { - chunkHolder = VISIBLE_CHUNKS.get(chunkMap).get(chunkPos.toLong()); - } - - if (chunkHolder != null) { - List relevantPlayers; - if (MOONRISE_SUPPORT) { - relevantPlayers = chunkHolder.moonrise$getPlayers(false); - } else { - relevantPlayers = chunkHolder.playerProvider.getPlayers(chunkPos, false); - } - Log.debug(Debug.GENERATE_BLOCK, "Relevant Players", relevantPlayers); - relevantPlayers.forEach(serverPlayer -> serverPlayer.connection.send(packet)); - } - } - - public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { + public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, + CompoundTag statesTag, CompoundTag tileEntity) { ServerLevel serverLevel = levelChunk.level; if (!isValidPosition(serverLevel, blockPos)) - return; + return null; BlockState blockState = Block.stateById(combinedId); @@ -392,7 +351,7 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || blockState.getBlock() instanceof BedBlock) { serverLevel.setBlock(blockPos, blockState, 3); - return; + return blockState; } int indexY = serverLevel.getSectionIndex(blockPos.getY()); @@ -432,6 +391,8 @@ public static void setBlock(LevelChunk levelChunk, BlockPos blockPos, int combin worldBlockEntity.loadWithComponents(tileEntityCompound, MinecraftServer.getServer().registryAccess()); } } + + return blockState; } public static boolean isDoubleBlock(Block block, BlockState blockState) { diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java index 9a26f90cc3..728fde018a 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java @@ -28,12 +28,12 @@ import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; @@ -246,12 +246,15 @@ public void setBlock(Location location, int combinedId) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - ClientboundBlockUpdatePacket blockUpdatePacket = new ClientboundBlockUpdatePacket(serverLevel, blockPos); - NMSUtils.sendPacketToRelevantPlayers(serverLevel, blockPos.getX() >> 4, blockPos.getZ() >> 4, blockUpdatePacket); + BlockState blockState = + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + if (blockState != null) { + serverLevel.getChunkSource().blockChanged(blockPos); + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } From 7e6ed5f885122862469a3e826d8405863615808a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Jun 2025 18:07:44 +0300 Subject: [PATCH 201/600] Adds support to 1.21.6 --- NMS/v1_21_6/build.gradle | 38 ++ .../nms/v1_21_6/NMSAlgorithmsImpl.java | 328 ++++++++++ .../nms/v1_21_6/NMSChunksImpl.java | 594 ++++++++++++++++++ .../nms/v1_21_6/NMSDragonFightImpl.java | 118 ++++ .../nms/v1_21_6/NMSEntitiesImpl.java | 52 ++ .../nms/v1_21_6/NMSHologramsImpl.java | 204 ++++++ .../nms/v1_21_6/NMSPlayersImpl.java | 172 +++++ .../nms/v1_21_6/NMSTagsImpl.java | 210 +++++++ .../nms/v1_21_6/NMSUtils.java | 495 +++++++++++++++ .../nms/v1_21_6/NMSWorldImpl.java | 412 ++++++++++++ .../nms/v1_21_6/crops/CropsBlockEntity.java | 103 +++ .../crops/CropsTickingBlockEntity.java | 31 + .../nms/v1_21_6/crops/CropsTickingMethod.java | 159 +++++ .../nms/v1_21_6/dragon/DragonUtils.java | 37 ++ .../dragon/EndWorldEndDragonFightHandler.java | 48 ++ .../v1_21_6/dragon/IslandEndDragonFight.java | 212 +++++++ .../dragon/IslandEntityEnderDragon.java | 103 +++ .../nms/v1_21_6/dragon/SpikesCache.java | 190 ++++++ .../generator/IslandsGeneratorImpl.java | 67 ++ .../menu/MenuBrewingStandBlockEntity.java | 24 + .../menu/MenuDispenserBlockEntity.java | 24 + .../v1_21_6/menu/MenuFurnaceBlockEntity.java | 24 + .../v1_21_6/menu/MenuHopperBlockEntity.java | 26 + .../TickingSpawnerBlockEntityNotifier.java | 57 ++ .../v1_21_6/trial/IslandPlayerDetector.java | 53 ++ .../vibration/IslandVibrationUser.java | 90 +++ .../nms/v1_21_6/world/BlockEntityCache.java | 34 + .../nms/v1_21_6/world/ChunkReaderImpl.java | 255 ++++++++ .../nms/v1_21_6/world/KeyBlocksCache.java | 32 + .../nms/v1_21_6/world/PropertiesMapper.java | 85 +++ .../v1_21_6/world/WorldEditSessionImpl.java | 399 ++++++++++++ build.gradle | 2 +- settings.gradle | 3 +- 33 files changed, 4679 insertions(+), 2 deletions(-) create mode 100644 NMS/v1_21_6/build.gradle create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSAlgorithmsImpl.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSChunksImpl.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSDragonFightImpl.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSEntitiesImpl.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSHologramsImpl.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSPlayersImpl.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSTagsImpl.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSUtils.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSWorldImpl.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsBlockEntity.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingBlockEntity.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingMethod.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/DragonUtils.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/EndWorldEndDragonFightHandler.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEndDragonFight.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEntityEnderDragon.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/SpikesCache.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/generator/IslandsGeneratorImpl.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuBrewingStandBlockEntity.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuDispenserBlockEntity.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuFurnaceBlockEntity.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuHopperBlockEntity.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/spawners/TickingSpawnerBlockEntityNotifier.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/trial/IslandPlayerDetector.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/vibration/IslandVibrationUser.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/BlockEntityCache.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/ChunkReaderImpl.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/KeyBlocksCache.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/PropertiesMapper.java create mode 100644 NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/WorldEditSessionImpl.java diff --git a/NMS/v1_21_6/build.gradle b/NMS/v1_21_6/build.gradle new file mode 100644 index 0000000000..23479215d3 --- /dev/null +++ b/NMS/v1_21_6/build.gradle @@ -0,0 +1,38 @@ +plugins { + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } +} + +group 'NMS:v1_21_6' + +dependencies { + paperweight.paperDevBundle("1.21.6-R0.1-SNAPSHOT") + compileOnly project(":NMS:Spigot-1_20_3") + compileOnly project(":NMS:Paper-1_20_3") + compileOnly project(":API") + compileOnly rootProject +} + +shadowJar { + archiveFileName = "${project.name}-exclude.jar" +} + +assemble { + dependsOn(reobfJar) +} + +tasks { + reobfJar { + File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") + outputJar.set(layout.buildDirectory.file(outputFile.getPath())) + } +} + +if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSAlgorithmsImpl.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSAlgorithmsImpl.java new file mode 100644 index 0000000000..6f6829000e --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSAlgorithmsImpl.java @@ -0,0 +1,328 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; +import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; +import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.menu.MenuBrewingStandBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.menu.MenuDispenserBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.menu.MenuFurnaceBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.BlockEntityCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.KeyBlocksCache; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.mojang.serialization.JsonOps; +import io.papermc.paper.chat.ChatRenderer; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.TextReplacementConfig; +import net.minecraft.SharedConstants; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.ComponentSerialization; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.Container; +import net.minecraft.world.entity.item.FallingBlockEntity; +import net.minecraft.world.entity.vehicle.AbstractMinecart; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.block.Biome; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; +import org.bukkit.command.defaults.BukkitCommand; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftFallingBlock; +import org.bukkit.craftbukkit.entity.CraftMinecart; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffect; +import org.jetbrains.annotations.NotNull; + +import java.util.EnumMap; +import java.util.Optional; +import java.util.function.BiFunction; + +public class NMSAlgorithmsImpl implements NMSAlgorithms { + + private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create(); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final Multimap EMPTY_ATTRIBUTES_MAP = + MultimapBuilder.hashKeys().hashSetValues().build(); + + private static final EnumBridge BIOME_ENUM_BRIDGE = new EnumBridge<>() { + @Override + public Biome[] getValues() { + return Biome.values(); + } + + @Override + public String getName(Biome enumValue) { + return enumValue.name(); + } + }; + + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); + + static { + MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); + } + + private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { + @Override + public byte[] processClass(byte[] classBytes, String path) { + return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); + } + }; + + @Override + public void registerCommand(BukkitCommand command) { + ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); + } + + @Override + public String parseSignLine(String original) { + RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE); + JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0]) + .getOrThrow(JsonParseException::new); + return COMPONENT_GSON.toJson(jsonElement); + } + + @Override + public int getCombinedId(Location location) { + org.bukkit.World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return 0; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(wrapper.getHandle()); + } + return Block.getId(blockState); + } + + @Override + public int getCombinedId(Material material, byte data) { + BlockState blockState; + + if (data == 0) { + Block block = CraftMagicNumbers.getBlock(material); + if (block == null) + return -1; + blockState = block.defaultBlockState(); + } else { + blockState = CraftMagicNumbers.getBlock(material, data); + } + + return blockState == null ? -1 : Block.getId(blockState); + } + + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + BlockState blockState = Block.stateById(combinedId); + + if (!blockState.hasBlockEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getBlockEntityId(blockState); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + + @Override + public int compareMaterials(Material o1, Material o2) { + int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); + int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); + return Integer.compare(firstMaterial, secondMaterial); + } + + @Override + public short getBlockDataValue(org.bukkit.block.BlockState blockState) { + BlockData blockData = blockState.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + BlockData blockData = block.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getMaxBlockDataValue(Material material) { + if (!material.isBlock()) + return 0; + + BlockData blockData = Bukkit.createBlockData(material); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); + } + + @Override + public Key getBlockKey(int combinedId) { + Block block = Block.stateById(combinedId).getBlock(); + return KeyBlocksCache.getBlockKey(block); + } + + @Override + public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { + AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); + Block block = minecart.getDisplayBlockState().getBlock(); + return KeyBlocksCache.getBlockKey(block); + } + + @Override + public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { + FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); + Block block = fallingBlock.getBlockState().getBlock(); + return KeyBlocksCache.getBlockKey(block); + } + + @Override + public void setCustomModel(ItemMeta itemMeta, int customModel) { + itemMeta.setCustomModelData(customModel); + } + + @Override + public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { + if (!potionMeta.hasCustomEffects()) + potionMeta.setColor(potionEffect.getType().getColor()); + potionMeta.addCustomEffect(potionEffect, true); + } + + @Override + public String getMinecraftKey(ItemStack itemStack) { + return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); + } + + @Override + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.setEnchantmentGlintOverride(true); + } + + @Nullable + @Override + public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { + MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); + return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); + } + + @Override + public int getMaxWorldSize() { + return Bukkit.getMaxWorldSize(); + } + + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + + @Override + public int getDataVersion() { + return SharedConstants.getCurrentVersion().dataVersion().version(); + } + + @Override + public ClassProcessor getClassProcessor() { + return CLASS_PROCESSOR; + } + + @Override + public void handlePaperChatRenderer(Object event) { + if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) + return; + + ChatRenderer originalRenderer = asyncChatEvent.renderer(); + asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); + } + + @Override + public void hideAttributes(ItemMeta itemMeta) { + itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); + } + + @Override + public EnumBridge getBiomeBridge() { + return BIOME_ENUM_BRIDGE; + } + + private interface MenuCreator extends BiFunction { + } + + private static class ChatRendererWrapper { + + private static final String MESSAGE_PLACEHOLDER = "{message}"; + private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = + net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); + + private final ChatRenderer renderer = new ChatRenderer() { + @Override + public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, + net.kyori.adventure.text.@NotNull Component sourceDisplayName, + net.kyori.adventure.text.@NotNull Component message, + @NotNull Audience viewer) { + String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer + .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); + Island island = superiorPlayer.getIsland(); + + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( + Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) + .replaceText(TextReplacementConfig.builder() + .matchLiteral(MESSAGE_PLACEHOLDER) + .replacement(message) + .build()); + } + }; + + private final ChatRenderer originalRenderer; + + public ChatRendererWrapper(ChatRenderer originalRenderer) { + this.originalRenderer = originalRenderer; + } + + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSChunksImpl.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSChunksImpl.java new file mode 100644 index 0000000000..c09dfdc365 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSChunksImpl.java @@ -0,0 +1,594 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.core.CalculatedChunk; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Counter; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.bgsoftware.superiorskyblock.nms.NMSChunks; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.crops.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.crops.CropsTickingMethod; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.mojang.logging.LogUtils; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; +import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.BitStorage; +import net.minecraft.util.ProblemReporter; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.Biomes; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.SlabType; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.phys.AABB; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.entity.CraftEntityType; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.generator.ChunkGenerator; +import org.slf4j.Logger; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +public class NMSChunksImpl implements NMSChunks { + + private static final Logger LOGGER = LogUtils.getLogger(); + + private final SuperiorSkyblockPlugin plugin; + + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + KeyBlocksCache.cacheAllBlocks(); + CropsTickingMethod.register(); + } + + @Override + public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, + Collection playersToUpdate) { + if (chunkPositions.isEmpty()) + return; + + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); + + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); + + ChunkPos chunkPos = levelChunk.getPos(); + + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + LevelChunkSection currentSection = chunkSections[i]; + if (currentSection != null) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); + } + } + + levelChunk.markUnsaved(); + + ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); + ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( + levelChunk, levelChunk.level.getLightEngine(), null, null); + + playersToUpdate.forEach(player -> { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + serverPlayer.connection.send(forgetLevelChunkPacket); + serverPlayer.connection.send(mapChunkPacket); + }); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + + Codec>> biomesCodec = PalettedContainer.codecRW( + biomesRegistry.asHolderIdMap(), + biomesRegistry.holderByNameCodec(), + PalettedContainer.Strategy.SECTION_BIOMES, + biomesRegistry.getOrThrow(Biomes.PLAINS) + ); + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); + Tag biomesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = unloadedChunkCompound.getSections(); + + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); + } + + @Override + public void onFinish() { + // Do nothing. + } + }); + } + + @Override + public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { + if (chunkPositions.isEmpty()) + return; + + chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), + chunkPosition.getX(), chunkPosition.getZ(), false)); + + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); + + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + chunkSections[i] = new LevelChunkSection(biomesRegistry); + } + + removeEntities(levelChunk); + removeBlockEntities(levelChunk); + removeBlocks(levelChunk); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + Codec> blocksCodec = PalettedContainer.codecRW( + Block.BLOCK_STATE_REGISTRY, + BlockState.CODEC, + PalettedContainer.Strategy.SECTION_STATES, + Blocks.AIR.defaultBlockState()); + + ListTag tileEntities = new ListTag(); + + unloadedChunkCompound.setEntities(new ListTag()); + unloadedChunkCompound.setBlockEntities(tileEntities); + + if (serverLevel.generator instanceof IslandsGenerator) { + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); + Tag blockStatesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = unloadedChunkCompound.getSections(); + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); + } else { + ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); + + try { + NMSUtils.buildSurfaceForChunk(serverLevel, protoChunk); + } catch (Exception ignored) { + } + + Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + Codec>> biomesCodec = PalettedContainer.codecRO( + biomesRegistry.asHolderIdMap(), + biomesRegistry.holderByNameCodec(), + PalettedContainer.Strategy.SECTION_BIOMES, + biomesRegistry.getOrThrow(Biomes.PLAINS) + ); + + LevelLightEngine lightEngine = serverLevel.getLightEngine(); + LevelChunkSection[] chunkSections = protoChunk.getSections(); + + ListTag sectionsList = new ListTag(); + + // Save blocks + for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { + int chunkSectionIndex = serverLevel.getSectionIndex(i); + + CompoundTag sectionCompound = new CompoundTag(); + + if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { + LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; + + { + DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); + sectionCompound.put("block_states", dataResult.getOrThrow()); + } + + { + DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); + sectionCompound.put("biomes", dataResult.getOrThrow()); + } + } + + if (!sectionCompound.isEmpty()) { + sectionCompound.putByte("Y", (byte) i); + sectionsList.add(sectionCompound); + } + } + + for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { + CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, + MinecraftServer.getServer().registryAccess()); + if (blockEntityCompound != null) + tileEntities.add(blockEntityCompound); + } + + unloadedChunkCompound.setSections(sectionsList); + } + } + + @Override + public void onFinish() { + if (onFinish != null) + onFinish.run(); + } + }); + } + + @Override + public CompletableFuture> calculateChunks(List chunkPositions, + Synchronized> unloadedChunksCache) { + List allCalculatedChunks = new LinkedList<>(); + List chunkPositionsToCalculate = new LinkedList<>(); + + Iterator chunkPositionsIterator = chunkPositions.iterator(); + while (chunkPositionsIterator.hasNext()) { + ChunkPosition chunkPosition = chunkPositionsIterator.next(); + CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); + if (cachedCalculatedChunk != null) { + allCalculatedChunks.add(cachedCalculatedChunk); + chunkPositionsIterator.remove(); + } else { + chunkPositionsToCalculate.add(chunkPosition); + } + } + + if (chunkPositions.isEmpty()) + return CompletableFuture.completedFuture(allCalculatedChunks); + + CompletableFuture> completableFuture = new CompletableFuture<>(); + + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + + Codec> blocksCodec = PalettedContainer.codecRW( + Block.BLOCK_STATE_REGISTRY, + BlockState.CODEC, + PalettedContainer.Strategy.SECTION_STATES, + Blocks.AIR.defaultBlockState() + ); + Codec>> biomesCodec = PalettedContainer.codecRW( + biomesRegistry.asHolderIdMap(), + biomesRegistry.holderByNameCodec(), + PalettedContainer.Strategy.SECTION_BIOMES, + biomesRegistry.getOrThrow(Biomes.PLAINS) + ); + + LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; + + ListTag sectionsList = unloadedChunkCompound.getSections(); + for (int i = 0; i < sectionsList.size(); ++i) { + CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); + byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); + int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); + + if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { + PalettedContainer blocksDataPalette; + Optional blockStatesCompound = sectionCompound.getCompound("block_states"); + if (blockStatesCompound.isPresent()) { + DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, + blockStatesCompound.get()).promotePartial((sx) -> { + }); + blocksDataPalette = dataResult.getOrThrow(); + } else { + blocksDataPalette = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + } + + PalettedContainer> biomesDataPalette; + Optional biomesCompound = sectionCompound.getCompound("biomes"); + if (biomesCompound.isPresent()) { + DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, + biomesCompound.get()).promotePartial((sx) -> { + }); + biomesDataPalette = dataResult.getOrThrow(); + } else { + biomesDataPalette = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); + } + + chunkSections[sectionIndex] = new LevelChunkSection(blocksDataPalette, biomesDataPalette); + } + + } + + CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + allCalculatedChunks.add(calculatedChunk); + unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + } + + @Override + public void onFinish() { + completableFuture.complete(allCalculatedChunks); + } + }); + + return completableFuture; + } + + @Override + public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { + CompletableFuture> completableFuture = new CompletableFuture<>(); + + KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + List unloadedChunkCompounds = new LinkedList<>(); + + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { + if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) + chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); + } + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + unloadedChunkCompounds.add(unloadedChunkCompound); + } + + @Override + public void onFinish() { + BukkitExecutor.ensureMain(() -> { + for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + for (Tag entityTag : unloadedChunkCompound.getEntities()) { + Entity fakeEntity; + EntityType entityType; + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(entityTag::toString, LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), (CompoundTag) entityTag); + + entityType = EntityType.by(valueInput).orElse(null); + if (entityType == null) + continue; + + fakeEntity = EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL).orElse(null); + } + + if (fakeEntity != null) { + fakeEntity.valid = false; + if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) + continue; + } + + Key entityKey = Keys.of(CraftEntityType.minecraftToBukkit(entityType)); + chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); + } + } + + completableFuture.complete(chunkEntities); + }); + } + }); + + return completableFuture; + } + + @Override + public void injectChunkSections(Chunk chunk) { + // No implementation + } + + @Override + public boolean isChunkEmpty(Chunk bukkitChunk) { + LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); + return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> + chunkSection == null || chunkSection.hasOnlyAir()); + } + + @Override + public Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); + return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; + } + + @Override + public void startTickingChunk(Island island, Chunk chunk, boolean stop) { + if (plugin.getSettings().getCropsInterval() <= 0) + return; + + if (stop) { + CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); + if (cropsBlockEntity != null) + cropsBlockEntity.remove(); + } else { + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); + CropsBlockEntity.create(island, levelChunk); + } + } + + @Override + public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { + if (chunkPositions.isEmpty()) return; + CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> + cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); + } + + @Override + public void shutdown() { + List> pendingTasks = NMSUtils.getPendingChunkActions(); + + if (pendingTasks.isEmpty()) + return; + + Log.info("Waiting for chunk tasks to complete."); + + CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); + } + + @Override + public List getBlockEntities(Chunk chunk) { + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); + List blockEntities = new LinkedList<>(); + + World bukkitWorld = chunk.getWorld(); + + levelChunk.getBlockEntities().keySet().forEach(blockPos -> + blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); + + return blockEntities; + } + + private static final ReflectField PALETTED_CONTAINER_DATA = new ReflectField<>( + PalettedContainer.class, Object.class, "d"); + + private static final ReflectField PALETTED_CONTAINER_DATA_STORAGE = new ReflectField<>( + PalettedContainer.class, BitStorage.class, "b"); + + private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { + KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); + List spawnersLocations = new LinkedList<>(); + + for (int i = 0; i < chunkSections.length; ++i) { + LevelChunkSection levelChunkSection = chunkSections[i]; + if (levelChunkSection != null && !levelChunkSection.hasOnlyAir()) { + int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4; + for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { + BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); + calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, + sectionBottomY, blockCounts, spawnersLocations); + } + } + } + + return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); + } + + private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, + int sectionBottomY, KeyMap blockCounts, + List spawnersLocations) { + Block block = blockState.getBlock(); + + if (block == Blocks.AIR) + return; + + Location location = new Location(chunkPosition.getWorld(), + (chunkPosition.getX() << 4) + x, + sectionBottomY + y, + (chunkPosition.getZ() << 4) + z); + + int blockAmount = 1; + + if (NMSUtils.isDoubleBlock(block, blockState)) { + blockAmount = 2; + blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); + } + + Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); + blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); + if (block == Blocks.SPAWNER) { + spawnersLocations.add(location); + } + } + + private static void removeEntities(ChunkAccess chunk) { + ChunkPos chunkPos = chunk.getPos(); + ServerLevel serverLevel = ((LevelChunk) chunk).level; + + int chunkWorldCoordX = chunkPos.x << 4; + int chunkWorldCoordZ = chunkPos.z << 4; + + AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinY(), chunkWorldCoordZ, + chunkWorldCoordX + 15, serverLevel.getMaxY(), chunkWorldCoordZ + 15); + + List worldEntities = new LinkedList<>(); + serverLevel.getEntities().get(chunkBounds, worldEntities::add); + + worldEntities.forEach(nmsEntity -> { + if (!(nmsEntity instanceof Player)) + nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); + }); + } + + private static void removeBlockEntities(ChunkAccess chunk) { + chunk.blockEntities.values().forEach(BlockEntity::setRemoved); + chunk.blockEntities.clear(); + } + + private static void removeBlocks(ChunkAccess chunk) { + ServerLevel serverLevel = ((LevelChunk) chunk).level; + + ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); + + if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { + NMSUtils.buildSurfaceForChunk(serverLevel, chunk); + } + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSDragonFightImpl.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSDragonFightImpl.java new file mode 100644 index 0000000000..6bc677c37f --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSDragonFightImpl.java @@ -0,0 +1,118 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.EndWorldEndDragonFightHandler; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.IslandEndDragonFight; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.IslandEntityEnderDragon; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.SpikesCache; +import com.google.common.cache.LoadingCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.levelgen.feature.SpikeFeature; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.NamespacedKey; +import org.bukkit.World; +import org.bukkit.advancement.Advancement; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.entity.Player; + +import java.lang.reflect.Modifier; +import java.util.List; + +public class NMSDragonFightImpl implements NMSDragonFight { + + private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( + EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) + .removeFinal(); + + private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField<>( + ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE, 1); + + private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( + SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) + .removeFinal(); + + private static boolean firstWorldPreparation = true; + + static { + ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); + } + + @Override + public void prepareEndWorld(World bukkitWorld) { + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); + + if (firstWorldPreparation) { + firstWorldPreparation = false; + SPIKE_CACHE.set(null, SpikesCache.getInstance()); + } + } + + @Nullable + @Override + public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { + World bukkitWorld = island.getCenter(dimension).getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + return null; + + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); + } + + @Override + public void startDragonBattle(Island island, Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + return; + + dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + } + + @Override + public void removeDragonBattle(Island island, Dimension dimension) { + World bukkitWorld = island.getCenter(dimension).getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + return; + + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + + if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { + islandEndDragonFight.removeBattlePlayers(); + islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); + } + } + + @Override + public void awardTheEndAchievement(Player player) { + Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); + if (advancement != null) + player.getAdvancementProgress(advancement).awardCriteria(""); + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSEntitiesImpl.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSEntitiesImpl.java new file mode 100644 index 0000000000..6bcd84b0f1 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSEntitiesImpl.java @@ -0,0 +1,52 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6; + +import com.bgsoftware.superiorskyblock.nms.NMSEntities; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PortalProcessor; +import org.bukkit.Material; +import org.bukkit.craftbukkit.entity.CraftAnimals; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Animals; +import org.bukkit.entity.minecart.PoweredMinecart; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.ItemStack; + +public class NMSEntitiesImpl implements NMSEntities { + + @Override + public ItemStack[] getEquipment(EntityEquipment entityEquipment) { + ItemStack[] itemStacks = new ItemStack[7]; + + itemStacks[0] = new ItemStack(Material.ARMOR_STAND); + itemStacks[1] = entityEquipment.getItemInMainHand(); + itemStacks[2] = entityEquipment.getItemInOffHand(); + itemStacks[3] = entityEquipment.getHelmet(); + itemStacks[4] = entityEquipment.getChestplate(); + itemStacks[5] = entityEquipment.getLeggings(); + itemStacks[6] = entityEquipment.getBoots(); + + return itemStacks; + } + + @Override + public boolean isAnimalFood(ItemStack itemStack, Animals animals) { + return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); + } + + @Override + public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); + } + + @Override + public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { + Entity entity = ((CraftEntity) bukkitEntity).getHandle(); + PortalProcessor portalProcessor = entity.portalProcess; + return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSHologramsImpl.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSHologramsImpl.java new file mode 100644 index 0000000000..a69ed3a172 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSHologramsImpl.java @@ -0,0 +1,204 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6; + +import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; +import com.bgsoftware.superiorskyblock.nms.NMSHolograms; +import com.google.common.base.Preconditions; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.level.storage.ValueOutput; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftArmorStand; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.entity.Entity; + +@SuppressWarnings("unused") +public class NMSHologramsImpl implements NMSHolograms { + + @Override + public Hologram createHologram(Location location) { + Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); + serverLevel.addFreshEntity(entityHologram); + return entityHologram; + } + + @Override + public boolean isHologram(Entity entity) { + return ((CraftEntity) entity).getHandle() instanceof Hologram; + } + + public static class EntityHologram extends ArmorStand implements Hologram { + + private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); + + private CraftEntity bukkitEntity; + + EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + + setInvisible(true); + setSmall(true); + setShowArms(false); + setNoGravity(true); + setNoBasePlate(true); + setMarker(true); + forceSetBoundingBox(EMPTY_BOUND); + + super.collides = false; + super.setCustomNameVisible(true); + } + + @Override + public void setHologramName(String name) { + super.setCustomName(CraftChatMessage.fromStringOrNull(name)); + } + + @Override + public void removeHologram() { + super.remove(RemovalReason.DISCARDED); + } + + @Override + public org.bukkit.entity.ArmorStand getHandle() { + return this.getBukkitEntity(); + } + + @Override + public void inactiveTick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + @Override + public boolean repositionEntityAfterLoad() { + return false; + } + + @Override + public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { + // Prevent stand being equipped + } + + @Override + protected void addAdditionalSaveData(ValueOutput output) { + // Do not save NBT. + } + + @Override + protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) { + // Do not save NBT. + } + + @Override + protected void readAdditionalSaveData(ValueInput input) { + // Do not load NBT. + } + + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + + @Override + public void tick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + public void forceSetBoundingBox(AABB boundingBox) { + super.setBoundingBox(boundingBox); + } + + @Override + public CraftArmorStand getBukkitEntity() { + if (bukkitEntity == null) { + bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); + } + return (CraftArmorStand) bukkitEntity; + } + + @Override + public void remove(RemovalReason removalReason) { + // Prevent being killed. + } + + @Override + public void playSound(SoundEvent soundEvent, float volume, float pitch) { + // Remove sounds. + } + + @Override + public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { + // Do not save NBT. + return false; + } + + @Override + public boolean saveAsPassenger(ValueOutput output) { + // Do not save NBT. + return false; + } + + @Override + public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { + // Do not save NBT. + } + + @Override + public void saveWithoutId(ValueOutput output) { + // Do not save NBT. + } + + @Override + public void load(ValueInput input) { + // Do not load NBT. + } + + @Override + public boolean isInvulnerableTo(ServerLevel serverLevel, DamageSource damageSource) { + /* + * The field Entity.invulnerable is private. + * It's only used while saving NBTTags, but since the entity would be killed + * on chunk unload, we prefer to override isInvulnerable(). + */ + return true; + } + + @Override + public void setCustomName(Component component) { + // Locks the custom name. + } + + @Override + public void setCustomNameVisible(boolean isCustomNameVisible) { + // Locks the custom name. + } + + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSPlayersImpl.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSPlayersImpl.java new file mode 100644 index 0000000000..b8aad72ff0 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSPlayersImpl.java @@ -0,0 +1,172 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.player.PlayerLocales; +import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; +import com.bgsoftware.superiorskyblock.world.Dimensions; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarStyle; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; + +import java.util.Locale; +import java.util.Optional; + +public class NMSPlayersImpl implements NMSPlayers { + + private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); + private static final ReflectMethod ENTITY_SET_LEVEL = new ReflectMethod<>( + Entity.class, 1, Level.class); + + private final SuperiorSkyblockPlugin plugin; + + public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + } + + @Override + public void clearInventory(OfflinePlayer offlinePlayer) { + if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { + Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); + assert player != null; + player.getInventory().clear(); + player.getEnderChest().clear(); + return; + } + + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); + Player targetPlayer = serverPlayer.getBukkitEntity(); + + targetPlayer.loadData(); + + clearInventory(targetPlayer); + + //Setting the entity to the spawn location + Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); + + if (spawnLocation != null) { + ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); + serverPlayer.absSnapTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), + spawnLocation.getYaw(), spawnLocation.getPitch()); + } + + targetPlayer.saveData(); + } + + @Override + public void setSkinTexture(SuperiorPlayer superiorPlayer) { + Player player = superiorPlayer.asPlayer(); + + if (player == null) + return; + + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() + .ifPresent(property -> setSkinTexture(superiorPlayer, property)); + } + + @Override + public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { + superiorPlayer.setTextureValue(property.value()); + } + + @SuppressWarnings("deprecation") + @Override + public void sendActionBar(Player player, String message) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); + } + + @Override + public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { + BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); + bossBar.addPlayer(player); + return bossBar; + } + + @SuppressWarnings("deprecation") + @Override + public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { + player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); + } + + @Override + public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { + return superiorPlayer.getUniqueId().equals(item.getThrower()); + } + + @Nullable + @Override + public Locale getPlayerLocale(Player player) { + if (PLAYER_LOCALE.isValid()) { + return player.locale(); + } else try { + //noinspection deprecation + return PlayerLocales.getLocale(player.getLocale()); + } catch (IllegalArgumentException error) { + return null; + } + } + + private static class BossBarImpl implements BossBar { + + private final org.bukkit.boss.BossBar bossBar; + private final BossBarTask bossBarTask; + + public BossBarImpl(String message, BarColor color, double ticksToRun) { + bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); + this.bossBarTask = BossBarTask.create(this, ticksToRun); + } + + @Override + public void addPlayer(Player player) { + this.bossBar.addPlayer(player); + this.bossBarTask.registerTask(player); + } + + @Override + public void removeAll() { + this.bossBar.removeAll(); + this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); + } + + @Override + public void setProgress(double progress) { + this.bossBar.setProgress(progress); + } + + @Override + public double getProgress() { + return this.bossBar.getProgress(); + } + + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSTagsImpl.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSTagsImpl.java new file mode 100644 index 0000000000..9e35a538c9 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSTagsImpl.java @@ -0,0 +1,210 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6; + +import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.nms.NMSTags; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.tag.ListTag; +import com.bgsoftware.superiorskyblock.tag.Tag; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.logging.LogUtils; +import com.mojang.serialization.Dynamic; +import net.minecraft.SharedConstants; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.ByteArrayTag; +import net.minecraft.nbt.IntArrayTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.NumericTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ResolvableProfile; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.slf4j.Logger; + +import java.util.Optional; +import java.util.Set; + +@SuppressWarnings({"unused"}) +public class NMSTagsImpl implements NMSTags { + + private static final Logger LOGGER = LogUtils.getLogger(); + + @Override + public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + RegistryOps context = + MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); + + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) + ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow(); + tagCompound.putInt("DataVersion", SharedConstants.getCurrentVersion().dataVersion().version()); + + return CompoundTag.fromNBT(tagCompound); + } + + @Override + public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { + if (compoundTag.containsKey("NBT")) { + // Old compound version, deserialize it accordingly + return deserializeItemOld(compoundTag); + } + + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); + + int currentVersion = SharedConstants.getCurrentVersion().dataVersion().version(); + int itemVersion = tagCompound.getIntOr("DataVersion", 0); + if (itemVersion < currentVersion) { + tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, + new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); + } + + RegistryOps context = + MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); + + ItemStack itemStack = ItemStack.CODEC.parse(context, tagCompound) + .resultOrPartial((itemId) -> LOGGER.error("Tried to load invalid item: '{}'", itemId)) + .orElseThrow(); + + return CraftItemStack.asCraftMirror(itemStack); + } + + private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + Material type = Material.valueOf(typeName); + int amount = compoundTag.getInt("amount"); + short data = compoundTag.getShort("data"); + CompoundTag nbtData = compoundTag.getCompound("NBT"); + + org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); + + return CraftItemStack.asCraftMirror(itemStack); + } + + @Override + public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + PropertyMap propertyMap = new PropertyMap(); + propertyMap.put("textures", new Property("textures", texture)); + + ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap); + + itemStack.set(DataComponents.PROFILE, resolvableProfile); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + @SuppressWarnings("ConstantConditions") + public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { + net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); + + if (compoundTag == null) + compoundTag = new net.minecraft.nbt.CompoundTag(); + + if (!compoundTag.contains("id")) + //noinspection deprecation + compoundTag.putString("id", entityType.getName()); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { + entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); + return !serverLevel.addWithUUID(entity) ? null : entity; + }); + } + + @Override + public byte[] getNBTByteArrayValue(Object object) { + return ((ByteArrayTag) object).getAsByteArray(); + } + + @Override + public byte getNBTByteValue(Object object) { + return ((NumericTag) object).byteValue(); + } + + @Override + public Set getNBTCompoundValue(Object object) { + return ((net.minecraft.nbt.CompoundTag) object).keySet(); + } + + @Override + public double getNBTDoubleValue(Object object) { + return ((NumericTag) object).doubleValue(); + } + + @Override + public float getNBTFloatValue(Object object) { + return ((NumericTag) object).floatValue(); + } + + @Override + public int[] getNBTIntArrayValue(Object object) { + return ((IntArrayTag) object).getAsIntArray(); + } + + @Override + public int getNBTIntValue(Object object) { + return ((NumericTag) object).intValue(); + } + + @Override + public Object getNBTListIndexValue(Object object, int index) { + return ((net.minecraft.nbt.ListTag) object).get(index); + } + + @Override + public long getNBTLongValue(Object object) { + return ((NumericTag) object).longValue(); + } + + @Override + public short getNBTShortValue(Object object) { + return ((NumericTag) object).shortValue(); + } + + @Override + public String getNBTStringValue(Object object) { + return ((StringTag) object).value(); + } + + @Override + public Object parseList(ListTag listTag) { + net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); + + for (Tag tag : listTag) + nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); + + return nbtTagList; + } + + @Override + public Object getNBTCompoundTag(Object object, String key) { + return ((net.minecraft.nbt.CompoundTag) object).get(key); + } + + @Override + public void setNBTCompoundTagValue(Object object, String key, Object value) { + ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); + } + + @Override + public int getNBTTagListSize(Object object) { + return ((net.minecraft.nbt.ListTag) object).size(); + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSUtils.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSUtils.java new file mode 100644 index 0000000000..ae7d4b80ea --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSUtils.java @@ -0,0 +1,495 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.PropertiesMapper; +import com.bgsoftware.superiorskyblock.tag.ByteTag; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.tag.IntArrayTag; +import com.bgsoftware.superiorskyblock.tag.StringTag; +import com.bgsoftware.superiorskyblock.tag.Tag; +import com.google.common.base.Suppliers; +import com.mojang.logging.LogUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerChunkCache; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.tags.BlockTags; +import net.minecraft.util.ProblemReporter; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.BedBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.block.state.properties.SlabType; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.ValueInput; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.slf4j.Logger; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.function.Consumer; + +public class NMSUtils { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final Logger LOGGER = LogUtils.getLogger(); + + private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( + ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( + EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); + + public static final ObjectsPool> BLOCK_POS_POOL = + ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); + + private NMSUtils() { + + } + + @Nullable + public static T getBlockEntityAt(Location location, Class type) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return null; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); + return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); + } + } + + public static void runActionOnEntityChunks(Collection chunksCoords, + ChunkCallback chunkCallback) { + runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> + runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); + } + + public static void runActionOnChunks(Collection chunksCoords, + boolean saveChunks, ChunkCallback chunkCallback) { + runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> + runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); + } + + private static void runActionOnChunksInternal(Collection chunksCoords, + ChunkCallback chunkCallback, + Consumer> onUnloadChunkAction) { + List unloadedChunks = new LinkedList<>(); + List loadedChunks = new LinkedList<>(); + + chunksCoords.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + ChunkAccess chunkAccess; + + try { + chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); + } catch (Throwable ex) { + chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); + } + + if (chunkAccess instanceof LevelChunk levelChunk) { + loadedChunks.add(levelChunk); + } else { + unloadedChunks.add(chunkPosition.copy()); + } + }); + + boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); + + if (!loadedChunks.isEmpty()) + runActionOnLoadedChunks(loadedChunks, chunkCallback); + + if (hasUnloadedChunks) { + onUnloadChunkAction.accept(unloadedChunks); + } else { + chunkCallback.onFinish(); + } + } + + private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { + chunks.forEach(chunkCallback::onLoadedChunk); + } + + private static void runActionOnUnloadedChunks(Collection chunks, + boolean saveChunks, ChunkCallback chunkCallback) { + if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { + Iterator chunksIterator = chunks.iterator(); + while (chunksIterator.hasNext()) { + ChunkPosition chunkPosition = chunksIterator.next(); + + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( + chunkPosition.getX(), chunkPosition.getZ()); + + if (cachedUnloadedChunk != null) { + chunkCallback.onLoadedChunk(cachedUnloadedChunk); + chunksIterator.remove(); + } + } + + if (chunks.isEmpty()) { + chunkCallback.onFinish(); + return; + } + } + + CompletableFuture pendingTask = new CompletableFuture<>(); + PENDING_CHUNK_ACTIONS.add(pendingTask); + + BukkitExecutor.createTask().runAsync(v -> { + List chunkCompounds = new LinkedList<>(); + + chunks.forEach(chunkPosition -> { + try { + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + + net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); + + if (chunkCompound == null) { + chunkCallback.onChunkNotExist(chunkPosition); + return; + } + + net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), + Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, + Optional.empty(), chunkPos, serverLevel); + + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + + if (saveChunks) + chunkCompounds.add(unloadedChunkCompound); + } catch (Exception error) { + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + + return chunkCompounds; + }).runSync(chunkCompounds -> { + chunkCompounds.forEach(unloadedChunkCompound -> { + + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + + ChunkPos chunkPos = unloadedChunkCompound.chunkPos(); + + try { + chunkMap.write(chunkPos, () -> unloadedChunkCompound.chunkCompound); + } catch (Exception error) { + Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); + } + }); + + chunkCallback.onFinish(); + + pendingTask.complete(null); + PENDING_CHUNK_ACTIONS.remove(pendingTask); + }); + } + + private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + CompletableFutureList readChunksTasksList = new CompletableFutureList<>(-1); + + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + CompletableFuture readTask = new CompletableFuture<>(); + readChunksTasksList.add(readTask); + + regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + readTask.completeExceptionally(error); + } else { + entityDataOptional.ifPresent(entityData -> { + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + }); + + readTask.complete(null); + } + }); + }); + + BukkitExecutor.createTask().runAsync(v -> { + readChunksTasksList.forEachCompleted(p -> { + // Wait for all chunks to load. + }, error -> { + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk:"); + }); + }).runSync(v -> { + chunkCallback.onFinish(); + }); + } else { + BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + MoonriseRegionFileIO.RegionDataController regionDataController = + serverLevel.moonrise$getEntityChunkDataController(); + int chunkX = chunkPosition.getX(); + int chunkZ = chunkPosition.getZ(); + MoonriseRegionFileIO.RegionDataController.ReadData readData = + regionDataController.readData(chunkX, chunkZ); + if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { + net.minecraft.nbt.CompoundTag entityData = readData.syncRead(); + if (entityData != null) { + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + } catch (IOException error) { + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }).runSync(v -> { + chunkCallback.onFinish(); + }); + } + } + + public static List> getPendingChunkActions() { + return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), + null); + } + + public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, + CompoundTag statesTag, CompoundTag tileEntity) { + ServerLevel serverLevel = levelChunk.level; + + if (!isValidPosition(serverLevel, blockPos)) + return null; + + BlockState blockState = Block.stateById(combinedId); + + if (statesTag != null) { + for (Map.Entry> entry : statesTag.entrySet()) { + try { + // noinspection rawtypes + Property property = PropertiesMapper.getProperty(entry.getKey()); + if (property != null) { + if (entry.getValue() instanceof ByteTag) { + // noinspection unchecked + blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); + } else if (entry.getValue() instanceof IntArrayTag) { + int[] data = ((IntArrayTag) entry.getValue()).getValue(); + // noinspection unchecked + blockState = blockState.setValue(property, data[0]); + } else if (entry.getValue() instanceof StringTag) { + String data = ((StringTag) entry.getValue()).getValue(); + // noinspection unchecked + blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); + } + } + } catch (Exception ignored) { + } + } + } + + if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || + blockState.getBlock() instanceof BedBlock) { + serverLevel.setBlock(blockPos, blockState, 3); + return blockState; + } + + int indexY = serverLevel.getSectionIndex(blockPos.getY()); + + LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; + + int blockX = blockPos.getX() & 15; + int blockY = blockPos.getY(); + int blockZ = blockPos.getZ() & 15; + + boolean isOriginallyChunkSectionEmpty = levelChunkSection.hasOnlyAir(); + + levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); + + levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); + levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); + levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); + levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); + + levelChunk.markUnsaved(); + + boolean isChunkSectionEmpty = levelChunkSection.hasOnlyAir(); + + if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) + serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); + + serverLevel.getLightEngine().checkBlock(blockPos); + + if (tileEntity != null) { + net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); + if (tileEntityCompound != null) { + tileEntityCompound.putInt("x", blockPos.getX()); + tileEntityCompound.putInt("y", blockPos.getY()); + tileEntityCompound.putInt("z", blockPos.getZ()); + BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); + if (worldBlockEntity != null) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "setblock@" + blockPos, LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), tileEntityCompound); + worldBlockEntity.loadWithComponents(valueInput); + } + } + } + } + + return blockState; + } + + public static boolean isDoubleBlock(Block block, BlockState blockState) { + return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && + blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; + } + + @Nullable + public static LevelChunk getCraftChunkHandle(CraftChunk craftChunk) { + ServerLevel serverLevel = craftChunk.getCraftWorld().getHandle(); + LevelChunk loadedChunk = serverLevel.getChunkIfLoaded(craftChunk.getX(), craftChunk.getZ()); + if (loadedChunk != null) + return loadedChunk; + + return (LevelChunk) serverLevel.getChunk(craftChunk.getX(), craftChunk.getZ(), ChunkStatus.FULL, true); + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkAccess chunkAccess) { + CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), serverLevel.generator); + + ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); + + // Unsafe: we do not provide chunks cache, even tho it is required. + // Should be fine in normal flow, as the only method that access the chunsk cache + // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 + WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); + + customChunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public record UnloadedChunkCompound(ChunkPosition chunkPosition, + net.minecraft.nbt.CompoundTag chunkCompound) { + + public ListTag getSections() { + return chunkCompound.getListOrEmpty("sections"); + } + + public ListTag getEntities() { + return chunkCompound.getListOrEmpty("Entities"); + } + + public void setSections(ListTag sectionsList) { + chunkCompound.put("sections", sectionsList); + } + + public void setEntities(ListTag entitiesList) { + chunkCompound.put("entities", entitiesList); + } + + public void setBlockEntities(ListTag blockEntitiesList) { + chunkCompound.put("block_entities", blockEntitiesList); + } + + public ServerLevel serverLevel() { + return ((CraftWorld) chunkPosition.getWorld()).getHandle(); + } + + public ChunkPos chunkPos() { + return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + } + + } + + private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { + return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && + blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && + blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); + } + + public interface ChunkCallback { + + void onLoadedChunk(LevelChunk levelChunk); + + void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + + default void onChunkNotExist(ChunkPosition chunkPosition) { + + } + + void onFinish(); + + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSWorldImpl.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSWorldImpl.java new file mode 100644 index 0000000000..b059d1ca98 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSWorldImpl.java @@ -0,0 +1,412 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; +import com.bgsoftware.superiorskyblock.nms.ICachedBlock; +import com.bgsoftware.superiorskyblock.nms.NMSWorld; +import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.generator.IslandsGeneratorImpl; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.trial.IslandPlayerDetector; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.ChunkReaderImpl; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.block.entity.SpawnerBlockEntity; +import net.minecraft.world.level.block.entity.TickingBlockEntity; +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; +import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; +import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.ChunkSnapshot; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.block.data.type.WallSign; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockState; +import org.bukkit.craftbukkit.block.CraftSign; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.lang.reflect.Modifier; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.function.IntFunction; + +public class NMSWorldImpl implements NMSWorld { + + private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); + private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( + SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + + private final SuperiorSkyblockPlugin plugin; + + public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + } + + @Override + public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); + Location location = new Location( + Bukkit.getWorld(chunkSnapshot.getWorldName()), + (chunkSnapshot.getX() << 4) + x, + y, + (chunkSnapshot.getZ() << 4) + z + ); + + return Keys.of(KeyBlocksCache.getBlockKey(block), location); + } + + @Override + public void listenSpawner(Location location, IntFunction delayChangeCallback) { + SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); + if (spawnerBlockEntity == null) + return; + + ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); + + List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? + LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; + + Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); + List tickersToAdd = new LinkedList<>(); + + while (blockEntityTickersIterator.hasNext()) { + TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); + if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && + !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { + blockEntityTickersIterator.remove(); + tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); + } + } + + if (!tickersToAdd.isEmpty()) + blockEntityTickers.addAll(tickersToAdd); + } + + @Override + public void replaceTrialBlockPlayerDetector(Island island, Location location) { + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); + if (blockEntity == null) + return; + + if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { + VaultConfig vaultConfig = vaultBlockEntity.getConfig(); + + PlayerDetector playerDetector = vaultConfig.playerDetector(); + if (playerDetector instanceof IslandPlayerDetector) + return; + + VaultConfig newConfig = new VaultConfig( + vaultConfig.lootTable(), + vaultConfig.activationRange(), + vaultConfig.deactivationRange(), + vaultConfig.keyItem(), + vaultConfig.overrideLootTableToDisplay(), + IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), + vaultConfig.entitySelector() + ); + + vaultBlockEntity.setConfig(newConfig); + } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { + TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); + PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); + + if (playerDetector instanceof IslandPlayerDetector) + return; + + trialSpawnerBlockEntity.trialSpawner.setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector)); + } + } + + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) + return; + + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } + + @Override + public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { + if (!plugin.getSettings().isWorldBorders()) + return; + + Player player = superiorPlayer.asPlayer(); + World world = superiorPlayer.getWorld(); + + if (world == null || player == null) + return; + + int islandSize = island == null ? 0 : island.getIslandSize(); + + boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; + + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + + WorldBorder worldBorder; + + if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { + worldBorder = serverLevel.getWorldBorder(); + } else { + Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); + if (dimension == null) + return; + + Location center = island.getCenter(dimension); + + worldBorder = new WorldBorder(); + worldBorder.world = serverLevel; + worldBorder.setWarningBlocks(0); + worldBorder.setCenter(center.getX(), center.getZ()); + + switch (superiorPlayer.getBorderColor()) { + case BLUE -> { + worldBorder.setSize((islandSize * 2) + 1D); + } + case GREEN -> { + worldBorder.setSize((islandSize * 2) + 1.001D); + worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); + } + case RED -> { + worldBorder.setSize((islandSize * 2) + 1D); + worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); + } + } + } + + ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); + ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); + } + + @Override + public Object getBlockData(org.bukkit.block.Block block) { + return block.getBlockData(); + } + + @Override + public void setBlock(Location location, int combinedId) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + + BlockState blockState = + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + if (blockState != null) { + serverLevel.getChunkSource().blockChanged(blockPos); + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } + } + } + + @Override + public ICachedBlock cacheBlock(org.bukkit.block.Block block) { + return NMSCachedBlock.obtain(block); + } + + @Override + public boolean isWaterLogged(org.bukkit.block.Block block) { + if (Materials.isWater(block.getType())) + return true; + + BlockData blockData = block.getBlockData(); + + return blockData instanceof BubbleColumn || + (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); + } + + @Override + public SignType getSignType(Object sign) { + if (sign instanceof WallSign) + return SignType.WALL_SIGN; + else if (sign instanceof Sign) + return SignType.STANDING_SIGN; + else if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return SignType.UNKNOWN; + } + + @Override + public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { + BlockState blockState = ((CraftBlock) block).getNMS(); + return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; + } + + @Override + public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { + return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); + } + + @Override + public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { + return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); + } + + private int getDefaultAmount(BlockState blockState) { + Block block = blockState.getBlock(); + return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; + } + + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + return !bukkitBlock.isPassable(); + } + + @Override + public void placeSign(Island island, Location location) { + SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); + if (signBlockEntity == null) + return; + + String[] lines = new String[4]; + Component[] messages = signBlockEntity.getFrontText().getMessages(false); + System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length); + String[] strippedLines = new String[4]; + for (int i = 0; i < 4; i++) + strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); + + Component[] newLines; + + IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); + if (result.isCancelEvent()) { + newLines = CraftSign.sanitizeLines(strippedLines); + } else { + newLines = CraftSign.sanitizeLines(lines); + } + + System.arraycopy(newLines, 0, messages, 0, 4); + } + + @Override + public void playGeneratorSound(Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + serverLevel.levelEvent(1501, blockPos, 0); + } + } + + @Override + public void playBreakAnimation(org.bukkit.block.Block block) { + ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(block.getX(), block.getY(), block.getZ()); + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + } + } + + @Override + public void playPlaceSound(Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); + + serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, + (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } + } + + @Override + public int getMinHeight(World world) { + return world.getMinHeight(); + } + + @Override + public void removeAntiXray(World bukkitWorld) { + // Doesn't exist in this version. + } + + @Override + public IslandsGenerator createGenerator(Dimension dimension) { + return new IslandsGeneratorImpl(dimension); + } + + @Override + public WorldEditSession createEditSession(World world) { + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); + } + + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } + + private static ReflectField> initializeLevelBlockEntityTickersField() { + ReflectField> field = new ReflectField<>( + Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + + if (!field.isValid()) + field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + + return field; + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsBlockEntity.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsBlockEntity.java new file mode 100644 index 0000000000..c32fb42888 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsBlockEntity.java @@ -0,0 +1,103 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.crops; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.crops.CropsTickingMethod; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; + +import java.lang.ref.WeakReference; +import java.util.List; +import java.util.function.Consumer; + +public class CropsBlockEntity extends BlockEntity { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); + + private final WeakReference island; + private final WeakReference chunk; + + private int currentTick = 0; + + private double cachedCropGrowthMultiplier; + + private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { + super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); + this.island = new WeakReference<>(island); + this.chunk = new WeakReference<>(levelChunk); + setLevel(levelChunk.level); + levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); + this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; + } + + public static void create(Island island, LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + long chunkPair = chunkPos.toLong(); + tickingChunks.computeIfAbsent(chunkPair, p -> { + BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); + return new CropsBlockEntity(island, levelChunk, blockPos); + }); + } + + public static CropsBlockEntity remove(long chunkPos) { + return tickingChunks.remove(chunkPos); + } + + public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { + if (tickingChunks.isEmpty()) + return; + + chunkPositions.forEach(chunkPosition -> { + long chunkKey = chunkPosition.asPair(); + CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); + if (cropsBlockEntity != null) + cropsBlockEntityConsumer.accept(cropsBlockEntity); + }); + } + + @Override + public boolean isValidBlockState(BlockState state) { + return true; + } + + public void remove() { + this.remove = true; + } + + public void tick() { + if (++currentTick <= plugin.getSettings().getCropsInterval()) + return; + + LevelChunk levelChunk = this.chunk.get(); + Island island = this.island.get(); + ServerLevel serverLevel = (ServerLevel) getLevel(); + + if (levelChunk == null || island == null || serverLevel == null) { + remove(); + return; + } + + currentTick = 0; + + int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); + int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); + if (chunkRandomTickSpeed > 0) + CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); + } + + public void setCropGrowthMultiplier(double cropGrowthMultiplier) { + this.cachedCropGrowthMultiplier = cropGrowthMultiplier; + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingBlockEntity.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingBlockEntity.java new file mode 100644 index 0000000000..105566b82b --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingBlockEntity.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.crops; + +import com.bgsoftware.superiorskyblock.nms.v1_21_6.crops.CropsBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.TickingBlockEntity; + +public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { + + + @Override + public void tick() { + cropsBlockEntity.tick(); + } + + @Override + public boolean isRemoved() { + return cropsBlockEntity.isRemoved(); + } + + @Override + public BlockPos getPos() { + return cropsBlockEntity.getBlockPos(); + } + + @Override + public String getType() { + return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingMethod.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingMethod.java new file mode 100644 index 0000000000..1c968c592c --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingMethod.java @@ -0,0 +1,159 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.crops; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; + +public abstract class CropsTickingMethod { + + private static final ReflectField SERVER_LEVEL_SIMPLE_RANDOM = new ReflectField<>( + ServerLevel.class, RandomSource.class, "simpleRandom"); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_SIMPLE_RANDOM.isValid() ? + new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); + + private static Set CROPS_TO_GROW_CACHE; + + static { + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); + } + + protected CropsTickingMethod() { + + } + + public static void register() { + // Calls the static initializer which registers the callback. + } + + public static void tick(LevelChunk levelChunk, int tickSpeed) { + INSTANCE.doTick(levelChunk, tickSpeed); + } + + protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); + + private static void onSettingsUpdate() { + CROPS_TO_GROW_CACHE = new HashSet<>(); + plugin.getSettings().getCropsToGrow().forEach(cropName -> { + Key key = Keys.ofMaterialAndData(cropName); + if (key instanceof MaterialKey materialKey) { + Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); + if (block != null && block.defaultBlockState().isRandomlyTicking()) + CROPS_TO_GROW_CACHE.add(block); + } + }); + } + + private static class PaperCropsTickingMethod extends CropsTickingMethod { + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + ServerLevel serverLevel = levelChunk.level; + LevelChunkSection[] sections = levelChunk.getSections(); + + int minSection = serverLevel.getMinSectionY(); + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + RandomSource simpleRandom = SERVER_LEVEL_SIMPLE_RANDOM.get(serverLevel); + + for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + ca.spottedleaf.moonrise.common.list.ShortList tickList = + levelChunkSection.moonrise$getTickingBlockList(); + int tickingBlocks = tickList.size(); + if (tickingBlocks <= 0) { + continue; + } + + PalettedContainer states = levelChunkSection.states; + + int offsetY = (sectionIndex + minSection) << 4; + + for (int i = 0; i < tickSpeed; ++i) { + int index = simpleRandom.nextInt() & 0xFFF; + + if (index >= tickingBlocks) { + continue; + } + + int location = (int) tickList.getRaw(index) & 0xFFFF; + BlockState blockState = states.get(location); + if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) + continue; + + // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! + BlockPos blockPos = new BlockPos((location & 15) | chunkOffsetX, + ((location >>> 8) & 15) | offsetY, + ((location >>> 4) & 15) | chunkOffsetZ); + + blockState.randomTick(serverLevel, blockPos, simpleRandom); + } + } + + } + + } + + private static class SpigotCropsTickingMethod extends CropsTickingMethod { + + private static int random = ThreadLocalRandom.current().nextInt(); + + @Override + protected void doTick(LevelChunk levelChunk, int tickSpeed) { + LevelChunkSection[] sections = levelChunk.getSections(); + ServerLevel serverLevel = levelChunk.level; + + ChunkPos chunkPos = levelChunk.getPos(); + int chunkOffsetX = chunkPos.x << 4; + int chunkOffsetZ = chunkPos.z << 4; + + for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { + LevelChunkSection levelChunkSection = sections[sectionIndex]; + if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { + continue; + } + + int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; + + for (int i = 0; i < tickSpeed; i++) { + random = random * 3 + 1013904223; + int factor = random >> 2; + int x = factor & 15; + int z = factor >> 8 & 15; + int y = factor >> 16 & 15; + BlockState blockState = levelChunkSection.getBlockState(x, y, z); + if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { + BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); + blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); + } + } + } + } + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/DragonUtils.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/DragonUtils.java new file mode 100644 index 0000000000..4de6663173 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/DragonUtils.java @@ -0,0 +1,37 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon; + +import com.bgsoftware.common.reflection.ReflectField; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; + +import java.lang.reflect.Modifier; + +public class DragonUtils { + + private static final ReflectField END_PODIUM_LOCATION = new ReflectField( + EndPodiumFeature.class, BlockPos.class, + Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) + .removeFinal(); + + private static BlockPos currentPodiumPosition = BlockPos.ZERO; + + private DragonUtils() { + + } + + public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { + try { + END_PODIUM_LOCATION.set(null, podiumPosition); + currentPodiumPosition = podiumPosition; + runnable.run(); + } finally { + END_PODIUM_LOCATION.set(null, BlockPos.ZERO); + currentPodiumPosition = BlockPos.ZERO; + } + } + + public static BlockPos getCurrentPodiumPosition() { + return currentPodiumPosition; + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/EndWorldEndDragonFightHandler.java new file mode 100644 index 0000000000..8af8eb4463 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/EndWorldEndDragonFightHandler.java @@ -0,0 +1,48 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.IslandEndDragonFight; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class EndWorldEndDragonFightHandler extends EndDragonFight { + + private final Map worldDragonFightsMap = new HashMap<>(); + private final List worldDragonFightsList = new LinkedList<>(); + + public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + this.worldDragonFightsList.forEach(EndDragonFight::tick); + } + + public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + if (oldDragonFight != null) + this.worldDragonFightsList.remove(oldDragonFight); + this.worldDragonFightsList.add(endDragonFight); + } + + @Nullable + public IslandEndDragonFight getDragonFight(UUID uuid) { + return this.worldDragonFightsMap.get(uuid); + } + + @Nullable + public IslandEndDragonFight removeDragonFight(UUID uuid) { + IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + if (endDragonFight != null) + this.worldDragonFightsList.remove(endDragonFight); + return endDragonFight; + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEndDragonFight.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEndDragonFight.java new file mode 100644 index 0000000000..a1f547f945 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEndDragonFight.java @@ -0,0 +1,212 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.IslandEntityEnderDragon; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; +import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; +import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; +import net.minecraft.world.level.block.state.pattern.BlockInWorld; +import net.minecraft.world.level.block.state.pattern.BlockPattern; +import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; +import net.minecraft.world.level.block.state.predicate.BlockPredicate; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.CreatureSpawnEvent; + +import java.lang.reflect.Modifier; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public class IslandEndDragonFight extends EndDragonFight { + + private static final ReflectField DRAGON_BATTLE = new ReflectField( + EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) + .removeFinal(); + private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( + EndDragonFight.class, boolean.class, Modifier.PRIVATE, 4); + private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( + EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); + + private static final ReflectField TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>( + EndDragonFight.class, int.class, Modifier.PRIVATE, 4); + private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( + DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); + + private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() + .aisle(" ", " ", " ", " # ", " ", " ", " ") + .aisle(" ", " ", " ", " # ", " ", " ", " ") + .aisle(" ", " ", " ", " # ", " ", " ", " ") + .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") + .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") + .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) + .build(); + + private final Island island; + private final BlockPos islandBlockPos; + private final Vec3 islandBlockVectored; + private final ServerLevel serverLevel; + private final IslandEntityEnderDragon entityEnderDragon; + + private byte currentTick = 0; + + public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { + this(island, serverLevel, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), null); + } + + public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, + @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + + this.island = island; + this.islandBlockPos = islandBlockPos; + this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); + this.serverLevel = serverLevel; + this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; + + SCAN_FOR_LEGACY_PORTALS.set(this, false); + WAS_DRAGON_KILLED.set(this, false); + DRAGON_BATTLE.set(this.entityEnderDragon, this); + + TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); + } + + @Override + public void tick() { + // doServerTick + + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); + + DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); + if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { + LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); + } + + if (++currentTick >= 20) { + updateBattlePlayers(); + currentTick = 0; + TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); + } + } + + @Nullable + @Override + public BlockPattern.BlockPatternMatch findExitPortal() { + int chunkX = this.islandBlockPos.getX() >> 4; + int chunkZ = this.islandBlockPos.getZ() >> 4; + + for (int x = -8; x <= 8; ++x) { + for (int z = -8; z <= 8; ++z) { + LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); + + for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { + if (blockEntity instanceof TheEndPortalBlockEntity) { + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( + this.serverLevel, blockEntity.getBlockPos()); + + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + + return blockPatternMatch; + } + } + } + } + } + + int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); + currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); + for (int y = highestBlock; y >= this.serverLevel.getMinY(); --y) { + currentPosition.setY(y); + + BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); + + if (blockPatternMatch != null) { + if (this.portalLocation == null) + this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + + return blockPatternMatch; + } + } + } + + return null; + } + + @Override + public void resetSpikeCrystals() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); + } + + public void removeBattlePlayers() { + List dragonEventPlayers = new SequentialListBuilder() + .build(this.dragonEvent.getPlayers()); + for (ServerPlayer serverPlayer : dragonEventPlayers) + this.dragonEvent.removePlayer(serverPlayer); + } + + public IslandEntityEnderDragon getEnderDragon() { + return this.entityEnderDragon; + } + + private void updateBattlePlayers() { + Set nearbyPlayers = new HashSet<>(); + + for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { + Player bukkitPlayer = superiorPlayer.asPlayer(); + if (bukkitPlayer != null) { + ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); + if (serverPlayer.level().equals(this.serverLevel)) { + this.dragonEvent.addPlayer(serverPlayer); + nearbyPlayers.add(serverPlayer.getUUID()); + } + } + } + + List dragonEventPlayers = new SequentialListBuilder() + .build(this.dragonEvent.getPlayers()); + + dragonEventPlayers.stream() + .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) + .forEach(this.dragonEvent::removePlayer); + } + + private IslandEntityEnderDragon spawnEnderDragon() { + IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); + + entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); + entityEnderDragon.absSnapTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), + this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); + + this.serverLevel.addFreshEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); + + this.dragonUUID = entityEnderDragon.getUUID(); + this.resetSpikeCrystals(); + + return entityEnderDragon; + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEntityEnderDragon.java new file mode 100644 index 0000000000..5ce4095bb2 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEntityEnderDragon.java @@ -0,0 +1,103 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon; + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.config.SettingsManager; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.SpawnGroupData; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; +import net.minecraft.world.level.storage.ValueInput; +import org.bukkit.Location; +import org.bukkit.craftbukkit.entity.CraftEnderDragon; + +public class IslandEntityEnderDragon extends EnderDragon { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + @NotNull + public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { + return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : + new EnderDragon(entityTypes, level); + } + + private final ServerLevel serverLevel; + private final Dimension dimension; + private BlockPos islandBlockPos; + + public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { + this(level); + this.islandBlockPos = islandBlockPos; + } + + private IslandEntityEnderDragon(Level level) { + super(EntityType.ENDER_DRAGON, level); + this.serverLevel = (ServerLevel) level; + this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + } + + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, + DifficultyInstance difficulty, + EntitySpawnReason spawnReason, + @Nullable SpawnGroupData spawnGroupData) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + } + + @Override + protected void readAdditionalSaveData(ValueInput input) { + // loadData + super.readAdditionalSaveData(input); + finalizeIslandEnderDragon(); + } + + @Override + public void aiStep() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); + } + + @Override + @NotNull + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + + private void finalizeIslandEnderDragon() { + if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) + return; + + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } + + if (island == null) + return; + + Location middleBlock = island.getCenter(dimension); + + SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); + if (dimensionConfig instanceof SettingsManager.Worlds.End) { + middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); + } + + this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); + + IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); + dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/SpikesCache.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/SpikesCache.java new file mode 100644 index 0000000000..810414939b --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/SpikesCache.java @@ -0,0 +1,190 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon; + + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.DragonUtils; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.CacheStats; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.level.levelgen.feature.SpikeFeature; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class SpikesCache implements LoadingCache> { + + private static final SpikesCache INSTANCE = new SpikesCache(); + + private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() + .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); + + private long worldSeed; + + public static SpikesCache getInstance() { + return INSTANCE; + } + + private SpikesCache() { + + } + + @Override + public @NotNull + List get(@NotNull Long worldSeed) throws ExecutionException { + try { + this.worldSeed = worldSeed; + return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); + } finally { + this.worldSeed = 0; + } + } + + @Override + public @NotNull + List getUnchecked(@NotNull Long worldSeed) { + try { + this.worldSeed = worldSeed; + return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); + } finally { + this.worldSeed = 0; + } + } + + @Override + public @NotNull + ImmutableMap> getAll(@NotNull Iterable keys) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public List apply(@NotNull Long worldSeed) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public void refresh(@NotNull Long worldSeed) { + try { + this.worldSeed = worldSeed; + cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); + } finally { + this.worldSeed = 0; + } + } + + @Override + public @NotNull + ConcurrentMap> asMap() { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Nullable + @Override + public List getIfPresent(@NotNull Object worldSeed) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public @NotNull + List get(@NotNull Long worldSeed, + @NotNull Callable> loader) throws ExecutionException { + try { + this.worldSeed = worldSeed; + return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); + } finally { + this.worldSeed = 0; + } + } + + @Override + public @NotNull + ImmutableMap> getAllPresent(@NotNull Iterable keys) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public void put(@NotNull Long worldSeed, @NotNull List spikes) { + try { + this.worldSeed = worldSeed; + cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); + } finally { + this.worldSeed = 0; + } + } + + @Override + public void putAll(Map> spikesMap) { + spikesMap.forEach(this::put); + } + + @Override + public void invalidate(@NotNull Object worldSeed) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public void invalidateAll(@NotNull Iterable keys) { + throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); + } + + @Override + public void invalidateAll() { + this.cachedSpikes.invalidateAll(); + } + + @Override + public long size() { + return this.cachedSpikes.size(); + } + + @Override + public @NotNull + CacheStats stats() { + return this.cachedSpikes.stats(); + } + + @Override + public void cleanUp() { + this.cachedSpikes.cleanUp(); + } + + private class InternalCacheLoader extends CacheLoader> { + + @Override + public @NotNull + List load(@NotNull BlockPos blockPos) { + List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); + + Collections.shuffle(list, new Random(worldSeed)); + List spikesList = Lists.newArrayList(); + + for (int i = 0; i < 10; ++i) { + int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); + int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); + int l = list.get(i); + int radius = 2 + l / 3; + int height = 76 + l * 3; + boolean guarded = l == 1 || l == 2; + + spikesList.add(new SpikeFeature.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded)); + } + + return spikesList; + } + + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/generator/IslandsGeneratorImpl.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/generator/IslandsGeneratorImpl.java new file mode 100644 index 0000000000..db6d778836 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/generator/IslandsGeneratorImpl.java @@ -0,0 +1,67 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.generator; + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Biome; +import org.bukkit.generator.BiomeProvider; +import org.bukkit.generator.BlockPopulator; +import org.bukkit.generator.WorldInfo; + +import java.util.Collections; +import java.util.List; +import java.util.Random; + +@SuppressWarnings({"unused", "NullableProblems"}) +public class IslandsGeneratorImpl extends IslandsGenerator { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Dimension dimension; + + public IslandsGeneratorImpl(Dimension dimension) { + this.dimension = dimension; + } + + @Override + public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, + @NotNull ChunkData chunkData) { + if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { + chunkData.setBlock(0, 99, 0, Material.BEDROCK); + } + } + + @Override + public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { + return new BiomeProvider() { + @Override + public @NotNull + Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { + return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension); + } + + @Override + public @NotNull + List getBiomes(@NotNull WorldInfo worldInfo) { + return IslandUtils.getDefaultWorldBiomes(); + } + + }; + } + + @Override + public List getDefaultPopulators(World world) { + return Collections.emptyList(); + } + + @Override + public Location getFixedSpawnLocation(World world, Random random) { + return new Location(world, 0, 100, 0); + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuBrewingStandBlockEntity.java new file mode 100644 index 0000000000..0c2a3b09d8 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuBrewingStandBlockEntity.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.menu; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; +import org.bukkit.inventory.InventoryHolder; + +public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { + + private final InventoryHolder holder; + + public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { + super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); + this.holder = holder; + this.name = Component.nullToEmpty(title); + } + + @Override + public InventoryHolder getOwner() { + return holder; + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuDispenserBlockEntity.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuDispenserBlockEntity.java new file mode 100644 index 0000000000..03a6356d38 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuDispenserBlockEntity.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.menu; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.DispenserBlockEntity; +import org.bukkit.inventory.InventoryHolder; + +public class MenuDispenserBlockEntity extends DispenserBlockEntity { + + private final InventoryHolder holder; + + public MenuDispenserBlockEntity(InventoryHolder holder, String title) { + super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); + this.holder = holder; + this.name = Component.nullToEmpty(title); + } + + @Override + public InventoryHolder getOwner() { + return holder; + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuFurnaceBlockEntity.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuFurnaceBlockEntity.java new file mode 100644 index 0000000000..16c1383864 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuFurnaceBlockEntity.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.menu; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.FurnaceBlockEntity; +import org.bukkit.inventory.InventoryHolder; + +public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { + + private final InventoryHolder holder; + + public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { + super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); + this.holder = holder; + this.name = Component.nullToEmpty(title); + } + + @Override + public InventoryHolder getOwner() { + return holder; + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuHopperBlockEntity.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuHopperBlockEntity.java new file mode 100644 index 0000000000..d2716bce8a --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuHopperBlockEntity.java @@ -0,0 +1,26 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.menu; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.HopperBlock; +import net.minecraft.world.level.block.entity.HopperBlockEntity; +import org.bukkit.inventory.InventoryHolder; + +public class MenuHopperBlockEntity extends HopperBlockEntity { + + private final InventoryHolder holder; + + public MenuHopperBlockEntity(InventoryHolder holder, String title) { + super(BlockPos.ZERO, Blocks.HOPPER.defaultBlockState().setValue(HopperBlock.FACING, Direction.DOWN)); + this.holder = holder; + this.name = Component.nullToEmpty(title); + } + + @Override + public InventoryHolder getOwner() { + return holder; + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/spawners/TickingSpawnerBlockEntityNotifier.java new file mode 100644 index 0000000000..145725f3fb --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/spawners/TickingSpawnerBlockEntityNotifier.java @@ -0,0 +1,57 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.spawners; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.BaseSpawner; +import net.minecraft.world.level.block.entity.SpawnerBlockEntity; +import net.minecraft.world.level.block.entity.TickingBlockEntity; + +import java.util.function.IntFunction; + +public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { + + private final SpawnerBlockEntity spawnerBlockEntity; + private final TickingBlockEntity tickingBlockEntity; + private final IntFunction delayChangeCallback; + + public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, + IntFunction delayChangeCallback) { + this.spawnerBlockEntity = spawnerBlockEntity; + this.tickingBlockEntity = tickingBlockEntity; + this.delayChangeCallback = delayChangeCallback; + updateDelay(); + } + + @Override + public void tick() { + BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); + int startDelay = baseSpawner.spawnDelay; + try { + tickingBlockEntity.tick(); + } finally { + int newDelay = baseSpawner.spawnDelay; + if (newDelay > startDelay) + updateDelay(); + } + } + + @Override + public boolean isRemoved() { + return tickingBlockEntity.isRemoved(); + } + + @Override + public BlockPos getPos() { + return tickingBlockEntity.getPos(); + } + + @Override + public String getType() { + return tickingBlockEntity.getType(); + } + + public void updateDelay() { + BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); + baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/trial/IslandPlayerDetector.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/trial/IslandPlayerDetector.java new file mode 100644 index 0000000000..e81272a8d1 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/trial/IslandPlayerDetector.java @@ -0,0 +1,53 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.trial; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +public class IslandPlayerDetector implements PlayerDetector { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final PlayerDetector original; + private final IslandPrivilege requiredPrivilege; + + public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + } + + public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + } + + private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + this.island = island; + this.original = original; + this.requiredPrivilege = requiredPrivilege; + } + + @Override + public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { + List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); + if (!players.isEmpty()) { + players = new LinkedList<>(players); + players.removeIf(uuid -> { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); + return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + }); + players = Collections.unmodifiableList(players); + } + return players; + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/vibration/IslandVibrationUser.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/vibration/IslandVibrationUser.java new file mode 100644 index 0000000000..03e2d0cedb --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/vibration/IslandVibrationUser.java @@ -0,0 +1,90 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.PositionSource; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; + +import javax.annotation.Nullable; + +public class IslandVibrationUser implements VibrationSystem.User { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final VibrationSystem.User original; + + public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + this.island = island; + this.original = sculkSensorBlockEntity.getVibrationUser(); + } + + @Override + public int getListenerRadius() { + return this.original.getListenerRadius(); + } + + @Override + public PositionSource getPositionSource() { + return this.original.getPositionSource(); + } + + @Override + public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { + if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) + return false; + + if (context.sourceEntity() instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + + @Override + public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { + this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); + } + + @Override + public TagKey getListenableEvents() { + return this.original.getListenableEvents(); + } + + @Override + public boolean canTriggerAvoidVibration() { + return this.original.canTriggerAvoidVibration(); + } + + @Override + public boolean requiresAdjacentChunksToBeTicking() { + return this.original.requiresAdjacentChunksToBeTicking(); + } + + @Override + public int calculateTravelTimeInTicks(float distance) { + return this.original.calculateTravelTimeInTicks(distance); + } + + @Override + public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { + return this.original.isValidVibration(gameEvent, context); + } + + @Override + public void onDataChanged() { + this.original.onDataChanged(); + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/BlockEntityCache.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/BlockEntityCache.java new file mode 100644 index 0000000000..5cb454b5e3 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/BlockEntityCache.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.world; + +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class BlockEntityCache { + + private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); + + private BlockEntityCache() { + + } + + public static String getBlockEntityId(BlockState blockState) { + return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { + for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { + if (blockEntityType.isValid(blockState)) { + ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); + if (resourceLocation != null) + return resourceLocation.toString(); + } + } + + return ""; + }); + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/ChunkReaderImpl.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/ChunkReaderImpl.java new file mode 100644 index 0000000000..a3124552b3 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/ChunkReaderImpl.java @@ -0,0 +1,255 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.mojang.logging.LogUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.core.SectionPos; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.ProblemReporter; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LightLayer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.chunk.DataLayer; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.storage.TagValueOutput; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.block.CraftBlockType; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.InventoryHolder; +import org.slf4j.Logger; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ChunkReaderImpl implements ChunkReader { + + private static final Logger LOGGER = LogUtils.getLogger(); + + private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( + Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + private static final byte[] FULL_LIGHT = new byte[2048]; + private static final byte[] EMPTY_LIGHT = new byte[2048]; + + static { + Arrays.fill(FULL_LIGHT, (byte) 0xFF); + } + + private final ServerLevel serverLevel; + private final int x; + private final int z; + + private final Map blockEntities = new HashMap<>(); + private final List entities = new LinkedList<>(); + private final PalettedContainerRO[] blockids; + private final byte[][] skylight; + private final byte[][] emitlight; + + public ChunkReaderImpl(Chunk bukkitChunk) { + LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); + + this.serverLevel = levelChunk.level; + ChunkPos chunkPos = levelChunk.getPos(); + this.x = chunkPos.x; + this.z = chunkPos.z; + + LevelChunkSection[] levelChunkSections = levelChunk.getSections(); + this.blockids = new PalettedContainerRO[levelChunkSections.length]; + this.skylight = new byte[levelChunkSections.length][]; + this.emitlight = new byte[levelChunkSections.length][]; + + LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); + + for (int i = 0; i < this.blockids.length; ++i) { + LevelChunkSection levelChunkSection = levelChunkSections[i]; + + this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); + + DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (skyLightArray == null) { + this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; + } else { + this.skylight[i] = new byte[2048]; + System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); + } + + DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) + .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); + if (emitLightArray == null) { + this.emitlight[i] = EMPTY_LIGHT; + } else { + this.emitlight[i] = new byte[2048]; + System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); + } + } + + levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { + net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + + compoundTag.remove("x"); + compoundTag.remove("y"); + compoundTag.remove("z"); + + InventoryHolder inventoryHolder = blockEntity.getOwner(); + if (inventoryHolder != null) + compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); + + blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); + }); + + for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) + entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); + } + + @Override + public int getX() { + return this.x; + } + + @Override + public int getZ() { + return this.z; + } + + @Override + public Material getType(int x, int y, int z) { + return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); + } + + @Override + public short getData(int x, int y, int z) { + return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); + } + + @Override + @Nullable + public CompoundTag getTileEntity(int x, int y, int z) { + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); + return this.blockEntities.get(blockPos); + } + } + + @Override + @Nullable + public CompoundTag readBlockStates(int x, int y, int z) { + BlockState blockState = getBlockState(x, y, z); + + if (blockState.getValues().isEmpty()) + return null; + + CompoundTag compoundTag = new CompoundTag(); + + blockState.getValues().forEach((property, value) -> { + String name = PropertiesMapper.getPropertyName(property); + + if (property instanceof BooleanProperty) { + compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); + } else if (property instanceof IntegerProperty integerProperty) { + compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); + } else if (property instanceof EnumProperty) { + compoundTag.setString(name, ((Enum) value).name()); + } + }); + + return compoundTag; + } + + @Override + public byte[] getLightLevels(int x, int y, int z) { + int off = (y & 15) << 7 | z << 3 | x >> 1; + int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; + } + + @Override + public void forEachEntity(EntityConsumer consumer) { + if (entities.isEmpty()) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = wrapper.getHandle(); + for (CachedEntity cachedEntity : entities) { + location.setX(cachedEntity.x); + location.setY(cachedEntity.y); + location.setZ(cachedEntity.z); + location.setYaw(cachedEntity.yaw); + location.setPitch(cachedEntity.pitch); + consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); + } + } + } + + private BlockState getBlockState(int x, int y, int z) { + return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); + } + + private int getSectionIndex(int y) { + int sectionIndex = SectionPos.blockToSectionCoord(y); + return sectionIndex - this.serverLevel.getMinSectionY(); + } + + private int getSectionYFromSectionIndex(int index) { + return index + this.serverLevel.getMinSectionY(); + } + + private static class CachedEntity { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + private final EntityType entityType; + private final CompoundTag entityTag; + + CachedEntity(Entity entity) { + this.x = entity.getX(); + this.y = entity.getY(); + this.z = entity.getZ(); + this.yaw = entity.getBukkitYaw(); + this.pitch = entity.getXRot(); + this.entityType = entity.getBukkitEntity().getType(); + + net.minecraft.nbt.CompoundTag compoundTag; + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "cached_entity@" + entity.getUUID(), LOGGER)) { + TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess()); + entity.save(valueOutput); + compoundTag = valueOutput.buildResult(); + } + + compoundTag.putFloat("Yaw", entity.getYRot()); + compoundTag.putFloat("Pitch", entity.getXRot()); + + this.entityTag = CompoundTag.fromNBT(compoundTag); + } + + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/KeyBlocksCache.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/KeyBlocksCache.java new file mode 100644 index 0000000000..bf2fa065ff --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/KeyBlocksCache.java @@ -0,0 +1,32 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.world; + +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.level.block.Block; +import org.bukkit.Material; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; + +import java.util.IdentityHashMap; +import java.util.Map; + +public class KeyBlocksCache { + + private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); + + private KeyBlocksCache() { + + } + + public static Key getBlockKey(Block block) { + return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { + Material blockType = CraftMagicNumbers.getMaterial(block); + return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); + }); + } + + public static void cacheAllBlocks() { + BuiltInRegistries.BLOCK.forEach(KeyBlocksCache::getBlockKey); + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/PropertiesMapper.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/PropertiesMapper.java new file mode 100644 index 0000000000..fd242d6824 --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/PropertiesMapper.java @@ -0,0 +1,85 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.world; + +import com.bgsoftware.superiorskyblock.core.logging.Log; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.Property; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Map; + +public class PropertiesMapper { + + private static final Map> nameToProperty = new HashMap<>(); + private static final Map, String> propertyToName = new HashMap<>(); + + static { + Map fieldsToNames = new IdentityHashMap<>(); + + fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); + fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); + fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); + fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); + fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); + fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); + fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); + fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); + fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); + fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); + fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); + fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); + fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); + fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); + fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); + fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); + fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); + fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); + fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); + fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); + fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); + fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); + fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); + fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); + fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); + fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); + fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); + fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); + fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); + fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); + + try { + for (Field field : BlockStateProperties.class.getFields()) { + field.setAccessible(true); + Object value = field.get(null); + if (value instanceof Property) { + Property property = (Property) value; + register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); + } + } + } catch (Exception error) { + Log.error(error, "An unexpected error occurred while loading properties mapper:"); + } + + } + + private static void register(String key, String fieldName, Property property) { + if (nameToProperty.containsKey(key)) { + Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); + } else { + nameToProperty.put(key, property); + propertyToName.put(property, key); + } + } + + public static Property getProperty(String name) { + return nameToProperty.get(name); + } + + public static String getPropertyName(Property property) { + return propertyToName.get(property); + } + +} diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/WorldEditSessionImpl.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/WorldEditSessionImpl.java new file mode 100644 index 0000000000..e33636404c --- /dev/null +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/WorldEditSessionImpl.java @@ -0,0 +1,399 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_6.world; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_6.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.ByteTag; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.tag.IntArrayTag; +import com.bgsoftware.superiorskyblock.tag.StringTag; +import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.gson.JsonParseException; +import com.mojang.logging.LogUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.util.ProblemReporter; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.BedBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.generator.ChunkGenerator; +import org.slf4j.Logger; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionImpl implements WorldEditSession { + + private static final Logger LOGGER = LogUtils.getLogger(); + + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + + private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); + private ServerLevel serverLevel; + private Dimension dimension; + + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { + return POOL.obtain().initialize(serverLevel); + } + + private WorldEditSessionImpl() { + } + + public WorldEditSessionImpl initialize(ServerLevel serverLevel) { + this.serverLevel = serverLevel; + this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + return this; + } + + @Override + public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, + @Nullable CompoundTag blockEntityData) { + BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + + if (!isValidPosition(blockPos)) + return; + + BlockState blockState = Block.stateById(combinedId); + + if (statesTag != null) { + for (Map.Entry> entry : statesTag.entrySet()) { + try { + // noinspection rawtypes + Property property = PropertiesMapper.getProperty(entry.getKey()); + if (property != null) { + if (entry.getValue() instanceof ByteTag) { + // noinspection unchecked + blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); + } else if (entry.getValue() instanceof IntArrayTag) { + int[] data = ((IntArrayTag) entry.getValue()).getValue(); + // noinspection unchecked + blockState = blockState.setValue(property, data[0]); + } else if (entry.getValue() instanceof StringTag) { + String data = ((StringTag) entry.getValue()).getValue(); + // noinspection unchecked + blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); + } + } + } catch (Exception ignored) { + } + } + } + + if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || + blockState.getBlock() instanceof BedBlock) { + blocksToUpdate.add(new Pair<>(blockPos, blockState)); + return; + } + + ChunkPos chunkPos = new ChunkPos(blockPos); + + if (blockEntityData != null) + blockEntities.add(new Pair<>(blockPos, blockEntityData)); + + ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); + + if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) + chunkData.lights.add(blockPos); + + LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + + int blockX = blockPos.getX() & 15; + int blockY = blockPos.getY(); + int blockZ = blockPos.getZ() & 15; + + levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); + + chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); + chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); + chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); + chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); + } + + @Override + public List getAffectedChunks() { + if (chunks.isEmpty()) + return Collections.emptyList(); + + List chunkPositions = new LinkedList<>(); + World bukkitWorld = serverLevel.getWorld(); + LongIterator iterator = chunks.keyIterator(); + while (iterator.hasNext()) { + long chunkKey = iterator.next(); + int chunkX = (int) chunkKey; + int chunkZ = (int) (chunkKey >> 32); + chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); + } + return chunkPositions; + } + + @Override + public void applyBlocks(Chunk bukkitChunk) { + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); + ChunkPos chunkPos = levelChunk.getPos(); + + long chunkKey = chunkPos.toLong(); + ChunkData chunkData = this.chunks.remove(chunkKey); + + if (chunkData == null) + return; + + int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); + for (int i = 0; i < chunkSectionsCount; ++i) { + levelChunk.getSections()[i] = chunkData.chunkSections[i]; + } + + chunkData.heightmaps.forEach(((type, heightmap) -> { + levelChunk.setHeightmap(type, heightmap.getRawData()); + })); + + if (plugin.getSettings().isLightsUpdate()) { + if (isStarLightInterface) { + this.lightenChunks.add(chunkPos); + } else { + ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); + chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); + // Queues chunk light for this chunk. + threadedLevelLightEngine.lightChunk(levelChunk, false); + } + } + + levelChunk.markUnsaved(); + } + + @Override + public void finish(Island island) { + // Update blocks + blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); + + // Update block entities + blockEntities.forEach(data -> { + net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); + if (blockEntityCompound != null) { + BlockPos blockPos = data.getKey(); + blockEntityCompound.putInt("x", blockPos.getX()); + blockEntityCompound.putInt("y", blockPos.getY()); + blockEntityCompound.putInt("z", blockPos.getZ()); + + applySignTextLines(blockEntityCompound, "front_text"); + applySignTextLines(blockEntityCompound, "back_text"); + convertLegacySignTextLines(blockEntityCompound); + + BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); + if (worldBlockEntity != null) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "block_entity@" + blockPos, LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), blockEntityCompound); + worldBlockEntity.loadWithComponents(valueInput); + } + } + } + }); + + if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { + ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); + threadedLevelLightEngine.starlight$serverRelightChunks(lightenChunks, chunkCallback -> { + }, completeCallback -> { + }); + this.lightenChunks.clear(); + } + + release(); + } + + @Override + public void release() { + this.chunks.clear(); + this.blocksToUpdate.clear(); + this.blockEntities.clear(); + this.lightenChunks.clear(); + this.serverLevel = null; + this.dimension = null; + POOL.release(this); + } + + private boolean isValidPosition(BlockPos blockPos) { + return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && + blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && + blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); + } + + private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { + blockEntityCompound.getCompound(key).ifPresent(textCompound -> { + ListTag messages = textCompound.getListOrEmpty("messages"); + List textLines = new ArrayList<>(); + for (net.minecraft.nbt.Tag lineTag : messages) { + try { + textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); + } catch (JsonParseException error) { + textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); + } + } + + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); + }); + } + + private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + + private class ChunkData { + private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; + private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); + private final List lights = isStarLightInterface ? Collections.emptyList() : new LinkedList<>(); + + public ChunkData(long chunkKey) { + ChunkPos chunkPos = new ChunkPos(chunkKey); + + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + + createChunkSections(biomesRegistry); + + ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), serverLevel, biomesRegistry, null); + + createHeightmaps(tempChunk); + runCustomWorldGenerator(tempChunk); + } + + private void createChunkSections(Registry biomesRegistry) { + Holder biome = CraftBiome.bukkitToMinecraftHolder( + IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); + + for (int i = 0; i < this.chunkSections.length; ++i) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + + this.chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + private void runCustomWorldGenerator(ProtoChunk tempChunk) { + ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); + + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; + + NMSUtils.buildSurfaceForChunk(serverLevel, tempChunk); + + // We want to copy the level chunk sections back + LevelChunkSection[] tempChunkSections = tempChunk.getSections(); + for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { + LevelChunkSection chunkSection = tempChunkSections[i]; + if (chunkSection != null) + this.chunkSections[i] = chunkSection; + } + } + + private void createHeightmaps(ProtoChunk tempChunk) { + for (Heightmap.Types heightmapType : Heightmap.Types.values()) { + if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { + this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); + } + } + } + + } + + +} diff --git a/build.gradle b/build.gradle index ca7fb66193..fe8bd22ff6 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b11' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b12' implementation 'com.zaxxer:HikariCP:4.0.3' implementation 'org.slf4j:slf4j-api:2.0.5' diff --git a/settings.gradle b/settings.gradle index 6e23229032..56608f7767 100644 --- a/settings.gradle +++ b/settings.gradle @@ -67,4 +67,5 @@ include 'NMS:v1_20_4' include 'NMS:v1_21' include 'NMS:v1_21_3' include 'NMS:v1_21_4' -include 'NMS:v1_21_5' \ No newline at end of file +include 'NMS:v1_21_5' +include 'NMS:v1_21_6' \ No newline at end of file From 6ee5e20e9bd1d708beecac54d47c794d86188aaf Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Mon, 23 Jun 2025 18:46:14 +0200 Subject: [PATCH 202/600] Added option to change default island's locked status (#2517) --- .../superiorskyblock/api/config/SettingsManager.java | 6 ++++++ .../superiorskyblock/config/SettingsContainer.java | 2 ++ .../superiorskyblock/config/SettingsManagerImpl.java | 5 +++++ .../superiorskyblock/config/section/GlobalSection.java | 4 ++++ .../superiorskyblock/island/builder/IslandBuilderImpl.java | 2 +- src/main/resources/config.yml | 3 +++ 6 files changed, 21 insertions(+), 1 deletion(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index c7f261b47a..077ba083a1 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -586,6 +586,12 @@ public interface SettingsManager { */ boolean isPublicWarps(); + /** + * Whether islands should be locked by default or not. + * Config-path: locked-islands + */ + boolean isLockedIslands(); + /** * Cooldown between recalculations of an island, in seconds. * If set to 0, no cooldown is set. diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 09701e87ed..be246b0daa 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -207,6 +207,7 @@ public class SettingsContainer { public final boolean physicsListener; public final double chargeOnWarp; public final boolean publicWarps; + public final boolean lockedIslands; public final long recalcTaskTimeout; public final boolean autoLanguageDetection; public final boolean autoUncoopWhenAlone; @@ -529,6 +530,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config physicsListener = config.getBoolean("physics-listener", true); chargeOnWarp = config.getDouble("charge-on-warp", 0D); publicWarps = config.getBoolean("public-warps"); + lockedIslands = config.getBoolean("locked-islands",false); recalcTaskTimeout = config.getLong("recalc-task-timeout"); autoLanguageDetection = config.getBoolean("auto-language-detection", true); autoUncoopWhenAlone = config.getBoolean("auto-uncoop-when-alone", false); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index cb3c696151..abcfe20439 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -541,6 +541,11 @@ public boolean isPublicWarps() { return this.global.isPublicWarps(); } + @Override + public boolean isLockedIslands() { + return this.global.isLockedIslands(); + } + @Override public long getRecalcTaskTimeout() { return this.global.getRecalcTaskTimeout(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index 39e2c8a40a..a252f86b2f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -332,6 +332,10 @@ public boolean isPublicWarps() { return getContainer().publicWarps; } + public boolean isLockedIslands() { + return getContainer().lockedIslands; + } + public long getRecalcTaskTimeout() { return getContainer().recalcTaskTimeout; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java index 6f8da343cc..0dab9913d1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java @@ -73,7 +73,7 @@ public class IslandBuilderImpl implements Island.Builder { public String paypal = "None"; public BigDecimal bonusWorth = BigDecimal.ZERO; public BigDecimal bonusLevel = BigDecimal.ZERO; - public boolean isLocked = false; + public boolean isLocked = plugin.getSettings().isLockedIslands(); public boolean isIgnored = false; public String description = ""; public EnumerateSet generatedSchematics = new EnumerateSet<>(Dimension.values()); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index a094d5852f..2880dfe8cb 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -810,6 +810,9 @@ charge-on-warp: 0 # Should island warps be public by default? public-warps: false +# Should islands be locked by default? +locked-islands: false + # Timeout for the recalculate task, in seconds. # If you want to disable the timeout, set this to 0 or below. recalc-task-timeout: 10 From 86503881cafd131e0bde58b2d507ace2217bc402 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Jun 2025 20:05:46 +0300 Subject: [PATCH 203/600] Adds the ability to disable player island-privileges (#2514) --- .../api/config/SettingsManager.java | 6 ++++ .../commands/player/CmdPermissions.java | 31 +++++++++---------- .../config/SettingsContainer.java | 4 ++- .../config/SettingsManagerImpl.java | 5 +++ .../config/section/GlobalSection.java | 4 +++ src/main/resources/config.yml | 4 +++ 6 files changed, 36 insertions(+), 18 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 077ba083a1..5bb446449d 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -103,6 +103,12 @@ public interface SettingsManager { */ boolean isCoopMembers(); + /** + * Should players be able to edit island privileges for other players? + * Config path: edit-player-permissions + */ + boolean isEditPlayerPermissions(); + /** * All settings related to the island-roles. * Config path: island-roles diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPermissions.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPermissions.java index 367372b580..420d46b436 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPermissions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPermissions.java @@ -21,6 +21,8 @@ public class CmdPermissions implements IPermissibleCommand { + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + @Override public List getAliases() { return Arrays.asList("permissions", "perms", "setpermission", "setperm"); @@ -33,7 +35,11 @@ public String getPermission() { @Override public String getUsage(java.util.Locale locale) { - return "permissions [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "] [reset]"; + if (plugin.getSettings().isEditPlayerPermissions()) { + return "permissions [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "] [reset]"; + } else { + return "permissions [reset]"; + } } @Override @@ -48,7 +54,7 @@ public int getMinArgs() { @Override public int getMaxArgs() { - return 3; + return plugin.getSettings().isEditPlayerPermissions() ? 3 : 2; } @Override @@ -72,7 +78,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer boolean setToDefault = (args.length == 2 ? args[1] : args.length == 3 ? args[2] : "").equalsIgnoreCase("reset"); - if ((!setToDefault && args.length == 2) || args.length == 3) { + if (plugin.getSettings().isEditPlayerPermissions() && ((!setToDefault && args.length == 2) || args.length == 3)) { SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(args[1]); if (targetPlayer == null) { @@ -115,23 +121,14 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { List tabVariables = new LinkedList<>(); - switch (args.length) { - case 2: - if ("reset".contains(args[1].toLowerCase(Locale.ENGLISH))) - tabVariables.add("reset"); - tabVariables.addAll(CommandTabCompletes.getOnlinePlayers(plugin, args[1], - plugin.getSettings().isTabCompleteHideVanished())); - break; - case 3: - break; - } - if (args.length == 2) { if ("reset".contains(args[1].toLowerCase(Locale.ENGLISH))) tabVariables.add("reset"); - tabVariables.addAll(CommandTabCompletes.getOnlinePlayers(plugin, args[1], - plugin.getSettings().isTabCompleteHideVanished())); - } else if (args.length == 3) { + if (plugin.getSettings().isEditPlayerPermissions()) { + tabVariables.addAll(CommandTabCompletes.getOnlinePlayers(plugin, args[1], + plugin.getSettings().isTabCompleteHideVanished())); + } + } else if (plugin.getSettings().isEditPlayerPermissions() && args.length == 3) { if ("reset".contains(args[2].toLowerCase(Locale.ENGLISH))) tabVariables.add("reset"); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index be246b0daa..11dd55e480 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -104,6 +104,7 @@ public class SettingsContainer { public final boolean autoBlocksTracking; public final String islandTopOrder; public boolean coopMembers; + public boolean editPlayerPermissions; public final ConfigurationSection islandRolesSection; public final long calcInterval; public final String signWarpLine; @@ -293,6 +294,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config autoBlocksTracking = config.getBoolean("auto-blocks-tracking", true); islandTopOrder = config.getString("island-top-order", "WORTH").toUpperCase(Locale.ENGLISH); coopMembers = config.getBoolean("coop-members", true); + editPlayerPermissions = config.getBoolean("edit-player-permissions", true); islandRolesSection = config.getConfigurationSection("island-roles"); signWarpLine = config.getString("sign-warp-line", "[IslandWarp]"); List signWarp = Formatters.formatList(config.getStringList("sign-warp"), Formatters.COLOR_FORMATTER); @@ -530,7 +532,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config physicsListener = config.getBoolean("physics-listener", true); chargeOnWarp = config.getDouble("charge-on-warp", 0D); publicWarps = config.getBoolean("public-warps"); - lockedIslands = config.getBoolean("locked-islands",false); + lockedIslands = config.getBoolean("locked-islands", false); recalcTaskTimeout = config.getLong("recalc-task-timeout"); autoLanguageDetection = config.getBoolean("auto-language-detection", true); autoUncoopWhenAlone = config.getBoolean("auto-uncoop-when-alone", false); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index abcfe20439..e684c4f3b4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -151,6 +151,11 @@ public boolean isCoopMembers() { return this.global.isCoopMembers(); } + @Override + public boolean isEditPlayerPermissions() { + return this.global.isEditPlayerPermissions(); + } + @Override public IslandRoles getIslandRoles() { return this.islandRoles; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index a252f86b2f..f7323f6f28 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -56,6 +56,10 @@ public boolean isCoopMembers() { return getContainer().coopMembers; } + public boolean isEditPlayerPermissions() { + return getContainer().editPlayerPermissions; + } + public String getSignWarpLine() { return getContainer().signWarpLine; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 2880dfe8cb..1b2222d45c 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -172,6 +172,10 @@ island-top-order: 'WORTH' # Whether coop members should be enabled or not. coop-members: true +# Should players be able to edit island privileges for other players? +# When set to false, island privileges could be edited only to island roles. +edit-player-permissions: true + # All settings related to island roles. # You can find a list of permissions here: https://wiki.bg-software.com/superiorskyblock/island-permissions island-roles: From 76afa248b0aa330fb329341c81c6d2dfb805c57c Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Mon, 23 Jun 2025 19:50:49 +0200 Subject: [PATCH 204/600] Added option to disable island rating change (#2516) --------- Co-authored-by: Ome_R --- .../api/config/SettingsManager.java | 6 +++ .../commands/player/CmdRate.java | 41 +++++++++++++++++-- .../config/SettingsContainer.java | 2 + .../config/SettingsManagerImpl.java | 5 +++ .../config/section/GlobalSection.java | 4 ++ .../core/messages/Message.java | 1 + src/main/resources/config.yml | 3 ++ src/main/resources/lang/de-DE.yml | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + 18 files changed, 69 insertions(+), 4 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 5bb446449d..3fa048ef72 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -272,6 +272,12 @@ public interface SettingsManager { */ boolean isRateOwnIsland(); + /** + * Whether players can change island rating or not. + * Config-path: change-island-rating + */ + boolean isChangeIslandRating(); + /** * All the default island-flags that will be enabled for new islands. * Config-path: default-settings diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRate.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRate.java index f54e5265f4..9b1ecfb6cf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRate.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRate.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; @@ -70,9 +71,15 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - if (!plugin.getSettings().isRateOwnIsland() && island.equals(superiorPlayer.getIsland())) { - Message.RATE_OWN_ISLAND.send(superiorPlayer); - return; + RateResult rateResult = canRateIsland(plugin, superiorPlayer, island); + + switch (rateResult) { + case RATE_OWN_ISLAND: + Message.RATE_OWN_ISLAND.send(superiorPlayer); + return; + case ALREADY_RATED: + Message.RATE_ALREADY_GIVEN.send(superiorPlayer); + return; } plugin.getMenus().openIslandRate(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); @@ -85,7 +92,33 @@ public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sen return args.length == 2 ? CommandTabCompletes.getOnlinePlayersWithIslands(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), (onlinePlayer, onlineIsland) -> onlineIsland != null && - (plugin.getSettings().isRateOwnIsland() || !onlineIsland.equals(island))) : Collections.emptyList(); + canRateIsland(plugin, superiorPlayer, island, onlineIsland) == RateResult.SUCCESS) : + Collections.emptyList(); + } + + private static RateResult canRateIsland(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island) { + return canRateIsland(plugin, superiorPlayer, superiorPlayer.getIsland(), island); + } + + private static RateResult canRateIsland(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, + Island playerIsland, Island island) { + if (!plugin.getSettings().isRateOwnIsland() && island.equals(playerIsland)) { + return RateResult.RATE_OWN_ISLAND; + } + + if (!plugin.getSettings().isChangeIslandRating() && island.getRating(superiorPlayer) != Rating.UNKNOWN) { + return RateResult.ALREADY_RATED; + } + + return RateResult.SUCCESS; + } + + private enum RateResult { + + SUCCESS, + RATE_OWN_ISLAND, + ALREADY_RATED + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 11dd55e480..f8dfeb8085 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -153,6 +153,7 @@ public class SettingsContainer { public final boolean teleportOnKick; public final boolean clearOnJoin; public final boolean rateOwnIsland; + public final boolean changeIslandRating; public final List defaultSettings; public final boolean disableRedstoneOffline; public final boolean disableRedstoneAFK; @@ -393,6 +394,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config teleportOnKick = config.getBoolean("teleport-on-kick", false); clearOnJoin = config.getBoolean("clear-on-join", false); rateOwnIsland = config.getBoolean("rate-own-island", false); + changeIslandRating = config.getBoolean("change-island-rating", true); defaultSettings = Collections.unmodifiableList(config.getStringList("default-settings") .stream().map(str -> str.toUpperCase(Locale.ENGLISH)).collect(Collectors.toList())); defaultGenerator = new EnumerateMap<>(Dimension.values()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index e684c4f3b4..cf0a6b6f27 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -291,6 +291,11 @@ public boolean isRateOwnIsland() { return this.global.isRateOwnIsland(); } + @Override + public boolean isChangeIslandRating() { + return this.global.isChangeIslandRating(); + } + @Override public List getDefaultSettings() { return this.global.getDefaultSettings(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index f7323f6f28..d17b1304d1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -144,6 +144,10 @@ public boolean isRateOwnIsland() { return getContainer().rateOwnIsland; } + public boolean isChangeIslandRating() { + return getContainer().changeIslandRating; + } + public List getDefaultSettings() { return getContainer().defaultSettings; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index c3f7fd33d9..7112416665 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -660,6 +660,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { RANKUP_SUCCESS_ALL, RANKUP_SUCCESS_NAME, RATE_ANNOUNCEMENT, + RATE_ALREADY_GIVEN, RATE_CHANGE_OTHER, RATE_OWN_ISLAND, RATE_REMOVE_ALL, diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 1b2222d45c..8d8589edac 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -499,6 +499,9 @@ clear-on-join: false # Should players be able to rate their own islands? rate-own-island: false +# Should players be able to change island rating? +change-island-rating: true + # A list of default settings for new islands. # You can find a list of settings here: https://wiki.bg-software.com/superiorskyblock/island-settings default-settings: diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 331f85e60d..0240dea29b 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -819,6 +819,7 @@ RANKUP_SUCCESS_ALL: '&e&lInsel | &7Das Upgrade-Level {0} für alle Inseln erfolg aktualisiert.' RANKUP_SUCCESS_NAME: '&e&lInsel | &7Die Aktualisierungsstufe {0} für {1} wurde erfolgreich aktualisiert.' +RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lInsel | &7{0} hat deine Insel mit {1} von 5 Punkten bewertet!.' RATE_CHANGE_OTHER: '&e&lInsel | &7Du hast die Bewertung von {0} in {1} geändert.' RATE_OWN_ISLAND: '&c&lError | &7Du kannst deine eigene Insel nicht bewerten.' diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 52dc58a6aa..4be9b395bc 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -643,6 +643,7 @@ PURGED_ISLANDS: |- RANKUP_SUCCESS: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for {1}''s island.' RANKUP_SUCCESS_ALL: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for all the islands.' RANKUP_SUCCESS_NAME: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for {1}.' +RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lIsland | &7{0} has rated your island {1} out of 5!.' RATE_CHANGE_OTHER: '&e&lIsland | &7You changed the rating of {0} to {1}.' RATE_OWN_ISLAND: '&c&lError | &7You can''t rate your own island.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 39e4efd653..a0cc9e1902 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -643,6 +643,7 @@ PURGED_ISLANDS: |- RANKUP_SUCCESS: '&e&lIsla | &7Se actualizó correctamente el nivel de la mejora {0} para la isla de {1}.' RANKUP_SUCCESS_ALL: '&e&lIsla | &7e actualizó correctamente el nivel de la mejora {0} para todas las islas.' RANKUP_SUCCESS_NAME: '&e&lIsla | &7&7Se actualizó correctamente el nivel de la mejora {0} para la isla de {1}.' +RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lIsla | &7¡{0} ha calificado tu isla con un {1} de 5 !' RATE_CHANGE_OTHER: '&e&lIsla | &7Cambiaste la calificación de {0} a {1}.' RATE_OWN_ISLAND: '&c&lError | &7No puedes calificar tu propia isla.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index cd14322b38..bae927c42d 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -645,6 +645,7 @@ PURGED_ISLANDS: |- RANKUP_SUCCESS: '&e&lIle | &7Niveau de l''amélioration {0} mis à jour pour l''île de {1}.' RANKUP_SUCCESS_ALL: '&e&lIle | &7Niveau de l''amélioration {0} mis à jour pour toutes les îles.' RANKUP_SUCCESS_NAME: '&e&lIle | &7Niveau de l''amélioration {0} mis à jour pour l''île {1}.' +RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lIle | &7{0} a noté votre île {1} / 5 !.' RATE_CHANGE_OTHER: '&e&lIle | &7Vous avez modifié la note de {0} sur {1}.' RATE_OWN_ISLAND: '&c&lErreur | &7Vous ne pouvez pas noter votre île.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index bfd1bd4fd0..11a482bdca 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -651,6 +651,7 @@ PURGED_ISLANDS: | RANKUP_SUCCESS: '&e&lIsola | &7Aggiornato con successo il livello del upgrade {0} per l''isola di {1}.' RANKUP_SUCCESS_ALL: '&e&lIsola | &7Aggiornato con successo il livello del upgrade {0} per tutte le isole.' RANKUP_SUCCESS_NAME: '&e&lIsola | &7Aggiornato con successo il livello del upgrade {0} per l''isola {1}.' +RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lIsola | &7{0} ha valutato la tua isola {1} stelle su 5!' RATE_CHANGE_OTHER: '&e&lIsola | &7Hai cambiato la valutazione di {0} a {1}.' RATE_OWN_ISLAND: '&c&lErrore | &7Non puoi valutare la tua isola.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 484ae20301..e02fa732f0 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -665,6 +665,7 @@ PURGED_ISLANDS: |- RANKUP_SUCCESS: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for {1}''s island.' RANKUP_SUCCESS_ALL: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for all the islands.' RANKUP_SUCCESS_NAME: '&e&lIsland | &7Successfully updated the level of the upgrade {0} for {1}.' +RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lיא | &75 ךותמ {1} ךלש יאה תא גריד {0}!' RATE_CHANGE_OTHER: '&e&lיא | &7{1} ל {0} לש גורידה תא תיניש.' RATE_OWN_ISLAND: '&c&lהאיגש | &7ךלש יאה תא גרדל לוכי אל התא.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 724bdf8937..f63040e159 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -645,6 +645,7 @@ PURGED_ISLANDS: |- RANKUP_SUCCESS: '&e&lWyspa | &7Pomyslnie zaktualizowano poziom uaktualnienia {0} dla wyspy {1}.' RANKUP_SUCCESS_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano poziom aktualizacji {0} dla wszystkich wysp.' RANKUP_SUCCESS_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano poziom uaktualnienia {0} dla {1}.' +RATE_ALREADY_GIVEN: '&c&lBlad | &7Oceniles juz te wyspe.' RATE_ANNOUNCEMENT: '&e&lWyspa | &7{0} ocenilo Twoja wyspe {1} na 5!.' RATE_CHANGE_OTHER: '&e&lWyspa | &7Zmieniles ocene z {0} na {1}.' RATE_OWN_ISLAND: '&c&lBlad | &7Nie mozesz ocenic wlasnej wyspy.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index fd22246410..4259b4b3eb 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -643,6 +643,7 @@ PURGED_ISLANDS: |- RANKUP_SUCCESS: '&e&lIlha | &7Atualizado com sucesso o nível da atualização {0} para a ilha de {1}.' RANKUP_SUCCESS_ALL: '&e&lIlha | &7Atualizado com sucesso o nível da atualização {0} para todas as ilhas.' RANKUP_SUCCESS_NAME: '&e&lIlha | &7Atualizado com sucesso o nível da atualização {0} para {1}.' +RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lIlha | &7{0} classificou sua ilha {1} de 5!.' RATE_CHANGE_OTHER: '&e&lIlha | &7Você alterou a classificação de {0} para {1}.' RATE_OWN_ISLAND: '&c&lErro | &7Você não pode classificar sua própria ilha.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 0442ab89ed..cea224873a 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -643,6 +643,7 @@ PURGED_ISLANDS: |- RANKUP_SUCCESS: '&e&lОстров | &7Успешно обновлен уровень улучшения {0} для острова {1}.' RANKUP_SUCCESS_ALL: '&e&lОстров | &7Успешно обновлен уровень улучшения {0} для всех островов.' RANKUP_SUCCESS_NAME: '&e&lОстров | &7Успешно обновлен уровень улучшения {0} для {1}.' +RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lОстров | &7{0} оценил ваш остров на {1} из 5.' RATE_CHANGE_OTHER: '&e&lОстров | &7Вы изменили рейтинг {0} на {1}.' RATE_OWN_ISLAND: '&c&lОшибка | &7Вы не можете оценить свой собственный остров.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 0c01b932fe..b3130e6ff5 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -725,6 +725,7 @@ PURGED_ISLANDS: |- RANKUP_SUCCESS: '&e&lĐảo | &7Cập nhật thành công mức độ nâng cấp {0} cho đảo của {1}.' RANKUP_SUCCESS_ALL: '&e&lĐảo | &7Cập nhật thành công mức độ nâng cấp {0} cho tất cả các đảo.' RANKUP_SUCCESS_NAME: '&e&lĐảo | &7Cập nhật thành công mức độ nâng cấp {0} cho {1}.' +RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&lĐánh giá | &7{0} đã đánh giá đảo của bạn {1} trên 5!.' RATE_CHANGE_OTHER: '&e&lĐánh giá | &7Bạn đã thay đổi đánh giá của đảo {0} thành {1}.' RATE_OWN_ISLAND: '&c&lLỗi | &7Bạn không thể đánh giả đảo của bạn.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 4004bc4a37..83e9725f8f 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -643,6 +643,7 @@ PURGED_ISLANDS: |- RANKUP_SUCCESS: '&e&l岛屿 | &7成功更新了玩家 {1} 的岛屿功能 {0} 等级.' RANKUP_SUCCESS_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的功能 {0} 等级.' RANKUP_SUCCESS_NAME: '&e&l岛屿 | &7成功更新了岛屿 {1} 的功能 {0} 等级.' +RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' RATE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 为你的岛屿评分 {1}, 满分为 5!.' RATE_CHANGE_OTHER: '&e&l岛屿 | &7你将 {0} 的评分修改为了 {1}.' RATE_OWN_ISLAND: '&c&l错误 | &7你不能对着自己的岛屿评分.' From d76bc7db6e73c6f536ad3e32dececf780c1a92c1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Jun 2025 21:01:00 +0300 Subject: [PATCH 205/600] Adds Turkish language (#2508) --- .../core/messages/Message.java | 1 + src/main/resources/lang/tr-TR.yml | 923 ++++++++++++++++++ .../resources/menus/player-language1_12.yml | 10 +- .../resources/menus/player-language1_13.yml | 9 +- 4 files changed, 941 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/lang/tr-TR.yml diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 7112416665..898c8d11c2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -890,6 +890,7 @@ public static void reload() { plugin.saveResource("lang/pl-PL.yml", false); plugin.saveResource("lang/pt-BR.yml", false); plugin.saveResource("lang/ru-RU.yml", false); + plugin.saveResource("lang/tr-TR.yml", false); plugin.saveResource("lang/vi-VN.yml", false); plugin.saveResource("lang/zh-CN.yml", false); } diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml new file mode 100644 index 0000000000..835d82ab23 --- /dev/null +++ b/src/main/resources/lang/tr-TR.yml @@ -0,0 +1,923 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## Translated by losadev ## +## ## +###################################################### + +# If you wish to create a new language file, please copy this one. +# Make sure you give the name a correct language name. +# https://www.oracle.com/technetwork/java/javase/java8locales-2095355.html +# You can find a tutorial about configuring messages here: +# https://wiki.bg-software.com/superiorskyblock/messages + +ADMIN_ADD_PLAYER: '&e&lAda | &7Oyuncu {0} başarıyla {1}''in adasına eklendi.' +ADMIN_ADD_PLAYER_NAME: '&e&lAda | &7Oyuncu {0} başarıyla {1} adasına eklendi.' +ADMIN_DEPOSIT_MONEY: '&e&lBanka | &7{1}''in ada bankasına ${0} yatırdın.' +ADMIN_DEPOSIT_MONEY_NAME: '&e&lBanka | &7{1} adasının bankasına ${0} yatırdın.' +ADMIN_HELP_FOOTER: '&e&lSuperiorSkyblock &7Geliştiren: Ome_R' +ADMIN_HELP_HEADER: '&e&lSuperiorSkyblock &7Yönetici Komutları Listesi [{0}/{1}]:' +ADMIN_HELP_LINE: '&e/{0} &f- &7{1}' +ADMIN_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Sonraki sayfa için /is admin {0} kullan.' +ALREADY_IN_ISLAND: '&c&lHata | &7Zaten bir adadasın.' +ALREADY_IN_ISLAND_OTHER: '&c&lHata | &7Bu oyuncu zaten adanın bir üyesi.' +BAN_ANNOUNCEMENT: '&e&lAda | &7{0}, {1} tarafından adadan YASAKLANDI.' +BAN_PLAYERS_WITH_LOWER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne sahip + oyuncuları yasaklayabilirsin.' +BANK_DEPOSIT_CUSTOM: '&e&lBanka | &7Yatırmak istediğin miktarı yaz:' +BANK_DEPOSIT_COMPLETED: Para Yatırma Tamamlandı +BANK_LIMIT_EXCEED: '&c&lHata | &7Banka limitini aştın.' +BANK_WITHDRAW_CUSTOM: '&e&lBanka | &7Çekmek istediğin miktarı yaz:' +BANK_WITHDRAW_COMPLETED: Para Çekme Tamamlandı +BANNED_FROM_ISLAND: '&c&lHata | &7Bu adadan yasaklandın.' +BLOCK_COUNT_CHECK: '&e&lAda | &7Bu adada x{0} {1} bulunuyor.' +BLOCK_COUNTS_CHECK: | + &e&lAda | &7Bu adada aşağıdaki bloklar bulunuyor: + &7{0} +BLOCK_COUNTS_CHECK_EMPTY: '&e&lAda | &7Bu adada takip edilen blok bulunmuyor.' +BLOCK_COUNTS_CHECK_MATERIAL: x{0} {1} +BLOCK_LEVEL: '&e&lSeviye | &7{0} bloğunun seviyesi {1}.' +BLOCK_LEVEL_WORTHLESS: '&e&lSeviye | &7{0} bloğu değersiz.' +BLOCK_VALUE: '&e&lDeğer | &7{0} bloğunun değeri {1}.' +BLOCK_VALUE_WORTHLESS: '&e&lDeğer | &7{0} bloğu değersiz.' +BONUS_SET_SUCCESS: '&e&lAda | &7Ada bonusu başarıyla {0} olarak güncellendi.' +BONUS_SYNC_ALL: '&e&lAda | &7Ada bonusu tüm adalarla başarıyla senkronize edildi.' +BONUS_SYNC_NAME: '&e&lAda | &7Ada bonusu {0} ile başarıyla senkronize edildi.' +BONUS_SYNC: '&e&lAda | &7Ada bonusu {0}''ın adasıyla başarıyla senkronize edildi.' +BORDER_PLAYER_COLOR_NAME_BLUE: Mavi +BORDER_PLAYER_COLOR_NAME_RED: Kırmızı +BORDER_PLAYER_COLOR_NAME_GREEN: Yeşil +BORDER_PLAYER_COLOR_UPDATED: '&e&lSınır | &7Kişisel sınır rengin başarıyla {0} olarak + değiştirildi.' +BUILD_OUTSIDE_ISLAND: '&c&lHata | &7Koruma menzilinin dışında inşa edemezsin.' +CANNOT_SET_ROLE: '&c&lHata | &7Oyuncunun rolünü {0} olarak ayarlayamazsın.' +CHANGE_PERMISSION_FOR_HIGHER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne + sahip rollerin izinlerini değiştirebilirsin.' +CHANGED_BANK_LIMIT: '&e&lYükseltmeler | &7{0}''ın adasının banka limiti başarıyla + güncellendi.' +CHANGED_BANK_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların banka limiti başarıyla + güncellendi.' +CHANGED_BANK_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının banka limiti başarıyla + güncellendi.' +CHANGED_BIOME: '&e&lAda | &7Biyom başarıyla {0} olarak değiştirildi. Değişiklikleri + görmek için sunucuya tekrar bağlanman gerekebilir.' +CHANGED_BIOME_ALL: '&e&lAda | &7Tüm adalar için biyom başarıyla {0} olarak değiştirildi.' +CHANGED_BIOME_NAME: '&e&lAda | &7{1} adası için biyom başarıyla {0} olarak değiştirildi.' +CHANGED_BIOME_OTHER: '&e&lAda | &7{1}''in adası için biyom başarıyla {0} olarak değiştirildi.' +CHANGED_BLOCK_AMOUNT: '&e&lBloklar | &7{0} konumundaki blok miktarı başarıyla {1} + olarak değiştirildi.' +CHANGED_BLOCK_LIMIT: '&e&lYükseltmeler | &7{0} Bloğunun {1}''in adası için limiti + başarıyla güncellendi.' +CHANGED_BLOCK_LIMIT_ALL: '&e&lYükseltmeler | &7{0} Bloğunun tüm adalar için limiti + başarıyla güncellendi.' +CHANGED_BLOCK_LIMIT_NAME: '&e&lYükseltmeler | &7{0} Bloğunun {1} adası için limiti + başarıyla güncellendi.' +CHANGED_CHEST_SIZE: '&e&lSandık | &7{2}''in adası için #{0} sayfasının satırları başarıyla + {1} olarak güncellendi.' +CHANGED_CHEST_SIZE_ALL: '&e&lSandık | &7Tüm adalar için #{0} sayfasının satırları + başarıyla {1} olarak güncellendi.' +CHANGED_CHEST_SIZE_NAME: '&e&lSandık | &7{2} adası için #{0} sayfasının satırları + başarıyla {1} olarak güncellendi.' +CHANGED_COOP_LIMIT: '&e&lYükseltmeler | &7{0}''ın adasının co-op oyuncu limiti başarıyla + güncellendi.' +CHANGED_COOP_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların co-op oyuncu limiti başarıyla + güncellendi.' +CHANGED_COOP_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının co-op oyuncu limiti başarıyla + güncellendi.' +CHANGED_CROP_GROWTH: '&e&lYükseltmeler | &7{0}''ın adasının bitki büyüme çarpanı başarıyla + güncellendi.' +CHANGED_CROP_GROWTH_ALL: '&e&lYükseltmeler | &7Tüm adaların bitki büyüme çarpanı başarıyla + güncellendi.' +CHANGED_CROP_GROWTH_NAME: '&e&lYükseltmeler | &7{0} adasının bitki büyüme çarpanı + başarıyla güncellendi.' +CHANGED_DISCORD: '&e&lAda | &7Ada discordu başarıyla {0} olarak değiştirildi.' +CHANGED_ENTITY_LIMIT: '&e&lYükseltmeler | &7{0} varlıklarının {1}''in adası için limiti + başarıyla güncellendi.' +CHANGED_ENTITY_LIMIT_ALL: '&e&lYükseltmeler | &7{0} varlıklarının tüm adalar için + limiti başarıyla güncellendi.' +CHANGED_ENTITY_LIMIT_NAME: '&e&lYükseltmeler | &7{0} varlıklarının {1} adası için + limiti başarıyla güncellendi.' +CHANGED_ISLAND_EFFECT_LEVEL: '&e&lYükseltmeler | &7{0} ada etkisinin {1}''in adası + için seviyesi başarıyla güncellendi.' +CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&lYükseltmeler | &7{0} ada etkisinin tüm adalar + için seviyesi başarıyla güncellendi.' +CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&lYükseltmeler | &7{0} ada etkisinin {1} adası + için seviyesi başarıyla güncellendi.' +CHANGED_ISLAND_SIZE: '&e&lYükseltmeler | &7{0}''ın adasının boyutu başarıyla güncellendi.' +CHANGED_ISLAND_SIZE_ALL: '&e&lYükseltmeler | &7Tüm adaların boyutu başarıyla güncellendi.' +CHANGED_ISLAND_SIZE_NAME: '&e&lYükseltmeler | &7{0} adasının boyutu başarıyla güncellendi.' +CHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&oOyuncular adalarının dışında inşa edebildiği + için ada boyutunun bir etkisi yoktur. Bu özelliği yapılandırma dosyasından kapatırsan + ada boyutu tekrar etkili olacaktır.' +CHANGED_LANGUAGE: '&e&lDil | &7Kişisel dilin başarıyla İngilizce olarak değiştirildi.' +CHANGED_MOB_DROPS: '&e&lYükseltmeler | &7{0}''ın adasının mob düşürme çarpanı başarıyla + güncellendi.' +CHANGED_MOB_DROPS_ALL: '&e&lYükseltmeler | &7Tüm adaların mob düşürme çarpanı başarıyla + güncellendi.' +CHANGED_MOB_DROPS_NAME: '&e&lYükseltmeler | &7{0} adasının mob düşürme çarpanı başarıyla + güncellendi.' +CHANGED_NAME: '&e&lAda | &7Adanın adını {0} olarak değiştirdin.' +CHANGED_NAME_OTHER: '&e&lAda | &7{0} adasının adını {1} olarak değiştirdin.' +CHANGED_NAME_OTHER_NAME: '&e&lAda | &7{0} adının adını {1} olarak değiştirdin.' +CHANGED_PAYPAL: '&e&lAda | &7Ada paypalı başarıyla {0} olarak değiştirildi.' +CHANGED_ROLE_LIMIT: '&e&lYükseltmeler | &7{0} rolünün {1}''in adası için limiti başarıyla + güncellendi.' +CHANGED_ROLE_LIMIT_ALL: '&e&lYükseltmeler | &7{0} rolünün tüm adalar için limiti başarıyla + güncellendi.' +CHANGED_ROLE_LIMIT_NAME: '&e&lYükseltmeler | &7{0} rolünün {1} adası için limiti başarıyla + güncellendi.' +CHANGED_SPAWNER_RATES: '&e&lYükseltmeler | &7{0}''ın adasının spawner oranları çarpanı + başarıyla güncellendi.' +CHANGED_SPAWNER_RATES_ALL: '&e&lYükseltmeler | &7Tüm adaların spawner oranları çarpanı + başarıyla güncellendi.' +CHANGED_SPAWNER_RATES_NAME: '&e&lYükseltmeler | &7{0} adasının spawner oranları çarpanı + başarıyla güncellendi.' +CHANGED_TEAM_LIMIT: '&e&lYükseltmeler | &7{0}''ın adasının takım limiti başarıyla + güncellendi.' +CHANGED_TEAM_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların takım limiti başarıyla + güncellendi.' +CHANGED_TEAM_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının takım limiti başarıyla + güncellendi.' +CHANGED_TELEPORT_LOCATION: '&e&lAda | &7Işınlanma konumu başarıyla güncellendi.' +CHANGED_WARPS_LIMIT: '&e&lYükseltmeler | &7{0}''ın adasının ışınlanma limiti başarıyla + güncellendi.' +CHANGED_WARPS_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların ışınlanma limiti başarıyla + güncellendi.' +CHANGED_WARPS_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının ışınlanma limiti başarıyla + güncellendi.' +COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_PLAYERS: '*' +COMMAND_ARGUMENT_AMOUNT: miktar +COMMAND_ARGUMENT_BIOME: biyom +COMMAND_ARGUMENT_BORDER_COLOR: sınır-rengi +COMMAND_ARGUMENT_COMMAND: komut... +COMMAND_ARGUMENT_DISCORD: discord... +COMMAND_ARGUMENT_EFFECT: iksir-efekti +COMMAND_ARGUMENT_EMAIL: e-posta +COMMAND_ARGUMENT_ENTITY: varlık +COMMAND_ARGUMENT_ISLAND_NAME: ada-adı +COMMAND_ARGUMENT_ISLAND_ROLE: ada-rolü +COMMAND_ARGUMENT_LEADER: lider +COMMAND_ARGUMENT_LEVEL: seviye +COMMAND_ARGUMENT_LIMIT: limit +COMMAND_ARGUMENT_MATERIAL: materyal +COMMAND_ARGUMENT_MENU: menü-adı +COMMAND_ARGUMENT_MESSAGE: mesaj... +COMMAND_ARGUMENT_MISSION_NAME: görev-adı +COMMAND_ARGUMENT_MODULE_NAME: modül-adı +COMMAND_ARGUMENT_MULTIPLIER: çarpan +COMMAND_ARGUMENT_NAME: isim +COMMAND_ARGUMENT_NEW_LEADER: yeni-lider +COMMAND_ARGUMENT_PAGE: sayfa +COMMAND_ARGUMENT_PATH: yol +COMMAND_ARGUMENT_PERMISSION: izin +COMMAND_ARGUMENT_PLAYER_NAME: oyuncu-adı +COMMAND_ARGUMENT_PRIVATE: özel +COMMAND_ARGUMENT_RATING: değerlendirme +COMMAND_ARGUMENT_ROWS: satırlar +COMMAND_ARGUMENT_SCHEMATIC_NAME: şematik-adı +COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR: havayı-kaydet +COMMAND_ARGUMENT_SETTINGS: ayarlar +COMMAND_ARGUMENT_SIZE: boyut +COMMAND_ARGUMENT_TIME: süre +COMMAND_ARGUMENT_TITLE_DURATION: süre +COMMAND_ARGUMENT_TITLE_FADE_IN: giriş-solması +COMMAND_ARGUMENT_TITLE_FADE_OUT: çıkış-solması +COMMAND_ARGUMENT_UPGRADE_NAME: yükseltme-adı +COMMAND_ARGUMENT_VALUE: değer +COMMAND_ARGUMENT_WARP_NAME: ışınlanma-adı +COMMAND_ARGUMENT_WARP_CATEGORY: ışınlanma-kategorisi +COMMAND_ARGUMENT_WORLD: dünya +COMMAND_COOLDOWN_FORMAT: '&c&lHata | &7Komutu sadece {0} içinde kullanabilirsin.' +COMMAND_DESCRIPTION_ACCEPT: Bir oyuncudan gelen daveti kabul et. +COMMAND_DESCRIPTION_ADMIN: Yönetici komutlarını kullan. +COMMAND_DESCRIPTION_ADMIN_ADD: Bir adaya kullanıcı ekle. +COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Başka bir oyuncunun adası için blok limitini + artır. +COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Bir oyuncuya bonus ekle. +COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: Başka bir oyuncunun adası için co-op oyuncu + limitini artır. +COMMAND_DESCRIPTION_ADMIN_ADD_CROP_GROWTH: Başka bir oyuncunun adası için bitki büyüme + çarpanını artır. +COMMAND_DESCRIPTION_ADMIN_ADD_EFFECT: Başka bir oyuncunun adası için bir ada efekti + ekle. +COMMAND_DESCRIPTION_ADMIN_ADD_ENTITY_LIMIT: Başka bir oyuncunun adası için varlık + limitini artır. +COMMAND_DESCRIPTION_ADMIN_ADD_GENERATOR: Çakıl taşı jeneratörü için bir materyalin + yüzdesini ekle. +COMMAND_DESCRIPTION_ADMIN_ADD_MOB_DROPS: Başka bir oyuncunun adası için mob düşürme + çarpanını artır. +COMMAND_DESCRIPTION_ADMIN_ADD_SIZE: Başka bir oyuncunun ada boyutunu genişlet. +COMMAND_DESCRIPTION_ADMIN_ADD_SPAWNER_RATES: Başka bir oyuncunun adası için spawner + oranları çarpanını artır. +COMMAND_DESCRIPTION_ADMIN_ADD_TEAM_LIMIT: Başka bir oyuncunun adası için üye limitini + artır. +COMMAND_DESCRIPTION_ADMIN_ADD_WARPS_LIMIT: Bir adanın ışınlanma limitini artır. +COMMAND_DESCRIPTION_ADMIN_BONUS: Bir oyuncuya bonus ver. +COMMAND_DESCRIPTION_ADMIN_BYPASS: Bypass modunu aç/kapat. +COMMAND_DESCRIPTION_ADMIN_CHEST: Başka bir adanın ada sandığını aç. +COMMAND_DESCRIPTION_ADMIN_CLEAR_GENERATOR: Belirli bir ada için jeneratör oranlarını + temizle. +COMMAND_DESCRIPTION_ADMIN_CLOSE: Bir adayı halka kapat. +COMMAND_DESCRIPTION_ADMIN_CMD_ALL: Tüm adaların üyeleri için bir komut çalıştır. +COMMAND_DESCRIPTION_ADMIN_COUNT: Belirli bir adadaki blok sayısını kontrol et. +COMMAND_DESCRIPTION_ADMIN_DATA: Oyuncuların veya adaların kalıcı verileriyle etkileşime + geç. +COMMAND_DESCRIPTION_ADMIN_DEBUG: Hata ayıklama çıktılarını aç/kapat. +COMMAND_DESCRIPTION_ADMIN_DEL_WARP: Bir ada için bir ışınlanma noktasını sil. +COMMAND_DESCRIPTION_ADMIN_DEMOTE: Başka bir oyuncunun adasındaki bir üyeyi rütbe düşür. +COMMAND_DESCRIPTION_ADMIN_DEPOSIT: Başka bir oyuncunun ada bankasına para yatır. +COMMAND_DESCRIPTION_ADMIN_DISBAND: Başka bir oyuncunun adasını kalıcı olarak dağıt. +COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Bir oyuncuya ada dağıtma hakkı ver. +COMMAND_DESCRIPTION_ADMIN_IGNORE: En iyi adalardan bir adayı yoksay. +COMMAND_DESCRIPTION_ADMIN_JOIN: Davet olmadan bir adaya katıl. +COMMAND_DESCRIPTION_ADMIN_KICK: Bir oyuncuyu adasından at. +COMMAND_DESCRIPTION_ADMIN_MODULES: Eklentinin modüllerini yönet. +COMMAND_DESCRIPTION_ADMIN_MISSION: Bir oyuncu için bir görevin durumunu değiştir. +COMMAND_DESCRIPTION_ADMIN_MSG: Bir oyuncuya ön ek olmadan mesaj gönder. +COMMAND_DESCRIPTION_ADMIN_MSG_ALL: Tüm ada üyelerine ön ek olmadan mesaj gönder. +COMMAND_DESCRIPTION_ADMIN_NAME: Bir adanın adını değiştir. +COMMAND_DESCRIPTION_ADMIN_OPEN: Bir adayı halka aç. +COMMAND_DESCRIPTION_ADMIN_OPEN_MENU: Bir oyuncu için özel bir menü aç. +COMMAND_DESCRIPTION_ADMIN_PROMOTE: Başka bir oyuncunun adasındaki bir üyeyi rütbe + yükselt. +COMMAND_DESCRIPTION_ADMIN_PURGE: Adaları temizle. +COMMAND_DESCRIPTION_ADMIN_RANKUP: Bir ada için bir yükseltmeyi seviye atlat. +COMMAND_DESCRIPTION_ADMIN_RECALC: Bir adanın değerini yeniden hesapla. +COMMAND_DESCRIPTION_ADMIN_RELOAD: Eklentinin tüm yapılandırmalarını ve görevlerini + yeniden yükle. +COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Bir adadan blok limitini kaldır. +COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Bir oyuncu tarafından verilen tüm değerlendirmeleri + kaldır. +COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Bir ada için bir dünyayı sıfırla. +COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Eklenti için şematikler oluştur. +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: Bir adaya banka limiti belirle. +COMMAND_DESCRIPTION_ADMIN_SET_BIOME: Bir adanın biyomunu ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Belirli bir konumdaki blok miktarını ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Başka bir oyuncunun adası için blok limiti + belirle. +COMMAND_DESCRIPTION_ADMIN_SET_CHEST_ROW: Başka bir oyuncunun adası için sandık satırlarını + ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_COOP_LIMIT: Başka bir oyuncunun adası için co-op oyuncu + limitini ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Başka bir oyuncunun adası için bitki büyüme + çarpanını ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Bir oyuncunun ada dağıtma miktarını ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Başka bir oyuncunun adasının ada efekt seviyesini + ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Başka bir oyuncunun adası için varlık + limitini ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_LEADER: Bir adayı başkasına devret. +COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Başka bir oyuncunun adası için mob düşürme + çarpanını ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Tüm adalar için bir izne gerekli rolü ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_RATE: Başka bir oyuncunun değerlendirmesini ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_ROLE_LIMIT: Başka bir oyuncunun adası için rol limitini + ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_SETTINGS: Belirli bir ada için ayarları aç/kapat. +COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR: Çakıl taşı jeneratörü için bir materyalin + yüzdesini değiştir. +COMMAND_DESCRIPTION_ADMIN_SET_SIZE: Başka bir oyuncunun ada boyutunu değiştir. +COMMAND_DESCRIPTION_ADMIN_SET_SPAWN: Sunucunun doğuş konumunu ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_SPAWNER_RATES: Başka bir oyuncunun adası için spawner + oranları çarpanını ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_TEAM_LIMIT: Başka bir oyuncunun adası için üye limitini + ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_UPGRADE: Başka bir oyuncunun adası için bir yükseltmenin + seviyesini ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_WARPS_LIMIT: Bir adanın ışınlanma limitini ayarla. +COMMAND_DESCRIPTION_ADMIN_SETTINGS: Eklenti ayarları düzenleyicisini aç. +COMMAND_DESCRIPTION_ADMIN_SHOW: Bir ada hakkında bilgi al. +COMMAND_DESCRIPTION_ADMIN_SPAWN: Doğuş konumuna ışınlan. +COMMAND_DESCRIPTION_ADMIN_SPY: Sohbet casusluk modunu aç/kapat. +COMMAND_DESCRIPTION_ADMIN_STATS: Eklenti hakkında istatistikleri göster. +COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: Bir adanın bonusunu oluşturulan dünyalarla senkronize + et. +COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: Bir ada için yükseltme değerlerini senkronize + et. +COMMAND_DESCRIPTION_ADMIN_TELEPORT: Diğer adalara ışınlan. +COMMAND_DESCRIPTION_ADMIN_TITLE: Bir oyuncuya başlık gönder. +COMMAND_DESCRIPTION_ADMIN_TITLE_ALL: Tüm ada üyelerine başlık gönder. +COMMAND_DESCRIPTION_ADMIN_UNIGNORE: En iyi adalardan bir adayı yoksaymayı bırak. +COMMAND_DESCRIPTION_ADMIN_UNLOCK_WORLD: Bir ada için bir dünyanın kilidini aç. +COMMAND_DESCRIPTION_ADMIN_WITHDRAW: Başka bir oyuncunun ada bankasından para çek. +COMMAND_DESCRIPTION_BALANCE: Bir adanın bankasındaki para miktarını kontrol et. +COMMAND_DESCRIPTION_BAN: Adandan bir oyuncuyu yasakla. +COMMAND_DESCRIPTION_BANK: Adanın bankasını aç. +COMMAND_DESCRIPTION_BIOME: Adanın biyomunu değiştir. +COMMAND_DESCRIPTION_BORDER: Adaların sınır rengini değiştir. +COMMAND_DESCRIPTION_CHEST: Adanın sandığını aç. +COMMAND_DESCRIPTION_CLOSE: Adanı halka kapat. +COMMAND_DESCRIPTION_COOP: Adana bir oyuncuyu co-op olarak ekle. +COMMAND_DESCRIPTION_COOPS: co-oplar menüsünü aç. +COMMAND_DESCRIPTION_COUNTS: Adandaki blok sayılarını gör. +COMMAND_DESCRIPTION_CREATE: Yeni bir ada oluştur. +COMMAND_DESCRIPTION_DEL_WARP: Bir ada ışınlanmasını sil. +COMMAND_DESCRIPTION_DEMOTE: Adandaki bir üyeyi rütbe düşür. +COMMAND_DESCRIPTION_DEPOSIT: Kişisel hesabından adanın bankasına para yatır. +COMMAND_DESCRIPTION_DISBAND: Adanı kalıcı olarak dağıt. +COMMAND_DESCRIPTION_EXPEL: Adandan bir ziyaretçiyi kov. +COMMAND_DESCRIPTION_FLY: Ada uçuşunu aç/kapat. +COMMAND_DESCRIPTION_HELP: Tüm komutların listesi. +COMMAND_DESCRIPTION_INVITE: Adana bir oyuncuyu davet et. +COMMAND_DESCRIPTION_KICK: Adandan bir oyuncuyu at. +COMMAND_DESCRIPTION_LANG: Kişisel dilini değiştir. +COMMAND_DESCRIPTION_LEAVE: Adandan ayrıl. +COMMAND_DESCRIPTION_MEMBERS: Üyeler menüsünü aç. +COMMAND_DESCRIPTION_MISSION: Bir görevi tamamla. +COMMAND_DESCRIPTION_MISSIONS: Görevler menüsünü aç. +COMMAND_DESCRIPTION_NAME: Adanın adını değiştir. +COMMAND_DESCRIPTION_OPEN: Adanı halka aç. +COMMAND_DESCRIPTION_PANEL: Ada panelini aç. +COMMAND_DESCRIPTION_PARDON: Adandan bir oyuncunun yasağını kaldır. +COMMAND_DESCRIPTION_PERMISSIONS: Bir ada rolü için tüm izinleri al. +COMMAND_DESCRIPTION_PROMOTE: Adandaki bir üyeyi rütbe yükselt. +COMMAND_DESCRIPTION_RANKUP: Bir yükseltmeyi seviye atlat. +COMMAND_DESCRIPTION_RATE: Bir adayı değerlendir. +COMMAND_DESCRIPTION_RATINGS: Tüm ada değerlendirmelerini göster. +COMMAND_DESCRIPTION_SETTINGS: Ayarlar menüsünü aç. +COMMAND_DESCRIPTION_RECALC: Ada değerini yeniden hesapla. +COMMAND_DESCRIPTION_SET_DISCORD: Ada ödemeleri için adanın discordunu ayarla. +COMMAND_DESCRIPTION_SET_PAYPAL: Ada ödemeleri için adanın paypal e-postasını ayarla. +COMMAND_DESCRIPTION_SET_ROLE: Adandaki bir oyuncunun rolünü değiştir. +COMMAND_DESCRIPTION_SET_TELEPORT: Adanın ışınlanma konumunu değiştir. +COMMAND_DESCRIPTION_SET_WARP: Yeni bir ada ışınlanması oluştur. +COMMAND_DESCRIPTION_SHOW: Bir ada hakkında bilgi al. +COMMAND_DESCRIPTION_TEAM: Ada üyelerinin durumu hakkında bilgi al. +COMMAND_DESCRIPTION_TEAM_CHAT: Takım sohbet modunu aç/kapat. +COMMAND_DESCRIPTION_TELEPORT: Adana ışınlan. +COMMAND_DESCRIPTION_TOGGLE: Ada sınırlarını ve istiflenmiş blok yerleşimlerini aç/kapat. +COMMAND_DESCRIPTION_TOP: En iyi adalar panelini aç. +COMMAND_DESCRIPTION_TRANSFER: Adanın liderliğini devret. +COMMAND_DESCRIPTION_UNCOOP: Adandan bir oyuncuyu co-op üyeliğinden çıkar. +COMMAND_DESCRIPTION_UPGRADE: Yükseltmeler panelini aç. +COMMAND_DESCRIPTION_VALUE: Bir bloğun değerini al. +COMMAND_DESCRIPTION_VALUES: Değerler menüsünü aç. +COMMAND_DESCRIPTION_VISIT: Bir adanın ziyaretçi konumuna ışınlan. +COMMAND_DESCRIPTION_VISITORS: Ziyaretçiler menüsünü aç. +COMMAND_DESCRIPTION_WARP: Bir ada ışınlanmasına ışınlan. +COMMAND_DESCRIPTION_WARPS: Işınlanmalar menüsünü aç. +COMMAND_DESCRIPTION_WITHDRAW: Adanın bankasından kişisel hesabına para çek. +COMMAND_USAGE: '&cHatalı Kullanım: /{0}' +COOP_ANNOUNCEMENT: '&e&lAda | &7{0}, {1}''i co-op üyesi olarak ekledi.' +COOP_BANNED_PLAYER: '&c&lHata | &7Bu oyuncu adadan yasaklandı ve co-op olamaz.' +COOP_LIMIT_EXCEED: '&c&lHata | &7Ada, sahip olabileceği maksimum co-op oyuncu sayısına + ulaştı.' +CREATE_ISLAND: '&e&lAda | &7Yeni bir ada {0} konumunda {1}ms içinde oluşturuldu.' +CREATE_ISLAND_FAILURE: '&c&lHata | &7Adanı oluştururken bir hata oluştu. Lütfen sorunu + araştırmak için yöneticiyle iletişime geç.' +CREATE_WORLD_FAILURE: '&c&lHata | &7Dünyanı oluştururken bir hata oluştu. Lütfen sorunu + araştırmak için yöneticiyle iletişime geç.' +DEBUG_MODE_DISABLED: '&e&lHata Ayıklama | &7Hata ayıklama modu &cKAPALI&7.' +DEBUG_MODE_ENABLED: '&e&lHata Ayıklama | &7Hata ayıklama modu &aAÇIK&7.' +DEBUG_MODE_FILTER_ADD: '&e&lHata Ayıklama | &7Hata ayıklama filtresi {0} &aAÇIK&7.' +DEBUG_MODE_FILTER_CLEAR: '&e&lHata Ayıklama | &7Tüm hata ayıklama filtreleri &cKAPALI&7.' +DEBUG_MODE_FILTER_REMOVE: '&e&lHata Ayıklama | &7Hata ayıklama filtresi {0} &cKAPALI&7.' +DELETE_WARP: '&e&lAda | &7{0} ışınlanmasını sildin.' +DELETE_WARP_SIGN_BROKE: '&7&oO ışınlanma için bir tabela vardı, kırıldı...' +DEMOTE_LEADER: '&c&lHata | &7Ada liderlerini rütbe düşüremezsin.' +DEMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne + sahip oyuncuları rütbe düşürebilirsin.' +DEMOTED_MEMBER: '&e&lAda | &7{0}''ı adasında {1} olarak rütbe düşürdün.' +DEPOSIT_ANNOUNCEMENT: '&e&lBanka | &7{0} ada bankasına ${1} yatırdı!' +DEPOSIT_ERROR: '&c&lHata | &7{0}.' +DESTROY_OUTSIDE_ISLAND: '&c&lHata | &7Koruma menzilinin dışında kıramazsın.' +DISBAND_ANNOUNCEMENT: '&e&lAda | &7Adan {0} tarafından dağıtıldı.' +DISBAND_GIVE: '&e&lAda | &7{0} dağıtma hakkı aldın.' +DISBAND_GIVE_ALL: '&e&lAda | &7Tüm oyunculara {0} dağıtma hakkı verdin.' +DISBAND_GIVE_OTHER: '&e&lAda | &7{1}''e {0} dağıtma hakkı verdin.' +DISBAND_ISLAND_BALANCE_REFUND: '&7&oAdan dağıtıldı ve ada bankasından hesabına ${0} + dolar iade edildi.' +DISBAND_SET: '&e&lAda | &7Dağıtma sayın {0} olarak ayarlandı.' +DISBAND_SET_ALL: '&e&lAda | &7Tüm oyuncuların dağıtma sayısını {0} olarak ayarladın.' +DISBAND_SET_OTHER: '&e&lAda | &7{0}''ın dağıtma sayısını {1} olarak ayarladın.' +DISBANDED_ISLAND: '&e&lAda | &7Adanı dağıttın.' +DISBANDED_ISLAND_OTHER: '&e&lAda | &7{0}''ın adasını dağıttın.' +DISBANDED_ISLAND_OTHER_NAME: '&e&lAda | &7{0} adasını dağıttın.' +ENTER_PVP_ISLAND: '&7&oPVP etkin olan bir adaya ışınlandın. Sonraki 10 saniye boyunca + PVP''ye karşı dokunulmazsın...' +EXPELLED_PLAYER: '&e&lAda | &7{0} adadan kovuldu.' +FORMAT_QUAD: Q +FORMAT_TRILLION: T +FORMAT_BILLION: B +FORMAT_MILLION: M +FORMAT_THOUSANDS: K +FORMAT_SECONDS_NAME: saniye +FORMAT_SECOND_NAME: saniye +FORMAT_MINUTES_NAME: dakika +FORMAT_MINUTE_NAME: dakika +FORMAT_HOURS_NAME: saat +FORMAT_HOUR_NAME: saat +FORMAT_DAYS_NAME: gün +FORMAT_DAY_NAME: gün +GENERATOR_CLEARED: '&e&lAda | &7{0}''ın adası için jeneratör miktarları başarıyla + temizlendi.' +GENERATOR_CLEARED_NAME: '&e&lAda | &7{0} adasının jeneratör miktarları başarıyla temizlendi.' +GENERATOR_CLEARED_ALL: '&e&lAda | &7Tüm adalar için jeneratör miktarları başarıyla + temizlendi.' +GENERATOR_UPDATED: '&e&lAda | &7{0}''ın jeneratör miktarı başarıyla {1}''in adasına + güncellendi.' +GENERATOR_UPDATED_NAME: '&e&lAda | &7{0}''ın jeneratör miktarı başarıyla {1} adasına + güncellendi.' +GENERATOR_UPDATED_ALL: '&e&lAda | &7{0}''ın jeneratör miktarı tüm adalar için başarıyla + güncellendi.' +GLOBAL_COMMAND_EXECUTED: '&e&lAda | &7Komut {0}''ın ada üyelerinde başarıyla çalıştırıldı!' +GLOBAL_COMMAND_EXECUTED_NAME: '&e&lAda | &7Komut {0} adasının üyelerinde başarıyla + çalıştırıldı!' +GLOBAL_MESSAGE_SENT: '&e&lAda | &7{0}''ın ada üyelerine mesaj başarıyla gönderildi!' +GLOBAL_MESSAGE_SENT_NAME: '&e&lAda | &7{0} adasının üyelerine mesaj başarıyla gönderildi!' +GLOBAL_TITLE_SENT: '&e&lAda | &7{0}''ın ada üyelerine başlık başarıyla gönderildi!' +GLOBAL_TITLE_SENT_NAME: '&e&lAda | &7{0} adasının üyelerine başlık başarıyla gönderildi!' +GOT_BANNED: '&e&lAda | &7{0}''ın adasından YASAKLANDIN.' +GOT_DEMOTED: '&e&lAda | &7Adanda {0} olarak rütbe düşürüldün.' +GOT_EXPELLED: '&e&lAda | &7&o{0} tarafından adadan kovuldun.' +GOT_INVITE: '&e&lAda | &7{0} seni adasına davet etti.' +GOT_INVITE_TOOLTIP: '&7Daveti kabul etmek için mesaja tıkla.' +GOT_KICKED: '&e&lAda | &7{0} tarafından adandan atıldın.' +GOT_PROMOTED: '&e&lAda | &7Adanda {0} olarak rütbe yükseltildin.' +GOT_REVOKED: '&e&lAda | &7{0} adasına olan davetini geri çekti.' +GOT_UNBANNED: '&e&lAda | &7{0}''ın adasından YASAĞIN KALDIRILDI.' +HIT_ISLAND_MEMBER: '&c&lHata | &7Ada üyelerine vuramazsın.' +HIT_PLAYER_IN_ISLAND: '&c&lHata | &7Adaların içindeki oyunculara vuramazsın.' +IGNORED_ISLAND: '&e&lAda | &7{0}''ın adası artık en iyi adalardan yoksayılıyor.' +IGNORED_ISLAND_NAME: '&e&lAda | &7{0} adası artık en iyi adalardan yoksayılıyor.' +INTERACT_OUTSIDE_ISLAND: '&c&lHata | &7Koruma menzilinin dışında etkileşime geçemezsin.' +INVALID_AMOUNT: '&c&lHata | &7Geçersiz miktar {0}.' +INVALID_BIOME: '&c&lHata | &7Geçersiz biyom {0}.' +INVALID_BLOCK: '&c&lHata | &7Geçersiz blok konumu {0}.' +INVALID_BORDER_COLOR: '&c&lHata | &7Geçersiz sınır rengi {0}.' +INVALID_EFFECT: '&c&lHata | &7Geçersiz efekt {0}.' +INVALID_ENTITY: '&c&lHata | &7Geçersiz varlık {0}.' +INVALID_ENVIRONMENT: '&c&lHata | &7Geçersiz dünya {0}.' +INVALID_INTERVAL: '&c&lHata | &7Geçersiz aralık {0}.' +INVALID_ISLAND: '&c&lHata | &7Bir adan yok.' +INVALID_ISLAND_LOCATION: '&c&lHata | &7Konumunda bir ada bulunmuyor.' +INVALID_ISLAND_OTHER: '&c&lHata | &7{0}''ın bir adası yok.' +INVALID_ISLAND_OTHER_NAME: '&c&lHata | &7{0} adında bir ada bulunmuyor.' +INVALID_ISLAND_PERMISSION: | + &c&lHata | &7Ada izni {0} bulunamadı. + &c&lHata | &7Ada İzinleri: {1} +INVALID_LEVEL: '&c&lHata | &7Geçersiz seviye {0}.' +INVALID_LIMIT: '&c&lHata | &7Geçersiz limit {0}.' +INVALID_MATERIAL: '&c&lHata | &7Geçersiz materyal {0}.' +INVALID_MATERIAL_DATA: '&c&lHata | &7Geçersiz materyal-veri {0}.' +INVALID_MENU: '&c&lError | &7Invalid menu {0}.' +INVALID_MISSION: '&c&lHata | &7Geçersiz görev {0}.' +INVALID_MODULE: '&c&lHata | &7Geçersiz modül {0}.' +INVALID_MULTIPLIER: '&c&lHata | &7Geçersiz çarpan {0}.' +INVALID_PAGE: '&c&lHata | &7Geçersiz sayfa {0}.' +INVALID_PERCENTAGE: '&c&lHata | &7Yüzde 0 ile 100 arasında olmalıdır.' +INVALID_PLAYER: '&c&lHata | &7{0} adında bir oyuncu bulunamadı.' +INVALID_RATE: | + &c&lHata | &7{0} adında bir değerlendirme bulunamadı. + &c&lHata | &7Ada Değerlendirmeleri: {1} +INVALID_ROWS: '&c&lHata | &7Geçersiz satır sayısı: {0}' +INVALID_ROLE: | + &c&lHata | &7Ada rolü {0} bulunamadı. + &c&lHata | &7Ada Rolleri: {1} +INVALID_SCHEMATIC: '&c&lHata | &7{0} adında bir şematik bulunamadı.' +INVALID_SETTINGS: | + &c&lHata | &7Ada ayarları {0} bulunamadı. + &c&lHata | &7Ada Ayarları: {1} +INVALID_SIZE: '&c&lHata | &7Geçersiz boyut {0}.' +INVALID_SLOT: '&c&lHata | &7Geçersiz yuva {0}.' +INVALID_TITLE: '&c&lHata | &7Geçersiz başlık girildi.' +INVALID_TOGGLE_MODE: '&c&lHata | &7{0} açılamaz/kapatılamaz.' +INVALID_UPGRADE: | + &c&lHata | &7{0} adında bir yükseltme bulunamadı. + &c&lHata | &7Yükseltmeler: {1} +INVALID_VISIT_LOCATION: '&c&lHata | &7Bu adanın ziyaretçi konumu yok.' +INVALID_VISIT_LOCATION_BYPASS: '&7&oBypass modundasın, adaya ışınlanıyorsun...' +INVALID_WARP: '&c&lHata | &7Geçersiz ışınlanma {0}.' +INVALID_WORLD: '&c&lHata | &7Geçersiz dünya {0}.' +INVITE_ANNOUNCEMENT: '&e&lAda | &7{0}, {1}''i adaya davet etti.' +INVITE_BANNED_PLAYER: '&c&lHata | &7Bu oyuncu adadan yasaklandı ve davet edilemez.' +INVITE_TO_FULL_ISLAND: '&c&lHata | &7Adana daha fazla üye davet edemezsin.' +ISLAND_ALREADY_CLOSED: '&c&lHata | &7Ada zaten halka kapalı.' +ISLAND_ALREADY_EXIST: '&c&lHata | &7Bu adla bir ada zaten var.' +ISLAND_ALREADY_OPENED: '&c&lHata | &7Ada zaten halka açık.' +ISLAND_BANK_EMPTY: '&e&lBanka | &7Ada bankası boş.' +ISLAND_BANK_SHOW: '&e&lBanka | &7Adanda ${0} var.' +ISLAND_BANK_SHOW_OTHER: '&e&lBanka | &7{0}''ın adasında ${1} var.' +ISLAND_BANK_SHOW_OTHER_NAME: '&e&lBanka | &7{0} adasında ${1} var.' +ISLAND_BEING_CALCULATED: '&c&lHata | &7Ada yeniden hesaplanırken bloklarla etkileşime + geçemezsin!' +ISLAND_CLOSED: '&e&lAda | &7Ada başarıyla halka kapatıldı.' +ISLAND_CREATE_PROCESS_FAIL: '&c&lHata | &7Zaten devam eden bir ada oluşturma görevin + var.' +ISLAND_CREATE_PROCCESS_REQUEST: '&e&lAda | &7İsteğiniz işleniyor...' +ISLAND_FLY_DISABLED: '&e&lUçuş | &7Ada uçuşu otomatik olarak &ckapatıldı&7.' +ISLAND_FLY_ENABLED: '&e&lUçuş | &7Ada uçuşu otomatik olarak &aaçıldı&7.' +ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lAda | &7&oDağıtılan bir adanın içindeydin, bu + yüzden doğuşa ışınlandın...' +ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE: '&e&lAda | &7&oPVP''nin açıldığı bir adanın içindeydin, + bu yüzden doğuşa ışınlandın...' +ISLAND_HELP_FOOTER: '&e&lSuperiorSkyblock &7Geliştiren: Ome_R' +ISLAND_HELP_HEADER: '&e&lSuperiorSkyblock &7Komutlar Listesi [{0}/{1}]:' +ISLAND_HELP_LINE: '&e/{0} &f- &7{1}' +ISLAND_HELP_NEXT_PAGE: '&e&lSuperiorSkyblock &7Sonraki sayfa için /is help {0} kullan.' +ISLAND_INFO_ADMIN_BANK_LIMIT: '&e&lAda | &7Banka Limiti: {0}' +ISLAND_INFO_ADMIN_BLOCKS_LIMITS: | + &e&lAda | &7Blok Limitleri: + {0} +ISLAND_INFO_ADMIN_BLOCKS_LIMITS_LINE: '&e&lAda | &7 {0}: {1}' +ISLAND_INFO_ADMIN_COOP_LIMIT: '&e&lAda | &7co-op Limiti: {0}' +ISLAND_INFO_ADMIN_CROPS_MULTIPLIER: '&e&lAda | &7Bitki Çarpanı: {0}' +ISLAND_INFO_ADMIN_DROPS_MULTIPLIER: '&e&lAda | &7Düşürme Çarpanı: {0}' +ISLAND_INFO_ADMIN_ISLAND_EFFECTS: | + &e&lAda | &7Ada Efektleri: + {0} +ISLAND_INFO_ADMIN_ISLAND_EFFECTS_LINE: '&e&lAda | &7 {0}: {1}' +ISLAND_INFO_ADMIN_ENTITIES_LIMITS: | + &e&lAda | &7Varlık Limitleri: + {0} +ISLAND_INFO_ADMIN_ENTITIES_LIMITS_LINE: '&e&lAda | &7 {0}: {1}' +ISLAND_INFO_ADMIN_GENERATOR_RATES: | + &e&lAda | &7Jeneratör Oranları ({1}): + {0} +ISLAND_INFO_ADMIN_GENERATOR_RATES_LINE: '&e&lAda | &7 {0}: %{1} ({2})' +ISLAND_INFO_ADMIN_ROLE_LIMITS: | + &e&lAda | &7Rol Limitleri: + {0} +ISLAND_INFO_ADMIN_ROLE_LIMITS_LINE: '&e&lAda | &7 {0}: {1}' +ISLAND_INFO_ADMIN_SIZE: '&e&lAda | &7Sınır Boyutu: {0}' +ISLAND_INFO_ADMIN_SPAWNERS_MULTIPLIER: '&e&lAda | &7Spawner Çarpanı: {0}' +ISLAND_INFO_ADMIN_TEAM_LIMIT: '&e&lAda | &7Takım Limiti: {0}' +ISLAND_INFO_ADMIN_UPGRADES: | + &e&lAda | &7Yükseltmeler: + {0} +ISLAND_INFO_ADMIN_UPGRADE_LINE: '&e&lAda | &7 {0}: {1}' +ISLAND_INFO_ADMIN_VALUE_SYNCED: '&a∞' +ISLAND_INFO_ADMIN_WARPS_LIMIT: '&e&lAda | &7Işınlanma Limiti: {0}' +ISLAND_INFO_BANK: '&e&lAda | &7Banka: {0}' +ISLAND_INFO_BONUS: '&e&lAda | &7Değer Bonusu: {0}' +ISLAND_INFO_BONUS_LEVEL: '&e&lAda | &7Seviye Bonusu: {0}' +ISLAND_INFO_CREATION_TIME: '&e&lAda | &7Oluşturma Süresi: {0}' +ISLAND_INFO_DISCORD: '&e&lAda | &7Discord: {0}' +ISLAND_INFO_FOOTER: '' +ISLAND_INFO_HEADER: '' +ISLAND_INFO_LAST_TIME_UPDATED: '&e&lAda | &7Son Güncelleme: {0} önce' +ISLAND_INFO_LAST_TIME_UPDATED_CURRENTLY_ACTIVE: '&e&lAda | &7Son Güncelleme: &aŞu + Anda Aktif' +ISLAND_INFO_LEVEL: '&e&lAda | &7Seviye: {0}' +ISLAND_INFO_LOCATION: '&e&lAda | &7Ev: {0}' +ISLAND_INFO_NAME: '&e&lAda | &7Adı: {0}' +ISLAND_INFO_OWNER: '&e&lAda | &7Lider: {0}' +ISLAND_INFO_PAYPAL: '&e&lAda | &7Paypal: {0}' +ISLAND_INFO_PLAYER_LINE: '&e&lAda | &7 - {0}' +ISLAND_INFO_RATE: '&e&lAda | &7Değerlendirme: {0} &7({1}/5) - {2} toplam değerlendirme.' +ISLAND_INFO_RATE_EMPTY_SYMBOL: '&f✧' +ISLAND_INFO_RATE_SYMBOL: ✦ +ISLAND_INFO_RATE_ONE_COLOR: '&4' +ISLAND_INFO_RATE_TWO_COLOR: '&6' +ISLAND_INFO_RATE_THREE_COLOR: '&e' +ISLAND_INFO_RATE_FOUR_COLOR: '&a' +ISLAND_INFO_RATE_FIVE_COLOR: '&2' +ISLAND_INFO_ROLES: | + &e&lAda | &7{0}lar: + {1} +ISLAND_INFO_VISITORS_COUNT: '&e&lAda | &7Ziyaretçi Sayısı: {0}' +ISLAND_INFO_WORTH: '&e&lAda | &7Değer: {0}' +ISLAND_OPENED: '&e&lAda | &7Ada başarıyla halka açıldı.' +ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lÖnizleme | &7Çok uzaklaştın ve artık önizleme + modunda değilsin.' +ISLAND_PREVIEW_CANCEL: '&e&lÖnizleme | &7Önizleme modunu iptal ettin.' +ISLAND_PREVIEW_CONFIRM_TEXT: ONAYLA +ISLAND_PREVIEW_CANCEL_TEXT: İPTAL ET +ISLAND_PREVIEW_START: | + &e&lÖnizleme | &7{0} şematiği için önizleme modunu başlattın. + &e&lÖnizleme | &7Yeni bir ada oluşturmak için &a&lONAYLA &7yaz, veya önizleme modunu iptal etmek için &c&lİPTAL ET &7yaz. + &e&lÖnizleme | &7Ada alanından ayrılamazsın, aksi takdirde önizleme modu otomatik olarak iptal edilir. +ISLAND_PROTECTED: '&c&lHata | &7Bu ada korumalı.' +ISLAND_PROTECTED_OPPED: '&7&o"/is admin bypass" komutunu kullanarak bu kısıtlamayı + atlayabilirsin.' +ISLAND_TEAM_STATUS_FOOTER: '' +ISLAND_TEAM_STATUS_HEADER: '&e&lAda | &7{0}''ın Adası Üyeleri &8[&e{1}&8/&e{2}&8]&7:' +ISLAND_TEAM_STATUS_OFFLINE: '&c(Çevrimdışı)' +ISLAND_TEAM_STATUS_ONLINE: '&a(Çevrimiçi)' +ISLAND_TEAM_STATUS_ROLES: '&e&lAda | &7 * [{0}] {1} {2} &7({3})' +ISLAND_TOP_STATUS_OFFLINE: '&c(Çevrimdışı)' +ISLAND_TOP_STATUS_ONLINE: '&a(Çevrimiçi)' +ISLAND_WARP_PUBLIC: '' +ISLAND_WARP_PRIVATE: '&c[Özel]' +ISLAND_WAS_CLOSED: '&e&lAda | &7&oİçinde bulunduğun ada kapatıldı ve doğuşa ışınlandın...' +ISLAND_WORTH_ERROR: '&c&lHata | &7Adanı hesaplarken beklenmedik bir hata oluştu. Sorun + devam ederse yöneticilerle iletişime geç.' +ISLAND_WORTH_RESULT: '&e&lAda | &7Adanın değeri {0} [Seviye {1}]' +ISLAND_WORTH_TIME_OUT: '&c&lHata | &7Hesaplama görevi zaman aşımına uğradı. Daha sonra + tekrar dene...' +JOIN_ADMIN_ANNOUNCEMENT: '&e&lAda | &7{0} adana katıldı.' +JOIN_ANNOUNCEMENT: '&e&lAda | &7{0} adana katıldı.' +JOIN_FULL_ISLAND: '&c&lHata | &7Bu ada, izin verilen maksimum üye sayısına ulaştı.' +JOIN_WHILE_IN_ISLAND: '&c&lHata | &7Zaten bir adadasın.' +JOINED_ISLAND: '&e&lAda | &7{0}''ın adasına katıldın.' +JOINED_ISLAND_NAME: '&e&lAda | &7{0} adasına katıldın.' +JOINED_ISLAND_AS_COOP: '&e&lAda | &7Artık {0}''ın adasında co-op üyesisin.' +JOINED_ISLAND_AS_COOP_NAME: '&e&lAda | &7Artık {0} adasında co-op üyesisin.' +KICK_ANNOUNCEMENT: '&e&lAda | &7{0}, {1} tarafından adadan atıldı.' +KICK_ISLAND_LEADER: '&c&lHata | &7Ada liderini atamazsın, bunun yerine /is admin disband + kullan.' +KICK_PLAYERS_WITH_LOWER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne sahip + oyuncuları atabilirsin.' +LACK_CHANGE_PERMISSION: '&c&lHata | &7Bu izni başka rollere değiştirebilmek için bu + izne sahip olmalısın.' +LAST_ROLE_DEMOTE: '&c&lHata | &7Bu oyuncuyu artık rütbe düşüremezsin.' +LAST_ROLE_PROMOTE: '&c&lHata | &7Bu oyuncuyu artık rütbe yükseltemezsin.' +LEAVE_ANNOUNCEMENT: '&e&lAda | &7{0} adadan ayrıldı.' +LEAVE_ISLAND_AS_LEADER: |- + &c&lHata | &7Sahibi olduğun adandan ayrılamazsın. + &c&lHata | &7Liderliği /is transfer kullanarak devredebilirsin.' +LEFT_ISLAND: '&e&lAda | &7Adandan ayrıldın.' +LEFT_ISLAND_COOP: '&e&lAda | &7Artık {0}''ın adasında co-op üyesi değilsin.' +LEFT_ISLAND_COOP_NAME: '&e&lAda | &7Artık {0} adasında co-op üyesi değilsin.' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the + island {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' +MATERIAL_NOT_SOLID: '&c&lHata | &7Katı bir materyal sağlamalısın.' +MAXIMUM_LEVEL: '&c&lHata | &7Bu yükseltme için maksimum seviye {0}.' +MESSAGE_SENT: '&e&lAda | &7{0}''e mesaj başarıyla gönderildi!' +MISSION_CANNOT_COMPLETE: '&c&lHata | &7Bu görevi henüz tamamlayamazsın.' +MISSION_NO_AUTO_REWARD: '&e&lGörev | &7{0}''i bitirmek için gerekli tüm materyallere + sahipsin - tamamlamak için /is missions kullan!' +MISSION_NOT_COMPLETE_REQUIRED_MISSIONS: '&c&lHata | &7Bu görevi tamamlamadan önce + {0}''i tamamlamalısın.' +MISSION_STATUS_COMPLETE: '&e&lGörev | &7{1} için {0} görevinin durumu tamamlandı olarak + değiştirildi.' +MISSION_STATUS_COMPLETE_ALL: '&e&lGörev | &7{0} için tüm görevlerin durumu tamamlandı + olarak değiştirildi.' +MISSION_STATUS_RESET: '&e&lGörev | &7{1} için {0} görevinin durumu sıfırlandı.' +MISSION_STATUS_RESET_ALL: '&e&lGörev | &7{0} için tüm görevlerin durumu sıfırlandı.' +MODULE_ALREADY_INITIALIZED: '&e&lModül | &7Bu modül zaten yüklü.' +MODULE_INFO: | + &e&lModül | &7{0} geliştiren: {1} + &e&lModül | &7&m-------------------- + &e&lModül | &7{2} +MODULE_LOADED_SUCCESS: '&e&lModül | &7{0} modülü başarıyla yüklendi.' +MODULE_LOADED_FAILURE: '&e&lModül | &7{0} modülü yüklenemedi. Daha fazla bilgi için + konsolu kontrol et.' +MODULE_UNLOADED_SUCCESS: '&e&lModül | &7Modül başarıyla kaldırıldı.' +MODULES_LIST: '&fModüller ({0}): {1}' +MODULES_LIST_MODULE_NAME: '&a{0}' +MODULES_LIST_SEPARATOR: '&f, ' +NAME_ANNOUNCEMENT: '&e&lAda | &7{0} adasının adını {1} olarak değiştirdi.' +NAME_BLACKLISTED: '&c&lHata | &7Bu adı kullanamazsın.' +NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' +NAME_SAME_AS_PLAYER: '&c&lHata | &7Oyuncu adlarını ada adı olarak kullanamazsın.' +NAME_TOO_LONG: '&c&lHata | &7Ada adları 16 karakterden uzun olamaz.' +NAME_TOO_SHORT: '&c&lHata | &7Ada adları 3 karakterden kısa olamaz.' +NO_BAN_PERMISSION: '&c&lHata | &7Oyuncuları yasaklayabilmek için en az {0} olmalısın.' +NO_CLOSE_BYPASS: '&c&lHata | &7Bu ada halka açık değil.' +NO_CLOSE_PERMISSION: '&c&lHata | &7Adanı halka kapatabilmek için en az {0} olmalısın.' +NO_COMMAND_PERMISSION: '&fBilinmeyen komut. Yardım için "/help" yaz.' +NO_COOP_PERMISSION: '&c&lHata | &7Oyuncuları co-op üyesi olarak ekleyebilmek için + en az {0} olmalısın.' +NO_DELETE_WARP_PERMISSION: '&c&lHata | &7Işınlanmaları silebilmek için en az {0} olmalısın.' +NO_DEMOTE_PERMISSION: '&c&lHata | &7Oyuncuları rütbe düşürebilmek için en az {0} olmalısın.' +NO_DEPOSIT_PERMISSION: '&c&lHata | &7Ada bankasına para yatırabilmek için en az {0} + olmalısın.' +NO_DISBAND_PERMISSION: '&c&lHata | &7Adanı dağıtabilmek için en az {0} olmalısın.' +NO_EXPEL_PERMISSION: '&c&lHata | &7Adandan oyuncuları kovabilmek için en az {0} olmalısın.' +NO_INVITE_PERMISSION: '&c&lHata | &7Oyuncuları davet edebilmek için en az {0} olmalısın.' +NO_ISLAND_CHEST_PERMISSION: '&c&lHata | &7Ada sandığına erişebilmek için en az {0} + olmalısın.' +NO_ISLAND_INVITE: '&c&lHata | &7Bu adadan herhangi bir davet bulunamadı.' +NO_ISLANDS_TO_PURGE: '&c&lHata | &7Temizlenecek ada bulunamadı.' +NO_KICK_PERMISSION: '&c&lHata | &7Oyuncuları atabilmek için en az {0} olmalısın.' +NO_MORE_DISBANDS: '&c&lHata | &7Daha fazla ada dağıtamazsın.' +NO_MORE_WARPS: '&c&lHata | &7Adanın daha fazla ışınlanma noktası olamaz.' +NO_NAME_PERMISSION: '&c&lHata | &7Adanın adını değiştiremezsin.' +NO_OPEN_PERMISSION: '&c&lHata | &7Adanı halka açabilmek için en az {0} olmalısın.' +NO_PERMISSION_CHECK_PERMISSION: '&c&lHata | &7İzinler hakkında bilgi alabilmek için + en az {0} olmalısın.' +NO_PROMOTE_PERMISSION: '&c&lHata | &7Oyuncuları rütbe yükseltebilmek için en az {0} + olmalısın.' +NO_RANKUP_PERMISSION: '&c&lHata | &7Yükseltmeleri seviye atlamak için iznin yok.' +NO_RATINGS_PERMISSION: '&c&lHata | &7Değerlendirmeleri kontrol edebilmek için en az + {0} olmalısın.' +NO_SET_BIOME_PERMISSION: '&c&lHata | &7Ada biyomunu değiştirebilmek için en az {0} + olmalısın.' +NO_SET_DISCORD_PERMISSION: '&c&lHata | &7Ada discordunu değiştirebilmek için en az + {0} olmalısın.' +NO_SET_HOME_PERMISSION: '&c&lHata | &7Adanın ışınlanma konumunu ayarlayabilmek için + en az {0} olmalısın.' +NO_SET_PAYPAL_PERMISSION: '&c&lHata | &7Ada paypal e-postasını değiştirebilmek için + en az {0} olmalısın.' +NO_SET_ROLE_PERMISSION: '&c&lHata | &7Oyuncular için rol ayarlayabilmek için en az + {0} olmalısın.' +NO_SET_SETTINGS_PERMISSION: '&c&lHata | &7Ada ayarlarını değiştirebilmek için en az + {0} olmalısın.' +NO_SET_WARP_PERMISSION: '&c&lHata | &7Ada ışınlanmalarını ayarlayabilmek için en az + {0} olmalısın.' +NO_TRANSFER_PERMISSION: '&c&lHata | &7Liderliği devredebilmek için adanın lideri olmalısın.' +NO_UNCOOP_PERMISSION: '&c&lHata | &7Oyuncuları co-op üyeliğinden çıkarabilmek için + en az {0} olmalısın.' +NO_UPGRADE_PERMISSION: '&c&lHata | &7Başka bir seviyeye yükseltmek için iznin yok.' +NO_WITHDRAW_PERMISSION: '&c&lHata | &7Ada bankasından para çekebilmek için en az {0} + olmalısın.' +NOT_ENOUGH_MONEY_TO_DEPOSIT: '&c&lHata | &7Adanın bankasına {0} dolar yatırmak için + yeterli paran yok.' +NOT_ENOUGH_MONEY_TO_UPGRADE: '&c&lHata | &7Yeterli paran yok.' +NOT_ENOUGH_MONEY_TO_WARP: '&c&lHata | &7Ada ışınlanmalarını kullanmak için yeterli + paran yok.' +OPEN_MENU_WHILE_SLEEPING: '&7&oMenülerle etkileşime geçmek için çok mu yorgunsun, + sence de öyle değil mi?' +PANEL_TOGGLE_OFF: |- + &e&lPanel | &7Ada paneli &cKAPALI&7. + &e&lPanel | &7/is çalıştırmak seni adaya ışınlayacak. +PANEL_TOGGLE_ON: |- + &e&lPanel | &7Ada paneli &aAÇIK&7. + &e&lPanel | &7/is çalıştırmak paneli senin için açacak. +PERMISSION_CHANGED: '&e&lAda | &7{1}''in adasının {0} izni başarıyla güncellendi.' +PERMISSION_CHANGED_NAME: '&e&lAda | &7{1} adasının {0} izni başarıyla güncellendi.' +PERMISSION_CHANGED_ALL: '&e&lAda | &7Tüm adalar için {0} izni başarıyla güncellendi.' +PERSISTENT_DATA_EMPTY: '&c&lHata | &7Sorgun için veri bulunamadı.' +PERSISTENT_DATA_MODIFY: '&e&lVeri | &7{0} için veri {1} ile {2} olarak başarıyla ayarlandı.' +PERSISTENT_DATA_SHOW: '&e&lVeri | &7{0} verisi: &f{{1}}' +PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' +PERSISTENT_DATA_SHOW_SPACER: '&f, ' +PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' +PERSISTENT_DATA_REMOVED: '&e&lVeri | &7{0} için {1} yolundan veri başarıyla kaldırıldı.' +PERMISSIONS_RESET_PLAYER: '&e&lAda | &7{0} için tüm izinler varsayılan değerlere başarıyla + sıfırlandı!' +PERMISSIONS_RESET_ROLES: '&e&lAda | &7Adanın tüm izinleri varsayılan değerlere başarıyla + sıfırlandı!' +PLACEHOLDER_NO: Hayır +PLACEHOLDER_YES: Evet +PLAYER_ALREADY_BANNED: '&c&lHata | &7Bu oyuncu zaten yasaklı.' +PLAYER_ALREADY_COOP: '&c&lHata | &7Bu oyuncu zaten co-op.' +PLAYER_ALREADY_IN_ISLAND: '&c&lHata | &7Bu oyuncu zaten bir adada.' +PLAYER_ALREADY_IN_ROLE: '&c&lHata | &7{0} zaten bir {1}.' +PLAYER_EXPEL_BYPASS: '&c&lHata | &7Bu kullanıcı adadan kovulamaz.' +PLAYER_JOIN_ANNOUNCEMENT: '&e&lAda | &7{0} sunucuya katıldı.' +PLAYER_NOT_BANNED: '&c&lHata | &7Bu oyuncu yasaklı değil.' +PLAYER_NOT_COOP: '&c&lHata | &7Bu oyuncu co-op değil.' +PLAYER_NOT_INSIDE_ISLAND: '&c&lHata | &7Bu oyuncu adanın içinde değil.' +PLAYER_NOT_ONLINE: '&c&lHata | &7Bu oyuncu çevrimiçi değil!' +PLAYER_QUIT_ANNOUNCEMENT: '&e&lAda | &7{0} sunucudan ayrıldı.' +PROMOTE_PLAYERS_WITH_LOWER_ROLE: '&c&lHata | &7Sadece senden daha düşük ada rolüne + sahip oyuncuları rütbe yükseltebilirsin.' +PROMOTED_MEMBER: '&e&lAda | &7{0}''ı adasında {1} olarak rütbe yükselttin.' +PURGE_CLEAR: '&e&lAda | &7Temizlenecek tüm sıralanmış adalar başarıyla temizlendi.' +PURGED_ISLANDS: |- + &e&lAda | &7Sunucu yeniden başladığında {0} ada temizlenecek. + &e&lAda | &7İstediğin zaman /is admin purge cancel kullanarak iptal edebilirsin.' +RANKUP_SUCCESS: '&e&lAda | &7{1}''in adası için {0} yükseltmesinin seviyesi başarıyla + güncellendi.' +RANKUP_SUCCESS_ALL: '&e&lAda | &7Tüm adalar için {0} yükseltmesinin seviyesi başarıyla + güncellendi.' +RANKUP_SUCCESS_NAME: '&e&lAda | &7{1} adası için {0} yükseltmesinin seviyesi başarıyla + güncellendi.' +RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' +RATE_ANNOUNCEMENT: '&e&lAda | &7{0} adanı 5 üzerinden {1} olarak değerlendirdi!.' +RATE_CHANGE_OTHER: '&e&lAda | &7{0}''ın değerlendirmesini {1} olarak değiştirdin.' +RATE_OWN_ISLAND: '&c&lHata | &7Kendi adanı değerlendiremezsin.' +RATE_REMOVE_ALL: '&e&lAda | &7{0}''ın tüm değerlendirmeleri başarıyla kaldırıldı.' +RATE_REMOVE_ALL_ISLANDS: '&e&lAda | &7Tüm adaların tüm değerlendirmeleri başarıyla + kaldırıldı.' +RATE_SUCCESS: '&e&lAda | &7Bu adayı {0} yıldızla değerlendirdin!' +REACHED_BLOCK_LIMIT: '&e&lYükseltmeler | &7Ada için {0} Bloğu limitine ulaştın.' +REACHED_ENTITY_LIMIT: '&e&lYükseltmeler | &7Varlık {0} için adanın limitine ulaştın.' +RECALC_ALREADY_RUNNING: '&c&lHata | &7Adan zaten yeniden hesaplanıyor.' +RECALC_ALREADY_RUNNING_OTHER: '&c&lHata | &7Bu ada zaten yeniden hesaplanıyor.' +RECALC_ALL_ISLANDS: '&e&lAda | &7Tüm adalar yeniden hesaplanıyor...' +RECALC_ALL_ISLANDS_DONE: '&e&lAda | &7Tüm adaların yeniden hesaplanması başarıyla + tamamlandı.' +RECALC_PROCCESS_REQUEST: '&e&lAda | &7İsteğiniz işleniyor...' +RELOAD_COMPLETED: '&e&lAda | &7Yeniden yükleme tamamlandı!' +RELOAD_PROCCESS_REQUEST: '&e&lAda | &7Yapılandırmalar yeniden yükleniyor...' +REVOKE_INVITE_ANNOUNCEMENT: '&e&lAda | &7{0}, {1}''e adaya olan davetini geri çekti.' +RESET_WORLD_SUCCEED: '&e&lAda | &7{1}''in adası için {0} dünyası başarıyla sıfırlandı.' +RESET_WORLD_SUCCEED_ALL: '&e&lAda | &7Tüm adalar için {0} dünyası başarıyla sıfırlandı.' +RESET_WORLD_SUCCEED_NAME: '&e&lAda | &7{1} adası için {0} dünyası başarıyla sıfırlandı.' +SAME_NAME_CHANGE: '&c&lHata | &7Mevcut ada adından farklı bir ad girmelisin.' +SCHEMATIC_LEFT_SELECT: '&e&lŞematikler | &7Konum #2 ({0}) seçildi.' +SCHEMATIC_NOT_READY: '&c&lHata | &7İki konum seçmedin.' +SCHEMATIC_PROCCESS_REQUEST: '&e&lŞematikler | &7İsteğiniz işleniyor...' +SCHEMATIC_READY_TO_CREATE: | + &e&lŞematikler | &7İki konum seçtin. Yeni bir şematik oluşturmak için /is admin schematic komutunu çalıştır. + &e&lŞematikler | &7Komutu çalıştırırken ışınlanma konumunda durduğundan emin ol. +SCHEMATIC_RIGHT_SELECT: '&e&lŞematikler | &7Konum #1 ({0}) seçildi.' +SCHEMATIC_SAVED: '&e&lŞematikler | &7Şematik başarıyla kaydedildi!' +SELF_ROLE_CHANGE: '&c&lHata | &7Kendi rolünü değiştiremezsin.' +SET_UPGRADE_LEVEL: '&e&lYükseltmeler | &7{1}''in adası için {0} seviyesi başarıyla + güncellendi.' +SET_UPGRADE_LEVEL_NAME: '&e&lYükseltmeler | &7{1} adası için {0} seviyesi başarıyla + güncellendi.' +SET_WARP: '&e&lAda | &7{0} konumunda yeni bir ışınlanma noktası başarıyla oluşturuldu.' +SET_WARP_OUTSIDE: '&c&lHata | &7Adanın dışında ışınlanma noktası ayarlayamazsın.' +SETTINGS_UPDATED: '&e&lAda | &7{1}''in adası için {0} ayarları başarıyla güncellendi.' +SETTINGS_UPDATED_NAME: '&e&lAda | &7{1} adası için {0} ayarları başarıyla güncellendi.' +SETTINGS_UPDATED_ALL: '&e&lAda | &7Tüm adalar için {0} ayarları başarıyla güncellendi.' +SIZE_BIGGER_MAX: '&c&lHata | &7Maksimum ada boyutundan daha büyük bir boyut ayarlayamazsın.' +SPAWN_TELEPORT_SUCCESS: '&e&lDoğuş | &7{0} başarıyla doğuşa ışınlandı.' +SPAWN_SET_SUCCESS: '&e&lDoğuş | &7Doğuş konumu {0} olarak başarıyla güncellendi.' +SPY_TEAM_CHAT_FORMAT: '&7[Casus] &e[{0}] {1}&f: &7{2}' +SYNC_UPGRADES: '&e&lYükseltmeler | &7{0}''ın adasının tüm yükseltme değerleri başarıyla + senkronize edildi.' +SYNC_UPGRADES_ALL: '&e&lYükseltmeler | &7Tüm adaların tüm yükseltme değerleri başarıyla + senkronize edildi.' +SYNC_UPGRADES_NAME: '&e&lYükseltmeler | &7{0} adasının tüm yükseltme değerleri başarıyla + senkronize edildi.' +TEAM_CHAT_FORMAT: '&e[{0}] {1}&f: &7{2}' +TELEPORT_LOCATION_OUTSIDE_ISLAND: '&c&lHata | &7Adanın içinde değilsin.' +TELEPORT_OUTSIDE_ISLAND: '&c&lHata | &7Koruma menzilinin dışına ışınlanamazsın.' +TELEPORT_WARMUP: '&7&o{0} içinde ışınlanacaksın... Hareket etme!' +TELEPORT_WARMUP_CANCEL: '&7&oHareket ettin ve ışınlanma iptal edildi.' +TITLE_SENT: '&e&lAda | &7{0}''e başlık başarıyla gönderildi!' +TELEPORTED_FAILED: '&e&lAda | &7Görünüşe göre bu adanın güvenli blokları yok. Lütfen + bir yetkiliyle iletişime geç.' +TELEPORTED_SUCCESS: '&e&lAda | &7Adana ışınlandın.' +TELEPORTED_TO_WARP: '&e&lAda | &7Bu ada ışınlanmasına başarıyla ışınlandın.' +TELEPORTED_TO_WARP_ANNOUNCEMENT: '&e&lAda | &7Oyuncu {0} {1} ada ışınlanmasına ışınlandı.' +TOGGLED_BYPASS_OFF: '&e&lBypass | &7Bypass modu &cKAPALI&7.' +TOGGLED_BYPASS_ON: '&e&lBypass | &7Bypass modu &aAÇIK&7.' +TOGGLED_FLY_OFF: '&e&lUçuş | &7Ada uçuşu &cKAPALI&7.' +TOGGLED_FLY_ON: '&e&lUçuş | &7Ada uçuşu &aAÇIK&7.' +TOGGLED_SCHEMATIC_OFF: '&e&lŞematikler | &7Şematik modu &cKAPALI&7.' +TOGGLED_SCHEMATIC_ON: |- + &e&lŞematikler | &7Şematik modu &aAÇIK&7. + &e&lŞematikler | &7Altın bir balta kullanarak bir alan seç. +TOGGLED_SPY_OFF: '&e&lCasus | &7Sohbet casusluğu &cKAPALI&7.' +TOGGLED_SPY_ON: '&e&lCasus | &7Sohbet casusluğu &aAÇIK&7.' +TOGGLED_STACKED_BLOCKS_OFF: '&e&lİstifleyici | &7Blok istifleyici &cKAPALI&7.' +TOGGLED_STACKED_BLOCKS_ON: '&e&lİstifleyici | &7Blok istifleyici &aAÇIK&7.' +TOGGLED_TEAM_CHAT_OFF: '&e&lSohbet | &7Takım sohbeti &cKAPALI&7.' +TOGGLED_TEAM_CHAT_ON: '&e&lSohbet | &7Takım sohbeti &aAÇIK&7.' +TOGGLED_WORLD_BORDER_OFF: '&e&lSınır | &7Dünya sınırı &cKAPALI&7.' +TOGGLED_WORLD_BORDER_ON: '&e&lSınır | &7Dünya sınırı &aAÇIK&7.' +TRANSFER_ADMIN: '&e&lAda | &7{0}''ın liderliğini {1}''e devrettin.' +TRANSFER_ADMIN_ALREADY_LEADER: '&c&lHata | &7{0} zaten adasının lideri.' +TRANSFER_ADMIN_DIFFERENT_ISLAND: '&c&lHata | &7Bu oyuncular aynı adalarda değil.' +TRANSFER_ADMIN_NOT_LEADER: '&c&lHata | &7Bu oyuncu hiçbir adanın lideri değil.' +TRANSFER_ALREADY_LEADER: '&c&lHata | &7Zaten bu adanın liderisin.' +TRANSFER_BROADCAST: '&e&lAda | &7Adanın liderliği {0}''e devredildi.' +UNBAN_ANNOUNCEMENT: '&e&lAda | &7{0}, {1} tarafından adadan YASAĞI KALDIRILDI.' +UNCOOP_ANNOUNCEMENT: '&e&lAda | &7{0}, {1}''i co-op üyeliğinden çıkardı.' +UNCOOP_AUTO_ANNOUNCEMENT: '&e&lAda | &7Çevrimiçi ada üyesi yok ve bu yüzden otomatik + olarak co-op üyeliğinden çıkarıldın.' +UNCOOP_LEFT_ANNOUNCEMENT: '&e&lAda | &7{0} oyundan ayrıldı ve artık co-op üyesi değil.' +UNIGNORED_ISLAND: '&e&lAda | &7{0}''ın adası artık en iyi adalardan yoksayılmıyor.' +UNIGNORED_ISLAND_NAME: '&e&lAda | &7{0} adası artık en iyi adalardan yoksayılmıyor.' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all + islands!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for + the island {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lDünyalar | &7{0} dünyan artık kilitli değil!' +UNSAFE_WARP: '&e&lAda | &7&oBu ışınlanma güvensiz görünüyor. Lütfen başka bir ışınlanmayı + dene.' +UPDATED_PERMISSION: '&e&lAda | &7{0} için izinler güncellendi.' +UPDATED_SETTINGS: '&e&lAda | &7Ada ayarları {0} güncellendi.' +UPGRADE_COOLDOWN_FORMAT: '&c&lHata | &7Sadece {0} içinde tekrar yükseltme yapabilirsin.' +VISITOR_BLOCK_COMMAND: '&c&lHata | &7Bu komutu başka adalarda kullanamazsın.' +WARP_ALREADY_EXIST: '&c&lHata | &7Bu adla bir ışınlanma noktası zaten var.' +WARP_CATEGORY_ICON_NEW_LORE: | + &e&lIşınlanmalar | &7Yeni bir açıklama gir (İptal etmek için "-cancel" yaz): + &e&lIşınlanmalar | &7Satırları "\n" kullanarak ayırabilirsin. +WARP_CATEGORY_ICON_NEW_NAME: '&e&lIşınlanmalar | &7Bir ad gir (İptal etmek için "-cancel" + yaz):' +WARP_CATEGORY_ICON_NEW_TYPE: '&e&lIşınlanmalar | &7Yeni bir materyal türü gir (İptal + etmek için "-cancel" yaz):' +WARP_CATEGORY_ICON_UPDATED: '&e&lIşınlanmalar | &7Kategorinin simgesi başarıyla güncellendi.' +WARP_CATEGORY_ILLEGAL_NAME: '&c&lHata | &7Işınlanma kategorisi adları boş olamaz.' +WARP_CATEGORY_NAME_TOO_LONG: '&c&lHata | Işınlanma kategorisi adları 255 karakterden + uzun olamaz.' +WARP_CATEGORY_SLOT: '&e&lIşınlanmalar | &7Yeni bir yuva gir (İptal etmek için "-cancel" + yaz):' +WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&lHata | &7Bu yuva zaten başka bir kategori tarafından + alınmış.' +WARP_CATEGORY_SLOT_SUCCESS: '&e&lIşınlanmalar | &7Kategorinin yuvası başarıyla {0} + olarak değiştirildi.' +WARP_CATEGORY_RENAME: '&e&lIşınlanmalar | &7Yeni bir ad gir (İptal etmek için "-cancel" + yaz):' +WARP_CATEGORY_RENAME_ALREADY_EXIST: '&c&lHata | &7Bu ad zaten başka bir kategori tarafından + alınmış.' +WARP_CATEGORY_RENAME_SUCCESS: '&e&lIşınlanmalar | &7Kategori adı başarıyla {0} olarak + değiştirildi.' +WARP_ICON_NEW_LORE: | + &e&lIşınlanmalar | &7Yeni bir açıklama gir (İptal etmek için "-cancel" yaz): + &e&lIşınlanmalar | &7Satırları "\n" kullanarak ayırabilirsin. +WARP_ICON_NEW_NAME: '&e&lIşınlanmalar | &7Bir ad gir (İptal etmek için "-cancel" yaz):' +WARP_ICON_NEW_TYPE: '&e&lIşınlanmalar | &7Yeni bir materyal türü gir (İptal etmek + için "-cancel" yaz):' +WARP_ICON_UPDATED: '&e&lIşınlanmalar | &7Işınlanmanın simgesi başarıyla güncellendi.' +WARP_ILLEGAL_NAME: '&c&lHata | &7Işınlanma adları boş olamaz.' +WARP_LOCATION_UPDATE: '&e&lIşınlanmalar | &7Işınlanmanın konumu senin konumuna başarıyla + güncellendi.' +WARP_NAME_TOO_LONG: '&c&lHata | Işınlanma adları 255 karakterden uzun olamaz.' +WARP_PUBLIC_UPDATE: '&e&lIşınlanmalar | &7Işınlanma başarıyla halka açıldı.' +WARP_PRIVATE_UPDATE: '&e&lIşınlanmalar | &7Işınlanma başarıyla halka kapatıldı.' +WARP_RENAME: '&e&lIşınlanmalar | &7Yeni bir ad gir (İptal etmek için "-cancel" yaz):' +WARP_RENAME_ALREADY_EXIST: '&c&lHata | &7Bu ad zaten başka bir ışınlanma tarafından + alınmış.' +WARP_RENAME_SUCCESS: '&e&lIşınlanmalar | &7Işınlanma adı başarıyla {0} olarak değiştirildi.' +WITHDRAW_ALL_MONEY: |- + &e&lBanka | &7Ada bankasında sadece {0} dolar var. + &e&lBanka | &7&oTüm para çekiliyor...' +WITHDRAW_ANNOUNCEMENT: '&e&lBanka | &7{0} ada bankasından ${1} çekti!' +WITHDRAW_ERROR: '&c&lHata | &7{0}.' +WITHDRAWN_MONEY: '&e&lBanka | &7{1}''in ada bankasından ${0} çektin!' +WITHDRAWN_MONEY_NAME: '&e&lBanka | &7{1} adasının bankasından ${0} çektin!' +WORLD_NOT_ENABLED: '&e&lDünyalar | &7Bu dünya sunucuda etkin değil.' +WORLD_NOT_UNLOCKED: '&e&lDünyalar | &7{0} dünyası henüz kilitli değil!' \ No newline at end of file diff --git a/src/main/resources/menus/player-language1_12.yml b/src/main/resources/menus/player-language1_12.yml index 98182f3de5..2b233318b4 100644 --- a/src/main/resources/menus/player-language1_12.yml +++ b/src/main/resources/menus/player-language1_12.yml @@ -11,7 +11,7 @@ previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ # % * + ^ ~ 1 @' - - '@ @ - = @ ! 2 @ @' + - '@ @ - = ! 2 3 @ @' - '@ @ @ @ @ @ @ @ @' items: @@ -103,6 +103,14 @@ items: name: '&eGerman' lore: - '&7Change language to German.' + '3': + language: 'tr-TR' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJiZWFmNTJlMWM0YmZjZDhhMWY0YzY5MTMyMzRiODQwMjQxYWE0ODgyOWMxNWFiYzZmZjhmZGY5MmNkODllIn19fQ==' + name: '&eTurkish' + lore: + - '&7Change language to Turkish.' sounds: '#': diff --git a/src/main/resources/menus/player-language1_13.yml b/src/main/resources/menus/player-language1_13.yml index fdd15362b9..abfbafe03c 100644 --- a/src/main/resources/menus/player-language1_13.yml +++ b/src/main/resources/menus/player-language1_13.yml @@ -11,7 +11,7 @@ previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ # % * + ^ ~ 1 @' - - '@ @ - = @ ! 2 @ @' + - '@ @ - = ! 2 3 @ @' - '@ @ @ @ @ @ @ @ @' items: @@ -92,6 +92,13 @@ items: name: '&eGerman' lore: - '&7Change language to German.' + '3': + language: 'tr-TR' + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJiZWFmNTJlMWM0YmZjZDhhMWY0YzY5MTMyMzRiODQwMjQxYWE0ODgyOWMxNWFiYzZmZjhmZGY5MmNkODllIn19fQ==' + name: '&eTurkish' + lore: + - '&7Change language to Turkish.' sounds: '#': From fa0e9e0098f72edc730c7e76767bddff38ad158c Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Jun 2025 21:03:34 +0300 Subject: [PATCH 206/600] Updated Vietnamese (#2484) --- src/main/resources/lang/vi-VN.yml | 60 +++++++++++++++---------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index b3130e6ff5..e22d65d921 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -44,12 +44,12 @@ BLOCK_LEVEL_WORTHLESS: '&e&lCấp Độ | &7Khối {0} vô giá trị.' BLOCK_VALUE: '&e&lĐáng giá | &7Khối {0} được đánh giá với {1}.' BLOCK_VALUE_WORTHLESS: '&e&lĐáng giá | &7Khối {0} vô giá trị.' BONUS_SET_SUCCESS: '&e&lĐảo | &7Cập nhật thành công phần thưởng đảo đến {0}.' -BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' -BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' -BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' -BORDER_PLAYER_COLOR_NAME_BLUE: 'Blue' -BORDER_PLAYER_COLOR_NAME_RED: 'Red' -BORDER_PLAYER_COLOR_NAME_GREEN: 'Green' +BONUS_SYNC_ALL: '&e&lĐảo | &7Đồng bộ thành công phần thưởng đảo đến tất cả các đảo.' +BONUS_SYNC_NAME: '&e&lĐảo | &7Đồng bộ thành công phần thưởng đảo đến {0}.' +BONUS_SYNC: '&e&lĐảo | &7Đồng bộ thành công phần thưởng đảo của {0}.' +BORDER_PLAYER_COLOR_NAME_BLUE: 'Xanh dương' +BORDER_PLAYER_COLOR_NAME_RED: 'Đỏ' +BORDER_PLAYER_COLOR_NAME_GREEN: 'Xanh lá' BORDER_PLAYER_COLOR_UPDATED: '&e&lBiên Giới | &7Thành công thay đổi màu giới hạn đảo của bạn thành {0}.' BUILD_OUTSIDE_ISLAND: '&c&lLỗi | &7Bạn không thể xây dựng ngoài phạm vi bảo vệ của @@ -337,12 +337,12 @@ COOP_BANNED_PLAYER: '&c&lLỗi | &7Người chơi này đang bị cấm khỏi COOP_LIMIT_EXCEED: '&c&lLỗi | &7Bạn đã đạt số lượng người chơi co-op tối đa mà hòn đảo có thể có.' CREATE_ISLAND: '&e&lĐảo | &7Tạo một hòn đảo mới tại {0} trong {1}ms.' CREATE_ISLAND_FAILURE: '&c&lLỗi | &7Đã xảy ra lỗi khi tạo đảo của bạn. Vui lòng liên hệ với quản trị viên để điều tra vấn đề.' -CREATE_WORLD_FAILURE: '&c&lError | &7An error occurred while generating your world. Please contact the administrator to investigate the issue.' +CREATE_WORLD_FAILURE: '&c&lLỗi | &7Đã xảy ra lỗi khi tạo thế giới của bạn. Vui lòng liên hệ với quản trị viên để điều tra vấn đề.' DEBUG_MODE_DISABLED: '&e&lGỡ Lỗi | &7Chế độ gỡ lỗi đã được &cTẮT&7.' DEBUG_MODE_ENABLED: '&e&lGỡ Lỗi | &7Chế độ gỡ lỗi đã được &aBẬT&7.' -DEBUG_MODE_FILTER_ADD: '&e&lDebug | &7Toggled debug filter {0} &aON&7.' -DEBUG_MODE_FILTER_CLEAR: '&e&lDebug | &7Toggled all debug filters &cOFF&7.' -DEBUG_MODE_FILTER_REMOVE: '&e&lDebug | &7Toggled debug filter {0} &cOFF&7.' +DEBUG_MODE_FILTER_ADD: '&e&lGỡ lỗi | &7Đã bật bộ lọc gỡ lỗi {0} &aBẬT&7.' +DEBUG_MODE_FILTER_CLEAR: '&e&lGỡ lỗi | &7Đã xóa tất cả bộ lọc gỡ lỗi &cTẮT&7.' +DEBUG_MODE_FILTER_REMOVE: '&e&lGỡ lỗi | &7Đã tắt bộ lọc gỡ lỗi {0} &cTẮT&7.' DELETE_WARP: '&e&lĐảo | &7Bạn đã xóa khu vực {0}.' DELETE_WARP_SIGN_BROKE: '&7&oChỗ đó từng có một bảng khu vực, nhưng nó đã bị hỏng...' DEMOTE_LEADER: '&c&lLỗi | &7Bạn không thể hạ cấp lãnh đạo đảo.' @@ -430,7 +430,7 @@ INVALID_LEVEL: '&c&lLỗi | &7Cấp độ không hợp lệ {0}.' INVALID_LIMIT: '&c&lLỗi | &7Giới hạn không hợp lệ {0}.' INVALID_MATERIAL: '&c&lLỗi | &7Vật liệu không hợp lệ {0}.' INVALID_MATERIAL_DATA: '&c&lLỗi | &7Dữ liệu-vật liệu không hợp lệ {0}.' -INVALID_MENU: '&c&lError | &7Invalid menu {0}.' +INVALID_MENU: '&c&lLỗi | &7Menu không hợp lệ {0}.' INVALID_MISSION: '&c&lLỗi | &7Nhiệm vụ không hợp lệ {0}.' INVALID_MODULE: '&c&lLỗi | &7Module không hợp lệ {0}.' INVALID_MULTIPLIER: '&c&lLỗi | &7Hệ số không hợp lệ {0}.' @@ -464,9 +464,9 @@ INVITE_BANNED_PLAYER: '&c&lLỗi | &7Người chơi này bị cấm từ đảo mời.' INVITE_TO_FULL_ISLAND: '&c&lLỗi | &7Bạn không thể mời thêm thành viên đến đảo của bạn.' -ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' +ISLAND_ALREADY_CLOSED: '&c&lLỗi | &7Đảo đã được đóng cửa biên giới.' ISLAND_ALREADY_EXIST: '&c&lLỗi | &7Một hòn đảo với tên đó đã tồn tại.' -ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' +ISLAND_ALREADY_OPENED: '&c&lLỗi | &7Đảo đã được mở cửa biên giới.' ISLAND_BANK_EMPTY: '&e&lNgân Hàng | &7Đảo ngân hàng trống rỗng.' ISLAND_BANK_SHOW: '&e&lNgân Hàng | &7Đảo bạn có ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&lNgân Hàng | &7Đảo của {0} có ${1}.' @@ -556,7 +556,7 @@ ISLAND_PREVIEW_START: | &e&lXem Trước | &7Nhập &a&lDONG-Y &7để tạo đảo mới, hoặc &c&lHUY-BO &7để dừng chế độ xem trước. &e&lXem Trước | &7Bạn không thể rời khỏi khu vực của hòn đảo, nếu không chế độ xem trước sẽ tự động bị hủy. ISLAND_PROTECTED: '&c&lLỗi | &7Hòn đảo này được bảo vệ.' -ISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' +ISLAND_PROTECTED_OPPED: '&7&oBạn có thể bỏ qua hạn chế này bằng cách sử dụng "/is admin bypass".' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lĐảo | &7Thành viên đảo của {0} &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(Ngoại tuyến)' @@ -568,9 +568,9 @@ ISLAND_WARP_PUBLIC: '' ISLAND_WARP_PRIVATE: '&c[Riêng Tư]' ISLAND_WAS_CLOSED: '&e&lĐảo | &7&oHòn đảo bạn đang ở đã bị đóng cửa và bạn sẽ dịch chuyển trở lại spawn...' -ISLAND_WORTH_ERROR: '&c&lError | &7An unexpected error occurred while calculating your island. Contact administrators if the issue persists.' +ISLAND_WORTH_ERROR: '&c&lLỗi | &7Đã xảy ra lỗi không mong muốn khi tính toán đảo của bạn. Liên hệ quản trị viên nếu vấn đề vẫn tiếp diễn.' ISLAND_WORTH_RESULT: '&e&lĐảo | &7Giá trị đảo của bạn là {0} [Cấp độ {1}]' -ISLAND_WORTH_TIME_OUT: '&c&lError | &7The calculation task has timed out. Try again later...' +ISLAND_WORTH_TIME_OUT: '&c&lLỗi | &7Quá trình tính toán đã hết thời gian. Vui lòng thử lại sau...' JOIN_ADMIN_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã gia nhập đảo của bạn.' JOIN_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã gia nhập đảo của bạn.' JOIN_FULL_ISLAND: '&c&lLỗi | &7Hòn đảo này đạt số lượng thành viên tối đa được phép.' @@ -597,9 +597,9 @@ LEFT_ISLAND_COOP: '&e&lĐảo | &7Bạn không còn là thành viên co-op đả nữa.' LEFT_ISLAND_COOP_NAME: '&e&lĐảo | &7Bạn không còn là thành viên co-op đảo {0} nữa.' -LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' -LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' -LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lThế giới | &7Thế giới {0} hiện đã bị khóa đối với tất cả các hòn đảo!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lThế giới | &7Thế giới {0} hiện đã bị khóa đối với hòn đảo {1}!' +LOCK_WORLD_ANNOUNCEMENT: '&e&lThế giới | &7Thế giới {0} hiện đã bị khóa đối với hòa đảo của {1}!' MATERIAL_NOT_SOLID: '&c&lLỗi | &7Bạn phải cung cấp một vật liệu rắn.' MAXIMUM_LEVEL: '&c&lLỗi | &7Mức tối đa cho việc nâng cấp này là {0}.' MESSAGE_SENT: '&e&lĐảo | &7Gửi thành công {0} tin nhắn!' @@ -619,7 +619,7 @@ MODULE_INFO: | &e&lModule | &7{2} MODULE_LOADED_SUCCESS: '&e&lModule | &7Thành công tải module {0}.' MODULE_LOADED_FAILURE: '&e&lModule | &7Không thể tải module {0}. Hãy kiểm tra console để có thêm thông tin.' -MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Successfully unloaded the module.' +MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Đã hủy tải thành công module.' MODULES_LIST: '&fModules ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' @@ -693,13 +693,13 @@ PERMISSION_CHANGED_NAME: '&e&lQuyền Lợi | &7Thay đổi thành công quyền {1}.' PERMISSION_CHANGED_ALL: '&e&lNâng Cấp | &7Thay đổi thành công quyền {0} cho tất cả các đảo.' -PERSISTENT_DATA_EMPTY: '&c&lError | &7No data was found for your query.' -PERSISTENT_DATA_MODIFY: '&e&lData | &7Successfully set data for {0} with {1}: {2}' -PERSISTENT_DATA_SHOW: '&e&lData | &7Data of {0}: &f{{1}}' +PERSISTENT_DATA_EMPTY: '&c&lLỗi | &7Không tìm thấy dữ liệu nào cho truy vấn của bạn.' +PERSISTENT_DATA_MODIFY: '&e&lDữ liệu | &7Đã đặt thành công dữ liệu cho {0} với {1}: {2}' +PERSISTENT_DATA_SHOW: '&e&lDữ liệu | &7Dữ liệu của {0}: &f{{1}}' PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' -PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' +PERSISTENT_DATA_REMOVED: '&e&lDữ liệu | &7Đã xóa thành công dữ liệu cho {0} từ đường dẫn {1}.' PERMISSIONS_RESET_PLAYER: '&e&lĐảo | &7Thành công đặt lại tất cả các quyền cho {0} thành giá trị mặc định!' PERMISSIONS_RESET_ROLES: '&e&lĐảo | &7Thành công đặt lại tất cả các quyền của hòn đảo thành giá trị mặc định!' PLACEHOLDER_NO: 'No' @@ -815,16 +815,16 @@ TRANSFER_BROADCAST: '&e&lĐảo | &7Lãnh đạo của hòn đảo đã được UNBAN_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã được dỡ bỏ lệnh cấm trong đảo bởi {1}.' UNCOOP_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã huỷ bỏ tư cách thành viên coop của {1}' -UNCOOP_AUTO_ANNOUNCEMENT: '&e&lIsland | &7There are no island members online and therefore you were un-cooped automatically.' +UNCOOP_AUTO_ANNOUNCEMENT: '&e&lĐảo | &7Không có thành viên đảo nào trực tuyến và do đó bạn đã tự động bị hủy chế độ co-op.' UNCOOP_LEFT_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã thoát khỏi trò chơi và không còn là một thành viên co-op.' UNIGNORED_ISLAND: '&e&lĐảo | &7Đảo của {0} bây giờ không được bỏ qua từ các đảo hàng đầu.' UNIGNORED_ISLAND_NAME: '&e&lĐảo | &7Đảo {0} bây giờ không được bỏ qua từ các đảo hàng đầu.' -UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' -UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lThế giới | &7Thế giới {0} hiện đã được mở khóa cho tất cả đảo!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lThế giới | &7Thế giới {0} hiện đã được mở khóa cho đảo {1}!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&lThế giới | &7Thế giới {0} hiện đã được mở khóa cho hòn đảo của {1}!' UNSAFE_WARP: '&e&lĐảo | &7&oCó vẻ như khu vực này không an toàn. Vui lòng thử lại với khu vực khác.' UPDATED_PERMISSION: '&e&lĐảo | &7Đã cập nhật quyền cho {0}.' @@ -867,5 +867,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&lNgân Hàng | &7{0} rút {1}$ từ ngân hàng của WITHDRAW_ERROR: '&c&lLỗi | &7{0}.' WITHDRAWN_MONEY: '&e&lNgân Hàng | &7Bạn đã rút ${0} từ đảo của {1}!' WITHDRAWN_MONEY_NAME: '&e&lNgân Hàng | &7Bạn đã rút ${0} từ đảo {1}!' -WORLD_NOT_ENABLED: '&e&lWorlds | &7This world is not enabled on the server.' -WORLD_NOT_UNLOCKED: '&e&lThế Giới | &7Thế giới {0} hiện chưa được mở khóa!' +WORLD_NOT_ENABLED: '&e&lThế giới | &7Thế giới này không được bật trên máy chủ.' +WORLD_NOT_UNLOCKED: '&e&lThế Giới | &7Thế giới {0} hiện chưa được mở khóa!' \ No newline at end of file From 87ae4a755107e7da037f365b354156de33e9c6ad Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 3 Jul 2025 08:05:07 +0300 Subject: [PATCH 207/600] Fix more errors in ChunkreaderImpl when using regular Spigot (#2512) --- .../nms/v1_12_R1/world/ChunkReaderImpl.java | 2 +- .../nms/v1_16_R3/world/ChunkReaderImpl.java | 19 +++++++++++-------- .../nms/v1_17/world/ChunkReaderImpl.java | 3 +-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java index f6ead4df34..caae6d20b1 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/ChunkReaderImpl.java @@ -189,7 +189,7 @@ private static class CachedEntity { this.x = entity.locX; this.y = entity.locY; this.z = entity.locZ; - this.yaw = entity.getBukkitYaw(); + this.yaw = entity.yaw; this.pitch = entity.pitch; this.entityType = entity.getBukkitEntity().getType(); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java index c0e22ff399..f35ccc4c9e 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java @@ -15,6 +15,7 @@ import net.minecraft.server.v1_16_R3.BlockStateInteger; import net.minecraft.server.v1_16_R3.Blocks; import net.minecraft.server.v1_16_R3.Chunk; +import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; import net.minecraft.server.v1_16_R3.ChunkSection; import net.minecraft.server.v1_16_R3.DataPaletteBlock; import net.minecraft.server.v1_16_R3.Entity; @@ -42,8 +43,7 @@ public class ChunkReaderImpl implements ChunkReader { - private static final DataPaletteBlock EMPTY_BLOCKS = - new ChunkSection(0, null, null, true).getBlocks(); + private static final DataPaletteBlock EMPTY_BLOCKS = new ChunkSection(0).getBlocks(); private static final byte[] EMPTY_LIGHT = new byte[2048]; private final int x; @@ -58,8 +58,9 @@ public class ChunkReaderImpl implements ChunkReader { public ChunkReaderImpl(org.bukkit.Chunk bukkitChunk) { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); - this.x = chunk.locX; - this.z = chunk.locZ; + ChunkCoordIntPair chunkCoords = chunk.getPos(); + this.x = chunkCoords.x; + this.z = chunkCoords.z; ChunkSection[] chunkSections = chunk.getSections(); this.blockids = new DataPaletteBlock[chunkSections.length]; @@ -83,7 +84,8 @@ public ChunkReaderImpl(org.bukkit.Chunk bukkitChunk) { this.skylight[i] = EMPTY_LIGHT; } else { this.skylight[i] = new byte[2048]; - System.arraycopy(skyLightArray.getIfSet(), 0, this.skylight[i], 0, 2048); + if (!skyLightArray.c()) + System.arraycopy(skyLightArray.asBytes(), 0, this.skylight[i], 0, 2048); } NibbleArray emitLightArray = lightEngine.a(EnumSkyBlock.BLOCK).a(SectionPosition.a(this.x, i, this.z)); @@ -91,7 +93,8 @@ public ChunkReaderImpl(org.bukkit.Chunk bukkitChunk) { this.emitlight[i] = EMPTY_LIGHT; } else { this.emitlight[i] = new byte[2048]; - System.arraycopy(emitLightArray.getIfSet(), 0, this.emitlight[i], 0, 2048); + if (!emitLightArray.c()) + System.arraycopy(emitLightArray.asBytes(), 0, this.emitlight[i], 0, 2048); } } } @@ -126,7 +129,7 @@ public int getZ() { @Override public Material getType(int x, int y, int z) { - return getBlockData(x, y, z).getBukkitMaterial(); + return CraftMagicNumbers.getMaterial(getBlockData(x, y, z).getBlock()); } @Override @@ -209,7 +212,7 @@ private static DataPaletteBlock copyDataPalette(DataPaletteBlock blockids = new DataPaletteBlock<>(ChunkSection.GLOBAL_PALETTE, Block.REGISTRY_ID, - GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData(), null, false); + GameProfileSerializer::c, GameProfileSerializer::a, Blocks.AIR.getBlockData()); blockids.a(data.getList("Palette", 10), data.getLongArray("BlockStates")); return blockids; diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java index 9e152be105..7c8e1a82fb 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java @@ -39,8 +39,7 @@ public class ChunkReaderImpl implements ChunkReader { - private static final PalettedContainer EMPTY_STATES = - new LevelChunkSection(0, null, null, true).getStates(); + private static final PalettedContainer EMPTY_STATES = new LevelChunkSection(0).getStates(); private static final byte[] EMPTY_LIGHT = new byte[2048]; private final ServerLevel serverLevel; From 6ca690f42b05c42b52906a85ed910255212350db Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 3 Jul 2025 08:25:46 +0300 Subject: [PATCH 208/600] Adds support to UltimateStacker4 (#2526) --- Hooks/UltimateStacker4/build.gradle | 13 +++ .../SpawnersProvider_UltimateStacker4.java | 84 +++++++++++++++++++ settings.gradle | 1 + .../external/ProvidersManagerImpl.java | 6 +- 4 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 Hooks/UltimateStacker4/build.gradle create mode 100644 Hooks/UltimateStacker4/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker4.java diff --git a/Hooks/UltimateStacker4/build.gradle b/Hooks/UltimateStacker4/build.gradle new file mode 100644 index 0000000000..5702335b36 --- /dev/null +++ b/Hooks/UltimateStacker4/build.gradle @@ -0,0 +1,13 @@ +group 'Hooks:UltimateStacker4' + +dependencies { + compileOnly 'com.songoda:UltimateStacker:4.3.0' + compileOnly "org.spigotmc:v1_8_R3-Taco:latest" + compileOnly project(":API") + compileOnly rootProject +} + +if (project.hasProperty('hook.compile_ultimatestacker') && + !Boolean.valueOf(project.findProperty("hook.compile_ultimatestacker").toString())) { + project.tasks.all { task -> task.enabled = false } +} diff --git a/Hooks/UltimateStacker4/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker4.java b/Hooks/UltimateStacker4/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker4.java new file mode 100644 index 0000000000..0a279898ee --- /dev/null +++ b/Hooks/UltimateStacker4/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker4.java @@ -0,0 +1,84 @@ +package com.bgsoftware.superiorskyblock.external.spawners; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.google.common.base.Preconditions; +import com.songoda.ultimatestacker.api.UltimateStackerApi; +import com.songoda.ultimatestacker.api.events.spawner.SpawnerBreakEvent; +import com.songoda.ultimatestacker.api.events.spawner.SpawnerPlaceEvent; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; + +public class SpawnersProvider_UltimateStacker4 implements SpawnersProviderItemMetaSpawnerType { + + private static boolean registered = false; + + private final SuperiorSkyblockPlugin plugin; + + public SpawnersProvider_UltimateStacker4(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + if (!registered) { + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + registered = true; + Log.info("Using UltimateStacker as a spawners provider."); + } + } + + @Override + public Pair getSpawner(Location location) { + Preconditions.checkNotNull(location, "location parameter cannot be null."); + + int blockCount = -1; + if (Bukkit.isPrimaryThread()) { + blockCount = UltimateStackerApi.getSpawnerStackManager().getSpawner(location).getAmount(); + } + + return new Pair<>(blockCount, null); + } + + @SuppressWarnings("unused") + private class StackerListener implements Listener { + + @EventHandler(priority = EventPriority.HIGHEST) + public void onSpawnerStack(SpawnerPlaceEvent e) { + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); + } + + if (island == null) + return; + + Key blockKey = Key.ofSpawner(e.getSpawnerType()); + int increaseAmount = e.getAmount(); + + if (island.hasReachedBlockLimit(blockKey, increaseAmount)) { + e.setCancelled(true); + Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(blockKey.toString())); + } else { + island.handleBlockPlace(blockKey, increaseAmount); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onSpawnerUnstack(SpawnerBreakEvent e) { + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); + } + if (island != null) + island.handleBlockBreak(e.getBlock(), e.getAmount()); + } + + } + +} diff --git a/settings.gradle b/settings.gradle index 56608f7767..40dd30de8d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -48,6 +48,7 @@ include 'Hooks:SuperVanish' include 'Hooks:TimbruSilkSpawners' include 'Hooks:UltimateStacker' include 'Hooks:UltimateStacker3' +include 'Hooks:UltimateStacker4' include 'Hooks:VanishNoPacket' include 'Hooks:Vault' include 'Hooks:WildStacker' diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java index 4631aed1a4..c69e58f87b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java @@ -534,7 +534,11 @@ private void registerSpawnersProvider() { } } else if (canRegisterHook("UltimateStacker") && (auto || configSpawnersProvider.equalsIgnoreCase("UltimateStacker"))) { - if (Bukkit.getPluginManager().getPlugin("UltimateStacker").getDescription().getVersion().startsWith("3")) { + String version = Bukkit.getPluginManager().getPlugin("UltimateStacker").getDescription().getVersion(); + int majorVersion = Integer.parseInt(String.valueOf(version.charAt(0))); + if (majorVersion >= 4) { + spawnersProvider = createInstance("spawners.SpawnersProvider_UltimateStacker4"); + } else if (majorVersion == 3) { spawnersProvider = createInstance("spawners.SpawnersProvider_UltimateStacker3"); } else { spawnersProvider = createInstance("spawners.SpawnersProvider_UltimateStacker"); From 84ecae463872e8f9b8e5f76d0913b605e2f89d58 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 3 Jul 2025 08:35:59 +0300 Subject: [PATCH 209/600] Removed access checks in ChunkPosition (#2524) --- .../superiorskyblock/core/ChunkPosition.java | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java index 9b0dd57326..ca2f37a63b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java @@ -25,9 +25,6 @@ public class ChunkPosition implements ObjectsPool.Releasable, AutoCloseable { protected WeakReference cachedBukkitWorld = new WeakReference<>(null); private final boolean isPool; - private Thread holder = Thread.currentThread(); - private StackTraceElement[] releaseStackTrace; - public static ChunkPosition of(Location location) { World world = location.getWorld(); return of(WorldInfo.of(world), location.getBlockX() >> 4, location.getBlockZ() >> 4).withBukkitWorld(world); @@ -77,27 +74,10 @@ private ChunkPosition initialize(WorldInfo worldInfo, int x, int z) { this.worldInfo = worldInfo; this.x = x; this.z = z; - this.holder = Thread.currentThread(); return this; } - private void checkAccess() { - if (isPool && Thread.currentThread() != this.holder) { - StringBuilder builder = new StringBuilder("Accessed ChunkPosition from " + Thread.currentThread() + " but holder is " + this.holder); - if (this.releaseStackTrace != null && this.releaseStackTrace.length > 0) { - builder.append("\n\n\tRelease stacktrace:"); - for (StackTraceElement traceElement : this.releaseStackTrace) { - builder.append("\n\t\tat ").append(traceElement); - } - builder.append("\n"); - } - throw new RuntimeException(builder.toString()); - } - } - public World getWorld() { - checkAccess(); - World cachedBukkitWorld = this.cachedBukkitWorld.get(); if (cachedBukkitWorld == null) { cachedBukkitWorld = Bukkit.getWorld(getWorldName()); @@ -108,27 +88,22 @@ public World getWorld() { } public WorldInfo getWorldsInfo() { - checkAccess(); return this.worldInfo; } public String getWorldName() { - checkAccess(); return this.worldInfo.getName(); } public int getX() { - checkAccess(); return x; } public int getZ() { - checkAccess(); return z; } public long asPair() { - checkAccess(); if (this.pairedXZ < 0) pairedXZ = (long) this.x & 4294967295L | ((long) this.z & 4294967295L) << 32; @@ -136,13 +111,11 @@ public long asPair() { } public boolean isInsideChunk(Location location) { - checkAccess(); return location.getWorld().getName().equals(worldInfo.getName()) && location.getBlockX() >> 4 == x && location.getBlockZ() >> 4 == z; } public int distanceSquared(ChunkPosition other) { - checkAccess(); int deltaX = this.x - other.x; int deltaZ = this.z - other.z; return (deltaX * deltaX) + (deltaZ * deltaZ); @@ -153,13 +126,9 @@ public void release() { if (!isPool) return; - checkAccess(); - this.worldInfo = null; this.pairedXZ = -1; this.cachedBukkitWorld.clear(); - this.holder = null; - this.releaseStackTrace = Thread.currentThread().getStackTrace(); POOL.release(this); } @@ -193,7 +162,6 @@ public String toString() { } private ChunkPosition withBukkitWorld(World world) { - checkAccess(); this.cachedBukkitWorld = new WeakReference<>(world); return this; } From 8d32f9ee84ef8a6f5b90dd34b067cf199184a21a Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Thu, 3 Jul 2025 08:42:58 +0200 Subject: [PATCH 210/600] Added display-menu option for settings menu and missing flags for menus (#2529) --- .../core/menu/impl/MenuIslandFlags.java | 4 +- src/main/resources/menus/permissions.yml | 18 + src/main/resources/menus/permissions1_13.yml | 18 + src/main/resources/menus/permissions1_16.yml | 18 + src/main/resources/menus/permissions1_17.yml | 18 + src/main/resources/menus/permissions1_20.yml | 24 + src/main/resources/menus/permissions1_21.yml | 24 + src/main/resources/menus/permissions1_9.yml | 18 + src/main/resources/menus/settings.yml | 26 + src/main/resources/menus/settings1_12.yml | 26 + src/main/resources/menus/settings1_13.yml | 26 + src/main/resources/menus/settings1_20.yml | 464 ++++++++++++++++++ 12 files changed, 683 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/menus/settings1_20.yml diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java index 6a06b18d1c..95287c6021 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java @@ -67,7 +67,9 @@ public static MenuIslandFlags createInstance() { Optional.ofNullable(cfg.getConfigurationSection("settings")).ifPresent(settingsSection -> { for (String islandFlagName : settingsSection.getKeys(false)) { Optional.ofNullable(settingsSection.getConfigurationSection(islandFlagName)).ifPresent(islandFlagSection -> { - islandFlags.add(loadIslandFlagInfo(islandFlagSection, islandFlagName, islandFlags.size())); + if (islandFlagSection.getBoolean("display-menu", true)) { + islandFlags.add(loadIslandFlagInfo(islandFlagSection, islandFlagName, islandFlags.size())); + } }); } }); diff --git a/src/main/resources/menus/permissions.yml b/src/main/resources/menus/permissions.yml index bb0b4e4e1a..cfb3371f5c 100644 --- a/src/main/resources/menus/permissions.yml +++ b/src/main/resources/menus/permissions.yml @@ -117,12 +117,16 @@ permissions: lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' @@ -131,6 +135,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ORB_PICKUP @@ -252,12 +258,16 @@ permissions: lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' @@ -266,6 +276,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ORB_PICKUP @@ -1902,12 +1914,16 @@ permissions: lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' @@ -1916,6 +1932,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ORB_PICKUP diff --git a/src/main/resources/menus/permissions1_13.yml b/src/main/resources/menus/permissions1_13.yml index 04272f34aa..c41fc7a18e 100644 --- a/src/main/resources/menus/permissions1_13.yml +++ b/src/main/resources/menus/permissions1_13.yml @@ -116,12 +116,16 @@ permissions: lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' @@ -130,6 +134,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -248,12 +254,16 @@ permissions: lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' @@ -262,6 +272,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -1965,12 +1977,16 @@ permissions: lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' @@ -1979,6 +1995,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP diff --git a/src/main/resources/menus/permissions1_16.yml b/src/main/resources/menus/permissions1_16.yml index 6d42737087..b130a84b42 100644 --- a/src/main/resources/menus/permissions1_16.yml +++ b/src/main/resources/menus/permissions1_16.yml @@ -116,12 +116,16 @@ permissions: lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' @@ -130,6 +134,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -248,12 +254,16 @@ permissions: lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' @@ -262,6 +272,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -1998,12 +2010,16 @@ permissions: lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' @@ -2012,6 +2028,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP diff --git a/src/main/resources/menus/permissions1_17.yml b/src/main/resources/menus/permissions1_17.yml index 7387fa3619..eca18a6c1b 100644 --- a/src/main/resources/menus/permissions1_17.yml +++ b/src/main/resources/menus/permissions1_17.yml @@ -116,12 +116,16 @@ permissions: lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' @@ -130,6 +134,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -248,12 +254,16 @@ permissions: lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' @@ -262,6 +272,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -2064,12 +2076,16 @@ permissions: lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' @@ -2078,6 +2094,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP diff --git a/src/main/resources/menus/permissions1_20.yml b/src/main/resources/menus/permissions1_20.yml index a337643bc7..cc297d6a02 100644 --- a/src/main/resources/menus/permissions1_20.yml +++ b/src/main/resources/menus/permissions1_20.yml @@ -116,12 +116,16 @@ permissions: lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' @@ -130,6 +134,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -248,12 +254,16 @@ permissions: lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' @@ -262,6 +272,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -2097,12 +2109,16 @@ permissions: lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' @@ -2111,6 +2127,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -2229,12 +2247,16 @@ permissions: lore: - '&7Access to break spawners inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ADDITIONAL_TOOLTIP permission-disabled: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ADDITIONAL_TOOLTIP role-permission: type: SPAWNER name: '&6Spawner Break' @@ -2243,6 +2265,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ADDITIONAL_TOOLTIP has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP diff --git a/src/main/resources/menus/permissions1_21.yml b/src/main/resources/menus/permissions1_21.yml index e526b17b08..e27ef995cd 100644 --- a/src/main/resources/menus/permissions1_21.yml +++ b/src/main/resources/menus/permissions1_21.yml @@ -116,12 +116,16 @@ permissions: lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' @@ -130,6 +134,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -248,12 +254,16 @@ permissions: lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' @@ -262,6 +272,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -2097,12 +2109,16 @@ permissions: lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' @@ -2111,6 +2127,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -2229,12 +2247,16 @@ permissions: lore: - '&7Access to break spawners inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ADDITIONAL_TOOLTIP permission-disabled: type: SPAWNER name: '&6Spawner Break' lore: - '&7Access to break spawners inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ADDITIONAL_TOOLTIP role-permission: type: SPAWNER name: '&6Spawner Break' @@ -2243,6 +2265,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ADDITIONAL_TOOLTIP has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP diff --git a/src/main/resources/menus/permissions1_9.yml b/src/main/resources/menus/permissions1_9.yml index 111ce2b540..aa436a7ed0 100644 --- a/src/main/resources/menus/permissions1_9.yml +++ b/src/main/resources/menus/permissions1_9.yml @@ -117,12 +117,16 @@ permissions: lore: - '&7Access to damage animals inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_SWORD name: '&6Animal Damage' lore: - '&7Access to damage animals inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_SWORD name: '&6Animal Damage' @@ -131,6 +135,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -252,12 +258,16 @@ permissions: lore: - '&7Access to break blocks inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_PICKAXE name: '&6Break' lore: - '&7Access to break blocks inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_PICKAXE name: '&6Break' @@ -266,6 +276,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP @@ -1935,12 +1947,16 @@ permissions: lore: - '&7Access to change roles for island members.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES permission-disabled: type: DIAMOND_CHESTPLATE name: '&6Set Role' lore: - '&7Access to change roles for island members.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES role-permission: type: DIAMOND_CHESTPLATE name: '&6Set Role' @@ -1949,6 +1965,8 @@ permissions: - '&7Role: &e{}&7.' - '' - '{0}' + flags: + - HIDE_ATTRIBUTES has-access: sound: type: ENTITY_EXPERIENCE_ORB_PICKUP diff --git a/src/main/resources/menus/settings.yml b/src/main/resources/menus/settings.yml index 41123e3fce..afa74a5205 100644 --- a/src/main/resources/menus/settings.yml +++ b/src/main/resources/menus/settings.yml @@ -39,6 +39,7 @@ items: settings: always_day: + display-menu: true settings-enabled: type: STAINED_CLAY data: 4 @@ -59,6 +60,7 @@ settings: pitch: 0.2 always_middle_day: + display-menu: true settings-enabled: type: STAINED_CLAY data: 1 @@ -79,6 +81,7 @@ settings: pitch: 0.2 always_night: + display-menu: true settings-enabled: type: STAINED_CLAY data: 3 @@ -99,6 +102,7 @@ settings: pitch: 0.2 always_middle_night: + display-menu: true settings-enabled: type: STAINED_CLAY data: 11 @@ -119,6 +123,7 @@ settings: pitch: 0.2 always_rain: + display-menu: true settings-enabled: type: WATER_LILY name: '&6Always Rain' @@ -137,6 +142,7 @@ settings: pitch: 0.2 always_shiny: + display-menu: true settings-enabled: type: DEAD_BUSH name: '&6Always Shiny' @@ -155,6 +161,7 @@ settings: pitch: 0.2 creeper_explosion: + display-menu: true settings-enabled: type: SKULL_ITEM data: 4 @@ -175,6 +182,7 @@ settings: pitch: 0.2 crops_growth: + display-menu: true settings-enabled: type: SEEDS name: '&6Crops Growth' @@ -193,6 +201,7 @@ settings: pitch: 0.2 egg_lay: + display-menu: true settings-enabled: type: EGG name: '&6Egg Lay' @@ -211,6 +220,7 @@ settings: pitch: 0.2 enderman_grief: + display-menu: true settings-enabled: type: ENDER_PEARL name: '&6Enderman Grief' @@ -229,6 +239,7 @@ settings: pitch: 0.2 fire_spread: + display-menu: true settings-enabled: type: FLINT_AND_STEEL name: '&6Fire Spread' @@ -247,6 +258,7 @@ settings: pitch: 0.2 ghast_fireball: + display-menu: true settings-enabled: type: FIREBALL name: '&6Ghast Fireball' @@ -265,6 +277,7 @@ settings: pitch: 0.2 lava_flow: + display-menu: true settings-enabled: type: LAVA_BUCKET name: '&6Lava Flow' @@ -283,6 +296,7 @@ settings: pitch: 0.2 natural_animals_spawn: + display-menu: true settings-enabled: type: MONSTER_EGG data: 90 @@ -303,6 +317,7 @@ settings: pitch: 0.2 natural_monster_spawn: + display-menu: true settings-enabled: type: MONSTER_EGG data: 54 @@ -323,24 +338,30 @@ settings: pitch: 0.2 pvp: + display-menu: true settings-enabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES settings-disabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES sound: type: ORB_PICKUP volume: 0.2 pitch: 0.2 spawner_animals_spawn: + display-menu: true settings-enabled: type: MOB_SPAWNER name: '&6Spawner Animals Spawn' @@ -359,6 +380,7 @@ settings: pitch: 0.2 spawner_monster_spawn: + display-menu: true settings-enabled: type: MOB_SPAWNER name: '&6Spawner Monster Spawn' @@ -377,6 +399,7 @@ settings: pitch: 0.2 tnt_explosion: + display-menu: true settings-enabled: type: TNT name: '&6TNT Explosion' @@ -395,6 +418,7 @@ settings: pitch: 0.2 tree_growth: + display-menu: true settings-enabled: type: SAPLING name: '&6Tree Growth' @@ -413,6 +437,7 @@ settings: pitch: 0.2 water_flow: + display-menu: true settings-enabled: type: WATER_BUCKET name: '&6Water Flow' @@ -431,6 +456,7 @@ settings: pitch: 0.2 wither_explosion: + display-menu: true settings-enabled: type: SKULL_ITEM data: 1 diff --git a/src/main/resources/menus/settings1_12.yml b/src/main/resources/menus/settings1_12.yml index 7a63dad0a8..b2f719b41a 100644 --- a/src/main/resources/menus/settings1_12.yml +++ b/src/main/resources/menus/settings1_12.yml @@ -39,6 +39,7 @@ items: settings: always_day: + display-menu: true settings-enabled: type: STAINED_CLAY data: 4 @@ -59,6 +60,7 @@ settings: pitch: 0.2 always_middle_day: + display-menu: true settings-enabled: type: STAINED_CLAY data: 1 @@ -79,6 +81,7 @@ settings: pitch: 0.2 always_night: + display-menu: true settings-enabled: type: STAINED_CLAY data: 3 @@ -99,6 +102,7 @@ settings: pitch: 0.2 always_middle_night: + display-menu: true settings-enabled: type: STAINED_CLAY data: 11 @@ -119,6 +123,7 @@ settings: pitch: 0.2 always_rain: + display-menu: true settings-enabled: type: WATER_LILY name: '&6Always Rain' @@ -137,6 +142,7 @@ settings: pitch: 0.2 always_shiny: + display-menu: true settings-enabled: type: DEAD_BUSH name: '&6Always Shiny' @@ -155,6 +161,7 @@ settings: pitch: 0.2 creeper_explosion: + display-menu: true settings-enabled: type: SKULL_ITEM data: 4 @@ -175,6 +182,7 @@ settings: pitch: 0.2 crops_growth: + display-menu: true settings-enabled: type: SEEDS name: '&6Crops Growth' @@ -193,6 +201,7 @@ settings: pitch: 0.2 egg_lay: + display-menu: true settings-enabled: type: EGG name: '&6Egg Lay' @@ -211,6 +220,7 @@ settings: pitch: 0.2 enderman_grief: + display-menu: true settings-enabled: type: ENDER_PEARL name: '&6Enderman Grief' @@ -229,6 +239,7 @@ settings: pitch: 0.2 fire_spread: + display-menu: true settings-enabled: type: FLINT_AND_STEEL name: '&6Fire Spread' @@ -247,6 +258,7 @@ settings: pitch: 0.2 ghast_fireball: + display-menu: true settings-enabled: type: FIREBALL name: '&6Ghast Fireball' @@ -265,6 +277,7 @@ settings: pitch: 0.2 lava_flow: + display-menu: true settings-enabled: type: LAVA_BUCKET name: '&6Lava Flow' @@ -283,6 +296,7 @@ settings: pitch: 0.2 natural_animals_spawn: + display-menu: true settings-enabled: type: MONSTER_EGG data: 90 @@ -303,6 +317,7 @@ settings: pitch: 0.2 natural_monster_spawn: + display-menu: true settings-enabled: type: MONSTER_EGG data: 54 @@ -323,24 +338,30 @@ settings: pitch: 0.2 pvp: + display-menu: true settings-enabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES settings-disabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 spawner_animals_spawn: + display-menu: true settings-enabled: type: MOB_SPAWNER name: '&6Spawner Animals Spawn' @@ -359,6 +380,7 @@ settings: pitch: 0.2 spawner_monster_spawn: + display-menu: true settings-enabled: type: MOB_SPAWNER name: '&6Spawner Monster Spawn' @@ -377,6 +399,7 @@ settings: pitch: 0.2 tnt_explosion: + display-menu: true settings-enabled: type: TNT name: '&6TNT Explosion' @@ -395,6 +418,7 @@ settings: pitch: 0.2 tree_growth: + display-menu: true settings-enabled: type: SAPLING name: '&6Tree Growth' @@ -413,6 +437,7 @@ settings: pitch: 0.2 water_flow: + display-menu: true settings-enabled: type: WATER_BUCKET name: '&6Water Flow' @@ -431,6 +456,7 @@ settings: pitch: 0.2 wither_explosion: + display-menu: true settings-enabled: type: SKULL_ITEM data: 1 diff --git a/src/main/resources/menus/settings1_13.yml b/src/main/resources/menus/settings1_13.yml index d5327e9777..77399611f2 100644 --- a/src/main/resources/menus/settings1_13.yml +++ b/src/main/resources/menus/settings1_13.yml @@ -38,6 +38,7 @@ items: settings: always_day: + display-menu: true settings-enabled: type: YELLOW_TERRACOTTA name: '&6Always Day' @@ -56,6 +57,7 @@ settings: pitch: 0.2 always_middle_day: + display-menu: true settings-enabled: type: ORANGE_TERRACOTTA name: '&6Always Middle Day' @@ -74,6 +76,7 @@ settings: pitch: 0.2 always_night: + display-menu: true settings-enabled: type: LIGHT_BLUE_TERRACOTTA name: '&6Always Night' @@ -92,6 +95,7 @@ settings: pitch: 0.2 always_middle_night: + display-menu: true settings-enabled: type: BLUE_TERRACOTTA name: '&6Always Middle Night' @@ -110,6 +114,7 @@ settings: pitch: 0.2 always_rain: + display-menu: true settings-enabled: type: LILY_PAD name: '&6Always Rain' @@ -128,6 +133,7 @@ settings: pitch: 0.2 always_shiny: + display-menu: true settings-enabled: type: DEAD_BUSH name: '&6Always Shiny' @@ -146,6 +152,7 @@ settings: pitch: 0.2 creeper_explosion: + display-menu: true settings-enabled: type: CREEPER_HEAD name: '&6Creeper Explosion' @@ -164,6 +171,7 @@ settings: pitch: 0.2 crops_growth: + display-menu: true settings-enabled: type: WHEAT_SEEDS name: '&6Crops Growth' @@ -182,6 +190,7 @@ settings: pitch: 0.2 egg_lay: + display-menu: true settings-enabled: type: EGG name: '&6Egg Lay' @@ -200,6 +209,7 @@ settings: pitch: 0.2 enderman_grief: + display-menu: true settings-enabled: type: ENDER_PEARL name: '&6Enderman Grief' @@ -214,6 +224,7 @@ settings: - '&7Currently &cDISABLED&7.' fire_spread: + display-menu: true settings-enabled: type: FLINT_AND_STEEL name: '&6Fire Spread' @@ -232,6 +243,7 @@ settings: pitch: 0.2 ghast_fireball: + display-menu: true settings-enabled: type: FIRE_CHARGE name: '&6Ghast Fireball' @@ -250,6 +262,7 @@ settings: pitch: 0.2 lava_flow: + display-menu: true settings-enabled: type: LAVA_BUCKET name: '&6Lava Flow' @@ -268,6 +281,7 @@ settings: pitch: 0.2 natural_animals_spawn: + display-menu: true settings-enabled: type: PIG_SPAWN_EGG name: '&6Natural Animals Spawn' @@ -286,6 +300,7 @@ settings: pitch: 0.2 natural_monster_spawn: + display-menu: true settings-enabled: type: ZOMBIE_SPAWN_EGG name: '&6Natural Monster Spawn' @@ -304,24 +319,30 @@ settings: pitch: 0.2 pvp: + display-menu: true settings-enabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES settings-disabled: type: DIAMOND_SWORD name: '&6PvP' lore: - '&7Allow players to pvp inside the island.' - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES sound: type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 spawner_animals_spawn: + display-menu: true settings-enabled: type: SPAWNER name: '&6Spawner Animals Spawn' @@ -340,6 +361,7 @@ settings: pitch: 0.2 spawner_monster_spawn: + display-menu: true settings-enabled: type: SPAWNER name: '&6Spawner Monster Spawn' @@ -358,6 +380,7 @@ settings: pitch: 0.2 tnt_explosion: + display-menu: true settings-enabled: type: TNT name: '&6TNT Explosion' @@ -376,6 +399,7 @@ settings: pitch: 0.2 tree_growth: + display-menu: true settings-enabled: type: OAK_SAPLING name: '&6Tree Growth' @@ -394,6 +418,7 @@ settings: pitch: 0.2 water_flow: + display-menu: true settings-enabled: type: WATER_BUCKET name: '&6Water Flow' @@ -412,6 +437,7 @@ settings: pitch: 0.2 wither_explosion: + display-menu: true settings-enabled: type: WITHER_SKELETON_SKULL name: '&6Wither Explosion' diff --git a/src/main/resources/menus/settings1_20.yml b/src/main/resources/menus/settings1_20.yml new file mode 100644 index 0000000000..d88bae8a90 --- /dev/null +++ b/src/main/resources/menus/settings1_20.yml @@ -0,0 +1,464 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Settings' +previous-menu: true + +pattern: + - '$ $ $ $ $ $ $ $ $' + - '$ @ @ @ @ @ @ @ $' + - '$ @ @ @ @ @ @ @ $' + - '$ @ @ @ @ @ @ @ $' + - '$ $ % $ * $ ^ $ $' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +items: + '$': + type: CYAN_STAINED_GLASS_PANE + name: '&f' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: SUNFLOWER + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + +settings: + always_day: + display-menu: true + settings-enabled: + type: YELLOW_TERRACOTTA + name: '&6Always Day' + lore: + - '&7Set a day time on your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: YELLOW_TERRACOTTA + name: '&6Always Day' + lore: + - '&7Set a day time on your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + always_middle_day: + display-menu: true + settings-enabled: + type: ORANGE_TERRACOTTA + name: '&6Always Middle Day' + lore: + - '&7Set a middle day time on your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: ORANGE_TERRACOTTA + name: '&6Always Middle Day' + lore: + - '&7Set a middle day time on your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + always_night: + display-menu: true + settings-enabled: + type: LIGHT_BLUE_TERRACOTTA + name: '&6Always Night' + lore: + - '&7Set a night time on your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: LIGHT_BLUE_TERRACOTTA + name: '&6Always Night' + lore: + - '&7Set a night time on your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + always_middle_night: + display-menu: true + settings-enabled: + type: BLUE_TERRACOTTA + name: '&6Always Middle Night' + lore: + - '&7Set a middle night day time on your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: BLUE_TERRACOTTA + name: '&6Always Middle Night' + lore: + - '&7Set a middle night day time on your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + always_rain: + display-menu: true + settings-enabled: + type: LILY_PAD + name: '&6Always Rain' + lore: + - '&7Set a rainy weather on your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: LILY_PAD + name: '&6Always Rain' + lore: + - '&7Set a rainy weather on your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + always_shiny: + display-menu: true + settings-enabled: + type: DEAD_BUSH + name: '&6Always Shiny' + lore: + - '&7Set a shiny weather on your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: DEAD_BUSH + name: '&6Always Shiny' + lore: + - '&7Set a shiny weather on your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + creeper_explosion: + display-menu: true + settings-enabled: + type: CREEPER_HEAD + name: '&6Creeper Explosion' + lore: + - '&7Allow creepers to explode blocks inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: CREEPER_HEAD + name: '&6Creeper Explosion' + lore: + - '&7Allow creepers to explode blocks inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + crops_growth: + display-menu: true + settings-enabled: + type: WHEAT_SEEDS + name: '&6Crops Growth' + lore: + - '&7Allow growth of crops inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: WHEAT_SEEDS + name: '&6Crops Growth' + lore: + - '&7Allow growth of crops inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + egg_lay: + display-menu: true + settings-enabled: + type: EGG + name: '&6Egg Lay' + lore: + - '&7Allow chickens to lay eggs inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: EGG + name: '&6Egg Lay' + lore: + - '&7Allow chickens to lay eggs inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + enderman_grief: + display-menu: true + settings-enabled: + type: ENDER_PEARL + name: '&6Enderman Grief' + lore: + - '&7Allow enderman to grief blocks inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: ENDER_PEARL + name: '&6Enderman Grief' + lore: + - '&7Allow enderman to grief blocks inside your island.' + - '&7Currently &cDISABLED&7.' + + fire_spread: + display-menu: true + settings-enabled: + type: FLINT_AND_STEEL + name: '&6Fire Spread' + lore: + - '&7Allow fire to spread inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: FLINT_AND_STEEL + name: '&6Fire Spread' + lore: + - '&7Allow fire to spread inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + ghast_fireball: + display-menu: true + settings-enabled: + type: FIRE_CHARGE + name: '&6Ghast Fireball' + lore: + - '&7Allow fireballs to break blocks inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: FIRE_CHARGE + name: '&6Ghast Fireball' + lore: + - '&7Allow fireballs to break blocks inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + lava_flow: + display-menu: true + settings-enabled: + type: LAVA_BUCKET + name: '&6Lava Flow' + lore: + - '&7Allow lava to flow inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: LAVA_BUCKET + name: '&6Lava Flow' + lore: + - '&7Allow lava to flow inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + natural_animals_spawn: + display-menu: true + settings-enabled: + type: PIG_SPAWN_EGG + name: '&6Natural Animals Spawn' + lore: + - '&7Allow natural spawning of animals inside the island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: PIG_SPAWN_EGG + name: '&6Natural Animals Spawn' + lore: + - '&7Allow natural spawning of animals inside the island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + natural_monster_spawn: + display-menu: true + settings-enabled: + type: ZOMBIE_SPAWN_EGG + name: '&6Natural Monster Spawn' + lore: + - '&7Allow natural spawning of monsters inside the island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: ZOMBIE_SPAWN_EGG + name: '&6Natural Monster Spawn' + lore: + - '&7Allow natural spawning of monsters inside the island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + pvp: + display-menu: true + settings-enabled: + type: DIAMOND_SWORD + name: '&6PvP' + lore: + - '&7Allow players to pvp inside the island.' + - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES + settings-disabled: + type: DIAMOND_SWORD + name: '&6PvP' + lore: + - '&7Allow players to pvp inside the island.' + - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + spawner_animals_spawn: + display-menu: true + settings-enabled: + type: SPAWNER + name: '&6Spawner Animals Spawn' + lore: + - '&7Allow spawner spawning of animals inside the island.' + - '&7Currently &aENABLED&7.' + flags: + - HIDE_ADDITIONAL_TOOLTIP + settings-disabled: + type: SPAWNER + name: '&6Spawner Animals Spawn' + lore: + - '&7Allow spawner spawning of animals inside the island.' + - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ADDITIONAL_TOOLTIP + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + spawner_monster_spawn: + display-menu: true + settings-enabled: + type: SPAWNER + name: '&6Spawner Monster Spawn' + lore: + - '&7Allow spawner spawning of monsters inside the island.' + - '&7Currently &aENABLED&7.' + flags: + - HIDE_ADDITIONAL_TOOLTIP + settings-disabled: + type: SPAWNER + name: '&6Spawner Monster Spawn' + lore: + - '&7Allow spawner spawning of monsters inside the island.' + - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ADDITIONAL_TOOLTIP + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + tnt_explosion: + display-menu: true + settings-enabled: + type: TNT + name: '&6TNT Explosion' + lore: + - '&7Allow TNT to explode blocks inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: TNT + name: '&6TNT Explosion' + lore: + - '&7Allow TNT to explode blocks inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + tree_growth: + display-menu: true + settings-enabled: + type: OAK_SAPLING + name: '&6Tree Growth' + lore: + - '&7Allow growth of trees inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: OAK_SAPLING + name: '&6Tree Growth' + lore: + - '&7Allow growth of trees inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + water_flow: + display-menu: true + settings-enabled: + type: WATER_BUCKET + name: '&6Water Flow' + lore: + - '&7Allow water to flow inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: WATER_BUCKET + name: '&6Water Flow' + lore: + - '&7Allow water to flow inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + + wither_explosion: + display-menu: true + settings-enabled: + type: WITHER_SKELETON_SKULL + name: '&6Wither Explosion' + lore: + - '&7Allow withers to explode blocks inside your island.' + - '&7Currently &aENABLED&7.' + settings-disabled: + type: WITHER_SKELETON_SKULL + name: '&6Wither Explosion' + lore: + - '&7Allow withers to explode blocks inside your island.' + - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file From e5e729868ddd142423a79e62a9fe984a4595f796 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Thu, 3 Jul 2025 08:59:13 +0200 Subject: [PATCH 211/600] Added transfer-confirm option (#2530) --- .../api/config/SettingsManager.java | 6 ++ .../api/handlers/MenusManager.java | 11 +++ .../api/hooks/MenusProvider.java | 11 +++ .../commands/player/CmdTransfer.java | 20 +--- .../config/SettingsContainer.java | 2 + .../config/SettingsManagerImpl.java | 5 + .../config/section/GlobalSection.java | 4 + .../core/menu/MenuIdentifiers.java | 1 + .../superiorskyblock/core/menu/Menus.java | 3 + .../core/menu/MenusManagerImpl.java | 5 + .../core/menu/button/impl/TransferButton.java | 68 ++++++++++++++ .../core/menu/impl/MenuConfirmTransfer.java | 91 +++++++++++++++++++ .../external/menus/MenusProvider_Default.java | 9 ++ .../superiorskyblock/island/IslandUtils.java | 28 ++++++ src/main/resources/config.yml | 3 + src/main/resources/menus/confirm-transfer.yml | 44 +++++++++ .../resources/menus/confirm-transfer1_12.yml | 44 +++++++++ .../resources/menus/confirm-transfer1_13.yml | 41 +++++++++ 18 files changed, 381 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TransferButton.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmTransfer.java create mode 100644 src/main/resources/menus/confirm-transfer.yml create mode 100644 src/main/resources/menus/confirm-transfer1_12.yml create mode 100644 src/main/resources/menus/confirm-transfer1_13.yml diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 3fa048ef72..c97bd73ab2 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -222,6 +222,12 @@ public interface SettingsManager { */ boolean isLeaveConfirm(); + /** + * Whether confirmation menu should be opened before transfering an island or not. + * Config-path: transfer-confirm + */ + boolean isTransferConfirm(); + /** * The spawners-provider to use. * If set to AUTO, the plugin will automatically detect an available spawners provider and use it. diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/MenusManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/MenusManager.java index c14e093383..346ba8f88e 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/MenusManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/MenusManager.java @@ -130,6 +130,17 @@ public interface MenusManager { */ void openConfirmLeave(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu); + /** + * Open the confirm-transfer menu. + * Used to confirm the transfer of an island. + * + * @param targetPlayer The player to open the menu for. + * @param previousMenu The previous menu that was opened, if exists. + * @param targetIsland The island to ban the player from. + * @param newOwner The player that will be banned. + */ + void openConfirmTransfer(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer newOwner); + /** * Open the control-panel menu. * Used when opening the control panel of an island. diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/MenusProvider.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/MenusProvider.java index cca16ebb22..82698b456c 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/MenusProvider.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/MenusProvider.java @@ -98,6 +98,17 @@ public interface MenusProvider { */ void openConfirmLeave(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu); + /** + * Open the confirm-transfer menu. + * Used to confirm the transfer of an island. + * + * @param targetPlayer The player to open the menu for. + * @param previousMenu The previous menu that was opened, if exists. + * @param targetIsland The island to ban the player from. + * @param newOwner The player that will be banned. + */ + void openConfirmTransfer(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer newOwner); + /** * Open the control-panel menu. * Used when opening the control panel of an island. diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTransfer.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTransfer.java index 51568f6861..4f45d3d011 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTransfer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTransfer.java @@ -63,29 +63,19 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); - - if (!superiorPlayer.getPlayerRole().isLastRole()) { - Message.NO_TRANSFER_PERMISSION.send(superiorPlayer); - return; - } - SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]); if (targetPlayer == null) return; - if (!island.isMember(targetPlayer)) { - Message.PLAYER_NOT_INSIDE_ISLAND.send(sender); + if (!IslandUtils.checkTransferRestrictions(superiorPlayer, island, targetPlayer)) return; - } - if (island.getOwner().getUniqueId().equals(targetPlayer.getUniqueId())) { - Message.TRANSFER_ALREADY_LEADER.send(superiorPlayer); - return; + if (plugin.getSettings().isTransferConfirm()) { + plugin.getMenus().openConfirmTransfer(superiorPlayer, null, island, targetPlayer); + } else { + IslandUtils.handleTransferIsland(superiorPlayer, island, targetPlayer); } - - if (island.transferIsland(targetPlayer)) - IslandUtils.sendMessage(island, Message.TRANSFER_BROADCAST, Collections.emptyList(), targetPlayer.getName()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index f8dfeb8085..4f1f8e8d45 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -139,6 +139,7 @@ public class SettingsContainer { public final boolean disbandConfirm; public final boolean kickConfirm; public final boolean leaveConfirm; + public final boolean transferConfirm; public final String spawnersProvider; public final String stackedBlocksProvider; public final boolean disbandInventoryClear; @@ -378,6 +379,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config disbandConfirm = config.getBoolean("disband-confirm"); kickConfirm = config.getBoolean("kick-confirm"); leaveConfirm = config.getBoolean("leave-confirm"); + transferConfirm = config.getBoolean("transfer-confirm"); spawnersProvider = config.getString("spawners-provider", "AUTO"); stackedBlocksProvider = config.getString("stacked-blocks-provider", "AUTO"); disbandInventoryClear = config.getBoolean("disband-inventory-clear", true); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index cf0a6b6f27..93beab68a9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -251,6 +251,11 @@ public boolean isLeaveConfirm() { return this.global.isLeaveConfirm(); } + @Override + public boolean isTransferConfirm() { + return this.global.isTransferConfirm(); + } + @Override public String getSpawnersProvider() { return this.global.getSpawnersProvider(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index d17b1304d1..268c00f081 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -116,6 +116,10 @@ public boolean isLeaveConfirm() { return getContainer().leaveConfirm; } + public boolean isTransferConfirm() { + return getContainer().transferConfirm; + } + public String getSpawnersProvider() { return getContainer().spawnersProvider; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuIdentifiers.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuIdentifiers.java index b632e77b94..23b5291a98 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuIdentifiers.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuIdentifiers.java @@ -11,6 +11,7 @@ public class MenuIdentifiers { public static final String MENU_CONFIRM_DISBAND = "MenuConfirmDisband"; public static final String MENU_CONFIRM_KICK = "MenuConfirmKick"; public static final String MENU_CONFIRM_LEAVE = "MenuConfirmLeave"; + public static final String MENU_CONFIRM_TRANSFER = "MenuConfirmTransfer"; public static final String MENU_CONTROL_PANEL = "MenuControlPanel"; public static final String MENU_COOPS = "MenuCoops"; public static final String MENU_COUNTS = "MenuCounts"; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/Menus.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/Menus.java index 08f3f0506b..89ce2a5d26 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/Menus.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/Menus.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmDisband; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmKick; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmLeave; +import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmTransfer; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuControlPanel; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuCoops; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuCounts; @@ -56,6 +57,7 @@ public class Menus { public static MenuConfirmDisband MENU_CONFIRM_DISBAND; public static MenuConfirmKick MENU_CONFIRM_KICK; public static MenuConfirmLeave MENU_CONFIRM_LEAVE; + public static MenuConfirmTransfer MENU_CONFIRM_TRANSFER; public static MenuControlPanel MENU_CONTROL_PANEL; public static MenuCoops MENU_COOPS; public static MenuCounts MENU_COUNTS; @@ -102,6 +104,7 @@ public static void registerMenus() { MENU_CONFIRM_DISBAND = createMenu(MenuConfirmDisband.createInstance()); MENU_CONFIRM_KICK = createMenu(MenuConfirmKick.createInstance()); MENU_CONFIRM_LEAVE = createMenu(MenuConfirmLeave.createInstance()); + MENU_CONFIRM_TRANSFER = createMenu(MenuConfirmTransfer.createInstance()); MENU_CONTROL_PANEL = createMenu(MenuControlPanel.createInstance()); MENU_COOPS = createMenu(MenuCoops.createInstance()); MENU_COUNTS = createMenu(MenuCounts.createInstance()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenusManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenusManagerImpl.java index 974b921bac..a6c4215056 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenusManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenusManagerImpl.java @@ -107,6 +107,11 @@ public void openConfirmLeave(SuperiorPlayer targetPlayer, @Nullable ISuperiorMen plugin.getProviders().getMenusProvider().openConfirmLeave(targetPlayer, previousMenu); } + @Override + public void openConfirmTransfer(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer newOwner) { + plugin.getProviders().getMenusProvider().openConfirmTransfer(targetPlayer, previousMenu, targetIsland, newOwner); + } + @Override public void openControlPanel(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { plugin.getProviders().getMenusProvider().openControlPanel(targetPlayer, previousMenu, targetIsland); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TransferButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TransferButton.java new file mode 100644 index 0000000000..7211bff9fb --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TransferButton.java @@ -0,0 +1,68 @@ +package com.bgsoftware.superiorskyblock.core.menu.button.impl; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; +import com.bgsoftware.superiorskyblock.api.world.GameSound; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; +import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; +import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; +import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; +import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmTransfer; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import org.bukkit.event.inventory.InventoryClickEvent; + +import java.util.List; + +public class TransferButton extends AbstractMenuViewButton { + + private TransferButton(AbstractMenuTemplateButton templateButton, MenuConfirmTransfer.View menuView) { + super(templateButton, menuView); + } + + @Override + public Template getTemplate() { + return (Template) super.getTemplate(); + } + + @Override + public void onButtonClick(InventoryClickEvent clickEvent) { + SuperiorPlayer clickedPlayer = plugin.getPlayers().getSuperiorPlayer(clickEvent.getWhoClicked()); + + if (getTemplate().newOwner) + IslandUtils.handleTransferIsland(clickedPlayer, menuView.getIsland(), menuView.getSuperiorPlayer()); + + BukkitExecutor.sync(menuView::closeView, 1L); + } + + public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { + + private boolean newOwner; + + public Builder setNewOwner(boolean newOwner) { + this.newOwner = newOwner; + return this; + } + + @Override + public MenuTemplateButton build() { + return new Template(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, newOwner); + } + + } + + public static class Template extends MenuTemplateButtonImpl { + + private final boolean newOwner; + + Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, + @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, boolean newOwner) { + super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, + TransferButton.class, TransferButton::new); + this.newOwner = newOwner; + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmTransfer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmTransfer.java new file mode 100644 index 0000000000..18949e97c7 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmTransfer.java @@ -0,0 +1,91 @@ +package com.bgsoftware.superiorskyblock.core.menu.impl; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.menu.Menu; +import com.bgsoftware.superiorskyblock.api.menu.layout.MenuLayout; +import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; +import com.bgsoftware.superiorskyblock.core.menu.AbstractMenu; +import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; +import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; +import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; +import com.bgsoftware.superiorskyblock.core.menu.button.impl.TransferButton; +import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IIslandMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.IPlayerMenuView; +import com.bgsoftware.superiorskyblock.core.menu.view.args.IslandViewArgs; +import org.bukkit.configuration.file.YamlConfiguration; + +public class MenuConfirmTransfer extends AbstractMenu { + + private MenuConfirmTransfer(MenuParseResult parseResult) { + super(MenuIdentifiers.MENU_CONFIRM_TRANSFER, parseResult); + } + + @Override + protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, + @Nullable MenuView previousMenuView) { + return new View(superiorPlayer, previousMenuView, this, args); + } + + @Nullable + public static MenuConfirmTransfer createInstance() { + MenuParseResult menuParseResult = MenuParserImpl.getInstance().loadMenu("confirm-transfer.yml", null); + + if (menuParseResult == null) + return null; + + MenuPatternSlots menuPatternSlots = menuParseResult.getPatternSlots(); + YamlConfiguration cfg = menuParseResult.getConfig(); + MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); + + patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "confirm", menuPatternSlots), + new TransferButton.Builder().setNewOwner(true)); + patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "cancel", menuPatternSlots), + new TransferButton.Builder()); + + return new MenuConfirmTransfer(menuParseResult); + } + + public static class Args extends IslandViewArgs { + + private final SuperiorPlayer targetPlayer; + + public Args(Island island, SuperiorPlayer targetPlayer) { + super(island); + this.targetPlayer = targetPlayer; + } + + } + + public static class View extends AbstractMenuView implements IIslandMenuView, IPlayerMenuView { + + private final Island island; + private SuperiorPlayer targetPlayer; + + protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previousMenuView, + Menu menu, Args args) { + super(inventoryViewer, previousMenuView, menu); + this.island = args.getIsland(); + this.targetPlayer = args.targetPlayer; + } + + @Override + public Island getIsland() { + return island; + } + + @Override + public SuperiorPlayer getSuperiorPlayer() { + return targetPlayer; + } + + public void setTargetPlayer(SuperiorPlayer targetPlayer) { + this.targetPlayer = targetPlayer; + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java b/src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java index 66722fbf9d..c233362ee6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java @@ -26,6 +26,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandCreationButton; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmBan; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmKick; +import com.bgsoftware.superiorskyblock.core.menu.impl.MenuConfirmTransfer; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandCreation; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandPrivileges; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuMissionsCategory; @@ -149,6 +150,14 @@ public void openConfirmLeave(SuperiorPlayer targetPlayer, @Nullable ISuperiorMen Menus.MENU_CONFIRM_LEAVE.createView(targetPlayer, EmptyViewArgs.INSTANCE, previousMenu); } + @Override + public void openConfirmTransfer(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland, SuperiorPlayer newOwner) { + Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); + Preconditions.checkNotNull(targetIsland, "targetIsland parameter cannot be null."); + Preconditions.checkNotNull(newOwner, "newOwner parameter cannot be null."); + Menus.MENU_CONFIRM_TRANSFER.createView(targetPlayer, new MenuConfirmTransfer.Args(targetIsland, newOwner), previousMenu); + } + @Override public void openControlPanel(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu, Island targetIsland) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java index cb0a249ac6..15e0fefcd9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java @@ -186,6 +186,34 @@ public static double getGeneratorPercentageDecimal(Island island, Key key, Dimen return totalAmount == 0 ? 0 : (island.getGeneratorAmount(key, dimension) * 100D) / totalAmount; } + public static boolean checkTransferRestrictions(SuperiorPlayer superiorPlayer, Island island, SuperiorPlayer targetPlayer) { + if (!superiorPlayer.getPlayerRole().isLastRole()) { + Message.NO_TRANSFER_PERMISSION.send(superiorPlayer); + return false; + } + + if (!island.isMember(targetPlayer)) { + Message.PLAYER_NOT_INSIDE_ISLAND.send(superiorPlayer); + return false; + } + + if (island.getOwner().getUniqueId().equals(targetPlayer.getUniqueId())) { + Message.TRANSFER_ALREADY_LEADER.send(superiorPlayer); + return false; + } + + return true; + } + + public static void handleTransferIsland(SuperiorPlayer caller, Island island, SuperiorPlayer target) { + if (!PluginEventsFactory.callIslandTransferEvent(island, caller, target)) + return; + + island.transferIsland(target); + + IslandUtils.sendMessage(island, Message.TRANSFER_BROADCAST, Collections.emptyList(), target.getName()); + } + public static boolean checkKickRestrictions(SuperiorPlayer superiorPlayer, Island island, SuperiorPlayer targetPlayer) { if (!island.isMember(targetPlayer)) { Message.PLAYER_NOT_INSIDE_ISLAND.send(superiorPlayer); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 8d8589edac..6130c0f275 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -450,6 +450,9 @@ kick-confirm: true # Should a confirm gui be displayed when /is leave is executed. leave-confirm: true +# Should a confirm gui be displayed when /is transfer is executed. +transfer-confirm: true + # If you want a specific spawners provider to use, specify it here. # Providers: Auto, WildStacker, EpicSpawners, MergedSpawner, PvpingSpawners, SilkSpawners, RoseStacker spawners-provider: 'AUTO' diff --git a/src/main/resources/menus/confirm-transfer.yml b/src/main/resources/menus/confirm-transfer.yml new file mode 100644 index 0000000000..95d4dd88e6 --- /dev/null +++ b/src/main/resources/menus/confirm-transfer.yml @@ -0,0 +1,44 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&l Confirm Transfer' +previous-menu: true +type: HOPPER + +pattern: + - '# @ # ^ #' + +confirm: '@' +cancel: '^' + +items: + '#': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + '@': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' + name: '&aConfirm' + lore: + - '&7Are you sure you want to transfer your island?' + '^': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' + name: '&4Cancel' + +sounds: + '@': + type: ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '^': + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/confirm-transfer1_12.yml b/src/main/resources/menus/confirm-transfer1_12.yml new file mode 100644 index 0000000000..8e28878a40 --- /dev/null +++ b/src/main/resources/menus/confirm-transfer1_12.yml @@ -0,0 +1,44 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&l Confirm Transfer' +previous-menu: true +type: HOPPER + +pattern: + - '# @ # ^ #' + +confirm: '@' +cancel: '^' + +items: + '#': + type: STAINED_GLASS_PANE + data: 15 + name: '&f' + '@': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' + name: '&aConfirm' + lore: + - '&7Are you sure you want to transfer your island?' + '^': + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' + name: '&4Cancel' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '^': + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/confirm-transfer1_13.yml b/src/main/resources/menus/confirm-transfer1_13.yml new file mode 100644 index 0000000000..eccfdf7086 --- /dev/null +++ b/src/main/resources/menus/confirm-transfer1_13.yml @@ -0,0 +1,41 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&l Confirm Transfer' +previous-menu: true +type: HOPPER + +pattern: + - '# @ # ^ #' + +confirm: '@' +cancel: '^' + +items: + '#': + type: BLACK_STAINED_GLASS_PANE + name: '&f' + '@': + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' + name: '&aConfirm' + lore: + - '&7Are you sure you want to transfer your island?' + '^': + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjk1M2IxMmEwOTQ2YjYyOWI0YzA4ODlkNDFmZDI2ZWQyNmZiNzI5ZDRkNTE0YjU5NzI3MTI0YzM3YmI3MGQ4ZCJ9fX0=' + name: '&4Cancel' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + '^': + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 \ No newline at end of file From eed2f83ea265dbad2b837c6c3b0a9ee3a4fcacca Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 3 Jul 2025 11:02:39 +0300 Subject: [PATCH 212/600] Fix incorrect block counts of falling blocks, especially dragon eggs related issues (#2523) --- .../listener/BlockChangesListener.java | 37 +++++++++++-------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index 974d53eff0..fa7132fdf5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -196,12 +196,26 @@ private void onSpawnerChange(GameEvent e) { } private void onEntityChangeBlock(GameEvent e) { - Key blockKey = e.getArgs().newType; + Key newBlockKey = e.getArgs().newType; Block block = e.getArgs().block; + Key oldBlockKey = Keys.of(block); + + if (newBlockKey.equals(oldBlockKey)) + return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockPlace(blockKey, block.getLocation(wrapper.getHandle()), 1, - block.getState(), WorldRecordFlags.SAVE_BLOCK_COUNT); + Location blockLocation = block.getLocation(wrapper.getHandle()); + + if (!oldBlockKey.equals(ConstantKeys.AIR)) { + this.worldRecordService.get().recordBlockBreak(oldBlockKey, blockLocation, + plugin.getNMSWorld().getDefaultAmount(block), + ALL_RECORD_FLAGS); + } + + if (!newBlockKey.equals(ConstantKeys.AIR)) { + this.worldRecordService.get().recordBlockPlace(newBlockKey, blockLocation, 1, + null, ALL_RECORD_FLAGS); + } } } @@ -215,17 +229,6 @@ private void onBlockDestroy(GameEvent e) { this.worldRecordService.get().recordBlockBreak(e.getArgs().block, WorldRecordFlags.DIRTY_CHUNKS); } - private void onEntityBlockDeath(GameEvent e) { - Entity entity = e.getArgs().entity; - if (entity instanceof FallingBlock) { - Key blockKey = plugin.getNMSAlgorithms().getFallingBlockType((FallingBlock) entity); - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockBreak(blockKey, entity.getLocation(wrapper.getHandle()), - 1, REGULAR_RECORD_FLAGS); - } - } - } - private void onBucketFill(GameEvent e) { Block clickedBlock = e.getArgs().clickedBlock; @@ -273,6 +276,11 @@ private void onLeavesDecay(GameEvent e) { } private void onBlockFromTo(GameEvent e) { + // Ignore dragon eggs, otherwise it will add +1 to the count of dragon eggs + // when right-clicking them + if (e.getArgs().block.getType() == Material.DRAGON_EGG) + return; + Block toBlock = e.getArgs().toBlock; if (toBlock.getType() != Material.AIR) { @@ -360,7 +368,6 @@ private void registerListeners() { registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.MONITOR, this::onEntityChangeBlock); registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.MONITOR, this::onBlockBreak); registerCallback(GameEventType.BLOCK_DESTROY_EVENT, GameEventPriority.MONITOR, this::onBlockDestroy); - registerCallback(GameEventType.ENTITY_DEATH_EVENT, GameEventPriority.MONITOR, this::onEntityBlockDeath); registerCallback(GameEventType.PLAYER_FILL_BUCKET_EVENT, GameEventPriority.MONITOR, this::onBucketFill); registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.MONITOR, this::onDragonEggDrop); registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.MONITOR, this::onPistonExtend); From b31d21f689e0998136a9fa751c5c89a147a05140 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Thu, 3 Jul 2025 10:29:49 +0200 Subject: [PATCH 213/600] Added separate protection message for spawn island (#2537) --- .../core/messages/Message.java | 21 +++++++++++++++++-- src/main/resources/lang/de-DE.yml | 2 ++ src/main/resources/lang/en-US.yml | 2 ++ src/main/resources/lang/es-ES.yml | 2 ++ src/main/resources/lang/fr-FR.yml | 2 ++ src/main/resources/lang/it-IT.yml | 2 ++ src/main/resources/lang/iw-IL.yml | 2 ++ src/main/resources/lang/pl-PL.yml | 6 ++++-- src/main/resources/lang/pt-BR.yml | 2 ++ src/main/resources/lang/ru-RU.yml | 2 ++ src/main/resources/lang/tr-TR.yml | 2 ++ src/main/resources/lang/vi-VN.yml | 2 ++ src/main/resources/lang/zh-CN.yml | 2 ++ 13 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 898c8d11c2..adb80f4117 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -4,11 +4,13 @@ import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; +import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.service.message.MessagesService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandsHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; @@ -27,6 +29,7 @@ import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -695,6 +698,8 @@ public void send(CommandSender sender, Locale locale, Object... args) { SET_WARP, SET_WARP_OUTSIDE, SIZE_BIGGER_MAX, + SPAWN_PROTECTED, + SPAWN_PROTECTED_OPPED, SPAWN_SET_SUCCESS, SPAWN_TELEPORT_SUCCESS, SPY_TEAM_CHAT_FORMAT, @@ -812,11 +817,23 @@ public void send(CommandSender sender, Locale locale, Object... args) { return; } - Message.ISLAND_PROTECTED.send(sender, locale, args); + boolean isSpawnIsland; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Island island = plugin.getGrid().getIslandAt(((Player) sender).getLocation(wrapper.getHandle())); + isSpawnIsland = island != null && island.isSpawn(); + } + + if (!isSpawnIsland) + Message.ISLAND_PROTECTED.send(sender, locale, args); + else + Message.SPAWN_PROTECTED.send(sender, locale, args); SuperiorCommand bypassCommand = plugin.getCommands().getAdminCommand("bypass"); if (CommandsHelper.hasCommandAccess(bypassCommand, sender)) - Message.ISLAND_PROTECTED_OPPED.send(sender, locale, args); + if (!isSpawnIsland) + Message.ISLAND_PROTECTED_OPPED.send(sender, locale, args); + else + Message.SPAWN_PROTECTED_OPPED.send(sender, locale, args); } }, diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 0240dea29b..275289f7c9 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -867,6 +867,8 @@ SETTINGS_UPDATED_ALL: '&e&lInsel | &7Die Einstellungen {0} wurden erfolgreich f alle Inseln aktualisiert.' SIZE_BIGGER_MAX: '&c&lError | &7Du kannst keine Größe festlegen, die größer als die maximale Inselgröße ist.' +SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' +SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Erfolgreich teleportiert {0} zum Spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Der Spawn-Speicherort wurde erfolgreich auf {0} aktualisiert.' diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 4be9b395bc..ac2c83567a 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -681,6 +681,8 @@ SETTINGS_UPDATED: '&e&lIsland | &7Successfully updated the settings {0} to {1}'' SETTINGS_UPDATED_NAME: '&e&lIsland | &7Successfully updated the settings {0} to the island {1}.' SETTINGS_UPDATED_ALL: '&e&lIsland | &7Successfully updated the settings {0} to all the islands.' SIZE_BIGGER_MAX: '&c&lError | &7You cannot set a size bigger than the max island size.' +SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' +SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Successfully teleported {0} to spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Successfully updated the spawn location to {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Spy] &e[{0}] {1}&f: &7{2}' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index a0cc9e1902..c1131c2223 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -681,6 +681,8 @@ SETTINGS_UPDATED: '&e&lIsla | &7Se actualizó correctamente la configuración {0 SETTINGS_UPDATED_NAME: '&e&lIsla | &7Se actualizó correctamente la configuración {0} de la isla {1}.' SETTINGS_UPDATED_ALL: '&e&lIsla | &7Se actualizó correctamente la configuración {0} en todas las islas.' SIZE_BIGGER_MAX: '&c&lError | &7No puede establecer un tamaño más grande que el tamaño máximo de la isla.' +SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' +SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Teletransportado exitosamente a {0} al spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Se actualizó correctamente la ubicación de spawn a {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Espía] &e[{0}] {1}&f: &7{2}' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index bae927c42d..1ea931b042 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -683,6 +683,8 @@ SETTINGS_UPDATED: '&e&lIle | &7Paramètre {0} mit à jour pour l''île de {1}.' SETTINGS_UPDATED_NAME: '&e&lIle | &7Paramètre {0} mit à jour pour l''île {1}.' SETTINGS_UPDATED_ALL: '&e&lIle | &7Paramètre {0} mit à jour pour toutes les îles.' SIZE_BIGGER_MAX: '&c&lErreur | &7Vous ne pouvez pas définir une taille d''île supérieure à la taille d''île maximale.' +SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' +SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Téléporation de {0} au spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Mise à jour de la position du spawn sur {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Espion] &e[{0}] {1}&f: &7{2}' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 11a482bdca..a30675fda9 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -689,6 +689,8 @@ SETTINGS_UPDATED: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} de SETTINGS_UPDATED_NAME: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} di {1}.' SETTINGS_UPDATED_ALL: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} a tutte le isole.' SIZE_BIGGER_MAX: '&c&lErrore | &7Non è possibile impostare una dimensione maggiore della dimensione massima dell''isola.' +SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' +SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Hai teletrasportato {0} con successo allo spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7La posizione di spawn è stata aggiornata correttamente alle coordinate: {0}' SPY_TEAM_CHAT_FORMAT: '&7[Spy] &e[{0}] {1}&f: &7{2}' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index e02fa732f0..3c06ca13ce 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -703,6 +703,8 @@ SETTINGS_UPDATED: '&e&lיא | &7{1} לש יאב החלצהב הנכדוע {0} ה SETTINGS_UPDATED_NAME: '&e&lיא | &7{1} יאב החלצהב הנכדוע {0} הרדגהה.' SETTINGS_UPDATED_ALL: '&e&lיא | &7םייאה לכב החלצהב הנכדוע {0} הרדגהה.' SIZE_BIGGER_MAX: '&c&lError | &7You cannot set a size bigger than the max island size.' +SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' +SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Successfully teleported {0} to spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Successfully updated the spawn location to {0}.' SPY_TEAM_CHAT_FORMAT: '&7[יומס] &e[{0}] {1}&f: &7{2}' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index f63040e159..256c5db546 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -501,8 +501,8 @@ ISLAND_PREVIEW_START: | &e&lPodglad | &7Wlaczyles tryb podgladu dla schematu {0}. &e&lPodglad | &7Wpisz &a&lCONFIRM &7by stworzyc nowa wyspe, lub &c&lCANCEL &7by wylaczyc tryb podladu. &e&lPodglad | &7Nie mozesz opuscic terenu wyspy, w przeciwnym razie tryb podgladowy zostanie anulowany. -ISLAND_PROTECTED: '&c&lBlad | &7Ta wyspa jest zabezpieczona.' -ISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' +ISLAND_PROTECTED: '&c&lBlad | &7Ta wyspa jest chroniona.' +ISLAND_PROTECTED_OPPED: '&7&oMozesz ominac to ograniczenie, uzywajac "/is admin bypass".' ISLAND_TEAM_STATUS_FOOTER: '' ISLAND_TEAM_STATUS_HEADER: '&e&lWyspa | &7Czlonkowie {0}''s Wyspy &8[&e{1}&8/&e{2}&8]&7:' ISLAND_TEAM_STATUS_OFFLINE: '&c(Offline)' @@ -683,6 +683,8 @@ SETTINGS_UPDATED: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} do wysp SETTINGS_UPDATED_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} do wyspy {1}.' SETTINGS_UPDATED_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} dla wszystkich wysp.' SIZE_BIGGER_MAX: '&c&lBlad | &7Nie mozna ustawic rozmiaru wiekszego niz maksymalny rozmiar wyspy.' +SPAWN_PROTECTED: '&c&lBlad | &7Spawn jest chroniony.' +SPAWN_PROTECTED_OPPED: '&7&oMozesz ominac to ograniczenie, uzywajac "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Pomyslnie teleportowano {0} do odrodzenia.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Pomyslnie zaktualizowano lokalizacje odradzania do {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Szpieg] &e[{0}] {1}&f: &7{2}' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 4259b4b3eb..80f7587e88 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -681,6 +681,8 @@ SETTINGS_UPDATED: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} p SETTINGS_UPDATED_NAME: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para a ilha {1}.' SETTINGS_UPDATED_ALL: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para todas as ilhas.' SIZE_BIGGER_MAX: '&c&lErro | &7Você não pode definir um tamanho maior que o tamanho máximo da ilha.' +SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' +SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lSpawn | &7Teletransportado com sucesso {0} para spawn.' SPAWN_SET_SUCCESS: '&e&lSpawn | &7Atualizado com sucesso o local de spawn para {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Spy] &e[{0}] {1}&f: &7{2}' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index cea224873a..db94bfc7f8 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -681,6 +681,8 @@ SETTINGS_UPDATED: '&e&lОстров | &7Успешно обновлены нас SETTINGS_UPDATED_NAME: '&e&lОстров | &7Успешно обновлены настройки {0} для острова {1}.' SETTINGS_UPDATED_ALL: '&e&lОстров | &7Успешно обновлены настройки {0} для всех островов.' SIZE_BIGGER_MAX: '&c&lОшибка | &7Вы не можете установить размер больше максимального размера острова.' +SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' +SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lСпавн | &7Успешно телепортирован {0} на спавн.' SPAWN_SET_SUCCESS: '&e&lСпавн | &7Успешно обновлено место спавна на {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Шпион] &e[{0}] {1}&f: &7{2}' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 835d82ab23..8d65dae166 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -811,6 +811,8 @@ SETTINGS_UPDATED: '&e&lAda | &7{1}''in adası için {0} ayarları başarıyla g SETTINGS_UPDATED_NAME: '&e&lAda | &7{1} adası için {0} ayarları başarıyla güncellendi.' SETTINGS_UPDATED_ALL: '&e&lAda | &7Tüm adalar için {0} ayarları başarıyla güncellendi.' SIZE_BIGGER_MAX: '&c&lHata | &7Maksimum ada boyutundan daha büyük bir boyut ayarlayamazsın.' +SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' +SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lDoğuş | &7{0} başarıyla doğuşa ışınlandı.' SPAWN_SET_SUCCESS: '&e&lDoğuş | &7Doğuş konumu {0} olarak başarıyla güncellendi.' SPY_TEAM_CHAT_FORMAT: '&7[Casus] &e[{0}] {1}&f: &7{2}' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index e22d65d921..1864c166a5 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -769,6 +769,8 @@ SETTINGS_UPDATED_NAME: '&e&lĐảo | &7Thay đổi thành công điều chỉnh SETTINGS_UPDATED_ALL: '&e&lĐảo | &7Thay đổi thành công điều chỉnh {0} cho tất cả các đảo.' SIZE_BIGGER_MAX: '&c&lLỗi | &7Bạn không thể đặt kích thước lớn hơn kích thước tối đa của đảo.' +SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' +SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&lTrung Tâm | &7Dịch chuyển thành công {0} đến trung tâm.' SPAWN_SET_SUCCESS: '&e&lTrung Tâm | &7Cập nhật thành công vị trí trung tâm thành {0}.' SPY_TEAM_CHAT_FORMAT: '&7[Bí Mật] &e[{0}] {1}&f: &7{2}' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 83e9725f8f..b5a2556439 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -681,6 +681,8 @@ SETTINGS_UPDATED: '&e&l岛屿 | &7成功修改了玩家 {1} 的岛屿设置 {0}. SETTINGS_UPDATED_NAME: '&e&l岛屿 | &7S成功修改了岛屿 {1} 的设置 {0}.' SETTINGS_UPDATED_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的 {0} 设置.' SIZE_BIGGER_MAX: '&c&l错误 | &7你不能将大小设置为超出岛屿最大大小的数值.' +SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' +SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' SPAWN_TELEPORT_SUCCESS: '&e&l主城 | &7成功将玩家 {0} 传送至主城.' SPAWN_SET_SUCCESS: '&e&l主城 | &7成功将出生点位置设置为了 {0}.' SPY_TEAM_CHAT_FORMAT: '&7[窃听] &e[{0}] {1}&f: &7{2}' From 7421e5a018c8dbb5fa587dcd614afaef9f88cf93 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 3 Jul 2025 11:38:51 +0300 Subject: [PATCH 214/600] Reuse empty args array in Message class --- .../core/messages/Message.java | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index adb80f4117..6c7f68f901 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -848,6 +848,8 @@ public void send(CommandSender sender, Locale locale, Object... args) { }; + private static final Object[] EMPTY_ARGS = new Object[0]; + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference messagesService = new LazyReference() { @Override @@ -969,16 +971,29 @@ public IMessageComponent getComponent(Locale locale) { return messages.get(locale); } + @Nullable + public String getMessage(Locale locale) { + return getMessage(locale, EMPTY_ARGS); + } + @Nullable public String getMessage(Locale locale, Object... args) { return isEmpty(locale) ? defaultMessage : messages.get(locale).getMessage(args); } + public final void send(SuperiorPlayer superiorPlayer) { + send(superiorPlayer, EMPTY_ARGS); + } + public final void send(SuperiorPlayer superiorPlayer, Object... args) { if (PluginEventsFactory.callAttemptPlayerSendMessageEvent(superiorPlayer, name(), args)) superiorPlayer.runIfOnline(player -> send(player, superiorPlayer.getUserLocale(), args)); } + public final void send(CommandSender sender) { + send(sender, EMPTY_ARGS); + } + public final void send(CommandSender sender, Object... args) { if (sender instanceof Player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); @@ -989,7 +1004,11 @@ public final void send(CommandSender sender, Object... args) { send(sender, PlayerLocales.getLocale(sender), args); } - public void send(CommandSender sender, Locale locale, Object... objects) { + public void send(CommandSender sender, Locale locale) { + send(sender, locale, EMPTY_ARGS); + } + + public void send(CommandSender sender, Locale locale, Object... args) { IMessageComponent messageComponent = getComponent(locale); if (messageComponent == null) return; @@ -1000,9 +1019,9 @@ public void send(CommandSender sender, Locale locale, Object... objects) { return; } - PluginEvent event = PluginEventsFactory.callSendMessageEvent(sender, name(), messageComponent, objects); + PluginEvent event = PluginEventsFactory.callSendMessageEvent(sender, name(), messageComponent, args); if (!event.isCancelled()) { - event.getArgs().messageComponent.sendMessage(sender, objects); + event.getArgs().messageComponent.sendMessage(sender, args); if (!(sender instanceof Player) && Log.isDebugged(Debug.SHOW_STACKTRACE)) { Thread.dumpStack(); } From 64670a5be4a4df45bcb0c7c39352e44f5c8fa9e9 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Thu, 3 Jul 2025 10:39:53 +0200 Subject: [PATCH 215/600] Added island-level-rounding-mode option (#2534) --- .../superiorskyblock/api/config/SettingsManager.java | 7 +++++++ .../superiorskyblock/config/SettingsContainer.java | 5 +++++ .../superiorskyblock/config/SettingsManagerImpl.java | 6 ++++++ .../superiorskyblock/config/section/GlobalSection.java | 5 +++++ .../com/bgsoftware/superiorskyblock/island/SIsland.java | 4 ++-- src/main/resources/config.yml | 6 ++++++ 6 files changed, 31 insertions(+), 2 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index c97bd73ab2..a9a777806d 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -15,6 +15,7 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.math.RoundingMode; import java.util.Collection; import java.util.List; import java.util.Map; @@ -85,6 +86,12 @@ public interface SettingsManager { */ boolean isRoundedIslandLevels(); + /** + * The rounding mode used for the island level when rounded-island-level feature is enabled. + * Config path: island-level-rounding-mode + */ + RoundingMode getIslandLevelRoundingMode(); + /** * Whether to automatic track block counts when players place and break blocks. * Config path: auto-blocks-tracking diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 4f1f8e8d45..9d5a263f2e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -46,6 +46,7 @@ import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; +import java.math.RoundingMode; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; @@ -101,6 +102,7 @@ public class SettingsContainer { public final String stackedBlocksMenuTitle; public final String islandLevelFormula; public final boolean roundedIslandLevel; + public final RoundingMode islandLevelRoundingMode; public final boolean autoBlocksTracking; public final String islandTopOrder; public boolean coopMembers; @@ -293,6 +295,9 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config stackedBlocksMenuTitle = Formatters.COLOR_FORMATTER.format(config.getString("stacked-blocks.deposit-menu.title", "&lDeposit Blocks")); islandLevelFormula = config.getString("island-level-formula", "{} / 2"); roundedIslandLevel = config.getBoolean("rounded-island-level", false); + islandLevelRoundingMode = Optional.ofNullable(EnumHelper.getEnum(RoundingMode.class, + config.getString("island-level-rounding-mode").toUpperCase(Locale.ENGLISH))) + .orElse(RoundingMode.HALF_UP); autoBlocksTracking = config.getBoolean("auto-blocks-tracking", true); islandTopOrder = config.getString("island-top-order", "WORTH").toUpperCase(Locale.ENGLISH); coopMembers = config.getBoolean("coop-members", true); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index 93beab68a9..dd85aec140 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -31,6 +31,7 @@ import java.io.File; import java.io.IOException; import java.math.BigInteger; +import java.math.RoundingMode; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -136,6 +137,11 @@ public boolean isRoundedIslandLevels() { return this.global.isRoundedIslandLevels(); } + @Override + public RoundingMode getIslandLevelRoundingMode() { + return this.global.getIslandLevelRoundingMode(); + } + @Override public boolean isAutoBlocksTracking() { return this.global.isAutoBlocksTracking(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index 268c00f081..c69ad28f42 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -9,6 +9,7 @@ import org.bukkit.Location; import java.math.BigInteger; +import java.math.RoundingMode; import java.util.Collection; import java.util.List; import java.util.Map; @@ -44,6 +45,10 @@ public boolean isRoundedIslandLevels() { return getContainer().roundedIslandLevel; } + public RoundingMode getIslandLevelRoundingMode() { + return getContainer().islandLevelRoundingMode; + } + public boolean isAutoBlocksTracking() { return getContainer().autoBlocksTracking; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 5fc212a832..e80427549f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -2921,7 +2921,7 @@ public BigDecimal getIslandLevel() { BigDecimal islandLevel = this.islandLevel.get().add(bonusLevel); if (plugin.getSettings().isRoundedIslandLevels()) { - islandLevel = islandLevel.setScale(0, RoundingMode.HALF_UP); + islandLevel = islandLevel.setScale(0, plugin.getSettings().getIslandLevelRoundingMode()); } if (!plugin.getSettings().isNegativeLevel() && islandLevel.compareTo(BigDecimal.ZERO) < 0) @@ -2935,7 +2935,7 @@ public BigDecimal getRawLevel() { BigDecimal islandLevel = this.islandLevel.get(); if (plugin.getSettings().isRoundedIslandLevels()) { - islandLevel = islandLevel.setScale(0, RoundingMode.HALF_UP); + islandLevel = islandLevel.setScale(0, plugin.getSettings().getIslandLevelRoundingMode()); } if (!plugin.getSettings().isNegativeLevel() && islandLevel.compareTo(BigDecimal.ZERO) < 0) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 6130c0f275..9c8f9cacd4 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -160,6 +160,12 @@ island-level-formula: '{} / 2' # Should the island levels be a rounded integer? rounded-island-level: false +# How should the island level be rounded when rounded-island-level feature is enabled? +# Use UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN or HALF_EVEN +# You can see more information about it here: +# https://docs.oracle.com/javase/8/docs/api/java/math/RoundingMode.html +island-level-rounding-mode: 'HALF_UP' + # Whether to automatic track block counts when players place and break blocks. # If set to true, block counts, worth and levels will automatically be updated upon # placement and breaking of blocks. From 05f3a186165547a2444264f652c0b631cb1d3258 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 4 Jul 2025 21:57:08 +0300 Subject: [PATCH 216/600] Fix `TEST_BLOCK_MODE` already in exists error when creating new island (#2538) --- .../superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java | 1 + .../superiorskyblock/nms/v1_21_6/world/PropertiesMapper.java | 1 + 2 files changed, 2 insertions(+) diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java index 02455b9d9e..50339bb510 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java @@ -49,6 +49,7 @@ public class PropertiesMapper { fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); + fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); try { for (Field field : BlockStateProperties.class.getFields()) { diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/PropertiesMapper.java b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/PropertiesMapper.java index fd242d6824..4a8b8f1c4a 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/PropertiesMapper.java +++ b/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/PropertiesMapper.java @@ -49,6 +49,7 @@ public class PropertiesMapper { fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); + fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); try { for (Field field : BlockStateProperties.class.getFields()) { From df486dddc836379254098bc9c1b1d4d720d5261a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 4 Jul 2025 22:54:27 +0300 Subject: [PATCH 217/600] Removes support to 1.21.6 & adds support to 1.21.7 --- NMS/{v1_21_6 => v1_21_7}/build.gradle | 4 ++-- .../nms/v1_21_7}/NMSAlgorithmsImpl.java | 14 +++++------ .../nms/v1_21_7}/NMSChunksImpl.java | 8 +++---- .../nms/v1_21_7}/NMSDragonFightImpl.java | 10 ++++---- .../nms/v1_21_7}/NMSEntitiesImpl.java | 2 +- .../nms/v1_21_7}/NMSHologramsImpl.java | 2 +- .../nms/v1_21_7}/NMSPlayersImpl.java | 2 +- .../nms/v1_21_7}/NMSTagsImpl.java | 2 +- .../nms/v1_21_7}/NMSUtils.java | 4 ++-- .../nms/v1_21_7}/NMSWorldImpl.java | 23 ++++++++++--------- .../nms/v1_21_7}/crops/CropsBlockEntity.java | 3 +-- .../crops/CropsTickingBlockEntity.java | 3 +-- .../v1_21_7}/crops/CropsTickingMethod.java | 2 +- .../nms/v1_21_7}/dragon/DragonUtils.java | 2 +- .../dragon/EndWorldEndDragonFightHandler.java | 3 +-- .../v1_21_7}/dragon/IslandEndDragonFight.java | 5 ++-- .../dragon/IslandEntityEnderDragon.java | 2 +- .../nms/v1_21_7}/dragon/SpikesCache.java | 4 ++-- .../generator/IslandsGeneratorImpl.java | 2 +- .../menu/MenuBrewingStandBlockEntity.java | 2 +- .../menu/MenuDispenserBlockEntity.java | 2 +- .../v1_21_7}/menu/MenuFurnaceBlockEntity.java | 2 +- .../v1_21_7}/menu/MenuHopperBlockEntity.java | 2 +- .../TickingSpawnerBlockEntityNotifier.java | 2 +- .../v1_21_7}/trial/IslandPlayerDetector.java | 2 +- .../vibration/IslandVibrationUser.java | 2 +- .../nms/v1_21_7}/world/BlockEntityCache.java | 2 +- .../nms/v1_21_7}/world/ChunkReaderImpl.java | 4 ++-- .../nms/v1_21_7}/world/KeyBlocksCache.java | 2 +- .../nms/v1_21_7}/world/PropertiesMapper.java | 2 +- .../v1_21_7}/world/WorldEditSessionImpl.java | 4 ++-- build.gradle | 2 +- settings.gradle | 2 +- 33 files changed, 63 insertions(+), 66 deletions(-) rename NMS/{v1_21_6 => v1_21_7}/build.gradle (91%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/NMSAlgorithmsImpl.java (96%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/NMSChunksImpl.java (99%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/NMSDragonFightImpl.java (93%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/NMSEntitiesImpl.java (97%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/NMSHologramsImpl.java (99%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/NMSPlayersImpl.java (99%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/NMSTagsImpl.java (99%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/NMSUtils.java (99%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/NMSWorldImpl.java (96%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/crops/CropsBlockEntity.java (96%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/crops/CropsTickingBlockEntity.java (83%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/crops/CropsTickingMethod.java (99%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/dragon/DragonUtils.java (94%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/dragon/EndWorldEndDragonFightHandler.java (91%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/dragon/IslandEndDragonFight.java (97%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/dragon/IslandEntityEnderDragon.java (98%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/dragon/SpikesCache.java (97%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/generator/IslandsGeneratorImpl.java (97%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/menu/MenuBrewingStandBlockEntity.java (92%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/menu/MenuDispenserBlockEntity.java (92%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/menu/MenuFurnaceBlockEntity.java (91%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/menu/MenuHopperBlockEntity.java (93%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/spawners/TickingSpawnerBlockEntityNotifier.java (96%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/trial/IslandPlayerDetector.java (97%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/vibration/IslandVibrationUser.java (98%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/world/BlockEntityCache.java (94%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/world/ChunkReaderImpl.java (98%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/world/KeyBlocksCache.java (94%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/world/PropertiesMapper.java (98%) rename NMS/{v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6 => v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7}/world/WorldEditSessionImpl.java (99%) diff --git a/NMS/v1_21_6/build.gradle b/NMS/v1_21_7/build.gradle similarity index 91% rename from NMS/v1_21_6/build.gradle rename to NMS/v1_21_7/build.gradle index 23479215d3..2f64d3bca5 100644 --- a/NMS/v1_21_6/build.gradle +++ b/NMS/v1_21_7/build.gradle @@ -8,10 +8,10 @@ java { } } -group 'NMS:v1_21_6' +group 'NMS:v1_21_7' dependencies { - paperweight.paperDevBundle("1.21.6-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.21.7-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSAlgorithmsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java similarity index 96% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSAlgorithmsImpl.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java index 6f6829000e..7a4750483c 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6; +package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; @@ -11,12 +11,12 @@ import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.menu.MenuBrewingStandBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.menu.MenuDispenserBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.menu.MenuFurnaceBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.menu.MenuHopperBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.BlockEntityCache; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.menu.MenuBrewingStandBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.menu.MenuDispenserBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.menu.MenuFurnaceBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.BlockEntityCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.KeyBlocksCache; import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; import com.google.gson.Gson; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSChunksImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java similarity index 99% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSChunksImpl.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java index c09dfdc365..1eda55a2f8 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSChunksImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6; +package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; @@ -17,9 +17,9 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.crops.CropsBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.crops.CropsTickingMethod; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.crops.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.crops.CropsTickingMethod; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.logging.LogUtils; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSDragonFightImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSDragonFightImpl.java similarity index 93% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSDragonFightImpl.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSDragonFightImpl.java index 6bc677c37f..3a9b50cd74 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSDragonFightImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSDragonFightImpl.java @@ -1,14 +1,14 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6; +package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.EndWorldEndDragonFightHandler; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.IslandEndDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.IslandEntityEnderDragon; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.SpikesCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.EndWorldEndDragonFightHandler; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.IslandEndDragonFight; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.IslandEntityEnderDragon; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.SpikesCache; import com.google.common.cache.LoadingCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSEntitiesImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java similarity index 97% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSEntitiesImpl.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java index 6bcd84b0f1..e41062769e 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSEntitiesImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6; +package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.tags.ItemTags; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSHologramsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSHologramsImpl.java similarity index 99% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSHologramsImpl.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSHologramsImpl.java index a69ed3a172..6c7aa11144 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSHologramsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSHologramsImpl.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6; +package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; import com.bgsoftware.superiorskyblock.nms.NMSHolograms; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSPlayersImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSPlayersImpl.java similarity index 99% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSPlayersImpl.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSPlayersImpl.java index b8aad72ff0..b552d07c5d 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSPlayersImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSPlayersImpl.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6; +package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSTagsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java similarity index 99% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSTagsImpl.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java index 9e35a538c9..684b240385 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSTagsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6; +package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.nms.NMSTags; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSUtils.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java similarity index 99% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSUtils.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java index ae7d4b80ea..073411ca3f 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSUtils.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6; +package com.bgsoftware.superiorskyblock.nms.v1_21_7; import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; import com.bgsoftware.common.annotations.Nullable; @@ -11,7 +11,7 @@ import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.PropertiesMapper; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.tag.ByteTag; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.IntArrayTag; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSWorldImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java similarity index 96% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSWorldImpl.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java index b059d1ca98..796e57f24e 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/NMSWorldImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java @@ -1,7 +1,8 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6; +package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.world.Dimension; @@ -15,13 +16,13 @@ import com.bgsoftware.superiorskyblock.nms.NMSWorld; import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.generator.IslandsGeneratorImpl; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.spawners.TickingSpawnerBlockEntityNotifier; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.trial.IslandPlayerDetector; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.vibration.IslandVibrationUser; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.ChunkReaderImpl; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.generator.IslandsGeneratorImpl; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.trial.IslandPlayerDetector; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.ChunkReaderImpl; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; @@ -204,14 +205,14 @@ public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { worldBorder.setCenter(center.getX(), center.getZ()); switch (superiorPlayer.getBorderColor()) { - case BLUE -> { + case BorderColor.BLUE -> { worldBorder.setSize((islandSize * 2) + 1D); } - case GREEN -> { + case BorderColor.GREEN -> { worldBorder.setSize((islandSize * 2) + 1.001D); worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); } - case RED -> { + case BorderColor.RED -> { worldBorder.setSize((islandSize * 2) + 1D); worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); } diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsBlockEntity.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsBlockEntity.java similarity index 96% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsBlockEntity.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsBlockEntity.java index c32fb42888..cf5f97410f 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsBlockEntity.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsBlockEntity.java @@ -1,11 +1,10 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.crops; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.crops; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.crops.CropsTickingMethod; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingBlockEntity.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingBlockEntity.java similarity index 83% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingBlockEntity.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingBlockEntity.java index 105566b82b..bc3066a417 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingBlockEntity.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingBlockEntity.java @@ -1,6 +1,5 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.crops; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.crops; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.crops.CropsBlockEntity; import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.TickingBlockEntity; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingMethod.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingMethod.java similarity index 99% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingMethod.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingMethod.java index 1c968c592c..fc978c0761 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/crops/CropsTickingMethod.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingMethod.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.crops; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.crops; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/DragonUtils.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/DragonUtils.java similarity index 94% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/DragonUtils.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/DragonUtils.java index 4de6663173..3dc973554b 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/DragonUtils.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/DragonUtils.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; import com.bgsoftware.common.reflection.ReflectField; import net.minecraft.core.BlockPos; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndWorldEndDragonFightHandler.java similarity index 91% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/EndWorldEndDragonFightHandler.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndWorldEndDragonFightHandler.java index 8af8eb4463..7dbfd2f017 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/EndWorldEndDragonFightHandler.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndWorldEndDragonFightHandler.java @@ -1,7 +1,6 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.IslandEndDragonFight; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEndDragonFight.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEndDragonFight.java similarity index 97% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEndDragonFight.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEndDragonFight.java index a1f547f945..f6806ce8ae 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEndDragonFight.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEndDragonFight.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; @@ -6,8 +6,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.IslandEntityEnderDragon; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java similarity index 98% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEntityEnderDragon.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java index 5ce4095bb2..58917abbdc 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/SpikesCache.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/SpikesCache.java similarity index 97% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/SpikesCache.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/SpikesCache.java index 810414939b..e3226b1a0e 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/dragon/SpikesCache.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/SpikesCache.java @@ -1,9 +1,9 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.dragon.DragonUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.DragonUtils; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheStats; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/generator/IslandsGeneratorImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/generator/IslandsGeneratorImpl.java similarity index 97% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/generator/IslandsGeneratorImpl.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/generator/IslandsGeneratorImpl.java index db6d778836..4b7239985b 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/generator/IslandsGeneratorImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/generator/IslandsGeneratorImpl.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.generator; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.generator; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuBrewingStandBlockEntity.java similarity index 92% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuBrewingStandBlockEntity.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuBrewingStandBlockEntity.java index 0c2a3b09d8..6eb85a5af8 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuBrewingStandBlockEntity.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuBrewingStandBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.menu; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.menu; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuDispenserBlockEntity.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuDispenserBlockEntity.java similarity index 92% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuDispenserBlockEntity.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuDispenserBlockEntity.java index 03a6356d38..00095c3346 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuDispenserBlockEntity.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuDispenserBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.menu; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.menu; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuFurnaceBlockEntity.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuFurnaceBlockEntity.java similarity index 91% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuFurnaceBlockEntity.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuFurnaceBlockEntity.java index 16c1383864..47a6e1a49d 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuFurnaceBlockEntity.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuFurnaceBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.menu; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.menu; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuHopperBlockEntity.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuHopperBlockEntity.java similarity index 93% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuHopperBlockEntity.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuHopperBlockEntity.java index d2716bce8a..1dc946fa3e 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/menu/MenuHopperBlockEntity.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuHopperBlockEntity.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.menu; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.menu; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/spawners/TickingSpawnerBlockEntityNotifier.java similarity index 96% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/spawners/TickingSpawnerBlockEntityNotifier.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/spawners/TickingSpawnerBlockEntityNotifier.java index 145725f3fb..44758ded5e 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/spawners/TickingSpawnerBlockEntityNotifier.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/spawners/TickingSpawnerBlockEntityNotifier.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.spawners; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.spawners; import net.minecraft.core.BlockPos; import net.minecraft.world.level.BaseSpawner; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/trial/IslandPlayerDetector.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java similarity index 97% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/trial/IslandPlayerDetector.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java index e81272a8d1..c3e36b40fe 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.trial; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.trial; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/vibration/IslandVibrationUser.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/vibration/IslandVibrationUser.java similarity index 98% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/vibration/IslandVibrationUser.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/vibration/IslandVibrationUser.java index 03e2d0cedb..2fed7e8e1f 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/vibration/IslandVibrationUser.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/vibration/IslandVibrationUser.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.vibration; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.vibration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/BlockEntityCache.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockEntityCache.java similarity index 94% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/BlockEntityCache.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockEntityCache.java index 5cb454b5e3..98e89479c0 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/BlockEntityCache.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockEntityCache.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.world; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/ChunkReaderImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/ChunkReaderImpl.java similarity index 98% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/ChunkReaderImpl.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/ChunkReaderImpl.java index a3124552b3..f064d3c74d 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/ChunkReaderImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/ChunkReaderImpl.java @@ -1,8 +1,8 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.world; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.mojang.logging.LogUtils; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/KeyBlocksCache.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/KeyBlocksCache.java similarity index 94% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/KeyBlocksCache.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/KeyBlocksCache.java index bf2fa065ff..035ea48438 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/KeyBlocksCache.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/KeyBlocksCache.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.world; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.key.Keys; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/PropertiesMapper.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapper.java similarity index 98% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/PropertiesMapper.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapper.java index 4a8b8f1c4a..84dc898dd0 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/PropertiesMapper.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapper.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.world; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; import com.bgsoftware.superiorskyblock.core.logging.Log; import net.minecraft.world.level.block.state.properties.BlockStateProperties; diff --git a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/WorldEditSessionImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java similarity index 99% rename from NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/WorldEditSessionImpl.java rename to NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java index e33636404c..c42845a8bc 100644 --- a/NMS/v1_21_6/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_6/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_6.world; +package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; @@ -12,7 +12,7 @@ import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.nms.v1_21_6.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.tag.ByteTag; import com.bgsoftware.superiorskyblock.tag.CompoundTag; diff --git a/build.gradle b/build.gradle index fe8bd22ff6..6366379394 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b12' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b13' implementation 'com.zaxxer:HikariCP:4.0.3' implementation 'org.slf4j:slf4j-api:2.0.5' diff --git a/settings.gradle b/settings.gradle index 40dd30de8d..20ab62ef19 100644 --- a/settings.gradle +++ b/settings.gradle @@ -69,4 +69,4 @@ include 'NMS:v1_21' include 'NMS:v1_21_3' include 'NMS:v1_21_4' include 'NMS:v1_21_5' -include 'NMS:v1_21_6' \ No newline at end of file +include 'NMS:v1_21_7' \ No newline at end of file From 70f0810a65b4ecba911acf103f17601eacc78c38 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 4 Jul 2025 22:24:50 +0200 Subject: [PATCH 218/600] Added teleport-on-create option (#2531) --- .../api/config/SettingsManager.java | 6 ++++++ .../api/events/IslandCreateEvent.java | 15 ++++++++++++++- .../config/SettingsContainer.java | 4 +++- .../config/SettingsManagerImpl.java | 5 +++++ .../config/section/GlobalSection.java | 4 ++++ .../core/events/plugin/PluginEventType.java | 2 +- .../core/events/plugin/PluginEventsFactory.java | 3 ++- .../algorithm/DefaultIslandCreationAlgorithm.java | 2 +- src/main/resources/config.yml | 3 +++ 9 files changed, 39 insertions(+), 5 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index a9a777806d..1caecd9b43 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -261,6 +261,12 @@ public interface SettingsManager { */ IslandNames getIslandNames(); + /** + * Whether to teleport players to their island when they create it or not. + * Config path: teleport-on-create + */ + boolean isTeleportOnCreate(); + /** * Whether to teleport players to their island when they join it or not. * Config-path: teleport-on-join diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCreateEvent.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCreateEvent.java index 61d44c9615..5f05b667cd 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCreateEvent.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandCreateEvent.java @@ -11,7 +11,7 @@ public class IslandCreateEvent extends IslandEvent implements Cancellable { private final SuperiorPlayer superiorPlayer; private final String schematic; - private boolean teleport = true; + private boolean teleport; private boolean cancelled = false; /** @@ -34,9 +34,22 @@ public IslandCreateEvent(SuperiorPlayer superiorPlayer, Island island) { * @param schematic The schematic that was used. */ public IslandCreateEvent(SuperiorPlayer superiorPlayer, Island island, String schematic) { + this(superiorPlayer, island, schematic, true); + } + + /** + * The constructor for the event. + * + * @param superiorPlayer The player who created the island. + * @param island The island object that was created. + * @param schematic The schematic that was used. + * @param teleport Whether the player should be teleported after creation. + */ + public IslandCreateEvent(SuperiorPlayer superiorPlayer, Island island, String schematic, boolean teleport) { super(island); this.superiorPlayer = superiorPlayer; this.schematic = schematic; + this.teleport = teleport; } /** diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 9d5a263f2e..8b55cede6b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -152,6 +152,7 @@ public class SettingsContainer { public final boolean islandNamesColorSupport; public final boolean islandNamesIslandTop; public final boolean islandNamesPreventPlayerNames; + public final boolean teleportOnCreate; public final boolean teleportOnJoin; public final boolean teleportOnKick; public final boolean clearOnJoin; @@ -397,8 +398,9 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config islandNamesColorSupport = config.getBoolean("island-names.color-support", true); islandNamesIslandTop = config.getBoolean("island-names.island-top", true); islandNamesPreventPlayerNames = config.getBoolean("island-names.prevent-player-names", true); + teleportOnCreate = config.getBoolean("teleport-on-create", true); teleportOnJoin = config.getBoolean("teleport-on-join", false); - teleportOnKick = config.getBoolean("teleport-on-kick", false); + teleportOnKick = config.getBoolean("teleport-on-kick", true); clearOnJoin = config.getBoolean("clear-on-join", false); rateOwnIsland = config.getBoolean("rate-own-island", false); changeIslandRating = config.getBoolean("change-island-rating", true); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index dd85aec140..2f20da140a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -282,6 +282,11 @@ public IslandNames getIslandNames() { return this.islandNames; } + @Override + public boolean isTeleportOnCreate() { + return this.global.isTeleportOnCreate(); + } + @Override public boolean isTeleportOnJoin() { return this.global.isTeleportOnJoin(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index c69ad28f42..3126cbcb89 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -137,6 +137,10 @@ public boolean isDisbandInventoryClear() { return getContainer().disbandInventoryClear; } + public boolean isTeleportOnCreate() { + return getContainer().teleportOnCreate; + } + public boolean isTeleportOnJoin() { return getContainer().teleportOnJoin; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java index c253798897..b4ea746823 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java @@ -646,7 +646,7 @@ public Event createBukkitEvent(IslandCoopPlayer args) { public static final PluginEventType ISLAND_CREATE_EVENT = new PluginEventType(IslandCreateEvent.class) { @Override public Event createBukkitEvent(IslandCreate args) { - return new IslandCreateEvent(args.superiorPlayer, args.island, args.schematicName); + return new IslandCreateEvent(args.superiorPlayer, args.island, args.schematicName, args.canTeleport); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java index f95d708446..e4104e1de8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java @@ -708,11 +708,12 @@ public static boolean callIslandCoopPlayerEvent(Island island, SuperiorPlayer su return !fireEvent(ISLAND_COOP_PLAYER_EVENT, islandCoopPlayer).isCancelled(); } - public static PluginEvent callIslandCreateEvent(Island island, SuperiorPlayer superiorPlayer, String schematicName) { + public static PluginEvent callIslandCreateEvent(Island island, SuperiorPlayer superiorPlayer, String schematicName, boolean canTeleport) { IslandCreate islandCreate = new IslandCreate(); islandCreate.island = island; islandCreate.superiorPlayer = superiorPlayer; islandCreate.schematicName = schematicName; + islandCreate.canTeleport = canTeleport; return fireEvent(ISLAND_CREATE_EVENT, islandCreate); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java index 5e5738310e..ca4adc3f5a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java @@ -92,7 +92,7 @@ public CompletableFuture createIsland(Island.Builder build island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.IDLE); - PluginEvent event = PluginEventsFactory.callIslandCreateEvent(island, builder.owner, builder.islandType); + PluginEvent event = PluginEventsFactory.callIslandCreateEvent(island, builder.owner, builder.islandType, plugin.getSettings().isTeleportOnCreate()); if (event.isCancelled()) { Log.debugResult(Debug.CREATE_ISLAND, "Creation Failed", "Event was cancelled for creating the island '" + builder.islandName + "'."); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 9c8f9cacd4..c6f6b2da6a 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -496,6 +496,9 @@ island-names: # Should the plugin prevent players from using player names as island names? prevent-player-names: false +# Should players get teleported to the island after they create it? +teleport-on-create: true + # Should players get teleported to the island after they accept an invite? teleport-on-join: false From 134f1e24b088c4150d1c16f0bcb9dfb141ac5f23 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 5 Jul 2025 13:47:41 +0300 Subject: [PATCH 219/600] Change some actions to not load worlds when not really necessary --- .../commands/admin/CmdAdminResetWorld.java | 2 +- .../superiorskyblock/commands/player/CmdVisit.java | 2 +- .../superiorskyblock/core/IslandWorlds.java | 11 ++++++++--- .../bgsoftware/superiorskyblock/island/SIsland.java | 13 ++++++++----- .../superiorskyblock/listener/PortalsListener.java | 2 +- .../algorithm/DefaultPlayerTeleportAlgorithm.java | 2 +- .../service/dragon/DragonBattleServiceImpl.java | 2 +- .../service/portals/PortalsManagerServiceImpl.java | 2 +- .../superiorskyblock/world/EntityTeleports.java | 2 +- 9 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java index 87dddbe056..b2027aa088 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java @@ -89,7 +89,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab ++islandsChangedCount; - IslandWorlds.accessIslandWorldAsync(island, dimension, islandWorldResult -> { + IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifLeft(world -> resetChunksInternal(island, world, dimension)); }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java index 05d95e23b9..da19bc5ef1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java @@ -73,7 +73,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); - IslandWorlds.accessIslandWorldAsync(targetIsland, dimension, islandWorldResult -> { + IslandWorlds.accessIslandWorldAsync(targetIsland, dimension, true, islandWorldResult -> { islandWorldResult.ifLeft(world -> teleportPlayerInternal(targetIsland, superiorPlayer)); }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java index f40bde7b1b..3f0335c8e6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java @@ -15,15 +15,15 @@ public class IslandWorlds { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - public static void accessIslandWorldsAsync(Island island, Consumer> consumer) { + public static void accessIslandWorldsAsync(Island island, boolean loadWorld, Consumer> consumer) { for (Dimension dimension : Dimension.values()) { if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && island.wasSchematicGenerated(dimension)) { - accessIslandWorldAsync(island, dimension, consumer); + accessIslandWorldAsync(island, dimension, loadWorld, consumer); } } } - public static void accessIslandWorldAsync(Island island, Dimension dimension, Consumer> consumer) { + public static void accessIslandWorldAsync(Island island, Dimension dimension, boolean loadWorld, Consumer> consumer) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); if (worldInfo == null) { consumer.accept(Either.right(new NullPointerException("Cannot find world for dimension " + dimension.getName()))); @@ -36,6 +36,11 @@ public static void accessIslandWorldAsync(Island island, Dimension dimension, Co return; } + if (!loadWorld) { + consumer.accept(Either.right(new NullPointerException("World is not loaded for dimension " + dimension.getName()))); + return; + } + WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); if (worldsProvider instanceof LazyWorldsProvider) { ((LazyWorldsProvider) worldsProvider).prepareWorld(island, dimension, () -> diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index e80427549f..23b6b8f1ba 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -1285,7 +1285,7 @@ public void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && wasSchematicGenerated(dimension)) { hasDimension = true; lastDimension.setValue(dimension); - IslandWorlds.accessIslandWorldAsync(this, dimension, result -> { + IslandWorlds.accessIslandWorldAsync(this, dimension, true, result -> { result.ifLeft(world -> { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, realFlags); @@ -1314,7 +1314,7 @@ public void resetChunks(Dimension dimension, @IslandChunkFlags int flags) { public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, @Nullable Runnable onFinish) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); - IslandWorlds.accessIslandWorldAsync(this, dimension, result -> { + IslandWorlds.accessIslandWorldAsync(this, dimension, true, result -> { if (result.getRight() == null) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); List chunkPositions = IslandUtils.getChunkCoords(this, @@ -2024,7 +2024,7 @@ private CompletableFuture getBiomeAsyncTask(CompletableFuture curr CompletableFuture newTask = new CompletableFuture<>(); - IslandWorlds.accessIslandWorldAsync(this, defaultWorldDimension, islandWorldResult -> { + IslandWorlds.accessIslandWorldAsync(this, defaultWorldDimension, true, islandWorldResult -> { if (islandWorldResult.getRight() != null) { newTask.completeExceptionally(islandWorldResult.getRight()); return; @@ -2071,7 +2071,7 @@ public void setBiome(Biome biome, boolean updateBlocks) { List playersToUpdate = new SequentialListBuilder() .build(getAllPlayersInside(), SuperiorPlayer::asPlayer); - IslandWorlds.accessIslandWorldsAsync(this, result -> { + IslandWorlds.accessIslandWorldsAsync(this, false, result -> { result.ifLeft(world -> { WorldInfo worldInfo = WorldInfo.of(world); Biome worldBiome = plugin.getSettings().getWorlds().getDefaultWorldDimension() == worldInfo.getDimension() ? @@ -5197,11 +5197,14 @@ private void notifyCropGrowthChange(double newCropGrowth) { if (!BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class)) return; + // If the world is not loaded, we can skip this + + final int flags = IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS; double newCropGrowthMultiplier = newCropGrowth - 1; - IslandWorlds.accessIslandWorldsAsync(this, result -> { + IslandWorlds.accessIslandWorldsAsync(this, false, result -> { result.ifLeft(world -> { WorldInfo worldInfo = WorldInfo.of(world); List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, flags); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java index a8999d8728..362e444f51 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java @@ -87,7 +87,7 @@ private void onEntityEnterPortal(GameEvent BukkitExecutor.sync(() -> { Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); - IslandWorlds.accessIslandWorldAsync(island, dimension, islandWorldResult -> { + IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifRight(error -> { if (teleportedPlayer != null) teleportedPlayer.removePlayerStatus(PlayerStatus.LEAVING_ISLAND); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java index f535d11ae4..d5e97cdad1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java @@ -45,7 +45,7 @@ public CompletableFuture teleport(Player player, Island island) { @Override public CompletableFuture teleport(Player player, Island island, Dimension dimension) { CompletableFuture result = new CompletableFuture<>(); - IslandWorlds.accessIslandWorldAsync(island, dimension, islandWorldResult -> { + IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifRight(result::completeExceptionally).ifLeft(world -> teleportInternal(player, island, dimension, result)); }); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java index 0a31e016c6..17dfd370fd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java @@ -85,7 +85,7 @@ public DragonBattleResetResult resetEnderDragonBattle(Island island, Dimension d stopEnderDragonBattle(island, dimension); - IslandWorlds.accessIslandWorldAsync(island, dimension, islandWorldResult -> { + IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { Location islandCenter = island.getCenter(dimension); plugin.getNMSDragonFight().startDragonBattle(island, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java index e1d3bb69fe..0223b1da8a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java @@ -237,7 +237,7 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island return EntityPortalResult.SUCCEED; } - IslandWorlds.accessIslandWorldAsync(island, destination, islandWorldResult -> { + IslandWorlds.accessIslandWorldAsync(island, destination, true, islandWorldResult -> { islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { Location schematicPlacementLocation = island.getCenter(destination).subtract(0, 1, 0); schematicPlacementLocation.setY(plugin.getSettings().getIslandHeight()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java index 5eb69710f2..7214dac92f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java @@ -88,7 +88,7 @@ public static void teleportUntilSuccess(Entity entity, Location location, long c public static CompletableFuture findIslandSafeLocation(Island island, Dimension dimension) { CompletableFuture result = new CompletableFuture<>(); - IslandWorlds.accessIslandWorldAsync(island, dimension, islandWorldResult -> { + IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifRight(result::completeExceptionally).ifLeft(world -> findIslandSafeLocation(island, dimension, result)); }); From 9f7bcfeffad0652a6690171b845fb441a2c842c7 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 19 Jul 2025 12:25:59 +0300 Subject: [PATCH 220/600] Adds support to 1.21.8 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6366379394..c34c8ac910 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b13' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b14' implementation 'com.zaxxer:HikariCP:4.0.3' implementation 'org.slf4j:slf4j-api:2.0.5' From 78e7264459ddc68f8bc6cccc952e0a98ca700d3e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 23 Jul 2025 22:01:11 +0300 Subject: [PATCH 221/600] Fixed an error caused when teleporting using the admin command to worlds that were not generated when the player is not inside the island (#2573) --- .../commands/admin/CmdAdminTeleport.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java index 80d7eecd6c..bb60135adb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java @@ -10,13 +10,10 @@ import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.LazyReference; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; -import org.bukkit.Location; import org.bukkit.PortalType; import org.bukkit.World; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; import java.util.Arrays; import java.util.Collections; @@ -96,10 +93,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (dimension != plugin.getSettings().getWorlds().getDefaultWorldDimension()) { if (!island.wasSchematicGenerated(dimension)) { PortalType portalType = dimension.getEnvironment() == World.Environment.NETHER ? PortalType.NETHER : PortalType.ENDER; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, - ((Player) sender).getLocation(wrapper.getHandle()), portalType, false); - } + portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, + island.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()), portalType, false); return; } } From fd0712f163de6abe11906ed7ce46b5f558a9b926 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Thu, 24 Jul 2025 10:18:02 +0200 Subject: [PATCH 222/600] Fixed creating schematics with signs on 1.21.7 (#2567) --- .../nms/v1_21_7/world/WorldEditSessionImpl.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java index c42845a8bc..00634b1ba4 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java @@ -296,8 +296,10 @@ private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntity } } - while (textLines.size() < 4) - textLines.add(Component.empty()); + for (int i = 0; i < 4; i++) { + if (textLines.get(i) == null) + textLines.set(i, Component.empty()); + } Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); From d109a14015abee61818304714f52c184c837caa6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 24 Jul 2025 14:05:07 +0300 Subject: [PATCH 223/600] Fixed list tags can have elements with different tag types (#2574) --- .../superiorskyblock/tag/ListTag.java | 120 +++++++++++++----- .../superiorskyblock/tag/NBTUtils.java | 4 +- 2 files changed, 92 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java index ce631e93b8..ff11002f5e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java @@ -33,16 +33,18 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) package com.bgsoftware.superiorskyblock.tag; import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; +import java.util.RandomAccess; /** * The TAG_List tag. @@ -52,40 +54,65 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @SuppressWarnings("rawtypes") public class ListTag extends Tag>> implements Iterable> { + private static final byte DYNAMIC_LIST_INDICATOR = (byte) 0xFF; /*package*/ static final Class CLASS = getNNTClass("NBTTagList"); /** - * The type. + * Hint to the type of elements in the list. */ - private final Class type; + @Nullable + private Class hintType; /** * Creates the tag. * - * @param type The type of item in the list. - * @param value The value. + * @param hintType Hint for the type of all items in the list. + * @param value The value. */ - public ListTag(Class type, List> value) { - super(new ArrayList<>(value), null); - this.type = type; + public ListTag(@Nullable Class hintType, List> value) { + this(value, hintType, true); + } + + private ListTag(List> value, @Nullable Class hintType, boolean cloneList) { + super(cloneListIfNeeded(value, cloneList), null); + this.hintType = hintType; } public ListTag copy() { - return new ListTag(type, value); + return new ListTag(this.hintType, this.value); + } + + public void addTag(Tag tag) { + this.value.add(tag); + // In case the type of the tag is not similar to the hintType, we reset it. + if (this.hintType != null && tag.getClass() != this.hintType) { + this.hintType = null; + } } public static ListTag fromNBT(Object tag) { Preconditions.checkArgument(tag.getClass().equals(CLASS), "Cannot convert " + tag.getClass() + " to ListTag!"); - List> list = new ArrayList<>(); + List> list = new LinkedList<>(); try { int size = plugin.getNMSTags().getNBTTagListSize(tag); + Class lastTagType = null; + boolean isSimilarType = true; + + for (int i = 0; i < size; i++) { + Tag currTag = Tag.fromNBT(plugin.getNMSTags().getNBTListIndexValue(tag, i)); + if (isSimilarType) { + if (lastTagType != null && currTag.getClass() != lastTagType) { + isSimilarType = false; + } else { + lastTagType = currTag.getClass(); + } + } + list.add(currTag); + } - for (int i = 0; i < size; i++) - list.add(Tag.fromNBT(plugin.getNMSTags().getNBTListIndexValue(tag, i))); - - return new ListTag(size == 0 ? EndTag.class : list.get(0).getClass(), list); + return new ListTag(list, !isSimilarType || size == 0 ? null : lastTagType, false); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag list from NMS:"); return null; @@ -94,18 +121,40 @@ public static ListTag fromNBT(Object tag) { public static ListTag fromStream(DataInputStream is, int depth) throws IOException { int childType = is.readByte(); + return childType == DYNAMIC_LIST_INDICATOR ? + fromStreamWithoutHint(is, depth) : fromStreamWithHint(is, depth, childType); + } + + private static ListTag fromStreamWithHint(DataInputStream is, int depth, int childType) throws IOException { + int length = is.readInt(); + + List> tagList = new LinkedList<>(); + + for (int i = 0; i < length; i++) { + Tag tag = Tag.fromStream(is, depth + 1, childType); + if (tag instanceof EndTag) { + throw new IOException("TAG_End not permitted in a list."); + } + tagList.add(tag); + } + + return new ListTag(tagList, NBTUtils.getTypeClass(childType), false); + } + + private static ListTag fromStreamWithoutHint(DataInputStream is, int depth) throws IOException { int length = is.readInt(); - List> tagList = new ArrayList<>(); + + List> tagList = new LinkedList<>(); for (int i = 0; i < length; i++) { - Tag tag = fromStream(is, depth + 1, childType); + Tag tag = Tag.fromStream(is, depth + 1); if (tag instanceof EndTag) { throw new IOException("TAG_End not permitted in a list."); } tagList.add(tag); } - return new ListTag(NBTUtils.getTypeClass(childType), tagList); + return new ListTag(tagList, null, false); } @Override @@ -126,7 +175,11 @@ public int size() { @Override public String toString() { StringBuilder bldr = new StringBuilder(); - bldr.append("TAG_List: ").append(value.size()).append(" entries of type ").append(NBTUtils.getTypeName(type)).append("\r\n{\r\n"); + bldr.append("TAG_List: ").append(value.size()).append(" entries"); + if (this.hintType != null) { + bldr.append(" of type ").append(NBTUtils.getTypeName(hintType)); + } + bldr.append("\r\n{\r\n"); for (Tag t : value) { bldr.append(" ").append(t.toString().replaceAll("\r\n", "\r\n ")).append("\r\n"); } @@ -136,29 +189,36 @@ public String toString() { @Override protected void writeData(DataOutputStream os) throws IOException { + if (this.hintType != null) { + writeDataWithHint(os); + } else { + writeDataWithoutHint(os); + } + } + + private void writeDataWithHint(DataOutputStream os) throws IOException { int size = value.size(); - os.writeByte(NBTUtils.getTypeCode(type)); + os.writeByte(NBTUtils.getTypeCode(this.hintType)); os.writeInt(size); for (Tag _tag : value) _tag.writeData(os); } + private void writeDataWithoutHint(DataOutputStream os) throws IOException { + int size = value.size(); + os.writeByte(DYNAMIC_LIST_INDICATOR); + os.writeInt(size); + for (Tag _tag : value) + _tag.write(os); + } + @Override public Object toNBT() { return plugin.getNMSTags().parseList(this); } - /** - * Gets the type of item in this list. - * - * @return The type of item in this list. - */ - public Class getType() { - return type; - } - - public void addTag(Tag tag) { - value.add(tag); + private static List cloneListIfNeeded(List list, boolean cloneList) { + return cloneList || list instanceof RandomAccess ? new LinkedList<>(list) : list; } } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/NBTUtils.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/NBTUtils.java index 53c5460421..8c2cd34404 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/NBTUtils.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/NBTUtils.java @@ -81,7 +81,7 @@ public static String getTypeName(Class clazz) { } else if (clazz.equals(IntArrayTag.class)) { return "TAG_Int_Array"; } else { - throw new IllegalArgumentException("Invalid tag classs (" + clazz.getName() + ")."); + throw new IllegalArgumentException("Invalid tag class (" + clazz.getName() + ")."); } } @@ -124,7 +124,7 @@ public static int getTypeCode(Class clazz) { } else if (clazz.equals(UUIDTag.class)) { return NBTTags.TYPE_UUID; } else { - throw new IllegalArgumentException("Invalid tag classs (" + clazz.getName() + ")."); + throw new IllegalArgumentException("Invalid tag class (" + clazz.getName() + ")."); } } From 67d3dcdc9e8736d97be730af85bbc039bd763383 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 24 Jul 2025 15:26:19 +0300 Subject: [PATCH 224/600] Reuse tag objects whenever possible --- .../nms/v1_12_R1/NMSTagsImpl.java | 11 +- .../nms/v1_16_R3/NMSTagsImpl.java | 11 +- .../nms/v1_16_R3/world/ChunkReaderImpl.java | 26 +-- .../nms/v1_17/NMSTagsImpl.java | 11 +- .../nms/v1_17/world/ChunkReaderImpl.java | 2 +- .../nms/v1_18/NMSTagsImpl.java | 11 +- .../nms/v1_18/world/ChunkReaderImpl.java | 2 +- .../nms/v1_19/NMSTagsImpl.java | 11 +- .../nms/v1_19/world/ChunkReaderImpl.java | 2 +- .../nms/v1_20_3/NMSTagsImpl.java | 11 +- .../nms/v1_20_3/world/ChunkReaderImpl.java | 2 +- .../nms/v1_20_4/NMSTagsImpl.java | 11 +- .../nms/v1_20_4/world/ChunkReaderImpl.java | 2 +- .../nms/v1_21/NMSTagsImpl.java | 11 +- .../nms/v1_21/world/ChunkReaderImpl.java | 2 +- .../nms/v1_21_3/NMSTagsImpl.java | 11 +- .../nms/v1_21_3/world/ChunkReaderImpl.java | 2 +- .../nms/v1_21_4/NMSTagsImpl.java | 11 +- .../nms/v1_21_4/world/ChunkReaderImpl.java | 2 +- .../nms/v1_21_5/NMSTagsImpl.java | 11 +- .../nms/v1_21_5/world/ChunkReaderImpl.java | 2 +- .../nms/v1_21_7/NMSTagsImpl.java | 11 +- .../nms/v1_21_7/world/ChunkReaderImpl.java | 2 +- .../nms/v1_8_R3/NMSTagsImpl.java | 11 +- .../config/SettingsContainer.java | 2 +- .../core/itemstack/ItemSkulls.java | 11 +- .../PersistenceDataTypeSerializer.java | 24 +-- .../PersistentDataContainerImpl.java | 8 +- .../core/schematic/SchematicBlock.java | 26 +-- .../impl/InventorySerializer.java | 14 +- .../impl/ItemStack2TagSerializer.java | 2 +- .../superiorskyblock/tag/BigDecimalTag.java | 8 +- .../superiorskyblock/tag/ByteArrayTag.java | 12 +- .../superiorskyblock/tag/ByteTag.java | 17 +- .../superiorskyblock/tag/CompoundTag.java | 129 +++++++------ .../superiorskyblock/tag/DoubleTag.java | 19 +- .../superiorskyblock/tag/EndTag.java | 10 +- .../superiorskyblock/tag/FloatTag.java | 19 +- .../superiorskyblock/tag/IntArrayTag.java | 24 ++- .../superiorskyblock/tag/IntTag.java | 19 +- .../superiorskyblock/tag/ListTag.java | 20 +- .../superiorskyblock/tag/LongTag.java | 19 +- .../superiorskyblock/tag/NumberTag.java | 2 +- .../tag/PersistentDataTag.java | 6 +- .../tag/PersistentDataTagSerialized.java | 10 +- .../superiorskyblock/tag/ShortTag.java | 19 +- .../superiorskyblock/tag/StringTag.java | 17 +- .../bgsoftware/superiorskyblock/tag/Tag.java | 2 +- .../superiorskyblock/tag/UUIDTag.java | 12 +- .../world/schematic/SchematicBuilder.java | 41 ++-- .../schematic/SchematicsManagerImpl.java | 26 +-- .../schematic/impl/SuperiorSchematic.java | 28 +-- .../impl/SuperiorSchematicDeserializer.java | 177 +++++++----------- 53 files changed, 487 insertions(+), 425 deletions(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSTagsImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSTagsImpl.java index fc977fa8cd..f1d29f0054 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSTagsImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSTagsImpl.java @@ -55,15 +55,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.setTag((NBTTagCompound) nbtData.toNBT()); + if (nbtData != null) + itemStack.setTag((NBTTagCompound) nbtData.toNBT()); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSTagsImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSTagsImpl.java index c2a34446ef..1eded48c8a 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSTagsImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSTagsImpl.java @@ -69,15 +69,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.setTag((NBTTagCompound) nbtData.toNBT()); + if (nbtData != null) + itemStack.setTag((NBTTagCompound) nbtData.toNBT()); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java index f35ccc4c9e..9db005aa3e 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/ChunkReaderImpl.java @@ -4,11 +4,7 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.tag.ByteTag; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.BlockStateBoolean; @@ -22,7 +18,6 @@ import net.minecraft.server.v1_16_R3.EnumSkyBlock; import net.minecraft.server.v1_16_R3.GameProfileSerializer; import net.minecraft.server.v1_16_R3.IBlockData; -import net.minecraft.server.v1_16_R3.IBlockState; import net.minecraft.server.v1_16_R3.LightEngine; import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.NBTTagFloat; @@ -155,24 +150,21 @@ public CompoundTag readBlockStates(int x, int y, int z) { if (blockData.getStateMap().isEmpty()) return null; - CompoundTag compoundTag = new CompoundTag(); + CompoundTag compoundTag = CompoundTag.of(); - for (Map.Entry, Comparable> entry : blockData.getStateMap().entrySet()) { - Tag value; - Class keyClass = entry.getKey().getClass(); - String name = BlockStatesMapper.getBlockStateName(entry.getKey()); + blockData.getStateMap().forEach((blockState, value) -> { + Class keyClass = blockState.getClass(); + String name = BlockStatesMapper.getBlockStateName(blockState); if (keyClass.equals(BlockStateBoolean.class)) { - value = new ByteTag((Boolean) entry.getValue() ? (byte) 1 : 0); + compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); } else if (keyClass.equals(BlockStateInteger.class)) { - BlockStateInteger key = (BlockStateInteger) entry.getKey(); - value = new IntArrayTag(new int[]{(Integer) entry.getValue(), key.min, key.max}); + BlockStateInteger key = (BlockStateInteger) blockState; + compoundTag.setIntArray(name, new int[]{(Integer) value, key.min, key.max}); } else { - value = new StringTag(((Enum) entry.getValue()).name()); + compoundTag.setString(name, ((Enum) value).name()); } - - compoundTag.setTag(name, value); - } + }); return compoundTag; } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java index 1731b94bfc..672f798645 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java @@ -59,15 +59,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.setTag((net.minecraft.nbt.CompoundTag) nbtData.toNBT()); + if (nbtData != null) + itemStack.setTag((net.minecraft.nbt.CompoundTag) nbtData.toNBT()); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java index 7c8e1a82fb..1fdfb6c1f4 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java @@ -153,7 +153,7 @@ public CompoundTag readBlockStates(int x, int y, int z) { if (blockState.getValues().isEmpty()) return null; - CompoundTag compoundTag = new CompoundTag(); + CompoundTag compoundTag = CompoundTag.of(); blockState.getValues().forEach((property, value) -> { String name = PropertiesMapper.getPropertyName(property); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java index 0dc7eb060e..a44b570218 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java @@ -59,15 +59,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.setTag((net.minecraft.nbt.CompoundTag) nbtData.toNBT()); + if (nbtData != null) + itemStack.setTag((net.minecraft.nbt.CompoundTag) nbtData.toNBT()); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java index 19e588d294..a4e5eeb5e3 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java @@ -147,7 +147,7 @@ public CompoundTag readBlockStates(int x, int y, int z) { if (blockState.getValues().isEmpty()) return null; - CompoundTag compoundTag = new CompoundTag(); + CompoundTag compoundTag = CompoundTag.of(); blockState.getValues().forEach((property, value) -> { String name = PropertiesMapper.getPropertyName(property); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java index b8610a0bde..1855b25ba0 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java @@ -59,15 +59,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.setTag((net.minecraft.nbt.CompoundTag) nbtData.toNBT()); + if (nbtData != null) + itemStack.setTag((net.minecraft.nbt.CompoundTag) nbtData.toNBT()); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java index 06dceae8a3..0138394d63 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java @@ -148,7 +148,7 @@ public CompoundTag readBlockStates(int x, int y, int z) { if (blockState.getValues().isEmpty()) return null; - CompoundTag compoundTag = new CompoundTag(); + CompoundTag compoundTag = CompoundTag.of(); blockState.getValues().forEach((property, value) -> { String name = PropertiesMapper.getPropertyName(property); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java index bdc04ac1a9..7b5f22efde 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java @@ -59,15 +59,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.setTag((net.minecraft.nbt.CompoundTag) nbtData.toNBT()); + if (nbtData != null) + itemStack.setTag((net.minecraft.nbt.CompoundTag) nbtData.toNBT()); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java index ba9173424c..887780d3df 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java @@ -155,7 +155,7 @@ public CompoundTag readBlockStates(int x, int y, int z) { if (blockState.getValues().isEmpty()) return null; - CompoundTag compoundTag = new CompoundTag(); + CompoundTag compoundTag = CompoundTag.of(); blockState.getValues().forEach((property, value) -> { String name = PropertiesMapper.getPropertyName(property); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java index 455a785e8a..926623604c 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java @@ -67,15 +67,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); + if (nbtData != null) + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java index b9156b44df..f437e7886a 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java @@ -156,7 +156,7 @@ public CompoundTag readBlockStates(int x, int y, int z) { if (blockState.getValues().isEmpty()) return null; - CompoundTag compoundTag = new CompoundTag(); + CompoundTag compoundTag = CompoundTag.of(); blockState.getValues().forEach((property, value) -> { String name = PropertiesMapper.getPropertyName(property); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java index 6564baad89..bc39b97ada 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java @@ -67,15 +67,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); + if (nbtData != null) + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java index 7dd5afc8d2..67740dd550 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java @@ -156,7 +156,7 @@ public CompoundTag readBlockStates(int x, int y, int z) { if (blockState.getValues().isEmpty()) return null; - CompoundTag compoundTag = new CompoundTag(); + CompoundTag compoundTag = CompoundTag.of(); blockState.getValues().forEach((property, value) -> { String name = PropertiesMapper.getPropertyName(property); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java index 6742096e05..35da93c380 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java @@ -68,15 +68,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); + if (nbtData != null) + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java index f415010496..398de5a92a 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java @@ -156,7 +156,7 @@ public CompoundTag readBlockStates(int x, int y, int z) { if (blockState.getValues().isEmpty()) return null; - CompoundTag compoundTag = new CompoundTag(); + CompoundTag compoundTag = CompoundTag.of(); blockState.getValues().forEach((property, value) -> { String name = PropertiesMapper.getPropertyName(property); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java index ded586dbfc..c2ea3b884b 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java @@ -68,15 +68,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); + if (nbtData != null) + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java index 8d18c1d5cc..77a0b094da 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java @@ -156,7 +156,7 @@ public CompoundTag readBlockStates(int x, int y, int z) { if (blockState.getValues().isEmpty()) return null; - CompoundTag compoundTag = new CompoundTag(); + CompoundTag compoundTag = CompoundTag.of(); blockState.getValues().forEach((property, value) -> { String name = PropertiesMapper.getPropertyName(property); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java index 43d0f34025..8b98b0402d 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java @@ -68,15 +68,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); + if (nbtData != null) + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java index f08e37e3a1..c63a16970e 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java @@ -156,7 +156,7 @@ public CompoundTag readBlockStates(int x, int y, int z) { if (blockState.getValues().isEmpty()) return null; - CompoundTag compoundTag = new CompoundTag(); + CompoundTag compoundTag = CompoundTag.of(); blockState.getValues().forEach((property, value) -> { String name = PropertiesMapper.getPropertyName(property); diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java index 684b240385..5e6de56260 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java @@ -81,15 +81,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); + if (nbtData != null) + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/ChunkReaderImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/ChunkReaderImpl.java index f064d3c74d..48f216ac92 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/ChunkReaderImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/ChunkReaderImpl.java @@ -162,7 +162,7 @@ public CompoundTag readBlockStates(int x, int y, int z) { if (blockState.getValues().isEmpty()) return null; - CompoundTag compoundTag = new CompoundTag(); + CompoundTag compoundTag = CompoundTag.of(); blockState.getValues().forEach((property, value) -> { String name = PropertiesMapper.getPropertyName(property); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSTagsImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSTagsImpl.java index 535f42721a..557ef4e028 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSTagsImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSTagsImpl.java @@ -55,15 +55,16 @@ public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { } private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type")); + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount"); - short data = compoundTag.getShort("data"); - CompoundTag nbtData = compoundTag.getCompound("NBT"); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - itemStack.setTag((NBTTagCompound) nbtData.toNBT()); + if (nbtData != null) + itemStack.setTag((NBTTagCompound) nbtData.toNBT()); return CraftItemStack.asCraftMirror(itemStack); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 8b55cede6b..0211d112a9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -444,7 +444,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config for (String container : config.getConfigurationSection("default-containers.containers").getKeys(false)) { try { InventoryType containerType = InventoryType.valueOf(container.toUpperCase(Locale.ENGLISH)); - ListTag items = new ListTag(CompoundTag.class, Collections.emptyList()); + ListTag items = ListTag.of(CompoundTag.class); defaultContainersContents.put(containerType, items); ConfigurationSection containerSection = config.getConfigurationSection("default-containers.containers." + container); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemSkulls.java b/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemSkulls.java index ede859f612..fa493b5c04 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemSkulls.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemSkulls.java @@ -14,7 +14,6 @@ import org.bukkit.inventory.ItemStack; import java.io.File; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.UUID; @@ -65,9 +64,9 @@ public static ItemStack getPlayerHead(ItemStack itemStack, String texture) { public static ItemStack getPlayerHeadNoNMS(ItemStack itemStack, String texture) { CompoundTag compoundTag = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.serialize(itemStack); - CompoundTag tagCompound = compoundTag.getCompound("tag", new CompoundTag()); + CompoundTag tagCompound = compoundTag.getCompound("tag").orElseGet(CompoundTag::of); - CompoundTag skullOwner = tagCompound.getCompound("SkullOwner", new CompoundTag()); + CompoundTag skullOwner = tagCompound.getCompound("SkullOwner").orElseGet(CompoundTag::of); UUID ownerUUID = new UUID(texture.hashCode(), texture.hashCode()); @@ -77,10 +76,10 @@ public static ItemStack getPlayerHeadNoNMS(ItemStack itemStack, String texture) skullOwner.setString("Id", ownerUUID.toString()); } - CompoundTag properties = new CompoundTag(); + CompoundTag properties = CompoundTag.of(); - ListTag textures = new ListTag(CompoundTag.class, Collections.emptyList()); - CompoundTag signature = new CompoundTag(); + ListTag textures = ListTag.of(CompoundTag.class); + CompoundTag signature = CompoundTag.of(); signature.setString("Value", texture); textures.addTag(signature); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/persistence/PersistenceDataTypeSerializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/persistence/PersistenceDataTypeSerializer.java index 8a1ac08fdd..70c874c4b8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/persistence/PersistenceDataTypeSerializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/persistence/PersistenceDataTypeSerializer.java @@ -28,17 +28,17 @@ public class PersistenceDataTypeSerializer { private static final Map, Function>> CLASS_TO_NBT = new ImmutableMap.Builder, Function>>() - .put(BigDecimal.class, value -> new BigDecimalTag((BigDecimal) value)) - .put(byte[].class, value -> new ByteArrayTag((byte[]) value)) - .put(Byte.class, value -> new ByteTag((byte) value)) - .put(Double.class, value -> new DoubleTag((double) value)) - .put(Float.class, value -> new FloatTag((float) value)) - .put(int[].class, value -> new IntArrayTag((int[]) value)) - .put(Integer.class, value -> new IntTag((int) value)) - .put(Long.class, value -> new LongTag((long) value)) - .put(Short.class, value -> new ShortTag((short) value)) - .put(String.class, value -> new StringTag((String) value)) - .put(UUID.class, value -> new UUIDTag((UUID) value)) + .put(BigDecimal.class, value -> BigDecimalTag.of((BigDecimal) value)) + .put(byte[].class, value -> ByteArrayTag.of((byte[]) value)) + .put(Byte.class, value -> ByteTag.of((byte) value)) + .put(Double.class, value -> DoubleTag.of((double) value)) + .put(Float.class, value -> FloatTag.of((float) value)) + .put(int[].class, value -> IntArrayTag.of((int[]) value)) + .put(Integer.class, value -> IntTag.of((int) value)) + .put(Long.class, value -> LongTag.of((long) value)) + .put(Short.class, value -> ShortTag.of((short) value)) + .put(String.class, value -> StringTag.of((String) value)) + .put(UUID.class, value -> UUIDTag.of((UUID) value)) .build(); private PersistenceDataTypeSerializer() { @@ -58,7 +58,7 @@ public static T deserialize(Tag tag, PersistentDataType type) throws I public static Tag serialize(T value, PersistentDataType type) { PersistentDataTypeContext serializer = type.getContext(); if (serializer != null) - return new PersistentDataTag<>(value, serializer); + return PersistentDataTag.of(value, serializer); Tag serializedTag = primitiveSerialize(value); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/persistence/PersistentDataContainerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/persistence/PersistentDataContainerImpl.java index 099b58fd2b..ebe840afa5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/persistence/PersistentDataContainerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/persistence/PersistentDataContainerImpl.java @@ -21,7 +21,7 @@ public class PersistentDataContainerImpl implements PersistentDataContainer { private final E holder; private final Consumer saveFunction; - private final CompoundTag innerTag = new CompoundTag(); + private final CompoundTag innerTag = CompoundTag.of(); public PersistentDataContainerImpl(E holder, Consumer saveFunction) { this.holder = holder; @@ -37,7 +37,7 @@ public boolean has(String key) { public boolean hasKeyOfType(String key, PersistentDataType type) { Preconditions.checkNotNull(key, "key parameter cannot be null"); Preconditions.checkNotNull(type, "type parameter cannot be null"); - Tag tag = innerTag.getTag(key); + Tag tag = innerTag.getTag(key).orElse(null); return tag != null && PersistenceDataTypeSerializer.isTagOfType(tag, type); } @@ -160,7 +160,7 @@ public void load(byte[] data) { @Nullable private T _getOfType(String key, PersistentDataType type, @Nullable T def) { - Tag tag = innerTag.getTag(key); + Tag tag = innerTag.getTag(key).orElse(null); if (tag == null) { return def; @@ -176,7 +176,7 @@ private T _getOfType(String key, PersistentDataType type, @Nullable T def @Nullable private Object _get(String key, @Nullable Object def) { - Tag tag = innerTag.getTag(key); + Tag tag = innerTag.getTag(key).orElse(null); return tag == null ? def : tag.getValue(); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java index 3fd6b72677..0e18815365 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java @@ -16,6 +16,8 @@ public class SchematicBlock { + private static final ListTag EMPTY_LIST_TAG = ListTag.of(Collections.emptyList()); + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final String SIGN_ID = ServerVersion.isLegacy() ? "Sign" : "minecraft:sign"; @@ -62,7 +64,7 @@ public CompoundTag getStatesTag() { @Nullable public CompoundTag getOriginalTileEntity() { CompoundTag tileEntity = this.extra == null ? null : this.extra.tileEntity; - return tileEntity == null ? null : new CompoundTag(tileEntity); + return tileEntity == null ? null : tileEntity.copy(); } @Nullable @@ -78,7 +80,7 @@ public void doPrePlace(Island island) { this.tileEntityData = CompoundTag.fromNBT(originalTileEntity.toNBT()); - String id = this.tileEntityData.getString("id"); + String id = this.tileEntityData.getString("id").orElse(null); if (id == null) { Log.warn("Weird tile-entity data detected: " + this.tileEntityData.getValue()); @@ -93,7 +95,7 @@ public void doPrePlace(Island island) { } } else if (id.equalsIgnoreCase(CHEST_ID)) { if (plugin.getSettings().getDefaultContainers().isEnabled()) { - String inventoryType = this.tileEntityData.getString("inventoryType"); + String inventoryType = this.tileEntityData.getString("inventoryType").orElse(null); if (inventoryType != null) { try { InventoryType containerType = InventoryType.valueOf(inventoryType); @@ -111,7 +113,7 @@ public boolean shouldPostPlace() { if (this.tileEntityData == null) return false; - String id = this.tileEntityData.getString("id"); + String id = this.tileEntityData.getString("id").orElse(null); return id != null && id.equalsIgnoreCase(SIGN_ID); } @@ -124,18 +126,18 @@ public void doPostPlace(Island island) { } private static void backFrontSignLinesReplace(CompoundTag tileEntityData, Island island) { - CompoundTag frontText = tileEntityData.getCompound("front_text"); - CompoundTag backText = tileEntityData.getCompound("back_text"); + CompoundTag frontText = tileEntityData.getCompound("front_text").orElse(null); + CompoundTag backText = tileEntityData.getCompound("back_text").orElse(null); if (frontText == null || backText == null) { // This should never occur Log.error("Invalid sign tile entity data: ", tileEntityData); } - ListTag frontTextMessages = frontText.getList("messages"); - ListTag backTextMessages = backText.getList("messages"); - ListTag newFrontTextMessages = new ListTag(StringTag.class, Collections.emptyList()); - ListTag newBackTextMessages = new ListTag(StringTag.class, Collections.emptyList()); + ListTag frontTextMessages = frontText.getList("messages").orElse(EMPTY_LIST_TAG); + ListTag backTextMessages = backText.getList("messages").orElse(EMPTY_LIST_TAG); + ListTag newFrontTextMessages = ListTag.of(StringTag.class); + ListTag newBackTextMessages = ListTag.of(StringTag.class); for (int i = 0; i < 8; ++i) { ListTag messages = i < 4 ? frontTextMessages : backTextMessages; @@ -153,7 +155,7 @@ private static void backFrontSignLinesReplace(CompoundTag tileEntityData, Island line = line.replace("{player}", island.getOwner().getName()) .replace("{island}", island.getName().isEmpty() ? island.getOwner().getName() : island.getName()); - newMessages.addTag(new StringTag(line)); + newMessages.addTag(StringTag.of(line)); } frontText.setTag("messages", newFrontTextMessages); @@ -168,7 +170,7 @@ private static void legacySignLinesReplace(CompoundTag tileEntityData, Island is String line; if ((i - 1) >= plugin.getSettings().getDefaultSign().size()) { - line = tileEntityData.getString("Text" + i); + line = tileEntityData.getString("Text" + i).orElse(null); } else { line = plugin.getSettings().getDefaultSign().get(i - 1); if (ServerVersion.isAtLeast(ServerVersion.v1_17)) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/InventorySerializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/InventorySerializer.java index 5b648aa588..1f84099b9f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/InventorySerializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/InventorySerializer.java @@ -25,6 +25,8 @@ public class InventorySerializer implements ISerializer { private static final ItemStack[] EMPTY_CONTENTS = new ItemStack[0]; private static final byte[] EMPTY_SERIALIZED_DATA = new byte[0]; + private static final byte[] EMPTY_SLOTS = new byte[0]; + private static final ListTag EMPTY_ITEMS_LIST = ListTag.of(Collections.emptyList()); private static final InventorySerializer INSTANCE = new InventorySerializer(); @@ -44,7 +46,7 @@ public byte[] serialize(@Nullable ItemStack[] serializable) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); DataOutputStream dataOutput = new DataOutputStream(outputStream); - CompoundTag compoundTag = new CompoundTag(); + CompoundTag compoundTag = CompoundTag.of(); List serializedItems = new ArrayList<>(serializable.length); byte[] slots = new byte[serializable.length * 2]; @@ -70,7 +72,7 @@ public byte[] serialize(@Nullable ItemStack[] serializable) { } } - ListTag items = new ListTag(CompoundTag.class, Collections.emptyList()); + ListTag items = ListTag.of(CompoundTag.class); for (ItemStack itemStack : serializedItems) items.addTag(Serializers.ITEM_STACK_TO_TAG_SERIALIZER.serialize(itemStack)); @@ -114,16 +116,16 @@ private static ItemStack[] deserialize(byte[] deserializable, boolean tryAgain) ItemStack[] contents; if (compoundTag.containsKey("Length")) { - contents = new ItemStack[compoundTag.getInt("Length")]; + contents = new ItemStack[compoundTag.getInt("Length").orElse(0)]; for (int i = 0; i < contents.length; i++) { - CompoundTag itemCompound = compoundTag.getCompound(i + ""); + CompoundTag itemCompound = compoundTag.getCompound(i + "").orElse(null); if (itemCompound != null) contents[i] = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize(itemCompound); } } else { - byte[] slots = compoundTag.getByteArray("Slots"); - ListTag items = compoundTag.getList("Items"); + byte[] slots = compoundTag.getByteArray("Slots").orElse(EMPTY_SLOTS); + ListTag items = compoundTag.getList("Items").orElse(EMPTY_ITEMS_LIST); ItemStack[] serializedItems = new ItemStack[items.size()]; contents = new ItemStack[slots.length / 2]; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/ItemStack2TagSerializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/ItemStack2TagSerializer.java index da3d63e9c8..b4b87d0387 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/ItemStack2TagSerializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/ItemStack2TagSerializer.java @@ -25,7 +25,7 @@ private ItemStack2TagSerializer() { @NotNull public CompoundTag serialize(@Nullable ItemStack serializable) { if (serializable == null) - return new CompoundTag(); + return CompoundTag.of(); return plugin.getNMSTags().serializeItem(serializable); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/BigDecimalTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/BigDecimalTag.java index a700765d6f..c13e245eef 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/BigDecimalTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/BigDecimalTag.java @@ -10,7 +10,11 @@ public class BigDecimalTag extends Tag { - public BigDecimalTag(BigDecimal value) { + public static BigDecimalTag of(BigDecimal value) { + return new BigDecimalTag(value); + } + + private BigDecimalTag(BigDecimal value) { super(value, null); } @@ -20,7 +24,7 @@ public static BigDecimalTag fromStream(DataInputStream is) throws IOException { byte[] data = new byte[is.readInt()]; is.readFully(data); - return new BigDecimalTag(new BigDecimal(new BigInteger(data), scale, new MathContext(precision))); + return BigDecimalTag.of(new BigDecimal(new BigInteger(data), scale, new MathContext(precision))); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java index 9b1a00f470..9ff1404b07 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java @@ -49,14 +49,20 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @SuppressWarnings("WeakerAccess") public class ByteArrayTag extends Tag { + private static final ByteArrayTag EMPTY = new ByteArrayTag(new byte[0]); + /*package*/ static final Class CLASS = getNNTClass("NBTTagByteArray"); + public static ByteArrayTag of(byte[] value) { + return value.length == 0 ? EMPTY : new ByteArrayTag(value); + } + /** * Creates the tag. * * @param value The value. */ - public ByteArrayTag(byte[] value) { + private ByteArrayTag(byte[] value) { super(value, CLASS, byte[].class); } @@ -65,7 +71,7 @@ public static ByteArrayTag fromNBT(Object tag) { try { byte[] value = plugin.getNMSTags().getNBTByteArrayValue(tag); - return new ByteArrayTag(value); + return ByteArrayTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag byte-array from NMS:"); return null; @@ -76,7 +82,7 @@ public static ByteArrayTag fromStream(DataInputStream is) throws IOException { int length = is.readInt(); byte[] bytes = new byte[length]; is.readFully(bytes); - return new ByteArrayTag(bytes); + return ByteArrayTag.of(bytes); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java index 1195a9496c..a9c8665cad 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java @@ -46,14 +46,25 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class ByteTag extends NumberTag { + private static final ByteTag[] CACHE = new ByteTag[256]; + /*package*/ static final Class CLASS = getNNTClass("NBTTagByte"); + + public static ByteTag of(byte value) { + int index = value - Byte.MIN_VALUE; + ByteTag tag = CACHE[index]; + if (tag == null) + tag = CACHE[index] = new ByteTag(value); + return tag; + } + /** * Creates the tag. * * @param value The value. */ - public ByteTag(byte value) { + private ByteTag(byte value) { super(value, CLASS, byte.class); } @@ -62,7 +73,7 @@ public static ByteTag fromNBT(Object tag) { try { byte value = plugin.getNMSTags().getNBTByteValue(tag); - return new ByteTag(value); + return ByteTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag byte from NMS:"); return null; @@ -70,7 +81,7 @@ public static ByteTag fromNBT(Object tag) { } public static ByteTag fromStream(DataInputStream is) throws IOException { - return new ByteTag(is.readByte()); + return ByteTag.of(is.readByte()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java index 592e46c9d0..bb37786f88 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java @@ -44,6 +44,10 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.OptionalInt; +import java.util.OptionalLong; import java.util.Set; /** @@ -55,101 +59,94 @@ public class CompoundTag extends Tag>> implements Iterable CLASS = getNNTClass("NBTTagCompound"); - public CompoundTag() { - this(new HashMap<>()); + public static CompoundTag of() { + return new CompoundTag(new HashMap<>(), false); } - public CompoundTag(CompoundTag other) { - super(new HashMap<>(other.value), CLASS); + public static CompoundTag of(Map> value) { + return new CompoundTag(value, true); } + public CompoundTag copy() { + return of(this.value); + } /** * Creates the tag. * * @param value The value. */ - public CompoundTag(Map> value) { - super(value, CLASS); - } - - public Tag getTag(String key) { - return getTag(key, null); + private CompoundTag(Map> value, boolean cloneMap) { + super(cloneMap ? new HashMap<>(value) : value, CLASS); } - public Tag getTag(String key, Tag def) { - return this.value.getOrDefault(key, def); + public Optional> getTag(String key) { + return Optional.ofNullable(getTagInternal(key)); } - public byte[] getByteArray(String key) { - Tag tag = getTag(key); - return tag instanceof ByteArrayTag ? (byte[]) tag.value : null; - } - - public byte getByte(String key) { - Number number = getNumber(key); - return number == null ? 0 : number.byteValue(); + @Nullable + private Tag getTagInternal(String key) { + return this.value.get(key); } - public CompoundTag getCompound(String key) { - return getCompound(key, null); + @Nullable + private > Optional getTagInternal(String key, Class valueType) { + Tag tag = this.value.get(key); + return valueType.isAssignableFrom(tag.getClass()) ? Optional.of(valueType.cast(tag)) : Optional.empty(); } - public CompoundTag getCompound(String key, CompoundTag def) { - Tag tag = getTag(key); - return tag instanceof CompoundTag ? (CompoundTag) tag : def; + public Optional getByteArray(String key) { + return getTagInternal(key, ByteArrayTag.class).map(tag -> tag.value); } - public double getDouble(String key) { - Number number = getNumber(key); - return number == null ? 0D : number.doubleValue(); + public OptionalInt getByte(String key) { + NumberTag tag = getTagInternal(key, NumberTag.class).orElse(null); + return tag == null ? OptionalInt.empty() : OptionalInt.of(tag.value.byteValue()); } - public float getFloat(String key) { - Number number = getNumber(key); - return number == null ? 0F : number.floatValue(); + public Optional getCompound(String key) { + return getTagInternal(key, CompoundTag.class); } - public int[] getIntArray(String key) { - Tag tag = getTag(key); - return tag instanceof IntArrayTag ? (int[]) tag.value : null; + public OptionalDouble getDouble(String key) { + NumberTag tag = getTagInternal(key, NumberTag.class).orElse(null); + return tag == null ? OptionalDouble.empty() : OptionalDouble.of(tag.value.doubleValue()); } - public int getInt(String key) { - return getInt(key, 0); + public OptionalDouble getFloat(String key) { + NumberTag tag = getTagInternal(key, NumberTag.class).orElse(null); + return tag == null ? OptionalDouble.empty() : OptionalDouble.of(tag.value.floatValue()); } - public int getInt(String key, int def) { - return getNumber(key, def).intValue(); + public Optional getIntArray(String key) { + return getTagInternal(key, IntArrayTag.class).map(tag -> tag.value); } - public ListTag getList(String key) { - Tag tag = getTag(key); - return tag instanceof ListTag ? (ListTag) tag : null; + public OptionalInt getInt(String key) { + NumberTag tag = getTagInternal(key, NumberTag.class).orElse(null); + return tag == null ? OptionalInt.empty() : OptionalInt.of(tag.value.intValue()); } - public long getLong(String key) { - Number number = getNumber(key); - return number == null ? 0L : number.longValue(); + public Optional getList(String key) { + return getTagInternal(key, ListTag.class); } - public Number getNumber(String key) { - return getNumber(key, null); + public OptionalLong getLong(String key) { + NumberTag tag = getTagInternal(key, NumberTag.class).orElse(null); + return tag == null ? OptionalLong.empty() : OptionalLong.of(tag.value.longValue()); } - public Number getNumber(String key, Number def) { - Tag tag = getTag(key); - return tag instanceof NumberTag ? (Number) tag.value : def; + public Optional getNumber(String key) { + return getTagInternal(key, NumberTag.class).map(tag -> (Number) tag.value); } - public short getShort(String key) { - Number number = getNumber(key); - return number == null ? 0 : number.shortValue(); + public OptionalInt getShort(String key) { + NumberTag tag = getTagInternal(key, NumberTag.class).orElse(null); + return tag == null ? OptionalInt.empty() : OptionalInt.of(tag.value.shortValue()); } - public String getString(String key) { - Tag tag = getTag(key); - return tag instanceof StringTag ? (String) tag.value : null; + public Optional getString(String key) { + return getTagInternal(key, StringTag.class).map(tag -> tag.value); } @Nullable @@ -158,39 +155,39 @@ public Tag setTag(String key, Tag value) { } public void setByteArray(String key, byte[] value) { - setTag(key, new ByteArrayTag(value)); + setTag(key, ByteArrayTag.of(value)); } public void setByte(String key, byte value) { - setTag(key, new ByteTag(value)); + setTag(key, ByteTag.of(value)); } public void setDouble(String key, double value) { - setTag(key, new DoubleTag(value)); + setTag(key, DoubleTag.of(value)); } public void setFloat(String key, float value) { - setTag(key, new FloatTag(value)); + setTag(key, FloatTag.of(value)); } public void setIntArray(String key, int[] value) { - setTag(key, new IntArrayTag(value)); + setTag(key, IntArrayTag.of(value)); } public void setInt(String key, int value) { - setTag(key, new IntTag(value)); + setTag(key, IntTag.of(value)); } public void setLong(String key, long value) { - setTag(key, new LongTag(value)); + setTag(key, LongTag.of(value)); } public void setShort(String key, short value) { - setTag(key, new ShortTag(value)); + setTag(key, ShortTag.of(value)); } public void setString(String key, String value) { - setTag(key, new StringTag(value)); + setTag(key, StringTag.of(value)); } public void putAll(CompoundTag other) { @@ -275,7 +272,7 @@ public static CompoundTag fromNBT(Object tag) { map.put(key, Tag.fromNBT(plugin.getNMSTags().getNBTCompoundTag(tag, key))); } - return new CompoundTag(map); + return new CompoundTag(map, false); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag compound from NMS:"); return null; @@ -294,7 +291,7 @@ public static CompoundTag fromStream(DataInputStream is, int depth) throws IOExc tagMap.put(key, tag); } - return new CompoundTag(tagMap); + return new CompoundTag(tagMap, false); } } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java index 2a878e0e40..3cd2f24e0f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java @@ -46,14 +46,27 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class DoubleTag extends NumberTag { + private static final DoubleTag[] CACHE = new DoubleTag[100]; + /*package*/ static final Class CLASS = getNNTClass("NBTTagDouble"); + public static DoubleTag of(double value) { + if (value == (int) value && value >= 0 && value < CACHE.length) { + DoubleTag tag = CACHE[(int) value]; + if (tag == null) + tag = CACHE[(int) value] = new DoubleTag(value); + return tag; + } else { + return new DoubleTag(value); + } + } + /** * Creates the tag. * * @param value The value. */ - public DoubleTag(double value) { + private DoubleTag(double value) { super(value, CLASS, double.class); } @@ -62,7 +75,7 @@ public static DoubleTag fromNBT(Object tag) { try { double value = plugin.getNMSTags().getNBTDoubleValue(tag); - return new DoubleTag(value); + return DoubleTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag double from NMS:"); return null; @@ -70,7 +83,7 @@ public static DoubleTag fromNBT(Object tag) { } public static DoubleTag fromStream(DataInputStream is) throws IOException { - return new DoubleTag(is.readDouble()); + return DoubleTag.of(is.readDouble()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java index f3eacd3a84..46a3c82e10 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java @@ -44,12 +44,18 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @SuppressWarnings("WeakerAccess") public class EndTag extends Tag { + private static final EndTag INSTANCE = new EndTag(); + /*package*/ static final Class CLASS = getNNTClass("NBTTagEnd"); + public static EndTag of() { + return INSTANCE; + } + /** * Creates the tag. */ - public EndTag() { + private EndTag() { super(null, CLASS); } @@ -57,7 +63,7 @@ public static EndTag fromStream(DataInputStream is, int depth) throws IOExceptio if (depth == 0) { throw new IOException("TAG_End found without a TAG_Compound/TAG_List tag preceding it."); } else { - return new EndTag(); + return EndTag.INSTANCE; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java index 009621dd3b..0af5da0c9d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java @@ -47,14 +47,27 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @SuppressWarnings("WeakerAccess") public class FloatTag extends NumberTag { + private static final FloatTag[] CACHE = new FloatTag[100]; + /*package*/ static final Class CLASS = getNNTClass("NBTTagFloat"); + public static FloatTag of(float value) { + if (value == (int) value && value >= 0 && value < CACHE.length) { + FloatTag tag = CACHE[(int) value]; + if (tag == null) + tag = CACHE[(int) value] = new FloatTag(value); + return tag; + } else { + return new FloatTag(value); + } + } + /** * Creates the tag. * * @param value The value. */ - public FloatTag(float value) { + private FloatTag(float value) { super(value, CLASS, float.class); } @@ -63,7 +76,7 @@ public static FloatTag fromNBT(Object tag) { try { float value = plugin.getNMSTags().getNBTFloatValue(tag); - return new FloatTag(value); + return FloatTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag float from NMS:"); return null; @@ -71,7 +84,7 @@ public static FloatTag fromNBT(Object tag) { } public static FloatTag fromStream(DataInputStream is) throws IOException { - return new FloatTag(is.readFloat()); + return FloatTag.of(is.readFloat()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java index 6c27a7083f..968ea9b922 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java @@ -53,14 +53,20 @@ @SuppressWarnings("WeakerAccess") public class IntArrayTag extends Tag { + private static final IntArrayTag EMPTY = new IntArrayTag(new int[0]); + /*package*/ static final Class CLASS = getNNTClass("NBTTagIntArray"); + public static IntArrayTag of(int[] value) { + return value.length == 0 ? EMPTY : new IntArrayTag(value); + } + /** * Creates the tag. * * @param value The value. */ - public IntArrayTag(int[] value) { + private IntArrayTag(int[] value) { super(value, CLASS, int[].class); } @@ -69,7 +75,7 @@ public static IntArrayTag fromNBT(Object tag) { try { int[] value = plugin.getNMSTags().getNBTIntArrayValue(tag); - return new IntArrayTag(value); + return IntArrayTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag int-array from NMS:"); return null; @@ -79,7 +85,7 @@ public static IntArrayTag fromNBT(Object tag) { public static IntArrayTag fromUUID(UUID uuid) { long MSB = uuid.getMostSignificantBits(); long LSB = uuid.getLeastSignificantBits(); - return new IntArrayTag(new int[]{(int) (MSB >> 32), (int) MSB, (int) (LSB >> 32), (int) LSB}); + return IntArrayTag.of(new int[]{(int) (MSB >> 32), (int) MSB, (int) (LSB >> 32), (int) LSB}); } public static IntArrayTag fromStream(DataInputStream is) throws IOException { @@ -88,7 +94,7 @@ public static IntArrayTag fromStream(DataInputStream is) throws IOException { for (int i = 0; i < length; i++) { data[i] = is.readInt(); } - return new IntArrayTag(data); + return IntArrayTag.of(data); } @Override @@ -97,7 +103,7 @@ public String toString() { for (int b : value) { integers.append(b).append(" "); } - return "TAG_Int_Array: " + integers.toString(); + return "TAG_Int_Array: " + integers; } @Override @@ -107,10 +113,6 @@ protected void writeData(DataOutputStream os) throws IOException { os.writeInt(i); } - /* - * (non-Javadoc) - * @see java.lang.Object#hashCode() - */ @Override public int hashCode() { int prime = 31; @@ -119,10 +121,6 @@ public int hashCode() { return result; } - /* - * (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ @Override public boolean equals(final Object obj) { return this == obj || (obj instanceof IntArrayTag && Arrays.equals(value, ((IntArrayTag) obj).value)); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java index 76726d172f..56349d9850 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java @@ -46,9 +46,22 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class IntTag extends NumberTag { + private static final IntTag[] CACHE = new IntTag[100]; + /*package*/ static final Class CLASS = getNNTClass("NBTTagInt"); - public IntTag(int value) { + public static IntTag of(int value) { + if (value >= 0 && value < CACHE.length) { + IntTag tag = CACHE[value]; + if (tag == null) + tag = CACHE[value] = new IntTag(value); + return tag; + } else { + return new IntTag(value); + } + } + + private IntTag(int value) { super(value, CLASS, int.class); } @@ -57,7 +70,7 @@ public static IntTag fromNBT(Object tag) { try { int value = plugin.getNMSTags().getNBTIntValue(tag); - return new IntTag(value); + return IntTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag int from NMS:"); return null; @@ -65,7 +78,7 @@ public static IntTag fromNBT(Object tag) { } public static IntTag fromStream(DataInputStream is) throws IOException { - return new IntTag(is.readInt()); + return IntTag.of(is.readInt()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java index ff11002f5e..15ded29f3c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java @@ -63,14 +63,16 @@ public class ListTag extends Tag>> implements Iterable> { @Nullable private Class hintType; - /** - * Creates the tag. - * - * @param hintType Hint for the type of all items in the list. - * @param value The value. - */ - public ListTag(@Nullable Class hintType, List> value) { - this(value, hintType, true); + public static ListTag of(@Nullable Class hintType) { + return new ListTag(new LinkedList<>(), hintType, false); + } + + public static ListTag of(List> value) { + return of(value, null); + } + + public static ListTag of(List> value, @Nullable Class hintType) { + return new ListTag(value, hintType, true); } private ListTag(List> value, @Nullable Class hintType, boolean cloneList) { @@ -79,7 +81,7 @@ private ListTag(List> value, @Nullable Class hintType, boo } public ListTag copy() { - return new ListTag(this.hintType, this.value); + return of(this.value, this.hintType); } public void addTag(Tag tag) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java index c63464a5a6..ec84289f02 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java @@ -47,9 +47,22 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @SuppressWarnings("WeakerAccess") public class LongTag extends NumberTag { + private static final LongTag[] CACHE = new LongTag[100]; + /*package*/ static final Class CLASS = getNNTClass("NBTTagLong"); - public LongTag(long value) { + public static LongTag of(long value) { + if (value >= 0 && value < CACHE.length) { + LongTag tag = CACHE[(int) value]; + if (tag == null) + tag = CACHE[(int) value] = new LongTag(value); + return tag; + } else { + return new LongTag(value); + } + } + + private LongTag(long value) { super(value, CLASS, long.class); } @@ -58,7 +71,7 @@ public static LongTag fromNBT(Object tag) { try { long value = plugin.getNMSTags().getNBTLongValue(tag); - return new LongTag(value); + return LongTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag long from NMS:"); return null; @@ -66,7 +79,7 @@ public static LongTag fromNBT(Object tag) { } public static LongTag fromStream(DataInputStream is) throws IOException { - return new LongTag(is.readLong()); + return LongTag.of(is.readLong()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/NumberTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/NumberTag.java index f7ec4be10c..e0432ddd24 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/NumberTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/NumberTag.java @@ -2,7 +2,7 @@ public abstract class NumberTag extends Tag { - public NumberTag(E value, Class clazz, Class... parameterTypes) { + protected NumberTag(E value, Class clazz, Class... parameterTypes) { super(value, clazz, parameterTypes); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTag.java index 9fe8709877..0c87e134f2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTag.java @@ -9,7 +9,11 @@ public class PersistentDataTag extends Tag { private final PersistentDataTypeContext serializer; - public PersistentDataTag(E value, PersistentDataTypeContext serializer) { + public static PersistentDataTag of(E value, PersistentDataTypeContext serializer) { + return new PersistentDataTag<>(value, serializer); + } + + private PersistentDataTag(E value, PersistentDataTypeContext serializer) { super(value, null); this.serializer = serializer; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTagSerialized.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTagSerialized.java index d6db945785..85b74fad3b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTagSerialized.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTagSerialized.java @@ -9,7 +9,13 @@ public class PersistentDataTagSerialized extends Tag { - public PersistentDataTagSerialized(byte[] value) { + private static final PersistentDataTagSerialized EMPTY = new PersistentDataTagSerialized(new byte[0]); + + public static PersistentDataTagSerialized of(byte[] value) { + return value.length == 0 ? EMPTY : new PersistentDataTagSerialized(value); + } + + private PersistentDataTagSerialized(byte[] value) { super(value, null); } @@ -17,7 +23,7 @@ public PersistentDataTag getPersistentDataTag(PersistentDataType type) PersistentDataTypeContext serializer = type.getContext(); if (serializer == null) throw new IllegalArgumentException("Cannot find a valid serializer for " + type); - return new PersistentDataTag<>(serializer.deserialize(value), serializer); + return PersistentDataTag.of(serializer.deserialize(value), serializer); } public static PersistentDataTagSerialized fromStream(DataInputStream is) throws IOException { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java index 5f94fa3920..c7996f3010 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java @@ -46,9 +46,22 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class ShortTag extends NumberTag { + private static final ShortTag[] CACHE = new ShortTag[100]; + /*package*/ static final Class CLASS = getNNTClass("NBTTagShort"); - public ShortTag(short value) { + public static ShortTag of(short value) { + if (value >= 0 && value < CACHE.length) { + ShortTag tag = CACHE[value]; + if (tag == null) + tag = CACHE[value] = new ShortTag(value); + return tag; + } else { + return new ShortTag(value); + } + } + + private ShortTag(short value) { super(value, CLASS, short.class); } @@ -57,7 +70,7 @@ public static ShortTag fromNBT(Object tag) { try { short value = plugin.getNMSTags().getNBTShortValue(tag); - return new ShortTag(value); + return ShortTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag short from NMS:"); return null; @@ -65,7 +78,7 @@ public static ShortTag fromNBT(Object tag) { } public static ShortTag fromStream(DataInputStream is) throws IOException { - return new ShortTag(is.readShort()); + return ShortTag.of(is.readShort()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java index ab9c46e8a8..018ebf633f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java @@ -47,14 +47,20 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class StringTag extends Tag { + private static final StringTag EMPTY = new StringTag(""); + /*package*/ static final Class CLASS = getNNTClass("NBTTagString"); + public static StringTag of(String value) { + return value.isEmpty() ? EMPTY : new StringTag(value); + } + /** * Creates the tag. * * @param value The value. */ - public StringTag(String value) { + private StringTag(String value) { super(value, CLASS, String.class); } @@ -63,7 +69,7 @@ public static StringTag fromNBT(Object tag) { try { String value = plugin.getNMSTags().getNBTStringValue(tag); - return new StringTag(value); + return StringTag.of(value); } catch (Exception error) { Log.error(error, "An unexpected error occurred while converting tag string from NMS:"); return null; @@ -72,16 +78,19 @@ public static StringTag fromNBT(Object tag) { public static StringTag fromStream(DataInputStream is) throws IOException { int length = is.readShort(); + if (length <= 0) + return EMPTY; byte[] bytes = new byte[length]; is.readFully(bytes); - return new StringTag(new String(bytes, StandardCharsets.UTF_8)); + return StringTag.of(new String(bytes, StandardCharsets.UTF_8)); } @Override protected void writeData(DataOutputStream os) throws IOException { byte[] bytes = value.getBytes(StandardCharsets.UTF_8); os.writeShort(bytes.length); - os.write(bytes); + if (bytes.length > 0) + os.write(bytes); } } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/Tag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/Tag.java index 02f2a98e58..7b144a1549 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/Tag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/Tag.java @@ -72,7 +72,7 @@ else if (tag.getClass().equals(CompoundTag.CLASS)) else if (tag.getClass().equals(DoubleTag.CLASS)) return DoubleTag.fromNBT(tag); else if (tag.getClass().equals(EndTag.CLASS)) - return new EndTag(); + return EndTag.of(); else if (tag.getClass().equals(FloatTag.CLASS)) return FloatTag.fromNBT(tag); else if (tag.getClass().equals(IntArrayTag.CLASS)) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/UUIDTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/UUIDTag.java index 50425086ef..679fea9362 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/UUIDTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/UUIDTag.java @@ -8,12 +8,20 @@ public class UUIDTag extends Tag { - public UUIDTag(UUID value) { + public static UUIDTag of(long mostSigBits, long leastSigBits) { + return new UUIDTag(new UUID(mostSigBits, leastSigBits)); + } + + public static UUIDTag of(UUID value) { + return new UUIDTag(value); + } + + private UUIDTag(UUID value) { super(value, null); } public static UUIDTag fromStream(DataInputStream is) throws IOException { - return new UUIDTag(new UUID(is.readLong(), is.readLong())); + return UUIDTag.of(is.readLong(), is.readLong()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java index 5a62624ce7..7ea3d6f78b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicBuilder.java @@ -5,36 +5,29 @@ import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.schematic.SchematicEntityFilter; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; -import com.bgsoftware.superiorskyblock.tag.ByteTag; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.EntityType; -import java.util.HashMap; -import java.util.Map; - @SuppressWarnings("UnusedReturnValue") public class SchematicBuilder { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private final Map> compoundValue = new HashMap<>(); + private final CompoundTag compoundTag = CompoundTag.of(); public SchematicBuilder withBlockOffset(BlockOffset blockOffset) { - compoundValue.put("blockPosition", new StringTag(Serializers.OFFSET_SERIALIZER.serialize(blockOffset))); + this.compoundTag.setString("blockPosition", Serializers.OFFSET_SERIALIZER.serialize(blockOffset)); return this; } public SchematicBuilder withBlockType(Material blockType, int data) { if (ServerVersion.isLegacy()) { - compoundValue.put("combinedId", new IntTag(plugin.getNMSAlgorithms().getCombinedId(blockType, (byte) data))); + this.compoundTag.setInt("combinedId", plugin.getNMSAlgorithms().getCombinedId(blockType, (byte) data)); } else { - compoundValue.put("type", new StringTag(blockType.name())); + this.compoundTag.setString("type", blockType.name()); if (data != 0) - compoundValue.put("data", new IntTag(data)); + this.compoundTag.setInt("data", data); } return this; @@ -42,40 +35,34 @@ public SchematicBuilder withBlockType(Material blockType, int data) { public SchematicBuilder withLightLevels(byte[] lightLevels) { if (lightLevels.length > 0 && lightLevels[0] > 0) - compoundValue.put("skyLightLevel", new ByteTag(lightLevels[0])); + this.compoundTag.setByte("skyLightLevel", lightLevels[0]); if (lightLevels.length > 1 && lightLevels[1] > 0) - compoundValue.put("blockLightLevel", new ByteTag(lightLevels[1])); + this.compoundTag.setByte("blockLightLevel", lightLevels[1]); return this; } public SchematicBuilder withStates(CompoundTag statesTag) { if (statesTag != null) - compoundValue.put("states", statesTag); + this.compoundTag.setTag("states", statesTag); return this; } public SchematicBuilder withTileEntity(CompoundTag tileEntity) { if (tileEntity != null) - compoundValue.put("tileEntity", tileEntity); + this.compoundTag.setTag("tileEntity", tileEntity); return this; } public SchematicBuilder applyEntity(EntityType entityType, CompoundTag entityTag, Location offset) { - compoundValue.put("offset", new StringTag(Serializers.LOCATION_SERIALIZER.serialize(offset))); - compoundValue.put("entityType", new StringTag(entityType.name())); - compoundValue.put("NBT", SchematicEntityFilter.filterNBTTag(entityTag)); + this.compoundTag.setString("offset", Serializers.LOCATION_SERIALIZER.serialize(offset)); + this.compoundTag.setString("entityType", entityType.name()); + this.compoundTag.setTag("NBT", SchematicEntityFilter.filterNBTTag(entityTag)); + return this; } public CompoundTag build() { - Map> compoundValue = new HashMap<>(); - - for (String key : this.compoundValue.keySet()) { - if (this.compoundValue.get(key) != null) - compoundValue.put(key, this.compoundValue.get(key)); - } - - return new CompoundTag(compoundValue); + return this.compoundTag; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index 12702b4a53..9e67cd2d5b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -314,21 +314,21 @@ public void saveSchematic(Location pos1, Location pos2, SchematicOptions schemat } Map> compoundValue = new HashMap<>(); - compoundValue.put("xSize", new IntTag(xSize)); - compoundValue.put("ySize", new IntTag(ySize)); - compoundValue.put("zSize", new IntTag(zSize)); - compoundValue.put("blocks", new ListTag(CompoundTag.class, blocks)); - compoundValue.put("entities", new ListTag(CompoundTag.class, entities)); - compoundValue.put("offsetX", new IntTag(schematicOptions.getOffsetX())); - compoundValue.put("offsetY", new IntTag(schematicOptions.getOffsetY())); - compoundValue.put("offsetZ", new IntTag(schematicOptions.getOffsetZ())); - compoundValue.put("yaw", new FloatTag(schematicOptions.getYaw())); - compoundValue.put("pitch", new FloatTag(schematicOptions.getPitch())); - compoundValue.put("version", new StringTag(ServerVersion.getBukkitVersion())); + compoundValue.put("xSize", IntTag.of(xSize)); + compoundValue.put("ySize", IntTag.of(ySize)); + compoundValue.put("zSize", IntTag.of(zSize)); + compoundValue.put("blocks", ListTag.of(blocks, CompoundTag.class)); + compoundValue.put("entities", ListTag.of(entities, CompoundTag.class)); + compoundValue.put("offsetX", IntTag.of(schematicOptions.getOffsetX())); + compoundValue.put("offsetY", IntTag.of(schematicOptions.getOffsetY())); + compoundValue.put("offsetZ", IntTag.of(schematicOptions.getOffsetZ())); + compoundValue.put("yaw", FloatTag.of(schematicOptions.getYaw())); + compoundValue.put("pitch", FloatTag.of(schematicOptions.getPitch())); + compoundValue.put("version", StringTag.of(ServerVersion.getBukkitVersion())); if (!ServerVersion.isLegacy()) - compoundValue.put("minecraftDataVersion", new IntTag(plugin.getNMSAlgorithms().getDataVersion())); + compoundValue.put("minecraftDataVersion", IntTag.of(plugin.getNMSAlgorithms().getDataVersion())); - CompoundTag schematicTag = new CompoundTag(compoundValue); + CompoundTag schematicTag = CompoundTag.of(compoundValue); SuperiorSchematic schematic = new SuperiorSchematic(schematicOptions.getSchematicName(), schematicTag); this.schematicsContainer.addSchematic(schematic); saveIntoFile(schematicOptions.getSchematicName(), schematicTag); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java index fafd1cb7c9..5d2ef37795 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java @@ -60,19 +60,19 @@ public class SuperiorSchematic extends BaseSchematic implements Schematic { public SuperiorSchematic(String name, CompoundTag compoundTag) { super(name); - int xSize = compoundTag.getInt("xSize"); - int ySize = compoundTag.getInt("ySize"); - int zSize = compoundTag.getInt("zSize"); + int xSize = compoundTag.getInt("xSize").orElse(0); + int ySize = compoundTag.getInt("ySize").orElse(0); + int zSize = compoundTag.getInt("zSize").orElse(0); - int offsetX = compoundTag.getInt("offsetX", xSize / 2); - int offsetY = compoundTag.getInt("offsetY", ySize / 2); - int offsetZ = compoundTag.getInt("offsetZ", zSize / 2); + int offsetX = compoundTag.getInt("offsetX").orElse(xSize / 2); + int offsetY = compoundTag.getInt("offsetY").orElse(ySize / 2); + int offsetZ = compoundTag.getInt("offsetZ").orElse(zSize / 2); BlockOffset schematicOffset = SBlockOffset.fromOffsets(offsetX, offsetY, offsetZ).negate(); - float yaw = compoundTag.getFloat("yaw"); - float pitch = compoundTag.getFloat("pitch"); + float yaw = (float) compoundTag.getFloat("yaw").orElse(0f); + float pitch = (float) compoundTag.getFloat("pitch").orElse(0f); - int dataVersion = compoundTag.getInt("minecraftDataVersion", -1); + int dataVersion = compoundTag.getInt("minecraftDataVersion").orElse(-1); ByteBigArray blockIds; BigBitSet bitSet; @@ -81,7 +81,7 @@ public SuperiorSchematic(String name, CompoundTag compoundTag) { int minY; int minZ; - ListTag blocksList = compoundTag.getList("blocks"); + ListTag blocksList = compoundTag.getList("blocks").orElse(null); if (blocksList == null) { blockIds = EMPTY_BLOCK_IDS; bitSet = EMPTY_BIT_SET; @@ -153,7 +153,7 @@ public SuperiorSchematic(String name, CompoundTag compoundTag) { } List entities; - ListTag entitiesList = compoundTag.getList("entities"); + ListTag entitiesList = compoundTag.getList("entities").orElse(null); if (entitiesList == null) { entities = Collections.emptyList(); } else { @@ -162,9 +162,9 @@ public SuperiorSchematic(String name, CompoundTag compoundTag) { for (Tag tag : entitiesList) { CompoundTag compound = (CompoundTag) tag; try { - EntityType entityType = EntityType.valueOf(compound.getString("entityType")); - CompoundTag entityTag = compound.getCompound("NBT"); - Location offset = Serializers.LOCATION_SERIALIZER.deserialize(compound.getString("offset")); + EntityType entityType = EntityType.valueOf(compound.getString("entityType").orElse(null)); + CompoundTag entityTag = compound.getCompound("NBT").orElse(null); + Location offset = Serializers.LOCATION_SERIALIZER.deserialize(compound.getString("offset").orElse(null)); if (offset != null) entities.add(new SchematicEntity(entityType, entityTag, SBlockOffset.fromOffsets(offset.getX(), offset.getY(), offset.getZ()))); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematicDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematicDeserializer.java index 282079c5d7..c459efa9e6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematicDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematicDeserializer.java @@ -23,6 +23,8 @@ public class SuperiorSchematicDeserializer { + private static final ListTag EMPTY_ITEMS_LIST = ListTag.of(Collections.emptyList()); + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final EnumMap rotationToByte = Maps.newEnumMap(BlockFace.class); @@ -50,150 +52,99 @@ private SuperiorSchematicDeserializer() { } public static void convertOldTileEntity(CompoundTag compoundTag) { - CompoundTag tileEntity = new CompoundTag(); - - { - String baseColor = compoundTag.getString("baseColor"); - if (baseColor != null) - //noinspection deprecation - tileEntity.setInt("Base", DyeColor.valueOf(baseColor).getDyeData()); - } + CompoundTag tileEntity = CompoundTag.of(); - { - CompoundTag patterns = compoundTag.getCompound("patterns"); - if (patterns != null) { - ListTag patternsList = new ListTag(CompoundTag.class, Collections.emptyList()); - - for (Tag tag : patterns) { - if (tag instanceof CompoundTag) { - CompoundTag oldPatternTag = (CompoundTag) tag; - CompoundTag patternTag = new CompoundTag(); - patternTag.setInt("Color", oldPatternTag.getInt("color")); - patternTag.setString("Pattern", oldPatternTag.getString("type")); - patternsList.addTag(patternTag); - } - } + compoundTag.getString("baseColor").ifPresent(baseColor -> + tileEntity.setInt("Base", DyeColor.valueOf(baseColor).getDyeData())); - tileEntity.setTag("Patterns", patternsList); - } - } + compoundTag.getCompound("patterns").ifPresent(patterns -> { + ListTag patternsList = ListTag.of(CompoundTag.class); - { - CompoundTag contents = compoundTag.getCompound("contents"); - if (contents != null) { - ListTag items = new ListTag(CompoundTag.class, Collections.emptyList()); - for (Map.Entry> item : contents.entrySet()) { - if (item.getValue() instanceof CompoundTag) { - try { - ItemStack itemStack = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize((CompoundTag) item.getValue()); - CompoundTag itemCompound = plugin.getNMSTags().serializeItem(itemStack); - itemCompound.setByte("Slot", Byte.parseByte(item.getKey())); - items.addTag(itemCompound); - } catch (Exception ignored) { - } - } + for (Tag tag : patterns) { + if (tag instanceof CompoundTag) { + CompoundTag oldPatternTag = (CompoundTag) tag; + CompoundTag patternTag = CompoundTag.of(); + patternTag.setInt("Color", oldPatternTag.getInt("color").orElse(0)); + patternTag.setString("Pattern", oldPatternTag.getString("type").orElse("")); + patternsList.addTag(patternTag); } - - tileEntity.setTag("Items", items); - - String inventoryType = compoundTag.getString("inventoryType"); - tileEntity.setString("inventoryType", inventoryType != null ? inventoryType : "CHEST"); } - } - { - String flower = compoundTag.getString("flower"); - if (flower != null) { - try { - String[] flowerSections = flower.split(":"); - tileEntity.setString("Item", plugin.getNMSAlgorithms().getMinecraftKey(new ItemStack(Material.valueOf(flowerSections[0])))); - tileEntity.setInt("Data", Integer.parseInt(flowerSections[1])); - } catch (Exception ignored) { + tileEntity.setTag("Patterns", patternsList); + }); + + compoundTag.getCompound("contents").ifPresent(contents -> { + ListTag items = ListTag.of(CompoundTag.class); + for (Map.Entry> item : contents.entrySet()) { + if (item.getValue() instanceof CompoundTag) { + try { + ItemStack itemStack = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize((CompoundTag) item.getValue()); + CompoundTag itemCompound = plugin.getNMSTags().serializeItem(itemStack); + itemCompound.setByte("Slot", Byte.parseByte(item.getKey())); + items.addTag(itemCompound); + } catch (Exception ignored) { + } } } - } - { - String skullType = compoundTag.getString("skullType"); - if (skullType != null) { - tileEntity.setByte("SkullType", (byte) (SkullType.valueOf(skullType).ordinal() - 1)); - } - } + tileEntity.setTag("Items", items); - { - String rotation = compoundTag.getString("rotation"); - if (rotation != null) { - tileEntity.setByte("Rot", rotationToByte.getOrDefault(BlockFace.valueOf(rotation), (byte) 0)); - } - } + String inventoryType = compoundTag.getString("inventoryType").orElse("CHEST"); + tileEntity.setString("inventoryType", inventoryType); + }); - { - String owner = compoundTag.getString("owner"); - if (owner != null) { - tileEntity.setString("Name", owner); + compoundTag.getString("flower").ifPresent(flower -> { + try { + String[] flowerSections = flower.split(":"); + tileEntity.setString("Item", plugin.getNMSAlgorithms().getMinecraftKey(new ItemStack(Material.valueOf(flowerSections[0])))); + tileEntity.setInt("Data", Integer.parseInt(flowerSections[1])); + } catch (Exception ignored) { } - } + }); - { - String signLine0 = compoundTag.getString("signLine0"); - if (signLine0 != null) { - tileEntity.setString("Text1", plugin.getNMSAlgorithms().parseSignLine(signLine0)); - } - } + compoundTag.getString("skullType").ifPresent(skullType -> + tileEntity.setByte("SkullType", (byte) (SkullType.valueOf(skullType).ordinal() - 1))); - { - String signLine1 = compoundTag.getString("signLine1"); - if (signLine1 != null) { - tileEntity.setString("Text2", plugin.getNMSAlgorithms().parseSignLine(signLine1)); - } - } + compoundTag.getString("rotation").ifPresent(rotation -> + tileEntity.setByte("Rot", rotationToByte.getOrDefault(BlockFace.valueOf(rotation), (byte) 0))); - { - String signLine2 = compoundTag.getString("signLine2"); - if (signLine2 != null) { - tileEntity.setString("Text3", plugin.getNMSAlgorithms().parseSignLine(signLine2)); - } - } + compoundTag.getString("owner").ifPresent(owner -> + tileEntity.setString("Name", owner)); - { - String signLine3 = compoundTag.getString("signLine3"); - if (signLine3 != null) { - tileEntity.setString("Text4", plugin.getNMSAlgorithms().parseSignLine(signLine3)); - } + for (int i = 0; i < 4; ++i) { + final String textLineKey = "Text" + (i + 1); + compoundTag.getString("signLine" + i).ifPresent(signLine -> + tileEntity.setString(textLineKey, plugin.getNMSAlgorithms().parseSignLine(signLine))); } - { - String spawnedType = compoundTag.getString("spawnedType"); - if (spawnedType != null) { - tileEntity.setString("EntityId", spawnedType); - } - } + compoundTag.getString("spawnedType").ifPresent(spawnedType -> + tileEntity.setString("EntityId", spawnedType)); - if (tileEntity.size() != 0) + if (!tileEntity.isEmpty()) compoundTag.setTag("tileEntity", tileEntity); } @Nullable public static SchematicBlockData deserializeSchematicBlock(CompoundTag compoundTag, int dataVersion) { - BlockOffset blockOffset = Serializers.OFFSET_SERIALIZER.deserialize(compoundTag.getString("blockPosition")); + BlockOffset blockOffset = Serializers.OFFSET_SERIALIZER.deserialize(compoundTag.getString("blockPosition").orElse(null)); int combinedId; if (compoundTag.containsKey("combinedId")) { - combinedId = compoundTag.getInt("combinedId"); + combinedId = compoundTag.getInt("combinedId").getAsInt(); } else if (compoundTag.containsKey("id") && compoundTag.containsKey("data")) { - int id = compoundTag.getInt("id"); - int data = compoundTag.getInt("data"); + int id = compoundTag.getInt("id").getAsInt(); + int data = compoundTag.getInt("data").getAsInt(); combinedId = id + (data << 12); } else if (compoundTag.containsKey("type")) { Material type; try { - type = Material.valueOf(compoundTag.getString("type")); + type = Material.valueOf(compoundTag.getString("type").get()); } catch (Exception ignored) { return null; } - int data = compoundTag.getInt("data"); + int data = compoundTag.getInt("data").orElse(0); combinedId = plugin.getNMSAlgorithms().getCombinedId(type, (byte) data); } else { @@ -223,8 +174,8 @@ private static SchematicBlock.Extra deserializeSchematicBlockExtra(CompoundTag c // byte skyLightLevel = compoundTag.getByte("skyLightLevel"); // byte blockLightLevel = compoundTag.getByte("blockLightLevel"); - CompoundTag statesTag = compoundTag.getCompound("states"); - CompoundTag tileEntity = compoundTag.getCompound("tileEntity"); + CompoundTag statesTag = compoundTag.getCompound("states").orElse(null); + CompoundTag tileEntity = compoundTag.getCompound("tileEntity").orElse(null); tileEntity = SuperiorSchematicDeserializer.upgradeTileEntity(tileEntity, dataVersion); return statesTag == null && tileEntity == null ? null : new SchematicBlock.Extra(statesTag, tileEntity); @@ -240,14 +191,14 @@ private static CompoundTag upgradeTileEntity(@Nullable CompoundTag compoundTag, return compoundTag; // Convert chest contents - ListTag itemsTag = compoundTag.getList("Items"); - if (itemsTag != null && itemsTag.size() > 0) { - ListTag newItemsTag = new ListTag(CompoundTag.class, Collections.emptyList()); + ListTag itemsTag = compoundTag.getList("Items").orElse(EMPTY_ITEMS_LIST); + if (itemsTag.size() > 0) { + ListTag newItemsTag = ListTag.of(CompoundTag.class); for (Tag tag : itemsTag) { if (tag instanceof CompoundTag) { CompoundTag itemTag = (CompoundTag) tag; - int slot = itemTag.getInt("Slot"); + int slot = itemTag.getInt("Slot").orElse(0); itemTag.setInt("DataVersion", dataVersion); ItemStack itemStack = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.deserialize(itemTag); CompoundTag newItemTag = Serializers.ITEM_STACK_TO_TAG_SERIALIZER.serialize(itemStack); From 34f0954479d82dd5fa26fadaf299d1562f19e482 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:34:06 +0200 Subject: [PATCH 225/600] Added skip-one-item-menus support for missions menu (#2571) --- .../external/menus/MenusProvider_Default.java | 7 +++++++ src/main/resources/config.yml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java b/src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java index c233362ee6..01f10fce80 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/menus/MenusProvider_Default.java @@ -345,6 +345,13 @@ public void refreshMembers(Island island) { @Override public void openMissions(SuperiorPlayer targetPlayer, @Nullable ISuperiorMenu previousMenu) { Preconditions.checkNotNull(targetPlayer, "targetPlayer parameter cannot be null."); + if (Menus.MENU_MISSIONS.isSkipOneItem()) { + List missionCategories = plugin.getMissions().getMissionCategories(); + if (missionCategories.size() == 1) { + openMissionsCategory(targetPlayer, previousMenu, missionCategories.get(0)); + return; + } + } Menus.MENU_MISSIONS.createView(targetPlayer, EmptyViewArgs.INSTANCE, previousMenu); } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index c6f6b2da6a..7209e0ca9e 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -568,7 +568,7 @@ number-format: "en-US" date-format: "dd/MM/yyyy HH:mm:ss" # Should players skip menus with only one items inside them? -# When enabled, creation, island-warps and island-chest menus will be skipped if only one item is inside them. +# When enabled, creation, island-warps, island-chest and missions menus will be skipped if only one item is inside them. skip-one-item-menus: false # Should visitors get teleported to spawn when pvp is enabled in an island? From 896c1b278b91b5384839201881f593e5274e280c Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 24 Jul 2025 17:15:35 +0300 Subject: [PATCH 226/600] Fixed errors due to recent commit --- .../superiorskyblock/tag/BigDecimalTag.java | 28 ++-- .../superiorskyblock/tag/ByteArrayTag.java | 61 ++++--- .../superiorskyblock/tag/ByteTag.java | 31 ++-- .../superiorskyblock/tag/CompoundTag.java | 75 ++++----- .../superiorskyblock/tag/DoubleTag.java | 32 ++-- .../superiorskyblock/tag/EndTag.java | 39 ++--- .../superiorskyblock/tag/FloatTag.java | 33 ++-- .../superiorskyblock/tag/IntArrayTag.java | 79 ++++----- .../superiorskyblock/tag/IntTag.java | 27 ++-- .../superiorskyblock/tag/ListTag.java | 151 +++++++++--------- .../superiorskyblock/tag/LongTag.java | 28 ++-- .../superiorskyblock/tag/NMSTagConverter.java | 47 ++++++ .../superiorskyblock/tag/NumberTag.java | 4 +- .../tag/PersistentDataTag.java | 10 +- .../tag/PersistentDataTagSerialized.java | 22 +-- .../superiorskyblock/tag/ShortTag.java | 27 ++-- .../superiorskyblock/tag/StringTag.java | 38 ++--- .../bgsoftware/superiorskyblock/tag/Tag.java | 65 +++----- .../superiorskyblock/tag/UUIDTag.java | 20 +-- 19 files changed, 430 insertions(+), 387 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/tag/NMSTagConverter.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/BigDecimalTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/BigDecimalTag.java index c13e245eef..7e546cc316 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/BigDecimalTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/BigDecimalTag.java @@ -10,21 +10,8 @@ public class BigDecimalTag extends Tag { - public static BigDecimalTag of(BigDecimal value) { - return new BigDecimalTag(value); - } - private BigDecimalTag(BigDecimal value) { - super(value, null); - } - - public static BigDecimalTag fromStream(DataInputStream is) throws IOException { - int scale = is.readInt(); - int precision = is.readInt(); - byte[] data = new byte[is.readInt()]; - is.readFully(data); - - return BigDecimalTag.of(new BigDecimal(new BigInteger(data), scale, new MathContext(precision))); + super(value); } @Override @@ -37,4 +24,17 @@ protected void writeData(DataOutputStream os) throws IOException { os.write(data); } + public static BigDecimalTag of(BigDecimal value) { + return new BigDecimalTag(value); + } + + public static BigDecimalTag fromStream(DataInputStream is) throws IOException { + int scale = is.readInt(); + int precision = is.readInt(); + byte[] data = new byte[is.readInt()]; + is.readFully(data); + + return BigDecimalTag.of(new BigDecimal(new BigInteger(data), scale, new MathContext(precision))); + } + } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java index 9ff1404b07..99425e6fec 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java @@ -46,28 +46,46 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * * @author Graham Edgecombe */ -@SuppressWarnings("WeakerAccess") public class ByteArrayTag extends Tag { + /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagByteArray", byte[].class); + private static final ByteArrayTag EMPTY = new ByteArrayTag(new byte[0]); - /*package*/ static final Class CLASS = getNNTClass("NBTTagByteArray"); + private ByteArrayTag(byte[] value) { + super(value); + } - public static ByteArrayTag of(byte[] value) { - return value.length == 0 ? EMPTY : new ByteArrayTag(value); + @Override + protected void writeData(DataOutputStream os) throws IOException { + os.writeInt(value.length); + os.write(value); } - /** - * Creates the tag. - * - * @param value The value. - */ - private ByteArrayTag(byte[] value) { - super(value, CLASS, byte[].class); + @Override + protected NMSTagConverter getNMSConverter() { + return TAG_CONVERTER; + } + + @Override + public String toString() { + StringBuilder hex = new StringBuilder(); + for (byte b : value) { + String hexDigits = Integer.toHexString(b).toUpperCase(Locale.ENGLISH); + if (hexDigits.length() == 1) { + hex.append("0"); + } + hex.append(hexDigits).append(" "); + } + return "TAG_Byte_Array: " + hex; + } + + public static ByteArrayTag of(byte[] value) { + return value.length == 0 ? EMPTY : new ByteArrayTag(value); } public static ByteArrayTag fromNBT(Object tag) { - Preconditions.checkArgument(tag.getClass().equals(CLASS), "Cannot convert " + tag.getClass() + " to ByteArrayTag!"); + Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to ByteArrayTag!"); try { byte[] value = plugin.getNMSTags().getNBTByteArrayValue(tag); @@ -85,23 +103,4 @@ public static ByteArrayTag fromStream(DataInputStream is) throws IOException { return ByteArrayTag.of(bytes); } - @Override - public String toString() { - StringBuilder hex = new StringBuilder(); - for (byte b : value) { - String hexDigits = Integer.toHexString(b).toUpperCase(Locale.ENGLISH); - if (hexDigits.length() == 1) { - hex.append("0"); - } - hex.append(hexDigits).append(" "); - } - return "TAG_Byte_Array: " + hex; - } - - @Override - protected void writeData(DataOutputStream os) throws IOException { - os.writeInt(value.length); - os.write(value); - } - } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java index a9c8665cad..a62cb7eedb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java @@ -46,10 +46,23 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class ByteTag extends NumberTag { + /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagByte", byte.class); + private static final ByteTag[] CACHE = new ByteTag[256]; - /*package*/ static final Class CLASS = getNNTClass("NBTTagByte"); + private ByteTag(byte value) { + super(value); + } + @Override + protected void writeData(DataOutputStream os) throws IOException { + os.writeByte(value); + } + + @Override + protected NMSTagConverter getNMSConverter() { + return TAG_CONVERTER; + } public static ByteTag of(byte value) { int index = value - Byte.MIN_VALUE; @@ -59,17 +72,8 @@ public static ByteTag of(byte value) { return tag; } - /** - * Creates the tag. - * - * @param value The value. - */ - private ByteTag(byte value) { - super(value, CLASS, byte.class); - } - public static ByteTag fromNBT(Object tag) { - Preconditions.checkArgument(tag.getClass().equals(CLASS), "Cannot convert " + tag.getClass() + " to ByteTag!"); + Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to ByteTag!"); try { byte value = plugin.getNMSTags().getNBTByteValue(tag); @@ -84,9 +88,4 @@ public static ByteTag fromStream(DataInputStream is) throws IOException { return ByteTag.of(is.readByte()); } - @Override - protected void writeData(DataOutputStream os) throws IOException { - os.writeByte(value); - } - } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java index bb37786f88..fdacb6324d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java @@ -57,44 +57,33 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class CompoundTag extends Tag>> implements Iterable> { - /*package*/ static final Class CLASS = getNNTClass("NBTTagCompound"); + /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagCompound"); - public static CompoundTag of() { - return new CompoundTag(new HashMap<>(), false); + private CompoundTag(Map> value, boolean cloneMap) { + super(cloneMap ? new HashMap<>(value) : value); } - public static CompoundTag of(Map> value) { - return new CompoundTag(value, true); + @Override + protected void writeData(DataOutputStream os) throws IOException { + for (Map.Entry> entry : value.entrySet()) { + entry.getValue().write(os); + + byte[] keyBytes = entry.getKey().getBytes(StandardCharsets.UTF_8); + os.writeShort(keyBytes.length); + os.write(keyBytes); + } + + os.writeByte((byte) 0); } public CompoundTag copy() { return of(this.value); } - /** - * Creates the tag. - * - * @param value The value. - */ - private CompoundTag(Map> value, boolean cloneMap) { - super(cloneMap ? new HashMap<>(value) : value, CLASS); - } - public Optional> getTag(String key) { return Optional.ofNullable(getTagInternal(key)); } - @Nullable - private Tag getTagInternal(String key) { - return this.value.get(key); - } - - @Nullable - private > Optional getTagInternal(String key, Class valueType) { - Tag tag = this.value.get(key); - return valueType.isAssignableFrom(tag.getClass()) ? Optional.of(valueType.cast(tag)) : Optional.empty(); - } - public Optional getByteArray(String key) { return getTagInternal(key, ByteArrayTag.class).map(tag -> tag.value); } @@ -231,23 +220,10 @@ public String toString() { return bldr.toString(); } - @Override - protected void writeData(DataOutputStream os) throws IOException { - for (Map.Entry> entry : value.entrySet()) { - entry.getValue().write(os); - - byte[] keyBytes = entry.getKey().getBytes(StandardCharsets.UTF_8); - os.writeShort(keyBytes.length); - os.write(keyBytes); - } - - os.writeByte((byte) 0); - } - @Override public Object toNBT() { try { - Object nbtTagCompound = CONSTRUCTOR.newInstance(); + Object nbtTagCompound = TAG_CONVERTER.toNBT(); for (Map.Entry> entry : value.entrySet()) { plugin.getNMSTags().setNBTCompoundTagValue(nbtTagCompound, entry.getKey(), entry.getValue().toNBT()); @@ -260,8 +236,27 @@ public Object toNBT() { } } + @Nullable + private Tag getTagInternal(String key) { + return this.value.get(key); + } + + @Nullable + private > Optional getTagInternal(String key, Class valueType) { + Tag tag = this.value.get(key); + return tag != null && valueType.isAssignableFrom(tag.getClass()) ? Optional.of(valueType.cast(tag)) : Optional.empty(); + } + + public static CompoundTag of() { + return new CompoundTag(new HashMap<>(), false); + } + + public static CompoundTag of(Map> value) { + return new CompoundTag(value, true); + } + public static CompoundTag fromNBT(Object tag) { - Preconditions.checkArgument(tag.getClass().equals(CLASS), "Cannot convert " + tag.getClass() + " to CompoundTag!"); + Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to CompoundTag!"); Map> map = new HashMap<>(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java index 3cd2f24e0f..fa5d5ffae7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java @@ -46,9 +46,23 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class DoubleTag extends NumberTag { + /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagDouble", double.class); + private static final DoubleTag[] CACHE = new DoubleTag[100]; - /*package*/ static final Class CLASS = getNNTClass("NBTTagDouble"); + private DoubleTag(double value) { + super(value); + } + + @Override + protected void writeData(DataOutputStream os) throws IOException { + os.writeDouble(value); + } + + @Override + protected NMSTagConverter getNMSConverter() { + return TAG_CONVERTER; + } public static DoubleTag of(double value) { if (value == (int) value && value >= 0 && value < CACHE.length) { @@ -61,17 +75,8 @@ public static DoubleTag of(double value) { } } - /** - * Creates the tag. - * - * @param value The value. - */ - private DoubleTag(double value) { - super(value, CLASS, double.class); - } - public static DoubleTag fromNBT(Object tag) { - Preconditions.checkArgument(tag.getClass().equals(CLASS), "Cannot convert " + tag.getClass() + " to DoubleTag!"); + Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to DoubleTag!"); try { double value = plugin.getNMSTags().getNBTDoubleValue(tag); @@ -86,9 +91,4 @@ public static DoubleTag fromStream(DataInputStream is) throws IOException { return DoubleTag.of(is.readDouble()); } - @Override - protected void writeData(DataOutputStream os) throws IOException { - os.writeDouble(value); - } - } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java index 46a3c82e10..73848065ba 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java @@ -41,30 +41,24 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * * @author Graham Edgecombe */ -@SuppressWarnings("WeakerAccess") public class EndTag extends Tag { - private static final EndTag INSTANCE = new EndTag(); + /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagEnd"); - /*package*/ static final Class CLASS = getNNTClass("NBTTagEnd"); + private static final EndTag INSTANCE = new EndTag(); - public static EndTag of() { - return INSTANCE; + private EndTag() { + super(null); } - /** - * Creates the tag. - */ - private EndTag() { - super(null, CLASS); + @Override + protected void writeData(DataOutputStream os) { + // Do nothing. } - public static EndTag fromStream(DataInputStream is, int depth) throws IOException { - if (depth == 0) { - throw new IOException("TAG_End found without a TAG_Compound/TAG_List tag preceding it."); - } else { - return EndTag.INSTANCE; - } + @Override + protected NMSTagConverter getNMSConverter() { + return TAG_CONVERTER; } @Override @@ -72,9 +66,16 @@ public String toString() { return "TAG_End"; } - @Override - protected void writeData(DataOutputStream os) { - // Do nothing. + public static EndTag of() { + return INSTANCE; + } + + public static EndTag fromStream(DataInputStream is, int depth) throws IOException { + if (depth == 0) { + throw new IOException("TAG_End found without a TAG_Compound/TAG_List tag preceding it."); + } else { + return EndTag.INSTANCE; + } } } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java index 0af5da0c9d..b2f9502b57 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java @@ -44,12 +44,25 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * * @author Graham Edgecombe */ -@SuppressWarnings("WeakerAccess") public class FloatTag extends NumberTag { + /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagFloat", float.class); + private static final FloatTag[] CACHE = new FloatTag[100]; - /*package*/ static final Class CLASS = getNNTClass("NBTTagFloat"); + private FloatTag(float value) { + super(value); + } + + @Override + protected void writeData(DataOutputStream os) throws IOException { + os.writeFloat(value); + } + + @Override + protected NMSTagConverter getNMSConverter() { + return TAG_CONVERTER; + } public static FloatTag of(float value) { if (value == (int) value && value >= 0 && value < CACHE.length) { @@ -62,17 +75,8 @@ public static FloatTag of(float value) { } } - /** - * Creates the tag. - * - * @param value The value. - */ - private FloatTag(float value) { - super(value, CLASS, float.class); - } - public static FloatTag fromNBT(Object tag) { - Preconditions.checkArgument(tag.getClass().equals(CLASS), "Cannot convert " + tag.getClass() + " to FloatTag!"); + Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to FloatTag!"); try { float value = plugin.getNMSTags().getNBTFloatValue(tag); @@ -87,9 +91,4 @@ public static FloatTag fromStream(DataInputStream is) throws IOException { return FloatTag.of(is.readFloat()); } - @Override - protected void writeData(DataOutputStream os) throws IOException { - os.writeFloat(value); - } - } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java index 968ea9b922..c119db7a75 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java @@ -53,13 +53,9 @@ @SuppressWarnings("WeakerAccess") public class IntArrayTag extends Tag { - private static final IntArrayTag EMPTY = new IntArrayTag(new int[0]); - - /*package*/ static final Class CLASS = getNNTClass("NBTTagIntArray"); + /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagIntArray", int[].class); - public static IntArrayTag of(int[] value) { - return value.length == 0 ? EMPTY : new IntArrayTag(value); - } + private static final IntArrayTag EMPTY = new IntArrayTag(new int[0]); /** * Creates the tag. @@ -67,34 +63,19 @@ public static IntArrayTag of(int[] value) { * @param value The value. */ private IntArrayTag(int[] value) { - super(value, CLASS, int[].class); - } - - public static IntArrayTag fromNBT(Object tag) { - Preconditions.checkArgument(tag.getClass().equals(CLASS), "Cannot convert " + tag.getClass() + " to IntArrayTag!"); - - try { - int[] value = plugin.getNMSTags().getNBTIntArrayValue(tag); - return IntArrayTag.of(value); - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while converting tag int-array from NMS:"); - return null; - } + super(value); } - public static IntArrayTag fromUUID(UUID uuid) { - long MSB = uuid.getMostSignificantBits(); - long LSB = uuid.getLeastSignificantBits(); - return IntArrayTag.of(new int[]{(int) (MSB >> 32), (int) MSB, (int) (LSB >> 32), (int) LSB}); + @Override + protected void writeData(DataOutputStream os) throws IOException { + os.writeInt(value.length); + for (int i : value) + os.writeInt(i); } - public static IntArrayTag fromStream(DataInputStream is) throws IOException { - int length = is.readInt(); - int[] data = new int[length]; - for (int i = 0; i < length; i++) { - data[i] = is.readInt(); - } - return IntArrayTag.of(data); + @Override + protected NMSTagConverter getNMSConverter() { + return TAG_CONVERTER; } @Override @@ -106,13 +87,6 @@ public String toString() { return "TAG_Int_Array: " + integers; } - @Override - protected void writeData(DataOutputStream os) throws IOException { - os.writeInt(value.length); - for (int i : value) - os.writeInt(i); - } - @Override public int hashCode() { int prime = 31; @@ -126,4 +100,35 @@ public boolean equals(final Object obj) { return this == obj || (obj instanceof IntArrayTag && Arrays.equals(value, ((IntArrayTag) obj).value)); } + public static IntArrayTag of(int[] value) { + return value.length == 0 ? EMPTY : new IntArrayTag(value); + } + + public static IntArrayTag fromNBT(Object tag) { + Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to IntArrayTag!"); + + try { + int[] value = plugin.getNMSTags().getNBTIntArrayValue(tag); + return IntArrayTag.of(value); + } catch (Exception error) { + Log.error(error, "An unexpected error occurred while converting tag int-array from NMS:"); + return null; + } + } + + public static IntArrayTag fromUUID(UUID uuid) { + long MSB = uuid.getMostSignificantBits(); + long LSB = uuid.getLeastSignificantBits(); + return IntArrayTag.of(new int[]{(int) (MSB >> 32), (int) MSB, (int) (LSB >> 32), (int) LSB}); + } + + public static IntArrayTag fromStream(DataInputStream is) throws IOException { + int length = is.readInt(); + int[] data = new int[length]; + for (int i = 0; i < length; i++) { + data[i] = is.readInt(); + } + return IntArrayTag.of(data); + } + } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java index 56349d9850..e317915c32 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java @@ -46,9 +46,23 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class IntTag extends NumberTag { + /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagInt", int.class); + private static final IntTag[] CACHE = new IntTag[100]; - /*package*/ static final Class CLASS = getNNTClass("NBTTagInt"); + private IntTag(int value) { + super(value); + } + + @Override + protected void writeData(DataOutputStream os) throws IOException { + os.writeInt(value); + } + + @Override + protected NMSTagConverter getNMSConverter() { + return TAG_CONVERTER; + } public static IntTag of(int value) { if (value >= 0 && value < CACHE.length) { @@ -61,12 +75,8 @@ public static IntTag of(int value) { } } - private IntTag(int value) { - super(value, CLASS, int.class); - } - public static IntTag fromNBT(Object tag) { - Preconditions.checkArgument(tag.getClass().equals(CLASS), "Cannot convert " + tag.getClass() + " to IntTag!"); + Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to IntTag!"); try { int value = plugin.getNMSTags().getNBTIntValue(tag); @@ -81,9 +91,4 @@ public static IntTag fromStream(DataInputStream is) throws IOException { return IntTag.of(is.readInt()); } - @Override - protected void writeData(DataOutputStream os) throws IOException { - os.writeInt(value); - } - } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java index 15ded29f3c..e3659e6fb4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java @@ -54,8 +54,9 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @SuppressWarnings("rawtypes") public class ListTag extends Tag>> implements Iterable> { + /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagList"); + private static final byte DYNAMIC_LIST_INDICATOR = (byte) 0xFF; - /*package*/ static final Class CLASS = getNNTClass("NBTTagList"); /** * Hint to the type of elements in the list. @@ -63,20 +64,8 @@ public class ListTag extends Tag>> implements Iterable> { @Nullable private Class hintType; - public static ListTag of(@Nullable Class hintType) { - return new ListTag(new LinkedList<>(), hintType, false); - } - - public static ListTag of(List> value) { - return of(value, null); - } - - public static ListTag of(List> value, @Nullable Class hintType) { - return new ListTag(value, hintType, true); - } - private ListTag(List> value, @Nullable Class hintType, boolean cloneList) { - super(cloneListIfNeeded(value, cloneList), null); + super(cloneListIfNeeded(value, cloneList)); this.hintType = hintType; } @@ -92,8 +81,80 @@ public void addTag(Tag tag) { } } + @Override + public List> getValue() { + return Collections.unmodifiableList(value); + } + + @NotNull + @Override + public Iterator> iterator() { + return value.iterator(); + } + + public int size() { + return this.value.size(); + } + + @Override + public String toString() { + StringBuilder bldr = new StringBuilder(); + bldr.append("TAG_List: ").append(value.size()).append(" entries"); + if (this.hintType != null) { + bldr.append(" of type ").append(NBTUtils.getTypeName(hintType)); + } + bldr.append("\r\n{\r\n"); + for (Tag t : value) { + bldr.append(" ").append(t.toString().replaceAll("\r\n", "\r\n ")).append("\r\n"); + } + bldr.append("}"); + return bldr.toString(); + } + + @Override + protected void writeData(DataOutputStream os) throws IOException { + if (this.hintType != null) { + writeDataWithHint(os); + } else { + writeDataWithoutHint(os); + } + } + + private void writeDataWithHint(DataOutputStream os) throws IOException { + int size = value.size(); + os.writeByte(NBTUtils.getTypeCode(this.hintType)); + os.writeInt(size); + for (Tag _tag : value) + _tag.writeData(os); + } + + private void writeDataWithoutHint(DataOutputStream os) throws IOException { + int size = value.size(); + os.writeByte(DYNAMIC_LIST_INDICATOR); + os.writeInt(size); + for (Tag _tag : value) + _tag.write(os); + } + + @Override + public Object toNBT() { + return plugin.getNMSTags().parseList(this); + } + + public static ListTag of(@Nullable Class hintType) { + return new ListTag(new LinkedList<>(), hintType, false); + } + + public static ListTag of(List> value) { + return of(value, null); + } + + public static ListTag of(List> value, @Nullable Class hintType) { + return new ListTag(value, hintType, true); + } + public static ListTag fromNBT(Object tag) { - Preconditions.checkArgument(tag.getClass().equals(CLASS), "Cannot convert " + tag.getClass() + " to ListTag!"); + Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to ListTag!"); List> list = new LinkedList<>(); @@ -159,66 +220,6 @@ private static ListTag fromStreamWithoutHint(DataInputStream is, int depth) thro return new ListTag(tagList, null, false); } - @Override - public List> getValue() { - return Collections.unmodifiableList(value); - } - - @NotNull - @Override - public Iterator> iterator() { - return value.iterator(); - } - - public int size() { - return this.value.size(); - } - - @Override - public String toString() { - StringBuilder bldr = new StringBuilder(); - bldr.append("TAG_List: ").append(value.size()).append(" entries"); - if (this.hintType != null) { - bldr.append(" of type ").append(NBTUtils.getTypeName(hintType)); - } - bldr.append("\r\n{\r\n"); - for (Tag t : value) { - bldr.append(" ").append(t.toString().replaceAll("\r\n", "\r\n ")).append("\r\n"); - } - bldr.append("}"); - return bldr.toString(); - } - - @Override - protected void writeData(DataOutputStream os) throws IOException { - if (this.hintType != null) { - writeDataWithHint(os); - } else { - writeDataWithoutHint(os); - } - } - - private void writeDataWithHint(DataOutputStream os) throws IOException { - int size = value.size(); - os.writeByte(NBTUtils.getTypeCode(this.hintType)); - os.writeInt(size); - for (Tag _tag : value) - _tag.writeData(os); - } - - private void writeDataWithoutHint(DataOutputStream os) throws IOException { - int size = value.size(); - os.writeByte(DYNAMIC_LIST_INDICATOR); - os.writeInt(size); - for (Tag _tag : value) - _tag.write(os); - } - - @Override - public Object toNBT() { - return plugin.getNMSTags().parseList(this); - } - private static List cloneListIfNeeded(List list, boolean cloneList) { return cloneList || list instanceof RandomAccess ? new LinkedList<>(list) : list; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java index ec84289f02..38975dee9e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java @@ -44,12 +44,25 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * * @author Graham Edgecombe */ -@SuppressWarnings("WeakerAccess") public class LongTag extends NumberTag { + /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagLong", long.class); + private static final LongTag[] CACHE = new LongTag[100]; - /*package*/ static final Class CLASS = getNNTClass("NBTTagLong"); + private LongTag(long value) { + super(value); + } + + @Override + protected void writeData(DataOutputStream os) throws IOException { + os.writeLong(value); + } + + @Override + protected NMSTagConverter getNMSConverter() { + return TAG_CONVERTER; + } public static LongTag of(long value) { if (value >= 0 && value < CACHE.length) { @@ -62,12 +75,8 @@ public static LongTag of(long value) { } } - private LongTag(long value) { - super(value, CLASS, long.class); - } - public static LongTag fromNBT(Object tag) { - Preconditions.checkArgument(tag.getClass().equals(CLASS), "Cannot convert " + tag.getClass() + " to LongTag!"); + Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to LongTag!"); try { long value = plugin.getNMSTags().getNBTLongValue(tag); @@ -82,9 +91,4 @@ public static LongTag fromStream(DataInputStream is) throws IOException { return LongTag.of(is.readLong()); } - @Override - protected void writeData(DataOutputStream os) throws IOException { - os.writeLong(value); - } - } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/NMSTagConverter.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/NMSTagConverter.java new file mode 100644 index 0000000000..99a4913b75 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/NMSTagConverter.java @@ -0,0 +1,47 @@ +package com.bgsoftware.superiorskyblock.tag; + +import com.bgsoftware.common.reflection.ReflectConstructor; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.core.ServerVersion; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import org.bukkit.Bukkit; + +public class NMSTagConverter { + + private final Class clazz; + private final ReflectMethod A; + private final ReflectConstructor CONSTRUCTOR; + + public NMSTagConverter(String nbtClassName, Class... parameterTypes) { + this.clazz = getNNTClass(nbtClassName); + this.A = new ReflectMethod<>(this.clazz, this.clazz, "a", parameterTypes); + this.CONSTRUCTOR = new ReflectConstructor<>(this.clazz, parameterTypes); + } + + public Class getNBTClass() { + return clazz; + } + + public Object toNBT(Object... args) { + if (A.isValid()) { + return A.invoke(null, args); + } else { + return CONSTRUCTOR.newInstance(args); + } + } + + private static Class getNNTClass(String nbtType) { + try { + if (ServerVersion.isAtLeast(ServerVersion.v1_17)) { + return Class.forName("net.minecraft.nbt." + nbtType); + } else { + String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; + return Class.forName("net.minecraft.server." + version + "." + nbtType); + } + } catch (Exception error) { + Log.error(error, "An unexpected error while loading nbt class ", nbtType, ":"); + return null; + } + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/NumberTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/NumberTag.java index e0432ddd24..b7c96560ef 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/NumberTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/NumberTag.java @@ -2,8 +2,8 @@ public abstract class NumberTag extends Tag { - protected NumberTag(E value, Class clazz, Class... parameterTypes) { - super(value, clazz, parameterTypes); + protected NumberTag(E value) { + super(value); } } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTag.java index 0c87e134f2..f7a8f8c21b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTag.java @@ -9,12 +9,8 @@ public class PersistentDataTag extends Tag { private final PersistentDataTypeContext serializer; - public static PersistentDataTag of(E value, PersistentDataTypeContext serializer) { - return new PersistentDataTag<>(value, serializer); - } - private PersistentDataTag(E value, PersistentDataTypeContext serializer) { - super(value, null); + super(value); this.serializer = serializer; } @@ -25,4 +21,8 @@ protected void writeData(DataOutputStream os) throws IOException { os.write(data); } + public static PersistentDataTag of(E value, PersistentDataTypeContext serializer) { + return new PersistentDataTag<>(value, serializer); + } + } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTagSerialized.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTagSerialized.java index 85b74fad3b..a7dd3f2d27 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTagSerialized.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/PersistentDataTagSerialized.java @@ -11,12 +11,8 @@ public class PersistentDataTagSerialized extends Tag { private static final PersistentDataTagSerialized EMPTY = new PersistentDataTagSerialized(new byte[0]); - public static PersistentDataTagSerialized of(byte[] value) { - return value.length == 0 ? EMPTY : new PersistentDataTagSerialized(value); - } - private PersistentDataTagSerialized(byte[] value) { - super(value, null); + super(value); } public PersistentDataTag getPersistentDataTag(PersistentDataType type) { @@ -26,6 +22,16 @@ public PersistentDataTag getPersistentDataTag(PersistentDataType type) return PersistentDataTag.of(serializer.deserialize(value), serializer); } + @Override + protected void writeData(DataOutputStream os) throws IOException { + os.writeInt(value.length); + os.write(value); + } + + public static PersistentDataTagSerialized of(byte[] value) { + return value.length == 0 ? EMPTY : new PersistentDataTagSerialized(value); + } + public static PersistentDataTagSerialized fromStream(DataInputStream is) throws IOException { int length = is.readInt(); byte[] bytes = new byte[length]; @@ -33,10 +39,4 @@ public static PersistentDataTagSerialized fromStream(DataInputStream is) throws return new PersistentDataTagSerialized(bytes); } - @Override - protected void writeData(DataOutputStream os) throws IOException { - os.writeInt(value.length); - os.write(value); - } - } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java index c7996f3010..63e2213817 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java @@ -46,9 +46,23 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class ShortTag extends NumberTag { + /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagShort", short.class); + private static final ShortTag[] CACHE = new ShortTag[100]; - /*package*/ static final Class CLASS = getNNTClass("NBTTagShort"); + private ShortTag(short value) { + super(value); + } + + @Override + protected void writeData(DataOutputStream os) throws IOException { + os.writeShort(value); + } + + @Override + protected NMSTagConverter getNMSConverter() { + return TAG_CONVERTER; + } public static ShortTag of(short value) { if (value >= 0 && value < CACHE.length) { @@ -61,12 +75,8 @@ public static ShortTag of(short value) { } } - private ShortTag(short value) { - super(value, CLASS, short.class); - } - public static ShortTag fromNBT(Object tag) { - Preconditions.checkArgument(tag.getClass().equals(CLASS), "Cannot convert " + tag.getClass() + " to ShortTag!"); + Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to ShortTag!"); try { short value = plugin.getNMSTags().getNBTShortValue(tag); @@ -81,9 +91,4 @@ public static ShortTag fromStream(DataInputStream is) throws IOException { return ShortTag.of(is.readShort()); } - @Override - protected void writeData(DataOutputStream os) throws IOException { - os.writeShort(value); - } - } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java index 018ebf633f..7f75dc12e4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java @@ -47,25 +47,33 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class StringTag extends Tag { + /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagString", String.class); + private static final StringTag EMPTY = new StringTag(""); - /*package*/ static final Class CLASS = getNNTClass("NBTTagString"); + private StringTag(String value) { + super(value); + } - public static StringTag of(String value) { - return value.isEmpty() ? EMPTY : new StringTag(value); + @Override + protected void writeData(DataOutputStream os) throws IOException { + byte[] bytes = value.getBytes(StandardCharsets.UTF_8); + os.writeShort(bytes.length); + if (bytes.length > 0) + os.write(bytes); } - /** - * Creates the tag. - * - * @param value The value. - */ - private StringTag(String value) { - super(value, CLASS, String.class); + @Override + protected NMSTagConverter getNMSConverter() { + return TAG_CONVERTER; + } + + public static StringTag of(String value) { + return value.isEmpty() ? EMPTY : new StringTag(value); } public static StringTag fromNBT(Object tag) { - Preconditions.checkArgument(tag.getClass().equals(CLASS), "Cannot convert " + tag.getClass() + " to StringTag!"); + Preconditions.checkArgument(tag.getClass().equals(TAG_CONVERTER.getNBTClass()), "Cannot convert " + tag.getClass() + " to StringTag!"); try { String value = plugin.getNMSTags().getNBTStringValue(tag); @@ -85,12 +93,4 @@ public static StringTag fromStream(DataInputStream is) throws IOException { return StringTag.of(new String(bytes, StandardCharsets.UTF_8)); } - @Override - protected void writeData(DataOutputStream os) throws IOException { - byte[] bytes = value.getBytes(StandardCharsets.UTF_8); - os.writeShort(bytes.length); - if (bytes.length > 0) - os.write(bytes); - } - } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/Tag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/Tag.java index 7b144a1549..e7bcdb13cf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/Tag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/Tag.java @@ -32,16 +32,13 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ package com.bgsoftware.superiorskyblock.tag; -import com.bgsoftware.common.reflection.ReflectConstructor; -import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.ServerVersion; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import org.bukkit.Bukkit; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.Objects; /** * Represents a single NBT tag. @@ -52,40 +49,36 @@ public abstract class Tag { protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - protected final ReflectMethod A; - protected final ReflectConstructor CONSTRUCTOR; protected final E value; - protected Tag(E value, Class clazz, Class... parameterTypes) { + protected Tag(E value) { this.value = value; - this.A = new ReflectMethod<>(clazz, clazz, "a", parameterTypes); - this.CONSTRUCTOR = new ReflectConstructor<>(clazz, parameterTypes); } public static Tag fromNBT(Object tag) { - if (tag.getClass().equals(ByteArrayTag.CLASS)) + if (tag.getClass().equals(ByteArrayTag.TAG_CONVERTER.getNBTClass())) return ByteArrayTag.fromNBT(tag); - else if (tag.getClass().equals(ByteTag.CLASS)) + else if (tag.getClass().equals(ByteTag.TAG_CONVERTER.getNBTClass())) return ByteTag.fromNBT(tag); - else if (tag.getClass().equals(CompoundTag.CLASS)) + else if (tag.getClass().equals(CompoundTag.TAG_CONVERTER.getNBTClass())) return CompoundTag.fromNBT(tag); - else if (tag.getClass().equals(DoubleTag.CLASS)) + else if (tag.getClass().equals(DoubleTag.TAG_CONVERTER.getNBTClass())) return DoubleTag.fromNBT(tag); - else if (tag.getClass().equals(EndTag.CLASS)) + else if (tag.getClass().equals(EndTag.TAG_CONVERTER.getNBTClass())) return EndTag.of(); - else if (tag.getClass().equals(FloatTag.CLASS)) + else if (tag.getClass().equals(FloatTag.TAG_CONVERTER.getNBTClass())) return FloatTag.fromNBT(tag); - else if (tag.getClass().equals(IntArrayTag.CLASS)) + else if (tag.getClass().equals(IntArrayTag.TAG_CONVERTER.getNBTClass())) return IntArrayTag.fromNBT(tag); - else if (tag.getClass().equals(IntTag.CLASS)) + else if (tag.getClass().equals(IntTag.TAG_CONVERTER.getNBTClass())) return IntTag.fromNBT(tag); - else if (tag.getClass().equals(ListTag.CLASS)) + else if (tag.getClass().equals(ListTag.TAG_CONVERTER.getNBTClass())) return ListTag.fromNBT(tag); - else if (tag.getClass().equals(LongTag.CLASS)) + else if (tag.getClass().equals(LongTag.TAG_CONVERTER.getNBTClass())) return LongTag.fromNBT(tag); - else if (tag.getClass().equals(ShortTag.CLASS)) + else if (tag.getClass().equals(ShortTag.TAG_CONVERTER.getNBTClass())) return ShortTag.fromNBT(tag); - else if (tag.getClass().equals(StringTag.CLASS)) + else if (tag.getClass().equals(StringTag.TAG_CONVERTER.getNBTClass())) return StringTag.fromNBT(tag); throw new IllegalArgumentException("Cannot convert " + tag.getClass() + " to Tag!"); @@ -133,20 +126,6 @@ protected static Tag fromStream(DataInputStream is, int depth, int type) thro throw new IllegalArgumentException("Invalid tag: " + type); } - protected static Class getNNTClass(String nbtType) { - try { - if (ServerVersion.isAtLeast(ServerVersion.v1_17)) { - return Class.forName("net.minecraft.nbt." + nbtType); - } else { - String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; - return Class.forName("net.minecraft.server." + version + "." + nbtType); - } - } catch (Exception error) { - Log.error(error, "An unexpected error while loading nbt class ", nbtType, ":"); - return null; - } - } - public E getValue() { return value; } @@ -170,12 +149,16 @@ public void write(DataOutputStream os) throws IOException { protected abstract void writeData(DataOutputStream outputStream) throws IOException; + @Nullable + protected NMSTagConverter getNMSConverter() { + return null; + } + public Object toNBT() { - if (A.isValid()) { - return A.invoke(null, value); - } else { - return CONSTRUCTOR.newInstance(value); - } + NMSTagConverter converter = getNMSConverter(); + if (converter == null) + throw new UnsupportedOperationException(); + return Objects.requireNonNull(converter.toNBT(this.value)); } } \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/UUIDTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/UUIDTag.java index 679fea9362..102b389eb4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/UUIDTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/UUIDTag.java @@ -8,6 +8,16 @@ public class UUIDTag extends Tag { + private UUIDTag(UUID value) { + super(value); + } + + @Override + protected void writeData(DataOutputStream os) throws IOException { + os.writeLong(value.getMostSignificantBits()); + os.writeLong(value.getLeastSignificantBits()); + } + public static UUIDTag of(long mostSigBits, long leastSigBits) { return new UUIDTag(new UUID(mostSigBits, leastSigBits)); } @@ -16,18 +26,8 @@ public static UUIDTag of(UUID value) { return new UUIDTag(value); } - private UUIDTag(UUID value) { - super(value, null); - } - public static UUIDTag fromStream(DataInputStream is) throws IOException { return UUIDTag.of(is.readLong(), is.readLong()); } - @Override - protected void writeData(DataOutputStream os) throws IOException { - os.writeLong(value.getMostSignificantBits()); - os.writeLong(value.getLeastSignificantBits()); - } - } \ No newline at end of file From 34cda2d310f0df54def13407c46b75494305f3ac Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 24 Jul 2025 17:19:45 +0300 Subject: [PATCH 227/600] [CI SKIP] Fix build issues --- NMS/Paper-1_20_3/build.gradle | 2 +- NMS/v1_17/build.gradle | 2 +- NMS/v1_18/build.gradle | 2 +- NMS/v1_19/build.gradle | 2 +- NMS/v1_20_3/build.gradle | 2 +- NMS/v1_20_4/build.gradle | 2 +- NMS/v1_21/build.gradle | 2 +- NMS/v1_21_3/build.gradle | 2 +- NMS/v1_21_4/build.gradle | 2 +- NMS/v1_21_5/build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/NMS/Paper-1_20_3/build.gradle b/NMS/Paper-1_20_3/build.gradle index 6dc5afd0de..7446737715 100644 --- a/NMS/Paper-1_20_3/build.gradle +++ b/NMS/Paper-1_20_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } group 'NMS:Paper-1_20_3' diff --git a/NMS/v1_17/build.gradle b/NMS/v1_17/build.gradle index 627e339389..bf5f5d8352 100644 --- a/NMS/v1_17/build.gradle +++ b/NMS/v1_17/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_18/build.gradle b/NMS/v1_18/build.gradle index 94104dbd12..bdcf38c1ca 100644 --- a/NMS/v1_18/build.gradle +++ b/NMS/v1_18/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_19/build.gradle b/NMS/v1_19/build.gradle index 5642e98ee6..39cf25b853 100644 --- a/NMS/v1_19/build.gradle +++ b/NMS/v1_19/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_20_3/build.gradle b/NMS/v1_20_3/build.gradle index 40ff4eaede..94cd254e76 100644 --- a/NMS/v1_20_3/build.gradle +++ b/NMS/v1_20_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_20_4/build.gradle b/NMS/v1_20_4/build.gradle index 4fd3c1b8f5..808202fdbe 100644 --- a/NMS/v1_20_4/build.gradle +++ b/NMS/v1_20_4/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_21/build.gradle b/NMS/v1_21/build.gradle index 8a98614ad7..fcc7b15fe0 100644 --- a/NMS/v1_21/build.gradle +++ b/NMS/v1_21/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_21_3/build.gradle b/NMS/v1_21_3/build.gradle index f551333bc2..4c164d66eb 100644 --- a/NMS/v1_21_3/build.gradle +++ b/NMS/v1_21_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_21_4/build.gradle b/NMS/v1_21_4/build.gradle index f5199ecaec..b868b25a2d 100644 --- a/NMS/v1_21_4/build.gradle +++ b/NMS/v1_21_4/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/NMS/v1_21_5/build.gradle b/NMS/v1_21_5/build.gradle index b4f455cdc5..00638de249 100644 --- a/NMS/v1_21_5/build.gradle +++ b/NMS/v1_21_5/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.11" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" } java { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d6e308a637..260504c0cb 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists From 59bd8c36f4c7ba828fa8f468c288024e2063dfad Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 26 Jul 2025 19:37:43 +0300 Subject: [PATCH 228/600] Fixed bank transactions of deleted islands are not deleted from DB --- .../core/database/bridge/IslandsDatabaseBridge.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index 704188518a..0f91bcff99 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -677,6 +677,7 @@ public static void deleteIsland(Island island) { databaseBridge.deleteObject("islands", createFilter("uuid", island)); databaseBridge.deleteObject("islands_banks", islandFilter); databaseBridge.deleteObject("islands_settings", islandFilter); + databaseBridge.deleteObject("bank_transactions", islandFilter); if (!island.getBannedPlayers().isEmpty()) From b7967810867d4c8250842cdcde01034af58263c6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 Aug 2025 14:39:14 +0300 Subject: [PATCH 229/600] Fixed the way block values are registered that caused conflicts with global and specific keys (#2586) --- .../core/values/container/BlockValuesContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/values/container/BlockValuesContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/values/container/BlockValuesContainer.java index 11bfe2ffb6..51d0af6aa4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/values/container/BlockValuesContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/values/container/BlockValuesContainer.java @@ -14,7 +14,7 @@ public class BlockValuesContainer { private final KeyMap valuesMap = KeyMaps.createHashMap(KeyIndicator.MATERIAL); public void setBlockValue(Key key, BlockValue value) { - valuesMap.put(getBlockValueKey(key), value); + valuesMap.put(key, value); } @Nullable From 48f1f863ba21f8577ba65461e16df7e88253a6a9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 Aug 2025 16:16:53 +0300 Subject: [PATCH 230/600] Fixed Chunk2ObjectMap not tracking its size correctly --- .../superiorskyblock/core/collections/Chunk2ObjectMap.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/Chunk2ObjectMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/Chunk2ObjectMap.java index a401ff015b..c95c4aaea2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/Chunk2ObjectMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/Chunk2ObjectMap.java @@ -74,7 +74,10 @@ public V computeIfAbsent(String worldName, long chunkPair, Supplier newValue) Long2ObjectMapView worldBackendData = this.backendMap.computeIfAbsent(worldName, n -> CollectionsFactory.createLong2ObjectLinkedHashMap()); - return worldBackendData.computeIfAbsent(chunkPair, p -> newValue.get()); + return worldBackendData.computeIfAbsent(chunkPair, p -> { + ++Chunk2ObjectMap.this.size; + return newValue.get(); + }); } @Nullable From 6fd30449b9666e47bdf44626e28bea7cc52e25b5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 Aug 2025 16:35:15 +0300 Subject: [PATCH 231/600] Fixed teleporting to other worlds for first time is not accurate (#2580) --- .../service/portals/PortalsManagerServiceImpl.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java index 0223b1da8a..6f3c681f97 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java @@ -30,6 +30,7 @@ import org.bukkit.Location; import org.bukkit.PortalType; import org.bukkit.World; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; @@ -239,8 +240,8 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island IslandWorlds.accessIslandWorldAsync(island, destination, true, islandWorldResult -> { islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { - Location schematicPlacementLocation = island.getCenter(destination).subtract(0, 1, 0); - schematicPlacementLocation.setY(plugin.getSettings().getIslandHeight()); + Location centerLocation = island.getCenter(destination); + Location schematicPlacementLocation = centerLocation.getBlock().getRelative(BlockFace.DOWN).getLocation(); BigDecimal originalWorth = island.getRawWorth(); BigDecimal originalLevel = island.getRawLevel(); @@ -267,7 +268,8 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island } } - Location destinationLocation = island.getIslandHome(destination); + Location homeLocation = schematic.adjustRotation(centerLocation); + island.setIslandHome(destination, homeLocation); if (destination.getEnvironment() == World.Environment.THE_END && superiorPlayer != null) { plugin.getNMSDragonFight().awardTheEndAchievement((Player) entity); @@ -275,9 +277,9 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island } if (superiorPlayer != null) { - superiorPlayer.teleport(schematic.adjustRotation(destinationLocation)); + superiorPlayer.teleport(homeLocation); } else { - EntityTeleports.teleport(entity, schematic.adjustRotation(destinationLocation)); + EntityTeleports.teleport(entity, homeLocation); } }, error -> { generatingSchematicsIslands.remove(island.getUniqueId()); From e31c78880839313a7ed5fbc129025b97f84f7899 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 Aug 2025 17:16:52 +0300 Subject: [PATCH 232/600] Better detection for caught fish types (#2577) --- .../modules/missions/FishingMissions | Bin 24687 -> 21712 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/modules/missions/FishingMissions b/src/main/resources/modules/missions/FishingMissions index be8262a41fe6f97b68a249c1f0cadd20b5e32ae2..0d2acf64b1f3e40e568f01dc6a1558f2cdec2acb 100644 GIT binary patch delta 6183 zcmY+IWmptU*T*SkQ9`=AOS)k}5SH#(Vrh_6x?w5lURk)`kj45ohe7f)l@;pc!q)k0H9#T0F3K#pP*tCMFWgsq^R<^ z{|Je|)CDFI6qI#w*f|3a%nVEn9W=%Y&|O^oohKsTJ8G>ci*}eVGmvi>Ei0q;BBV|p zmXBp#PzX#(vmUW#naDz&t7ux%H$JLp(r&60Zf=sVdddK)Ycfh+YIblm=s3GKm1f!$ zyY4a+pvT&}4txm8@ICAHpO(76&AX2%V$Ho_2o^tO=o_To>RvnD&~N30wttFBZ_=;Y zjKk=|uk<$e=UtyQ{zO_=B_nFRSc3zW3eohAb*~KrTni<(tRLbrDTz9!#dmPj7mj~! z6sF)4_nTBaCEow&!06!A_>K}TA{fcI(e%lxt1HB=x@{a=-Z2YZe*ybkPIjZ*1<|ke zJyA&?glnM?!B6sy*NZ$HN^n~dFOS~4MpD${q{c=;K9dYehhNEnfW1Yz1P%(P3$%hy z!3&&=X-6%V3wpaZoGYvv|MkOVm{b8h!jnXmw;b(n!w>UH^~X9;U)>{wm>TS z2@Va&r`5lY3i5oav}}eQl?e z?yxa_`sxReALk9oX)|fgM2H?CSuHp=5^qSbF$7@w}yDNYN{+Xm0$HX#=)6}qn z33cKgQMdjeTCe)(g>mN!$1G54KGUh$QB;EL*Du?s{sxvxx%gM`>u!=|ti9umfxbhT zo>5?T&M6VjCqe0vqYWvmmldRCc>QzrItFN?yY5;<9) zr){QD(NU@FJuumDJtwu|ULO$_ZHl~tvzi(6-Psr6V>i2l8D#j*9HS z1J>hOzBjyAFcT$-+25|7kd$CvHd7KP^4!#&-R*a7g*=>{hQsG$P(0RqeYjK4hg^8m z*<4bTHjf5PJ7cYUiS%dAX-KTo@Z&Nl+ry!^r7>K=eUaB&>O7xgJ4Dg1hQVX8$Z$<~ z{urF-YzXsWt6yqDU3t~8q}wAP$(^}!?&Sfu!pN6jSO;(eYxYNbSo%d^>t?L~IelNJ zE6ec>phI@xghZ24%Y0T_Ha@;|c-`#i#_Glg2#mo5RBDiaLZJ9l=b7)W;S0t`;X(1R zE+__ApG(~k75F}UNw>SE6Fale*T22l`mt*H;tDy%^^~L!PQ3%9`pBKKLbC_Z%tBJ| zq&rNdd*>$O}f4Zfb`WinQ3$ypG^`8<66-Ug3BfE(m(ftMel7;f|<{`z(Wd1 zwPT(}@!jjwtB2oZ)HxZ>XHQ32?Q<1cJ(Ls1FsNTrr!ffTG<%GOP;20-&HYe0qfHTh zWdj&zH&OpCt}eO=*!MWZiG))02mX2`;74)j+GCtl+_D6~2)x03d>Qhf;bo@h`r4NE z(K+!kvZS#UslrkszXyBU@csqJsh!Za#);&c#{_7esPo5<;@CP4ni~gGsO=wjkh}!U%MDwn-B=*sVNR zQz*I}p`&GFV29AliRsd1P;KWL4L*2-3S0FfrJXD`jC*;6y+}s^(L&CPnROg36awEb zMvQ`z#zNE&JFMzajK>K9o|*oD>pXF3E8m~?lIk`;l~OhQI^NQ98?_B|x!^|j;5QB( z(zVpQmT4>p$Ai8i{l5E;^a9d2$*H4Ired2~!U zz*$EnWVIiW0C!0#EXkHagIix;v2_fPA#|J$V~+^1MBeTOLg#LnNf+Y1yN4jWq{`p+ z9SJMJOEwm?pxxIn{7fHKBL>=$S>GFLs9_Os%@FKOzpeUhe@5K6PtX)()gp zAy-_h_K>u3gK{M8RB#rHlxGlap7eMTB$s_D&Ld|{VeLx>%C+Hd-Lc5B8^%q-R zf0g&ZDHssLS7`uy(QjRq3lkwYZSD_^+SO&R@A|0tV-Ce@1Uuijm``+jRlE19NQ`pr zmq3IYR$kcaf-1vjjuiQz>45CXLG()0;- ze&6m)FPG1bsB)leYk?&Chn)7<;=AEP!FnOb3qSO(Srv4Tu)u+2mS1XRq(__9J(%YH z-&eAnp*9;SS5xjbOqSSXIwtw?jrcrGf+zxvQqVW9@P| zTIC5vLR1d%Pr`tHtdO0OuFIEVVJ7{&vxg^_v;OwL&H4L<*+`_BlJCBk_QAKp>+uM0 zWRYQcg4ZM2Ak)Tl@x_MR{lGks?Q9Q?UZ*P;3i~z2-)t;wG>%pq!{64hIVs$}GjJDX5D=C_in>?mf%17*mf}(qKOHZ*W`ou9 zpiPOu?Bz95+ZoDh9PxJ-0O}+)8XHzSlQ#Q}yZGg5X9u%9S0iD1<;2+?U$$a;;~`O^ ziI-Mr%hZJytB+WH@QeBbHEO9K)0rL8lMfWo94_ihrVx(+djchBbOInHD5cJcH(CJpLSs;ue>QnUw-q$UYfco3oSB9Ra53D zQ>kk-Ly$&N!7Q!e7U$D1{R#nV+CV}crHDI{#EKa6{)+OY%TX5=QJ85y>HD@cz<{gx z78|jsU5|a!El@xuYJ@P?AU*paA1w7^IiMc>69EOA@oo|As^-x!cB(0Rgi3HC6r}cj zcG^kz!M&rv{_K!X!s->){)Gom-L^)yh;Vd`=bE|dCzm_4g3XrWIT&K@n)Mp zA?1rEoIw(uN;N645hbi0c!V-9kc4NO{v;Rz)t19N#e4Tk7^z|?*4^&~M?!{7;{$vQ zEuCxkl^>Pmsc+V5zldb->sar<;?}95g0j+DmX4DUHs^LfWiQ%wy0UMB8qxTd?Q<_Q z1@vXZh|4DB*97}EeoudsxKfd*t|OzVj(ScfVWYDgk@Q68TEb=lTkYJN&vIvROCdQu-hHo6v*H@-$D zv~Gc+2I1V>Z7=nNAkmbegOeGA6ai}ir|XiZRMl}mDRABqL{Q+2s|tTAM44=yBA)?t$hOmx>% zUj+52TM=&Gx}wc$>Z_1*2H2Ow2Df5(^5}v4`@zItLQmZQG~V+8p&B1ai0G?RpSf3IUtYl z7P9u_L5#X)CmmsR?y5Rp|ERZKxX?f}e}jy9QnSVWoR6?6efX)}07KQVB^Vrf{iAC7 z3j>QUR;~`{PxaV~cG*$porgPnI*Eq+yDB^hhubdz6OQGk7J^N2t8A|3)&) zN*ox;^F37s+K~j>c&Li`-JQ<+)v_CQn>!}w!!e(db{mLy490(Cd|K;1Rd0G zr0U6u`e6(kRpf;r%zGT$9LtS~#NytiSji-A?vS~}o3Nw%9lP(}xJR6au6KF^HoJmu zRlS?y0?ZVGM8ornrGVjPke&r8Q8$;;`)0A0_t&vdUFBQm!UtLEVRiGT$=bh(mEp?p zr{H+WDjT^fIr>a6cbe7HOszzcZU=c<;e1*HcEdDe;jtlK&(OQu7-p3+Z;_zLP2{C7 zU<>c2Nc$b>{3b6>pV@Z<&=z#BP1e&mv)cr(1OA4M^XN2| z@bfol_4PzK$s)7o&gjhKMQ`$(1Ig?eWmglf+V`s-#R+e3L| zJWoJMPOv)s*(ulV@+rjb?!_cosQ`q`QAzUM=(By9$*x7YFvb?VgeqXt_Yh_m+Q_tc zsB|dtjM$cY#I^)vXl;N!7{3#>W`MBHvhl+TmOJs`@ROBM8tRZ{|v%Z5H9wd(algHnRk*iXYszMs$3SnImwRc&GWC&ai4UTyR}`b=a6T(PI+nQ!=S1A>4yozD>f)pgAmT$* zrBCCRO~fBN$J0@3H}A1MC|=iW`bRA-9N-k%KBTHq;A*J^=1QO0b5U6Nt?NZVkCbs# zx`JAy-<5httzm*VFg2*u;C0pC*9KLH8=CRC%H@dRSj#lr4yTJ$#clh>w_8f9b ze;Yhh$wIhjEEsLw%k-z_KjN?r#-EsoxXO2CaBgP#W*OhCR%a)F9%5|Sq3@)g-l6t+ z;{D~#%6QjQhn@ImHPS7qMzpgcsDf8nQ>%&?M7pEz2U}r$WAw&P;%@~a^NS-pZN3#o ze!iYLQbUc2W$hWUC4y>uFGb+V>a|7OC)w3Eh%p>7wi5T$OuyOnJjiHgY+!YuHcmiP_bF%bVq(#t2kyR2Z4=8nIh-7UR)-x7ZV)A|&D4LWU~n+tnpa`eWz zMoe+~xf?#EzS}vmTF^aRAS<~5@=I>WPT@yFR?Uj}pajeWw32@L2?3Yjt=^)zdm1Z% z70MeiCM481O%t{!o>i{+ZNgQ@uHiXVperOgn4WtQ7?4A~P z7&5s-J)WHWpnMp40zIH{uE*ItLbbchSIWzO5xa{(wFHz|}%9 z?TYFH3}N3DcxeFXyYh^2SA%p_(CN{W%=|6`Ebi*gHVayr$3sD_73`g_89(Gc@QLI; zTsJT2;@GbNcSl?9lY5g54wErH0Wry{dEybJhA~Z~ytF)S4t~*<%iigyX~dsOCZ+<2 z>}a?_dNs^gsBk-Rq?+cza>H|c(~&HQv#i>)RxHCUHq?A44q6Z) zV2JM8&YDyQTQ&=WvYuCuaK3>}HOHn4`NEGEWfOI%) z*i@K$kn`cB8tL-%L7nhq4qkR<;#^J`kDb)27R7s0UkjZ4MPW88yrxb)wWyI@xj9FB z)N&;`i6DO9`CkN$gfmo;%zZd#DKaqj)X-mM4O*zm^|CNp^_^{7r oFJSIw6li9kKd#1~lmm@P>2IODITbD$3K`00tUttG`JWd52hi@xEC2ui delta 8986 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 H|FZrIy-3?k From 8ff7c691dc1730f3580d64c191a175555875ae79 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 Aug 2025 17:31:07 +0300 Subject: [PATCH 233/600] Fixed errors when placing down signs in 1.8/1.12 (#2578) --- .../superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java | 11 +++++++++-- .../superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java | 10 ++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java index 345b58aa60..5a44a982a9 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java @@ -25,6 +25,7 @@ import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockDoubleStep; import net.minecraft.server.v1_12_R1.BlockPosition; +import net.minecraft.server.v1_12_R1.Blocks; import net.minecraft.server.v1_12_R1.EnumParticle; import net.minecraft.server.v1_12_R1.IBlockData; import net.minecraft.server.v1_12_R1.IChatBaseComponent; @@ -153,8 +154,7 @@ public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { @Override public Object getBlockData(org.bukkit.block.Block block) { - // Doesn't exist - return null; + throw new UnsupportedOperationException(); } @Override @@ -182,6 +182,13 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { return blockType == Material.WATER || blockType == Material.STATIONARY_WATER; } + @Override + public SignType getSignType(org.bukkit.block.Block block) { + Material blockType = block.getType(); + return blockType == Material.SIGN_POST ? SignType.STANDING_SIGN : + blockType == Material.WALL_SIGN ? SignType.WALL_SIGN : SignType.UNKNOWN; + } + @Override public SignType getSignType(Object sign) { throw new UnsupportedOperationException("Not supported"); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java index d508f3a8ad..735beff363 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java @@ -158,8 +158,7 @@ public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { @Override public Object getBlockData(org.bukkit.block.Block block) { - // Doesn't exist - return null; + throw new UnsupportedOperationException(); } @Override @@ -186,6 +185,13 @@ public boolean isWaterLogged(org.bukkit.block.Block block) { return blockType == Material.WATER || blockType == Material.STATIONARY_WATER; } + @Override + public SignType getSignType(org.bukkit.block.Block block) { + Material blockType = block.getType(); + return blockType == Material.SIGN_POST ? SignType.STANDING_SIGN : + blockType == Material.WALL_SIGN ? SignType.WALL_SIGN : SignType.UNKNOWN; + } + @Override public SignType getSignType(Object sign) { throw new UnsupportedOperationException("Not supported"); From 66bf89fa04ef8a330cc7976959894b5286f815cf Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 Aug 2025 17:44:36 +0300 Subject: [PATCH 234/600] Fixed menu views are leaked when opening them fails (#2576) --- .../core/menu/view/AbstractMenuView.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractMenuView.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractMenuView.java index e655564f2e..eed68f1954 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractMenuView.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/view/AbstractMenuView.java @@ -90,22 +90,30 @@ public String replaceTitle(String title) { return title; } - @SuppressWarnings({"rawtypes", "unchecked"}) private void openView() { + boolean success = openViewInternal(); + if (!success) { + AbstractMenu menu = (AbstractMenu) getMenu(); + menu.removeView(this); + } + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + private boolean openViewInternal() { Player player = inventoryViewer.asPlayer(); if (player == null) - return; + return false; if (player.isSleeping()) { Message.OPEN_MENU_WHILE_SLEEPING.send(inventoryViewer); - return; + return false; } AbstractMenu menu = (AbstractMenu) getMenu(); if (!PluginEventsFactory.callPlayerOpenMenuEvent(inventoryViewer, this)) - return; + return false; Log.debug(Debug.OPEN_MENU, inventoryViewer.getName()); @@ -113,7 +121,7 @@ private void openView() { if (!(menu instanceof MenuBlank)) { Menus.MENU_BLANK.createView(inventoryViewer, EmptyViewArgs.INSTANCE, previousMenuView); } - return; + return false; } MenuView currentOpenedView = inventoryViewer.getOpenedView(); @@ -122,7 +130,7 @@ private void openView() { } if (Arrays.equals(player.getOpenInventory().getTopInventory().getContents(), inventory.getContents())) - return; + return false; if (previousMenuView != null) previousMenuView.setPreviousMove(false); @@ -141,6 +149,8 @@ private void openView() { GameSoundImpl.playSound(player, menu.getOpeningSound()); this.previousMenuView = previousMenuView != null ? previousMenuView : previousMove ? currentOpenedView : null; + + return true; } public void onClose() { From 11fb67392be6e867c75ec80e7c077ff610e9278b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 Aug 2025 17:56:46 +0300 Subject: [PATCH 235/600] Fixed the ability to place harness on happy ghast on other islands (#2561) --- .../com/bgsoftware/superiorskyblock/core/Materials.java | 9 ++++++++- .../service/region/RegionManagerServiceImpl.java | 7 ++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java index ca1ae88170..ccd284a2e4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java @@ -111,6 +111,10 @@ public static boolean isCarpet(Material material) { return hasTag(material, Tag.CARPET); } + public static boolean isHarness(Material material) { + return hasTag(material, Tag.HARNESS); + } + public static boolean isBed(Material material) { return hasTag(material, Tag.BED); } @@ -170,6 +174,8 @@ private static EnumMap> setupMaterialTags() { materialTags.add(Tag.SPAWN_EGG); if (materialName.contains("CARPET")) materialTags.add(Tag.CARPET); + if (materialName.contains("HARNESS")) + materialTags.add(Tag.HARNESS); if (materialName.contains("BED")) materialTags.add(Tag.BED); @@ -207,7 +213,8 @@ public enum Tag { DYE, SPAWN_EGG, CARPET, - BED + BED, + HARNESS } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index ff9df84525..ef854f6b73 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -83,9 +83,9 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService @Nullable private static final EntityType AXOLOTL_TYPE = EnumHelper.getEnum(EntityType.class, "AXOLOTL"); @Nullable - private static final EntityType CAMEL_TYPE = EnumHelper.getEnum(EntityType.class, "CAMEL"); - @Nullable private static final EntityType LLAMA_TYPE = EnumHelper.getEnum(EntityType.class, "LLAMA"); + @Nullable + private static final EntityType HAPPY_GHAST_TYPE = EnumHelper.getEnum(EntityType.class, "HAPPY_GHAST"); private static final int MAX_PICKUP_DISTANCE = 1; private static EnumerateSet WORLD_PERMISSIONS_CACHE; @@ -259,7 +259,8 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent islandPrivilege = IslandPrivileges.ANIMAL_BREED; } else if (usedItemType == Material.NAME_TAG) { islandPrivilege = IslandPrivileges.NAME_ENTITY; - } else if (usedItemType == Material.SADDLE || (entityType == LLAMA_TYPE && Materials.isCarpet(usedItemType))) { + } else if (usedItemType == Material.SADDLE || (entityType == LLAMA_TYPE && Materials.isCarpet(usedItemType)) || + (entityType == HAPPY_GHAST_TYPE && (usedItemType == Material.SHEARS || Materials.isHarness(usedItemType)))) { islandPrivilege = IslandPrivileges.SADDLE_ENTITY; } else if (entity instanceof Villager) { islandPrivilege = IslandPrivileges.VILLAGER_TRADING; From 403e0bc52ca43d95af047c9c1543a5900945c32d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 Aug 2025 18:12:45 +0300 Subject: [PATCH 236/600] Potential fix for NPE errors when caching equipment (#2554) --- .../world/BukkitEntities.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java index 6aee49bad8..ed9769baa3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java @@ -34,19 +34,20 @@ import org.bukkit.projectiles.ProjectileSource; import java.util.Arrays; +import java.util.Collections; import java.util.EnumSet; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Predicate; public class BukkitEntities { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final Map> entityContent = new HashMap<>(); + private static final Map> entityContent = new ConcurrentHashMap<>(); private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); @@ -58,18 +59,19 @@ private BukkitEntities() { } public static boolean isEquipment(LivingEntity livingEntity, ItemStack itemStack) { - List entityEquipment = entityContent.get(livingEntity.getUniqueId()); - - if (entityEquipment == null) { - cacheEntityEquipment(livingEntity); - entityEquipment = entityContent.get(livingEntity.getUniqueId()); - } + List entityEquipment = entityContent.computeIfAbsent(livingEntity.getUniqueId(), u -> + cacheEntityEquipmentInternal(livingEntity)); return entityEquipment.stream().anyMatch(equipmentItem -> equipmentItem != null && equipmentItem.getType() == itemStack.getType()); } public static void cacheEntityEquipment(LivingEntity livingEntity) { + List entityEquipment = cacheEntityEquipmentInternal(livingEntity); + entityContent.put(livingEntity.getUniqueId(), entityEquipment); + } + + private static List cacheEntityEquipmentInternal(LivingEntity livingEntity) { List entityEquipment = new LinkedList<>(Arrays.asList(plugin.getNMSEntities().getEquipment(livingEntity.getEquipment()))); if (livingEntity instanceof Pig) { @@ -108,7 +110,7 @@ public static void cacheEntityEquipment(LivingEntity livingEntity) { } catch (Throwable ignored) { } - entityContent.put(livingEntity.getUniqueId(), entityEquipment); + return entityEquipment.isEmpty() ? Collections.emptyList() : entityEquipment; } public static void clearEntityEquipment(LivingEntity livingEntity) { From 67d70df57c5023fb8628e9fb3bd4f29411abdbac Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 Aug 2025 18:45:52 +0300 Subject: [PATCH 237/600] Potential fix for "chunk is not cached" errors when using WildStacker (#2366) --- .../WildStackerSnapshotsContainer.java | 98 +++++++++++++++++-- .../SpawnersProvider_WildStacker.java | 7 +- .../StackedBlocksProvider_WildStacker.java | 27 +++-- 3 files changed, 103 insertions(+), 29 deletions(-) diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java index 41b3aedc4c..e61117f7b8 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/WildStackerSnapshotsContainer.java @@ -8,9 +8,11 @@ import com.bgsoftware.wildstacker.api.objects.StackedSnapshot; import org.bukkit.Chunk; +import java.util.function.Function; + public class WildStackerSnapshotsContainer { - private static final Synchronized> cachedSnapshots = Synchronized.of(new Chunk2ObjectMap<>()); + private static final Synchronized>> cachedSnapshots = Synchronized.of(new Chunk2ObjectMap<>()); private WildStackerSnapshotsContainer() { @@ -23,9 +25,14 @@ public static void takeSnapshot(Chunk chunk) { } } - private static void takeSnapshotInternal(Chunk chunk, ChunkPosition chunkPosition, Chunk2ObjectMap cachedSnapshots) { - if (cachedSnapshots.containsKey(chunkPosition)) + private static void takeSnapshotInternal(Chunk chunk, ChunkPosition chunkPosition, Chunk2ObjectMap> cachedSnapshots) { + RefCount refCountBase = cachedSnapshots.get(chunkPosition); + if (refCountBase != null) { + refCountBase.incRef(); return; + } + + refCountBase = new RefCount<>(); try { StackedSnapshot stackedSnapshot; @@ -38,7 +45,8 @@ private static void takeSnapshotInternal(Chunk chunk, ChunkPosition chunkPositio } if (stackedSnapshot != null) { - cachedSnapshots.put(chunkPosition, stackedSnapshot); + refCountBase.set(stackedSnapshot); + cachedSnapshots.put(chunkPosition, refCountBase); } } catch (Throwable error) { Log.error(error, "Received an unexpected error while taking a snapshot for WildStacker:"); @@ -46,17 +54,87 @@ private static void takeSnapshotInternal(Chunk chunk, ChunkPosition chunkPositio } public static void releaseSnapshot(ChunkPosition chunkPosition) { - cachedSnapshots.write(m -> m.remove(chunkPosition)); + cachedSnapshots.write(m -> { + RefCount refCountBase = m.get(chunkPosition); + if (refCountBase != null) { + if (refCountBase.defRef()) + m.remove(chunkPosition); + } + }); + } + + public static R accessStackedSnapshot(ChunkPosition chunkPosition, Function function) { + return cachedSnapshots.readAndGet(cachedSnapshots -> { + RefCount refCountBase = cachedSnapshots.get(chunkPosition); + if (refCountBase == null) + return null; + return refCountBase.readAndGet(function); + }); } - public static StackedSnapshot getSnapshot(ChunkPosition chunkPosition) { - StackedSnapshot stackedSnapshot = cachedSnapshots.readAndGet(m -> m.get(chunkPosition)); + private static class RefCount { + + private int refCount; + private Synchronized handle; + + synchronized void incRef() { + if (this.handle == null) + throw new IllegalStateException("Inc ref on null RefCount object " + this); + + int ref = this.handle.writeAndGet(unused -> { + return ++this.refCount; + }); + + if (ref <= 0) + throw new IllegalStateException("Inc ref on null RefCount object " + this); + } + + synchronized boolean defRef() { + if (this.handle == null) + throw new IllegalStateException("Dec ref on null RefCount object " + this); - if (stackedSnapshot == null) { - throw new RuntimeException("Chunk " + chunkPosition + " is not cached."); + int ref = this.handle.writeAndGet(unused -> { + return --this.refCount; + }); + + if (ref == 0) { + this.handle = null; + return true; + } else if (ref < 0) { + throw new IllegalStateException("Dec ref on null RefCount object " + this); + } + + return false; + } + + synchronized R readAndGet(Function function) { + if (this.handle == null) + throw new IllegalStateException("Access null RefCount object " + this); + + return this.handle.writeAndGet(handle -> { + if (this.refCount <= 0) + throw new IllegalStateException("Access null RefCount object " + this); + + return function.apply(handle); + }); + } + + synchronized void set(T handle) { + this.handle = Synchronized.of(handle); + incRef(); } - return stackedSnapshot; + @Override + public synchronized String toString() { + if (this.handle == null) { + return "{ ref = " + this.refCount + ", handle = " + this.handle + "}"; + } else { + return this.handle.readAndGet(handle -> { + return "{ ref = " + this.refCount + ", handle = " + handle + "}"; + }); + } + + } } } diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java index cddd595d64..6658f26774 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java @@ -21,7 +21,6 @@ import com.bgsoftware.wildstacker.api.events.SpawnerPlaceInventoryEvent; import com.bgsoftware.wildstacker.api.events.SpawnerStackEvent; import com.bgsoftware.wildstacker.api.events.SpawnerUnstackEvent; -import com.bgsoftware.wildstacker.api.objects.StackedSnapshot; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; @@ -57,11 +56,11 @@ public SpawnersProvider_WildStacker(SuperiorSkyblockPlugin plugin) { @Override public Pair getSpawner(Location location) { - StackedSnapshot cachedSnapshot; + Map.Entry entry; try (ChunkPosition chunkPosition = ChunkPosition.of(location)) { - cachedSnapshot = WildStackerSnapshotsContainer.getSnapshot(chunkPosition); + entry = WildStackerSnapshotsContainer.accessStackedSnapshot(chunkPosition, + stackedSnapshot -> stackedSnapshot.getStackedSpawner(location)); } - Map.Entry entry = cachedSnapshot.getStackedSpawner(location); return new Pair<>(entry.getKey(), entry.getValue() + ""); } diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java index c6c7198f61..52c0010f0c 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java @@ -22,7 +22,6 @@ import com.bgsoftware.wildstacker.api.events.BarrelUnstackEvent; import com.bgsoftware.wildstacker.api.handlers.SystemManager; import com.bgsoftware.wildstacker.api.objects.StackedBarrel; -import com.bgsoftware.wildstacker.api.objects.StackedSnapshot; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; @@ -73,21 +72,19 @@ public boolean isCustomKey(Key key) { @Override public Collection> getBlocks(World world, int chunkX, int chunkZ) { - StackedSnapshot stackedSnapshot; - try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) { - stackedSnapshot = WildStackerSnapshotsContainer.getSnapshot(chunkPosition); - } - - try { - return stackedSnapshot.getAllBarrelsItems().values().stream() - .filter(entry -> entry.getValue() != null) - .map(entry -> new Pair<>(Key.of(entry.getValue()), entry.getKey())) - .collect(Collectors.toSet()); - } catch (Throwable ex) { - return stackedSnapshot.getAllBarrels().values().stream() - .map(entry -> new Pair<>(Key.of(entry.getValue(), (short) 0), entry.getKey())) - .collect(Collectors.toSet()); + return WildStackerSnapshotsContainer.accessStackedSnapshot(chunkPosition, stackedSnapshot -> { + try { + return stackedSnapshot.getAllBarrelsItems().values().stream() + .filter(entry -> entry.getValue() != null) + .map(entry -> new Pair<>(Key.of(entry.getValue()), entry.getKey())) + .collect(Collectors.toSet()); + } catch (Throwable ex) { + return stackedSnapshot.getAllBarrels().values().stream() + .map(entry -> new Pair<>(Key.of(entry.getValue(), (short) 0), entry.getKey())) + .collect(Collectors.toSet()); + } + }); } } From 1f1ba27834433c269aef7decd0ca1523026efc92 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 Aug 2025 20:01:15 +0300 Subject: [PATCH 238/600] Fixed counting of entities not done correctly (#2541) --- .../listener/BlockChangesListener.java | 14 -------------- .../listener/BukkitEventsListener.java | 4 ++-- .../service/world/WorldRecordServiceImpl.java | 11 +++-------- 3 files changed, 5 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index fa7132fdf5..a7bcbe2d55 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -317,19 +317,6 @@ private void onEntityExplode(GameEvent e) { } } - private void onMinecartBreak(GameEvent e) { - Entity vehicle = e.getArgs().entity; - - if (vehicle instanceof Minecart) { - Key blockKey = plugin.getNMSAlgorithms().getMinecartBlock((Minecart) vehicle); - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockBreak(blockKey, vehicle.getLocation(wrapper.getHandle()), - 1, REGULAR_RECORD_FLAGS); - } - vehicle.setMetadata("SSB-VehicleDestory", new FixedMetadataValue(plugin, true)); - } - } - private void onChorusHit(GameEvent e) { BukkitEntities.getPlayerSource(e.getArgs().entity).ifPresent(shooter -> { Block hitBlock = e.getArgs().hitBlock; @@ -374,7 +361,6 @@ private void registerListeners() { registerCallback(GameEventType.LEAVES_DECAY_EVENT, GameEventPriority.MONITOR, this::onLeavesDecay); registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.MONITOR, this::onBlockFromTo); registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.MONITOR, this::onEntityExplode); - registerCallback(GameEventType.ENTITY_DEATH_EVENT, GameEventPriority.MONITOR, this::onMinecartBreak); registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.MONITOR, this::onChorusHit); registerCallback(GameEventType.SPONGE_ABSORB_EVENT, GameEventPriority.MONITOR, this::onSpongeAbsorb); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index 351d8f6cd0..f44c523826 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -134,14 +134,13 @@ public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, EntityChangeBlockEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_BREAK_EVENT, BlockBreakEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_DEATH_EVENT, EntityDeathEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_SPAWN_EVENT, ItemSpawnEvent.class, this::createGameEvent); createEventListener(GameEventType.PISTON_EXTEND_EVENT, BlockPistonExtendEvent.class, this::createGameEvent); createEventListener(GameEventType.PISTON_RETRACT_EVENT, BlockPistonRetractEvent.class, this::createGameEvent); createEventListener(GameEventType.LEAVES_DECAY_EVENT, LeavesDecayEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_FROM_TO_EVENT, BlockFromToEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_EXPLODE_EVENT, EntityExplodeEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_DEATH_EVENT, VehicleDestroyEvent.class, this::createGameEvent); +// createEventListener(GameEventType.ENTITY_DEATH_EVENT, VehicleDestroyEvent.class, this::createGameEvent); createEventListener(GameEventType.CHUNK_LOAD_EVENT, ChunkLoadEvent.class, this::createGameEvent); createEventListener(GameEventType.CHUNK_UNLOAD_EVENT, ChunkUnloadEvent.class, this::createGameEvent); createEventListener(GameEventType.WORLD_UNLOAD_EVENT, WorldUnloadEvent.class, this::createGameEvent); @@ -201,6 +200,7 @@ public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { Class.forName("com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent"); createEventListener(GameEventType.ENTITY_DEATH_EVENT, com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent.class, new EntityRemoveFromWorldEventFunction()); } catch (ClassNotFoundException ignored) { + createEventListener(GameEventType.ENTITY_DEATH_EVENT, EntityDeathEvent.class, this::createGameEvent); } try { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java index 8f32ce5714..e04e6da871 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java @@ -305,14 +305,9 @@ public RecordResult recordEntityDespawn(Entity entity) { return recordResult; if (entity instanceof Minecart) { - if (entity.hasMetadata("SSB-VehicleDestory")) { - entity.removeMetadata("SSB-VehicleDestory", plugin); - } else { - // Vehicle was not registered by VehicleDestroyEvent; We want to register its block break - Key blockKey = plugin.getNMSAlgorithms().getMinecartBlock((Minecart) entity); - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - recordBlockBreak(blockKey, entity.getLocation(wrapper.getHandle()), 1, REGULAR_RECORD_FLAGS); - } + Key blockKey = plugin.getNMSAlgorithms().getMinecartBlock((Minecart) entity); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + recordBlockBreak(blockKey, entity.getLocation(wrapper.getHandle()), 1, REGULAR_RECORD_FLAGS); } } From cc13737732251a7f9159c8865d742722ad5b7db2 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 9 Aug 2025 11:40:49 +0300 Subject: [PATCH 239/600] Fixed saddling of mobs in 1.21.6+ does not require the SADDLE_ENTITY permission (#2561) --- .../service/region/RegionManagerServiceImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index ef854f6b73..b609437cb8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -87,6 +87,9 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService @Nullable private static final EntityType HAPPY_GHAST_TYPE = EnumHelper.getEnum(EntityType.class, "HAPPY_GHAST"); + // Shearing saddles introduced in 1.21.6, when Happy Ghast was added as well. + private static final boolean HAS_SHEARING_SADDLE_SUPPORT = HAPPY_GHAST_TYPE != null; + private static final int MAX_PICKUP_DISTANCE = 1; private static EnumerateSet WORLD_PERMISSIONS_CACHE; private static KeySet INTERACTABLES_CACHE; @@ -260,7 +263,8 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent } else if (usedItemType == Material.NAME_TAG) { islandPrivilege = IslandPrivileges.NAME_ENTITY; } else if (usedItemType == Material.SADDLE || (entityType == LLAMA_TYPE && Materials.isCarpet(usedItemType)) || - (entityType == HAPPY_GHAST_TYPE && (usedItemType == Material.SHEARS || Materials.isHarness(usedItemType)))) { + (entityType == HAPPY_GHAST_TYPE && Materials.isHarness(usedItemType)) || + (HAS_SHEARING_SADDLE_SUPPORT && usedItemType == Material.SHEARS)) { islandPrivilege = IslandPrivileges.SADDLE_ENTITY; } else if (entity instanceof Villager) { islandPrivilege = IslandPrivileges.VILLAGER_TRADING; From 51d00620795db72f356a34d34fafc383fbfac731 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 9 Aug 2025 13:43:42 +0300 Subject: [PATCH 240/600] Add [true/false] suffix to the save-air argument in the schematic command usage (#2396) --- .../superiorskyblock/commands/admin/CmdAdminSchematic.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java index 3597f0b3e5..07067b0101 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java @@ -25,7 +25,7 @@ public String getPermission() { @Override public String getUsage(java.util.Locale locale) { return "admin schematic [" + Message.COMMAND_ARGUMENT_SCHEMATIC_NAME.getMessage(locale) + "] [" + - Message.COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR.getMessage(locale) + "]"; + Message.COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR.getMessage(locale) + "[true/false]]"; } @Override From 8c762f1bdd704b08f2f2a286e25ef071214211b5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 9 Aug 2025 13:52:45 +0300 Subject: [PATCH 241/600] Do not load transactions from db when adding new transaction when using bank logs in db mode (#2478) --- .../island/bank/logs/DatabaseBankLogs.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/DatabaseBankLogs.java b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/DatabaseBankLogs.java index a3b9390a5c..1159d1de7d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/DatabaseBankLogs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/DatabaseBankLogs.java @@ -25,9 +25,19 @@ public class DatabaseBankLogs implements IBankLogs { .build(new CacheLoader>() { @Override public List load(@NotNull Integer ignored) { + sessionBankTransactions.invalidateAll(); return loadTransactionsFromDatabase(); } }); + private final LoadingCache> sessionBankTransactions = CacheBuilder.newBuilder() + .maximumSize(1) + .expireAfterAccess(10, TimeUnit.MINUTES) + .build(new CacheLoader>() { + @Override + public List load(@NotNull Integer ignored) { + return new LinkedList<>(); + } + }); private final Island island; private int lastTransactionPosition = -1; @@ -47,20 +57,26 @@ public int getLastTransactionPosition() { @Override public List getTransactions() { - return new SequentialListBuilder().build(cachedBankTransactions.getUnchecked(0)); + return collectBankTransactions(); } @Override public List getTransactions(UUID playerUUID) { return new SequentialListBuilder() .filter(bankTransaction -> playerUUID.equals(bankTransaction.getPlayer())) - .build(cachedBankTransactions.getUnchecked(0)); + .build(collectBankTransactions()); } @Override public void addTransaction(BankTransaction bankTransaction, UUID senderUUID, boolean loadFromDatabase) { - if (cachedBankTransactions.size() != 0) - cachedBankTransactions.getUnchecked(0).add(bankTransaction); + sessionBankTransactions.getUnchecked(0).add(bankTransaction); + } + + private List collectBankTransactions() { + List bankTransactionList = new LinkedList<>(); + bankTransactionList.addAll(cachedBankTransactions.getUnchecked(0)); + bankTransactionList.addAll(sessionBankTransactions.getUnchecked(0)); + return bankTransactionList; } private List loadTransactionsFromDatabase() { From cd3f4a9986ef8e3d3d75c0b22434824ab99f9b23 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 9 Aug 2025 18:07:21 +0200 Subject: [PATCH 242/600] Added reset island settings option (#2545) --- .../api/events/IslandClearFlagsEvent.java | 44 +++++++++++++ .../api/island/DelegateIsland.java | 5 ++ .../superiorskyblock/api/island/Island.java | 5 ++ .../commands/player/CmdSettings.java | 19 +++++- .../bridge/IslandsDatabaseBridge.java | 5 ++ .../core/events/args/PluginEventArgs.java | 4 ++ .../core/events/plugin/PluginEventType.java | 8 +++ .../events/plugin/PluginEventsFactory.java | 9 +++ .../superiorskyblock/core/logging/Debug.java | 1 + .../core/messages/Message.java | 1 + .../superiorskyblock/island/SIsland.java | 63 ++++++++++++++++++- .../superiorskyblock/island/SpawnIsland.java | 5 ++ src/main/resources/lang/de-DE.yml | 3 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 3 +- src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/tr-TR.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + 24 files changed, 180 insertions(+), 5 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearFlagsEvent.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearFlagsEvent.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearFlagsEvent.java new file mode 100644 index 0000000000..85773aa109 --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearFlagsEvent.java @@ -0,0 +1,44 @@ +package com.bgsoftware.superiorskyblock.api.events; + +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import org.bukkit.event.Cancellable; + +/** + * IslandClearFlagsEvent is called when flags are cleared on an island. + */ +public class IslandClearFlagsEvent extends IslandEvent implements Cancellable { + + private final SuperiorPlayer superiorPlayer; + + private boolean cancelled = false; + + /** + * The constructor of the event. + * + * @param island The island that the flags were cleared in. + * @param superiorPlayer The player that cleared the flags. + */ + public IslandClearFlagsEvent(Island island, SuperiorPlayer superiorPlayer) { + super(island); + this.superiorPlayer = superiorPlayer; + } + + /** + * Get the player that cleared the flags to the other player. + */ + public SuperiorPlayer getPlayer() { + return superiorPlayer; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + +} diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index deae4f964a..541101e8d2 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -1795,6 +1795,11 @@ public void disableSettings(IslandFlag islandFlag) { this.handle.disableSettings(islandFlag); } + @Override + public void resetSettings() { + this.handle.resetSettings(); + } + @Override @Deprecated public void setGeneratorPercentage(Key key, int percentage, World.Environment environment) { diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java index 99dfcf3eec..ca78798cd4 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java @@ -2472,6 +2472,11 @@ List> getAllChunksAsync(World.Environment environment, */ void disableSettings(IslandFlag islandFlag); + /** + * Reset the island settings to default values. + */ + void resetSettings(); + /* * Generator related methods */ diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSettings.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSettings.java index c639dab1c1..2e932bcccf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSettings.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSettings.java @@ -1,5 +1,7 @@ package com.bgsoftware.superiorskyblock.commands.player; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; @@ -26,7 +28,7 @@ public String getPermission() { @Override public String getUsage(java.util.Locale locale) { - return "settings"; + return "settings [reset]"; } @Override @@ -41,7 +43,7 @@ public int getMinArgs() { @Override public int getMaxArgs() { - return 1; + return 2; } @Override @@ -61,7 +63,20 @@ public Message getPermissionLackMessage() { @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { + if (args.length == 2 && args[1].equalsIgnoreCase("reset")) { + if (PluginEventsFactory.callIslandClearFlagsEvent(island, superiorPlayer)) { + island.resetSettings(); + Message.SETTINGS_RESET.send(superiorPlayer); + } + return; + } + plugin.getMenus().openSettings(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } + @Override + public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { + return args.length == 2 ? CommandTabCompletes.getCustomComplete(args[1], "reset") : Collections.emptyList(); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index 0f91bcff99..fb89ea9b7a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -454,6 +454,11 @@ public static void removeIslandFlag(Island island, IslandFlag islandFlag) { )); } + public static void clearIslandFlags(Island island) { + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_flags", + createFilter("island", island))); + } + public static void saveGeneratorRate(Island island, Dimension dimension, Key blockKey, int rate) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_generators", new Pair<>("island", island.getUniqueId().toString()), diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java index 51024cb61c..a12adb5479 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java @@ -263,6 +263,10 @@ public static class IslandChunkReset extends PluginEventArgs { } + public static class IslandClearFlags extends IslandDoActionArgs { + + } + public static class IslandClearGeneratorRates extends IslandDoActionArgs { public Dimension dimension; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java index b4ea746823..3d4fbea1fb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java @@ -34,6 +34,7 @@ import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChatEvent; import com.bgsoftware.superiorskyblock.api.events.IslandChunkResetEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandClearFlagsEvent; import com.bgsoftware.superiorskyblock.api.events.IslandClearGeneratorRatesEvent; import com.bgsoftware.superiorskyblock.api.events.IslandClearPlayerPrivilegesEvent; import com.bgsoftware.superiorskyblock.api.events.IslandClearRatingsEvent; @@ -150,6 +151,7 @@ import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWorthBonus; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChat; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChunkReset; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearFlags; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearGeneratorRates; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearPlayerPrivileges; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearRatings; @@ -691,6 +693,12 @@ public Event createBukkitEvent(IslandEnableFlag args) { return new IslandEnableFlagEvent(args.superiorPlayer, args.island, args.islandFlag); } }; + public static final PluginEventType ISLAND_CLEAR_FLAGS_EVENT = new PluginEventType(IslandClearFlagsEvent.class) { + @Override + public Event createBukkitEvent(IslandClearFlags args) { + return new IslandClearFlagsEvent(args.island, args.superiorPlayer); + } + }; public static final PluginEventType ISLAND_ENTER_EVENT = new PluginEventType(IslandEnterEvent.class) { @Override public Event createBukkitEvent(IslandEnter args) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java index e4104e1de8..d757fe4d25 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java @@ -79,6 +79,7 @@ import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWorthBonus; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChat; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChunkReset; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearFlags; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearGeneratorRates; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearPlayerPrivileges; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearRatings; @@ -184,6 +185,7 @@ import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WORTH_BONUS_EVENT; import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHAT_EVENT; import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHUNK_RESET_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_FLAGS_EVENT; import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_GENERATOR_RATES_EVENT; import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_PLAYER_PRIVILEGES_EVENT; import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_RATINGS_EVENT; @@ -642,6 +644,13 @@ public static void callIslandChunkResetEvent(Island island, ChunkPosition chunkP fireEvent(ISLAND_CHUNK_RESET_EVENT, islandChunkReset); } + public static boolean callIslandClearFlagsEvent(Island island, SuperiorPlayer superiorPlayer) { + IslandClearFlags islandClearFlags = new IslandClearFlags(); + islandClearFlags.island = island; + islandClearFlags.superiorPlayer = superiorPlayer; + return !fireEvent(ISLAND_CLEAR_FLAGS_EVENT, islandClearFlags).isCancelled(); + } + public static boolean callIslandClearGeneratorRatesEvent(Island island, CommandSender commandSender, Dimension dimension) { return callIslandClearGeneratorRatesEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java index c3bce21dc6..4bde65c75d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java @@ -77,6 +77,7 @@ public enum Debug { REMOVE_RATINGS, ENABLE_ISLAND_FLAG, DISABLE_ISLAND_FLAG, + RESET_ISLAND_FLAGS, SET_GENERATOR_PERCENTAGE, SET_GENERATOR_RATE, REMOVE_GENERATOR_RATE, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 6c7f68f901..6eeef3872a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -690,6 +690,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { SCHEMATIC_RIGHT_SELECT, SCHEMATIC_SAVED, SELF_ROLE_CHANGE, + SETTINGS_RESET, SETTINGS_UPDATED, SETTINGS_UPDATED_ALL, SETTINGS_UPDATED_NAME, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 23b6b8f1ba..d12e92dd94 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -124,7 +124,6 @@ import java.math.BigDecimal; import java.math.BigInteger; -import java.math.RoundingMode; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -3993,6 +3992,68 @@ public void disableSettings(IslandFlag settings) { plugin.getMenus().refreshSettings(this); } + @Override + public void resetSettings() { + Log.debug(Debug.RESET_ISLAND_FLAGS, owner.getName()); + + if (islandFlags.isEmpty()) + return; + + islandFlags.clear(); + + Long time = null; + WeatherType weather = null; + boolean enablePvP = false; + + for (String islandFlag : plugin.getSettings().getDefaultSettings()) { + switch (islandFlag) { + case "ALWAYS_DAY": + time = 0L; + break; + case "ALWAYS_MIDDLE_DAY": + time = 6000L; + break; + case "ALWAYS_NIGHT": + time = 14000L; + break; + case "ALWAYS_MIDDLE_NIGHT": + time = 18000L; + break; + case "ALWAYS_SHINY": + weather = WeatherType.CLEAR; + break; + case "ALWAYS_RAIN": + weather = WeatherType.DOWNFALL; + break; + case "PVP": + enablePvP = true; + break; + } + } + + boolean teleportOnPvPEnable = plugin.getSettings().isTeleportOnPvPEnable(); + + for (SuperiorPlayer superiorPlayer : getAllPlayersInside()) { + Player player = superiorPlayer.asPlayer(); + if (player != null) { + if (time == null) player.resetPlayerTime(); + else player.setPlayerTime(time, false); + + if (weather == null) player.resetPlayerWeather(); + else player.setPlayerWeather(weather); + + if (enablePvP && teleportOnPvPEnable && isVisitor(superiorPlayer, false)) { + superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); + Message.ISLAND_GOT_PVP_ENABLED_WHILE_INSIDE.send(superiorPlayer); + } + } + } + + IslandsDatabaseBridge.clearIslandFlags(this); + + plugin.getMenus().refreshSettings(this); + } + @Override public void setGeneratorPercentage(Key key, int percentage, Dimension dimension) { setGeneratorPercentage(key, percentage, dimension, null, false); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index c57a6d4e0e..b0bfabef22 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -1960,6 +1960,11 @@ public void disableSettings(IslandFlag islandFlag) { // Do nothing. } + @Override + public void resetSettings() { + // Do nothing. + } + @Override public void setGeneratorPercentage(Key key, int percentage, Dimension dimension) { // Do nothing. diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 275289f7c9..d5de8cc4e6 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -305,6 +305,7 @@ COMMAND_DESCRIPTION_ADMIN_SHOW: Informationen über eine Insel abrufen. COMMAND_DESCRIPTION_ADMIN_SPAWN: Teleport zum Spawn-Ort. COMMAND_DESCRIPTION_ADMIN_SPY: Chat-Spionagemodus umschalten COMMAND_DESCRIPTION_ADMIN_STATS: Statistiken über das Plugin anzeigen. +COMMAND_DESCRIPTION_ADMIN_SYNC_BONUS: 'Sync the bonus of an island with the generated worlds.' COMMAND_DESCRIPTION_ADMIN_SYNC_UPGRADES: Upgrade-Werte für eine Insel synchronisieren. COMMAND_DESCRIPTION_ADMIN_TELEPORT: Teleport zur anderen Inseln. COMMAND_DESCRIPTION_ADMIN_TITLE: Sende einem Spieler einen Titel. @@ -487,6 +488,7 @@ INVALID_LEVEL: '&c&lError | &7Ungültige Ebene {0}.' INVALID_LIMIT: '&c&lError | &7Ungültiges Limit {0}.' INVALID_MATERIAL: '&c&lError | &7Ungültiges Material {0}.' INVALID_MATERIAL_DATA: '&c&lError | &7Ungültige Materialdaten {0}.' +INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lError | &7Ungültige Mission {0}.' INVALID_MODULE: '&c&lError | &7Ungültiges Modul {0}.' INVALID_MULTIPLIER: '&c&lError | &7Ungültiger Multiplikator {0}.' @@ -859,6 +861,7 @@ SET_UPGRADE_LEVEL_NAME: '&e&lUpgrades | &7Die Ebene von {0} für {1} wurde erfol aktualisiert.' SET_WARP: '&e&lInsel | &7Erzeugt erfolgreich einen neuen Warp am {0}.' SET_WARP_OUTSIDE: '&c&lError | &7Du kannst keine Warps außerhalb Ihrer Insel setzen.' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lInsel | &7Die Einstellungen {0} wurden erfolgreich auf die Insel von {1} aktualisiert.' SETTINGS_UPDATED_NAME: '&e&lInsel | &7Die Einstellungen {0} wurden erfolgreich auf diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index ac2c83567a..d455bc7878 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -677,6 +677,7 @@ SET_UPGRADE_LEVEL: '&e&lUpgrades | &7Successfully updated the level of {0} for { SET_UPGRADE_LEVEL_NAME: '&e&lUpgrades | &7Successfully updated the level of {0} for {1}.' SET_WARP: '&e&lIsland | &7Successfully created a new warp at {0}.' SET_WARP_OUTSIDE: '&c&lError | &7You cannot set warps outside your island.' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIsland | &7Successfully updated the settings {0} to {1}''s island.' SETTINGS_UPDATED_NAME: '&e&lIsland | &7Successfully updated the settings {0} to the island {1}.' SETTINGS_UPDATED_ALL: '&e&lIsland | &7Successfully updated the settings {0} to all the islands.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index c1131c2223..02e15440d3 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -677,6 +677,7 @@ SET_UPGRADE_LEVEL: '&e&lMejoras| &7Se actualizó correctamente el nivel de {0} p SET_UPGRADE_LEVEL_NAME: '&e&lMejoras| &7Se actualizó correctamente el nivel de {0} para {1}.' SET_WARP: '&e&lIsla | &7Se creó con éxito una nuevo warp en {0}.' SET_WARP_OUTSIDE: '&c&lError | &7No puedes establecer warps fuera de tu isla.' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIsla | &7Se actualizó correctamente la configuración {0} a la isla de {1}.' SETTINGS_UPDATED_NAME: '&e&lIsla | &7Se actualizó correctamente la configuración {0} de la isla {1}.' SETTINGS_UPDATED_ALL: '&e&lIsla | &7Se actualizó correctamente la configuración {0} en todas las islas.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 1ea931b042..02de4470c3 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -679,6 +679,7 @@ SET_UPGRADE_LEVEL: '&e&lAméliorations | &7Niveau de {0} augmenté sur l''île d SET_UPGRADE_LEVEL_NAME: '&e&lAméliorations | &7Niveau de {0} augmenté sur {1}.' SET_WARP: '&e&lIle | &7Nouveau warp crée au coordonnées {0}.' SET_WARP_OUTSIDE: '&c&lErreur | &7Vous ne pouvez pas définir de warps hors de votre île.' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIle | &7Paramètre {0} mit à jour pour l''île de {1}.' SETTINGS_UPDATED_NAME: '&e&lIle | &7Paramètre {0} mit à jour pour l''île {1}.' SETTINGS_UPDATED_ALL: '&e&lIle | &7Paramètre {0} mit à jour pour toutes les îles.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index a30675fda9..a47efb4d1c 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -685,6 +685,7 @@ SET_UPGRADE_LEVEL: '&e&lAggiornamenti | &7Aggiornato con successo il livello di SET_UPGRADE_LEVEL_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il livello di {0} per {1}.' SET_WARP: '&e&lIsola | &7Creato con successo un nuovo warp a {0}.' SET_WARP_OUTSIDE: '&c&lErrore | &7Non puoi impostare warp fuori dalla tua isola.' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} dell''isola di {1}.' SETTINGS_UPDATED_NAME: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} di {1}.' SETTINGS_UPDATED_ALL: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} a tutte le isole.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 3c06ca13ce..669a82b707 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -699,6 +699,7 @@ SET_UPGRADE_LEVEL: '&e&lםיגורדש | &7החלצהב התנוש {1} לש יא SET_UPGRADE_LEVEL_NAME: '&e&lםיגורדש | &7החלצהב התנוש {1} יאב {0} גורדשה לש המרה.' SET_WARP: '&e&lיא | &7{0} ב החלצהב שדח םוקימ תרצי.' SET_WARP_OUTSIDE: '&c&lהאיגש | &7ךלש יאל ץוחמ םימוקימ רוציל לוכי אל התא.' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lיא | &7{1} לש יאב החלצהב הנכדוע {0} הרדגהה.' SETTINGS_UPDATED_NAME: '&e&lיא | &7{1} יאב החלצהב הנכדוע {0} הרדגהה.' SETTINGS_UPDATED_ALL: '&e&lיא | &7םייאה לכב החלצהב הנכדוע {0} הרדגהה.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 256c5db546..13721c92b1 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -112,7 +112,6 @@ COMMAND_ARGUMENT_DISCORD: 'niezgoda...' COMMAND_ARGUMENT_EFFECT: 'efekt mikstury' COMMAND_ARGUMENT_EMAIL: 'e-mail' COMMAND_ARGUMENT_ENTITY: 'podmiot' -COMMAND_ARGUMENT_ISLAND: 'wyspa' COMMAND_ARGUMENT_ISLAND_NAME: 'nazwa-wyspy' COMMAND_ARGUMENT_ISLAND_ROLE: 'rola-wyspy' COMMAND_ARGUMENT_LEADER: 'lider' @@ -129,7 +128,6 @@ COMMAND_ARGUMENT_NEW_LEADER: 'nowy lider' COMMAND_ARGUMENT_PAGE: 'strona' COMMAND_ARGUMENT_PATH: 'path' COMMAND_ARGUMENT_PERMISSION: 'uprawnienie' -COMMAND_ARGUMENT_PLAYER: 'gracz' COMMAND_ARGUMENT_PLAYER_NAME: 'nazwa gracza' COMMAND_ARGUMENT_PRIVATE: 'prywatny' COMMAND_ARGUMENT_RATING: 'ocena' @@ -679,6 +677,7 @@ SET_UPGRADE_LEVEL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla SET_UPGRADE_LEVEL_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla {1}.' SET_WARP: '&e&lWyspa | &7Pomyslnie utworzono nowe wypaczenie w {0}.' SET_WARP_OUTSIDE: '&c&lBlad | &7Nie mozesz ustawic warp poza swoja wyspa.' +SETTINGS_RESET: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie ustawienia wyspy do domyslnych wartosci!' SETTINGS_UPDATED: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} do wyspy {1}.' SETTINGS_UPDATED_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} do wyspy {1}.' SETTINGS_UPDATED_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} dla wszystkich wysp.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 80f7587e88..f3a90c85e6 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -677,6 +677,7 @@ SET_UPGRADE_LEVEL: '&e&lAtualizações | &7Atualizou com sucesso o nível de {0} SET_UPGRADE_LEVEL_NAME: '&e&lAtualizações | &7Atualizou com sucesso o nível de {0} para {1}.' SET_WARP: '&e&lIlha | &7Criou com sucesso um novo warp em {0}.' SET_WARP_OUTSIDE: '&c&lErro | &7Você não pode definir warps fora da sua ilha.' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para a ilha de {1}.' SETTINGS_UPDATED_NAME: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para a ilha {1}.' SETTINGS_UPDATED_ALL: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para todas as ilhas.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index db94bfc7f8..c7e2bca774 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -677,6 +677,7 @@ SET_UPGRADE_LEVEL: '&e&lУлучшения | &7Успешно обновлен SET_UPGRADE_LEVEL_NAME: '&e&lУлучшения | &7Успешно обновлен уровень {0} для {1}.' SET_WARP: '&e&lОстров | &7Успешно создан новый варп на {0}.' SET_WARP_OUTSIDE: '&c&lОшибка | &7Вы не можете устанавливать варпы за пределами вашего острова.' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lОстров | &7Успешно обновлены настройки {0} для острова {1}.' SETTINGS_UPDATED_NAME: '&e&lОстров | &7Успешно обновлены настройки {0} для острова {1}.' SETTINGS_UPDATED_ALL: '&e&lОстров | &7Успешно обновлены настройки {0} для всех островов.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 8d65dae166..ad530c2d03 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -807,6 +807,7 @@ SET_UPGRADE_LEVEL_NAME: '&e&lYükseltmeler | &7{1} adası için {0} seviyesi ba güncellendi.' SET_WARP: '&e&lAda | &7{0} konumunda yeni bir ışınlanma noktası başarıyla oluşturuldu.' SET_WARP_OUTSIDE: '&c&lHata | &7Adanın dışında ışınlanma noktası ayarlayamazsın.' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lAda | &7{1}''in adası için {0} ayarları başarıyla güncellendi.' SETTINGS_UPDATED_NAME: '&e&lAda | &7{1} adası için {0} ayarları başarıyla güncellendi.' SETTINGS_UPDATED_ALL: '&e&lAda | &7Tüm adalar için {0} ayarları başarıyla güncellendi.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 1864c166a5..97413ba362 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -762,6 +762,7 @@ SET_UPGRADE_LEVEL: '&e&lNâng Cấp | &7Nâng cấp thành công cấp độ c SET_UPGRADE_LEVEL_NAME: '&e&lNâng Cấp | &7Thay đổi thành công cấp độ {0} cho đảo {1}.' SET_WARP: '&e&lĐảo | &7Tạo thành công một khu vực mới tại {0}.' SET_WARP_OUTSIDE: '&c&lLỗi | &7Bạn không thể đặt khu vực bên ngoài hòn đảo của bạn.' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lĐảo | &7Thay đổi thành công điều chỉnh {0} cho đảo của {1}.' SETTINGS_UPDATED_NAME: '&e&lĐảo | &7Thay đổi thành công điều chỉnh {0} cho diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index b5a2556439..59d7172e24 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -677,6 +677,7 @@ SET_UPGRADE_LEVEL: '&e&l升级 | &7成功更新了玩家 {1} 的岛屿等级 {0} SET_UPGRADE_LEVEL_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的等级 {0}.' SET_WARP: '&e&l岛屿 | &7成功在 {0} 处设置了传送点.' SET_WARP_OUTSIDE: '&c&l错误 | &7你不能在岛屿外设置传送点.' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&l岛屿 | &7成功修改了玩家 {1} 的岛屿设置 {0}.' SETTINGS_UPDATED_NAME: '&e&l岛屿 | &7S成功修改了岛屿 {1} 的设置 {0}.' SETTINGS_UPDATED_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的 {0} 设置.' From 3a8abdc3a790b08bdf8858253bc68db9230a7bf9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 9 Aug 2025 19:20:01 +0300 Subject: [PATCH 243/600] Added admin resetsettings command (#2545) --- .../api/events/IslandClearFlagsEvent.java | 9 +- .../commands/admin/AdminCommandsMap.java | 1 + .../commands/admin/CmdAdminResetSettings.java | 82 +++++++++++++++++++ .../commands/player/CmdSettings.java | 2 +- .../events/plugin/PluginEventsFactory.java | 4 + .../core/messages/Message.java | 4 + src/main/resources/lang/de-DE.yml | 5 +- src/main/resources/lang/en-US.yml | 8 +- src/main/resources/lang/es-ES.yml | 5 +- src/main/resources/lang/fr-FR.yml | 5 +- src/main/resources/lang/it-IT.yml | 5 +- src/main/resources/lang/iw-IL.yml | 5 +- src/main/resources/lang/pl-PL.yml | 5 +- src/main/resources/lang/pt-BR.yml | 5 +- src/main/resources/lang/ru-RU.yml | 5 +- src/main/resources/lang/tr-TR.yml | 5 +- src/main/resources/lang/vi-VN.yml | 5 +- src/main/resources/lang/zh-CN.yml | 5 +- src/main/resources/plugin.yml | 2 + 19 files changed, 151 insertions(+), 16 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetSettings.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearFlagsEvent.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearFlagsEvent.java index 85773aa109..7329326df8 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearFlagsEvent.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearFlagsEvent.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.api.events; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; @@ -9,6 +10,7 @@ */ public class IslandClearFlagsEvent extends IslandEvent implements Cancellable { + @Nullable private final SuperiorPlayer superiorPlayer; private boolean cancelled = false; @@ -17,16 +19,17 @@ public class IslandClearFlagsEvent extends IslandEvent implements Cancellable { * The constructor of the event. * * @param island The island that the flags were cleared in. - * @param superiorPlayer The player that cleared the flags. + * @param superiorPlayer The player that cleared the flags, or null if it was done by console. */ - public IslandClearFlagsEvent(Island island, SuperiorPlayer superiorPlayer) { + public IslandClearFlagsEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) { super(island); this.superiorPlayer = superiorPlayer; } /** - * Get the player that cleared the flags to the other player. + * Get the player that cleared the flags to the island, or null if it was done by console. */ + @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java index 972b525db7..a3543cbcfc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java @@ -46,6 +46,7 @@ public void loadDefaultCommands() { registerCommand(new CmdAdminReload()); registerCommand(new CmdAdminRemoveBlockLimit()); registerCommand(new CmdAdminRemoveRatings()); + registerCommand(new CmdAdminResetSettings()); registerCommand(new CmdAdminResetWorld()); registerCommand(new CmdAdminSchematic()); registerCommand(new CmdAdminSetBankLimit()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetSettings.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetSettings.java new file mode 100644 index 0000000000..52bf10317a --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetSettings.java @@ -0,0 +1,82 @@ +package com.bgsoftware.superiorskyblock.commands.admin; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.messages.Message; +import org.bukkit.command.CommandSender; + +import java.util.Collections; +import java.util.List; + +public class CmdAdminResetSettings implements IAdminIslandCommand { + + @Override + public List getAliases() { + return Collections.singletonList("resetsettings"); + } + + @Override + public String getPermission() { + return "superior.admin.resetsettings"; + } + + @Override + public String getUsage(java.util.Locale locale) { + return "admin resetsettings <" + + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + ">"; + } + + @Override + public String getDescription(java.util.Locale locale) { + return Message.COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS.getMessage(locale); + } + + @Override + public int getMinArgs() { + return 3; + } + + @Override + public int getMaxArgs() { + return 3; + } + + @Override + public boolean canBeExecutedByConsole() { + return true; + } + + @Override + public boolean supportMultipleIslands() { + return true; + } + + @Override + public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { + int islandsChangedCount = 0; + + for (Island island : islands) { + if (PluginEventsFactory.callIslandClearFlagsEvent(island, sender)) { + ++islandsChangedCount; + island.resetSettings(); + } + } + + if (islandsChangedCount <= 0) + return; + + if (islands.size() != 1) + Message.SETTINGS_RESET_ALL.send(sender); + else if (targetPlayer == null) + Message.SETTINGS_RESET_NAME.send(sender, islands.get(0).getName()); + else + Message.SETTINGS_RESET.send(sender, targetPlayer.getName()); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSettings.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSettings.java index 2e932bcccf..cff9c44772 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSettings.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSettings.java @@ -66,7 +66,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer if (args.length == 2 && args[1].equalsIgnoreCase("reset")) { if (PluginEventsFactory.callIslandClearFlagsEvent(island, superiorPlayer)) { island.resetSettings(); - Message.SETTINGS_RESET.send(superiorPlayer); + Message.SETTINGS_RESET_SELF.send(superiorPlayer); } return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java index d757fe4d25..a605c15451 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java @@ -644,6 +644,10 @@ public static void callIslandChunkResetEvent(Island island, ChunkPosition chunkP fireEvent(ISLAND_CHUNK_RESET_EVENT, islandChunkReset); } + public static boolean callIslandClearFlagsEvent(Island island, CommandSender commandSender) { + return callIslandClearFlagsEvent(island, commandSenderToSuperiorPlayer(commandSender)); + } + public static boolean callIslandClearFlagsEvent(Island island, SuperiorPlayer superiorPlayer) { IslandClearFlags islandClearFlags = new IslandClearFlags(); islandClearFlags.island = island; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 6eeef3872a..c48df035f6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -221,6 +221,7 @@ public enum Message { COMMAND_DESCRIPTION_ADMIN_RELOAD, COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT, COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS, + COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS, COMMAND_DESCRIPTION_ADMIN_RESET_WORLD, COMMAND_DESCRIPTION_ADMIN_SCHEMATIC, COMMAND_DESCRIPTION_ADMIN_SETTINGS, @@ -691,6 +692,9 @@ public void send(CommandSender sender, Locale locale, Object... args) { SCHEMATIC_SAVED, SELF_ROLE_CHANGE, SETTINGS_RESET, + SETTINGS_RESET_ALL, + SETTINGS_RESET_NAME, + SETTINGS_RESET_SELF, SETTINGS_UPDATED, SETTINGS_UPDATED_ALL, SETTINGS_UPDATED_NAME, diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index d5de8cc4e6..a3aefea6a9 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -861,7 +861,10 @@ SET_UPGRADE_LEVEL_NAME: '&e&lUpgrades | &7Die Ebene von {0} für {1} wurde erfol aktualisiert.' SET_WARP: '&e&lInsel | &7Erzeugt erfolgreich einen neuen Warp am {0}.' SET_WARP_OUTSIDE: '&c&lError | &7Du kannst keine Warps außerhalb Ihrer Insel setzen.' -SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' +SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' +SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' +SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lInsel | &7Die Einstellungen {0} wurden erfolgreich auf die Insel von {1} aktualisiert.' SETTINGS_UPDATED_NAME: '&e&lInsel | &7Die Einstellungen {0} wurden erfolgreich auf diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index d455bc7878..50e0784b36 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -660,6 +660,9 @@ RECALC_PROCCESS_REQUEST: '&e&lIsland | &7Processing your request...' RELOAD_COMPLETED: '&e&lIsland | &7Reload is finished!' RELOAD_PROCCESS_REQUEST: '&e&lIsland | &7Starting to reload configurations...' REVOKE_INVITE_ANNOUNCEMENT: '&e&lIsland | &7{0} revoked the invitation of {1} to the island.' +RESET_SETTINGS: '&e&lIsland | &7Successfully reset island settings for {0}''s island.' +RESET_SETTINGS_ALL: '&e&lIsland | &7Successfully reset island settings for all the islands.' +RESET_SETTINGS_NAME: '&e&lIsland | &7Successfully reset island settings for all the islands.' RESET_WORLD_SUCCEED: '&e&lIsland | &7Successfully reset the world {0} for {1}''s island.' RESET_WORLD_SUCCEED_ALL: '&e&lIsland | &7Successfully reset the world {0} for all the islands.' RESET_WORLD_SUCCEED_NAME: '&e&lIsland | &7Successfully reset the world {0} for {1}.' @@ -677,7 +680,10 @@ SET_UPGRADE_LEVEL: '&e&lUpgrades | &7Successfully updated the level of {0} for { SET_UPGRADE_LEVEL_NAME: '&e&lUpgrades | &7Successfully updated the level of {0} for {1}.' SET_WARP: '&e&lIsland | &7Successfully created a new warp at {0}.' SET_WARP_OUTSIDE: '&c&lError | &7You cannot set warps outside your island.' -SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' +SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' +SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' +SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIsland | &7Successfully updated the settings {0} to {1}''s island.' SETTINGS_UPDATED_NAME: '&e&lIsland | &7Successfully updated the settings {0} to the island {1}.' SETTINGS_UPDATED_ALL: '&e&lIsland | &7Successfully updated the settings {0} to all the islands.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 02e15440d3..00efbe446b 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -677,7 +677,10 @@ SET_UPGRADE_LEVEL: '&e&lMejoras| &7Se actualizó correctamente el nivel de {0} p SET_UPGRADE_LEVEL_NAME: '&e&lMejoras| &7Se actualizó correctamente el nivel de {0} para {1}.' SET_WARP: '&e&lIsla | &7Se creó con éxito una nuevo warp en {0}.' SET_WARP_OUTSIDE: '&c&lError | &7No puedes establecer warps fuera de tu isla.' -SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' +SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' +SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' +SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIsla | &7Se actualizó correctamente la configuración {0} a la isla de {1}.' SETTINGS_UPDATED_NAME: '&e&lIsla | &7Se actualizó correctamente la configuración {0} de la isla {1}.' SETTINGS_UPDATED_ALL: '&e&lIsla | &7Se actualizó correctamente la configuración {0} en todas las islas.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 02de4470c3..13880cb2e9 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -679,7 +679,10 @@ SET_UPGRADE_LEVEL: '&e&lAméliorations | &7Niveau de {0} augmenté sur l''île d SET_UPGRADE_LEVEL_NAME: '&e&lAméliorations | &7Niveau de {0} augmenté sur {1}.' SET_WARP: '&e&lIle | &7Nouveau warp crée au coordonnées {0}.' SET_WARP_OUTSIDE: '&c&lErreur | &7Vous ne pouvez pas définir de warps hors de votre île.' -SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' +SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' +SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' +SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIle | &7Paramètre {0} mit à jour pour l''île de {1}.' SETTINGS_UPDATED_NAME: '&e&lIle | &7Paramètre {0} mit à jour pour l''île {1}.' SETTINGS_UPDATED_ALL: '&e&lIle | &7Paramètre {0} mit à jour pour toutes les îles.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index a47efb4d1c..4296dbee57 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -685,7 +685,10 @@ SET_UPGRADE_LEVEL: '&e&lAggiornamenti | &7Aggiornato con successo il livello di SET_UPGRADE_LEVEL_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il livello di {0} per {1}.' SET_WARP: '&e&lIsola | &7Creato con successo un nuovo warp a {0}.' SET_WARP_OUTSIDE: '&c&lErrore | &7Non puoi impostare warp fuori dalla tua isola.' -SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' +SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' +SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' +SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} dell''isola di {1}.' SETTINGS_UPDATED_NAME: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} di {1}.' SETTINGS_UPDATED_ALL: '&e&lIsola | &7Aggiornate correttamente le impostazioni {0} a tutte le isole.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 669a82b707..df44078f93 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -699,7 +699,10 @@ SET_UPGRADE_LEVEL: '&e&lםיגורדש | &7החלצהב התנוש {1} לש יא SET_UPGRADE_LEVEL_NAME: '&e&lםיגורדש | &7החלצהב התנוש {1} יאב {0} גורדשה לש המרה.' SET_WARP: '&e&lיא | &7{0} ב החלצהב שדח םוקימ תרצי.' SET_WARP_OUTSIDE: '&c&lהאיגש | &7ךלש יאל ץוחמ םימוקימ רוציל לוכי אל התא.' -SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' +SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' +SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' +SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lיא | &7{1} לש יאב החלצהב הנכדוע {0} הרדגהה.' SETTINGS_UPDATED_NAME: '&e&lיא | &7{1} יאב החלצהב הנכדוע {0} הרדגהה.' SETTINGS_UPDATED_ALL: '&e&lיא | &7םייאה לכב החלצהב הנכדוע {0} הרדגהה.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 13721c92b1..06f1b46325 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -677,7 +677,10 @@ SET_UPGRADE_LEVEL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla SET_UPGRADE_LEVEL_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla {1}.' SET_WARP: '&e&lWyspa | &7Pomyslnie utworzono nowe wypaczenie w {0}.' SET_WARP_OUTSIDE: '&c&lBlad | &7Nie mozesz ustawic warp poza swoja wyspa.' -SETTINGS_RESET: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie ustawienia wyspy do domyslnych wartosci!' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' +SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' +SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' +SETTINGS_RESET_SELF: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie ustawienia wyspy do domyslnych wartosci!' SETTINGS_UPDATED: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} do wyspy {1}.' SETTINGS_UPDATED_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} do wyspy {1}.' SETTINGS_UPDATED_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano ustawienia {0} dla wszystkich wysp.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index f3a90c85e6..95df74b030 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -677,7 +677,10 @@ SET_UPGRADE_LEVEL: '&e&lAtualizações | &7Atualizou com sucesso o nível de {0} SET_UPGRADE_LEVEL_NAME: '&e&lAtualizações | &7Atualizou com sucesso o nível de {0} para {1}.' SET_WARP: '&e&lIlha | &7Criou com sucesso um novo warp em {0}.' SET_WARP_OUTSIDE: '&c&lErro | &7Você não pode definir warps fora da sua ilha.' -SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' +SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' +SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' +SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para a ilha de {1}.' SETTINGS_UPDATED_NAME: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para a ilha {1}.' SETTINGS_UPDATED_ALL: '&e&lIlha | &7Atualizadas com sucesso as configurações {0} para todas as ilhas.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index c7e2bca774..7a43635be1 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -677,7 +677,10 @@ SET_UPGRADE_LEVEL: '&e&lУлучшения | &7Успешно обновлен SET_UPGRADE_LEVEL_NAME: '&e&lУлучшения | &7Успешно обновлен уровень {0} для {1}.' SET_WARP: '&e&lОстров | &7Успешно создан новый варп на {0}.' SET_WARP_OUTSIDE: '&c&lОшибка | &7Вы не можете устанавливать варпы за пределами вашего острова.' -SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' +SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' +SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' +SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lОстров | &7Успешно обновлены настройки {0} для острова {1}.' SETTINGS_UPDATED_NAME: '&e&lОстров | &7Успешно обновлены настройки {0} для острова {1}.' SETTINGS_UPDATED_ALL: '&e&lОстров | &7Успешно обновлены настройки {0} для всех островов.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index ad530c2d03..776ce1e435 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -807,7 +807,10 @@ SET_UPGRADE_LEVEL_NAME: '&e&lYükseltmeler | &7{1} adası için {0} seviyesi ba güncellendi.' SET_WARP: '&e&lAda | &7{0} konumunda yeni bir ışınlanma noktası başarıyla oluşturuldu.' SET_WARP_OUTSIDE: '&c&lHata | &7Adanın dışında ışınlanma noktası ayarlayamazsın.' -SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' +SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' +SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' +SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lAda | &7{1}''in adası için {0} ayarları başarıyla güncellendi.' SETTINGS_UPDATED_NAME: '&e&lAda | &7{1} adası için {0} ayarları başarıyla güncellendi.' SETTINGS_UPDATED_ALL: '&e&lAda | &7Tüm adalar için {0} ayarları başarıyla güncellendi.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 97413ba362..29deb17a1e 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -762,7 +762,10 @@ SET_UPGRADE_LEVEL: '&e&lNâng Cấp | &7Nâng cấp thành công cấp độ c SET_UPGRADE_LEVEL_NAME: '&e&lNâng Cấp | &7Thay đổi thành công cấp độ {0} cho đảo {1}.' SET_WARP: '&e&lĐảo | &7Tạo thành công một khu vực mới tại {0}.' SET_WARP_OUTSIDE: '&c&lLỗi | &7Bạn không thể đặt khu vực bên ngoài hòn đảo của bạn.' -SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' +SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' +SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' +SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&lĐảo | &7Thay đổi thành công điều chỉnh {0} cho đảo của {1}.' SETTINGS_UPDATED_NAME: '&e&lĐảo | &7Thay đổi thành công điều chỉnh {0} cho diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 59d7172e24..194583b107 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -677,7 +677,10 @@ SET_UPGRADE_LEVEL: '&e&l升级 | &7成功更新了玩家 {1} 的岛屿等级 {0} SET_UPGRADE_LEVEL_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的等级 {0}.' SET_WARP: '&e&l岛屿 | &7成功在 {0} 处设置了传送点.' SET_WARP_OUTSIDE: '&c&l错误 | &7你不能在岛屿外设置传送点.' -SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' +SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' +SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' +SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' +SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' SETTINGS_UPDATED: '&e&l岛屿 | &7成功修改了玩家 {1} 的岛屿设置 {0}.' SETTINGS_UPDATED_NAME: '&e&l岛屿 | &7S成功修改了岛屿 {1} 的设置 {0}.' SETTINGS_UPDATED_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的 {0} 设置.' diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 8a5d0c570d..8976a64480 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -262,6 +262,8 @@ permissions: description: Remove a block limit for an island. superior.admin.removeratings: description: Remove all ratings given by a player. + superior.admin.resetsettings: + description: Reset all island settings for a specific island. superior.admin.resetworld: description: Reset a world for an island. superior.admin.schematic: From a152f096b10eb61aedf32a57340f932916e478dd Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 9 Aug 2025 18:22:04 +0200 Subject: [PATCH 244/600] Fixed opening missions menu when there are per island missions (#2570) --- .../core/menu/button/impl/OpenMissionCategoryButton.java | 9 +++++++++ .../module/missions/commands/CmdMissions.java | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenMissionCategoryButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenMissionCategoryButton.java index 3b942470af..53c4ecc1e4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenMissionCategoryButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenMissionCategoryButton.java @@ -2,6 +2,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; +import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; @@ -10,6 +11,7 @@ import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; +import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; @@ -28,6 +30,11 @@ public Template getTemplate() { @Override public void onButtonClick(InventoryClickEvent clickEvent) { + if (getTemplate().requireIsland && !menuView.getInventoryViewer().hasIsland()) { + Message.INVALID_ISLAND.send(menuView.getInventoryViewer()); + return; + } + menuView.setPreviousMove(false); plugin.getMenus().openMissionsCategory(menuView.getInventoryViewer(), MenuViewWrapper.fromView(menuView), getTemplate().missionCategory); } @@ -51,12 +58,14 @@ public MenuTemplateButton build() { public static class Template extends MenuTemplateButtonImpl { private final MissionCategory missionCategory; + private final boolean requireIsland; Template(@Nullable TemplateItem buttonItem, @Nullable GameSound clickSound, @Nullable List commands, @Nullable String requiredPermission, @Nullable GameSound lackPermissionSound, MissionCategory missionCategory) { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, OpenMissionCategoryButton.class, OpenMissionCategoryButton::new); this.missionCategory = Objects.requireNonNull(missionCategory, "missionCategory cannot be null"); + this.requireIsland = missionCategory.getMissions().stream().allMatch(Mission::getIslandMission); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMissions.java b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMissions.java index 6429177d2e..bcd339e5fb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMissions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMissions.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.module.missions.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; @@ -51,6 +52,13 @@ public boolean canBeExecutedByConsole() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); + boolean requireIsland = plugin.getMissions().getAllMissions().stream().allMatch(Mission::getIslandMission); + + if (requireIsland && !superiorPlayer.hasIsland()) { + Message.INVALID_ISLAND.send(superiorPlayer); + return; + } + plugin.getMenus().openMissions(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView())); } From 1358a70b740d4f4aab836718eebaf146810249dc Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 9 Aug 2025 18:24:30 +0200 Subject: [PATCH 245/600] Added missing blocks to counts button (#2559) --- .../button/impl/CountsPagedObjectButton.java | 145 +++++++++--------- 1 file changed, 76 insertions(+), 69 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java index 3e75d4f424..01c0a21402 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java @@ -34,29 +34,46 @@ public class CountsPagedObjectButton extends AbstractPagedMenuButton BLOCKS_TO_ITEMS = new MapBuilder() .put("ACACIA_DOOR", "ACACIA_DOOR_ITEM") + .put("ACACIA_WALL_HANGING_SIGN", "ACACIA_HANGING_SIGN") .put("ACACIA_WALL_SIGN", "ACACIA_SIGN") + .put("ATTACHED_MELON_STEM", "MELON_SEEDS") + .put("ATTACHED_PUMPKIN_STEM", "PUMPKIN_SEEDS") .put("BAMBOO_SAPLING", "BAMBOO") + .put("BAMBOO_WALL_HANGING_SIGN", "BAMBOO_HANGING_SIGN") + .put("BAMBOO_WALL_SIGN", "BAMBOO_SIGN") .put("BED_BLOCK", "BED") .put("BEETROOT_BLOCK", "BEETROOT") .put("BEETROOTS", "BEETROOT") + .put("BIG_DRIPLEAF_STEM", "BIG_DRIPLEAF") .put("BIRCH_DOOR", "BIRCH_DOOR_ITEM") + .put("BIRCH_WALL_HANGING_SIGN", "BIRCH_HANGING_SIGN") .put("BIRCH_WALL_SIGN", "BIRCH_SIGN") + .put("BLACK_CANDLE_CAKE", "BLACK_CANDLE") .put("BLACK_WALL_BANNER", "BLACK_BANNER") + .put("BLUE_CANDLE_CAKE", "BLUE_CANDLE") .put("BLUE_WALL_BANNER", "BLUE_BANNER") .put("BRAIN_CORAL_WALL_FAN", "BRAIN_CORAL") - .put("BURNING_FURNACE", "FURNACE") .put("BREWING_STAND", "BREWING_STAND_ITEM") + .put("BROWN_CANDLE_CAKE", "BROWN_CANDLE") .put("BROWN_WALL_BANNER", "BROWN_BANNER") .put("BUBBLE_CORAL_WALL_FAN", "BUBBLE_CORAL") + .put("BURNING_FURNACE", "FURNACE") .put("CAKE_BLOCK", "CAKE") + .put("CANDLE_CAKE", "CANDLE") .put("CARROT", "CARROT_ITEM") .put("CARROTS", "CARROT") .put("CAULDRON", "CAULDRON_ITEM") + .put("CHERRY_WALL_HANGING_SIGN", "CHERRY_HANGING_SIGN") + .put("CHERRY_WALL_SIGN", "CHERRY_SIGN") .put("COCOA", ServerVersion.isLegacy() ? "INK_SACK:3" : "COCOA_BEANS") .put("CREEPER_WALL_HEAD", "CREEPER_HEAD") + .put("CRIMSON_WALL_HANGING_SIGN", "CRIMSON_HANGING_SIGN") + .put("CRIMSON_WALL_SIGN", "CRIMSON_SIGN") .put("CROPS", "SEEDS") + .put("CYAN_CANDLE_CAKE", "CYAN_CANDLE") .put("CYAN_WALL_BANNER", "CYAN_BANNER") .put("DARK_OAK_DOOR", "DARK_OAK_DOOR_ITEM") + .put("DARK_OAK_WALL_HANGING_SIGN", "DARK_OAK_HANGING_SIGN") .put("DARK_OAK_WALL_SIGN", "DARK_OAK_SIGN") .put("DAYLIGHT_DETECTOR_INVERTED", "DAYLIGHT_DETECTOR") .put("DEAD_BRAIN_CORAL_WALL_FAN", "DEAD_BRAIN_CORAL") @@ -67,151 +84,141 @@ public class CountsPagedObjectButton extends AbstractPagedMenuButton Date: Fri, 15 Aug 2025 11:13:30 +0300 Subject: [PATCH 246/600] Fixed dark sky in y levels below 60 (#2596) --- .../external/worlds/WorldsProvider_Default.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java index 9177f92615..415c192de6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java @@ -173,7 +173,7 @@ private World loadWorld(String worldName, Difficulty difficulty, Dimension dimen } World world = WorldCreator.name(worldName) - .type(WorldType.NORMAL) + .type(WorldType.FLAT) .environment(dimension.getEnvironment()) .generator(WorldGenerator.getWorldGenerator(dimension)) .createWorld(); From 91b6ff7bfd1490449158773e6a26ca982a9921eb Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 15 Aug 2025 11:37:02 +0300 Subject: [PATCH 247/600] Added specific permissions to the members and visitors menus (#2592) --- .../superiorskyblock/commands/player/CmdMembers.java | 2 +- .../superiorskyblock/commands/player/CmdVisitors.java | 2 +- src/main/resources/plugin.yml | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdMembers.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdMembers.java index c43ba50164..eaaeb34b68 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdMembers.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdMembers.java @@ -22,7 +22,7 @@ public List getAliases() { @Override public String getPermission() { - return "superior.island.panel"; + return "superior.island.members"; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisitors.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisitors.java index e13190a4de..86de386907 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisitors.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisitors.java @@ -22,7 +22,7 @@ public List getAliases() { @Override public String getPermission() { - return "superior.island.panel"; + return "superior.island.visitors"; } @Override diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 8976a64480..b501ec11c9 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -109,6 +109,11 @@ permissions: description: Open the island to the public. superior.island.panel: description: Open island panel. + children: + superior.island.visitors: + description: Open the visitors menu. + superior.island.members: + description: Open the members menu. superior.island.pardon: description: Unban a player from your island. superior.island.permissions: From d8ba5cdda6e1c4772c33356850801ad8a9f418ab Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 15 Aug 2025 15:46:28 +0200 Subject: [PATCH 248/600] Changed disband count option behavior to allow setting 0 disbands by default (#2579) --- .../superiorskyblock/api/config/SettingsManager.java | 6 +++--- .../superiorskyblock/commands/player/CmdDisband.java | 7 +++++-- .../superiorskyblock/config/SettingsContainer.java | 4 ++-- .../superiorskyblock/config/SettingsManagerImpl.java | 4 ++++ .../superiorskyblock/config/section/GlobalSection.java | 2 +- .../core/menu/button/impl/DisbandButton.java | 4 +++- .../superiorskyblock/player/SSuperiorPlayer.java | 2 -- .../player/builder/SuperiorPlayerBuilderImpl.java | 1 - src/main/resources/config.yml | 8 ++++---- 9 files changed, 22 insertions(+), 16 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 1caecd9b43..5ab45fce44 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -187,9 +187,9 @@ public interface SettingsManager { boolean isCoopDamage(); /** - * The default amount of disbands players receive when they first join the server. - * If 0, then the disbands limit is disabled. - * Config-path: disband-count + * The default number of disbands players receive when they first join the server. + * If -1, then the disbands limit is disabled. + * Config-path: default-disband-count */ int getDisbandCount(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java index b827f2029c..884b5cf6bb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java @@ -67,7 +67,7 @@ public Message getPermissionLackMessage() { @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { - if (!superiorPlayer.hasDisbands() && plugin.getSettings().getDisbandCount() > 0) { + if (!superiorPlayer.hasDisbands() && plugin.getSettings().getDisbandCount() >= 0) { Message.NO_MORE_DISBANDS.send(superiorPlayer); return; } @@ -84,7 +84,10 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer island.getIslandBank().getBalance().multiply(BigDecimal.valueOf(BuiltinModules.BANK.disbandRefund)))); } - superiorPlayer.setDisbands(superiorPlayer.getDisbands() - 1); + if (plugin.getSettings().getDisbandCount() >= 0) { + superiorPlayer.setDisbands(superiorPlayer.getDisbands() - 1); + } + island.disbandIsland(); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 0211d112a9..c7244242ff 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -134,7 +134,6 @@ public class SettingsContainer { public final KeySet safeBlocks; public final boolean visitorsDamage; public final boolean coopDamage; - public final int disbandCount; public final boolean islandTopIncludeLeader; public final Map defaultPlaceholders; public final boolean banConfirm; @@ -186,6 +185,7 @@ public class SettingsContainer { public final int cropsInterval; public final boolean onlyBackButton; public final boolean buildOutsideIsland; + public final int defaultDisbandCount; public final String defaultLanguage; public final boolean defaultWorldBorder; public final boolean defaultBlocksStacker; @@ -375,7 +375,6 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config safeBlocks = loadSafeBlocks(plugin); visitorsDamage = config.getBoolean("visitors-damage", false); coopDamage = config.getBoolean("coop-damage", true); - disbandCount = config.getInt("disband-count", 5); islandTopIncludeLeader = config.getBoolean("island-top-include-leader", true); defaultPlaceholders = Collections.unmodifiableMap(config.getStringList("default-placeholders").stream().collect(Collectors.toMap( line -> line.split(":")[0].replace("superior_", "").toLowerCase(Locale.ENGLISH), @@ -495,6 +494,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config cropsInterval = config.getInt("crops-interval", 5); onlyBackButton = config.getBoolean("only-back-button", false); buildOutsideIsland = config.getBoolean("build-outside-island", false); + defaultDisbandCount = config.getInt("default-disband-count", 5); defaultLanguage = config.getString("default-language", "en-US"); defaultWorldBorder = config.getBoolean("default-world-border", true); defaultBlocksStacker = config.getBoolean("default-blocks-stacker", true); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index 2f20da140a..b1518d7544 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -661,6 +661,10 @@ private void loadContainerFromConfig(YamlConfiguration cfg) throws ManagerLoadEx } private void convertData(YamlConfiguration cfg) { + if (cfg.contains("disband-count")) { + cfg.set("default-disband-count", cfg.getInt("disband-count") == 0 ? -1 : cfg.getInt("disband-count")); + cfg.set("disband-count", null); + } if (cfg.contains("default-hoppers-limit")) { cfg.set("default-limits", Collections.singletonList("HOPPER:" + cfg.getInt("default-hoppers-limit"))); cfg.set("default-hoppers-limit", null); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index 3126cbcb89..a26959df68 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -94,7 +94,7 @@ public boolean isCoopDamage() { } public int getDisbandCount() { - return getContainer().disbandCount; + return getContainer().defaultDisbandCount; } public boolean isIslandTopIncludeLeader() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java index 5086ab2221..3b1d71e1d5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java @@ -48,7 +48,9 @@ public void onButtonClick(InventoryClickEvent clickEvent) { targetIsland.getIslandBank().getBalance().multiply(BigDecimal.valueOf(BuiltinModules.BANK.disbandRefund)))); } - inventoryViewer.setDisbands(inventoryViewer.getDisbands() - 1); + if (plugin.getSettings().getDisbandCount() >= 0) { + inventoryViewer.setDisbands(inventoryViewer.getDisbands() - 1); + } targetIsland.disbandIsland(); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index a35beecee1..0ea7b2d52f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -568,8 +568,6 @@ public int getDisbands() { @Override public void setDisbands(int disbands) { - disbands = Math.max(disbands, 0); - Log.debug(Debug.SET_DISBANDS, getName(), disbands); if (this.disbands == disbands) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/builder/SuperiorPlayerBuilderImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/player/builder/SuperiorPlayerBuilderImpl.java index 4277f3725f..bb4e0ffc2e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/builder/SuperiorPlayerBuilderImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/builder/SuperiorPlayerBuilderImpl.java @@ -79,7 +79,6 @@ public PlayerRole getPlayerRole() { @Override public SuperiorPlayer.Builder setDisbands(int disbands) { - Preconditions.checkArgument(disbands >= 0, "Cannot set negative disbands count."); this.disbands = disbands; return this; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 7209e0ca9e..2665aabcbb 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -429,10 +429,6 @@ visitors-damage: false # When disabled, coop won't get damaged in islands they are coop with. coop-damage: true -# The amount of times a player can disband an island. -# If you want to disable this feature, set it to 0. -disband-count: 5 - # Should the list of members in island top also include the island leader? island-top-include-leader: true @@ -724,6 +720,10 @@ only-back-button: false # It's recommended to have a low max island size when this feature is enabled! build-outside-island: false +# The default number of times new players can disband their island. +# If you want to disable this feature, set it to -1. +default-disband-count: 5 + # The default language to be used. # This should be the same as your language file's name. default-language: 'en-US' From 2f763c9809cc104ec9edce2a1b2a83b1533bdcdf Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 15 Aug 2025 17:50:03 +0300 Subject: [PATCH 249/600] Ensure island calculation is called in main thread --- .../algorithm/DefaultIslandCalculationAlgorithm.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java index 9add5e24d0..4080032c2a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java @@ -59,6 +59,12 @@ public static DefaultIslandCalculationAlgorithm getInstance() { @Override public CompletableFuture calculateIsland(Island island) { + CompletableFuture result = new CompletableFuture<>(); + BukkitExecutor.ensureMain(() -> calculateIslandInternal(island, result)); + return result; + } + + private void calculateIslandInternal(Island island, CompletableFuture result) { CompletableFutureList> chunksToLoad = new CompletableFutureList<>(plugin.getSettings().getRecalcTaskTimeout()); long profiler = Profiler.start(ProfileType.CALCULATE_ISLAND); @@ -87,8 +93,6 @@ public CompletableFuture calculateIsland(Island island) } BlockCountsTracker blockCounts = new BlockCountsTracker(); - CompletableFuture result = new CompletableFuture<>(); - Set spawnersToCheck = new HashSet<>(); Set chunksToCheck = new HashSet<>(); @@ -169,8 +173,6 @@ public CompletableFuture calculateIsland(Island island) result.complete(blockCounts); }); - - return result; } private static List> createMinecartBlockTypes() { From 88704f4e351076acbeec35cc7bedad53743f2783 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 15 Aug 2025 18:04:09 +0300 Subject: [PATCH 250/600] Fixed panel command shows members and visitors even when player does not have permission to open the menus (#2592) --- .../commands/CommandTabCompletes.java | 6 +++++- .../commands/player/CmdPanel.java | 20 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index bd3f9a0a96..c532914645 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -119,7 +119,11 @@ public static List getIslandVisitors(Island island, String argument, boo } public static List getCustomComplete(String argument, String... tabVariables) { - return filterByArgument(Arrays.asList(tabVariables), argument.toLowerCase(Locale.ENGLISH)); + return getCustomComplete(argument, Arrays.asList(tabVariables)); + } + + public static List getCustomComplete(String argument, Collection tabVariables) { + return filterByArgument(tabVariables, argument.toLowerCase(Locale.ENGLISH)); } public static List getCustomComplete(String argument, Predicate predicate, String... tabVariables) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPanel.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPanel.java index 67925ad5b6..115798672d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPanel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPanel.java @@ -11,9 +11,11 @@ import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import java.util.Arrays; import java.util.Collections; +import java.util.LinkedList; import java.util.List; public class CmdPanel implements ISuperiorCommand { @@ -91,7 +93,23 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { - return args.length == 2 ? CommandTabCompletes.getCustomComplete(args[1], "members", "visitors", "toggle") : Collections.emptyList(); + if (args.length != 2) + return Collections.emptyList(); + + List extraArgument = new LinkedList<>(); + extraArgument.add("toggle"); + if (!(sender instanceof Player)) { + extraArgument.add("visitors"); + extraArgument.add("members"); + } else { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); + if (superiorPlayer.hasPermission("superior.island.visitors")) + extraArgument.add("visitors"); + if (superiorPlayer.hasPermission("superior.island.members")) + extraArgument.add("members"); + } + + return CommandTabCompletes.getCustomComplete(args[1], extraArgument); } } From 9b7b46b5040064c9b3ded3354a08cf9fc930bb58 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:01:01 +0200 Subject: [PATCH 251/600] Fixed control panel button actions (#2604) --- .../menu/button/impl/ControlPanelButton.java | 25 +++---------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ControlPanelButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ControlPanelButton.java index 89b4965981..e4fa6aee10 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ControlPanelButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/ControlPanelButton.java @@ -1,19 +1,13 @@ package com.bgsoftware.superiorskyblock.core.menu.button.impl; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; -import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; -import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.event.inventory.InventoryClickEvent; import java.util.List; @@ -32,30 +26,17 @@ public Template getTemplate() { @Override public void onButtonClick(InventoryClickEvent clickEvent) { - SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); - Island targetIsland = menuView.getIsland(); - switch (getTemplate().controlPanelAction) { case OPEN_MEMBERS: - plugin.getMenus().openMembers(inventoryViewer, MenuViewWrapper.fromView(menuView), targetIsland); + plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "members"); break; case OPEN_SETTINGS: - if (inventoryViewer.hasPermission("superior.island.settings")) { - if (!inventoryViewer.hasPermission(IslandPrivileges.SET_SETTINGS)) { - Message.NO_SET_SETTINGS_PERMISSION.send(inventoryViewer, - targetIsland.getRequiredPlayerRole(IslandPrivileges.SET_SETTINGS)); - return; - } - - plugin.getMenus().openSettings(inventoryViewer, MenuViewWrapper.fromView(menuView), targetIsland); - } + plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "settings"); break; case OPEN_VISITORS: - plugin.getMenus().openVisitors(inventoryViewer, MenuViewWrapper.fromView(menuView), targetIsland); + plugin.getCommands().dispatchSubCommand(clickEvent.getWhoClicked(), "visitors"); break; } - - BukkitExecutor.sync(menuView::closeView, 1L); } public enum ControlPanelAction { From 832b887139e8c4041d0bc75a534bdf6d2d4452e7 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:02:41 +0200 Subject: [PATCH 252/600] Fixed no command permission message (#2603) --- .../superiorskyblock/commands/CommandsManagerImpl.java | 7 +++++-- .../superiorskyblock/commands/player/CmdAdmin.java | 4 ++-- .../superiorskyblock/commands/player/CmdHelp.java | 2 +- .../superiorskyblock/commands/player/CmdToggle.java | 4 ++-- src/main/resources/lang/de-DE.yml | 2 +- src/main/resources/lang/en-US.yml | 2 +- src/main/resources/lang/es-ES.yml | 2 +- src/main/resources/lang/fr-FR.yml | 2 +- src/main/resources/lang/it-IT.yml | 2 +- src/main/resources/lang/iw-IL.yml | 2 +- src/main/resources/lang/pl-PL.yml | 2 +- src/main/resources/lang/pt-BR.yml | 2 +- src/main/resources/lang/ru-RU.yml | 2 +- src/main/resources/lang/tr-TR.yml | 2 +- src/main/resources/lang/vi-VN.yml | 2 +- src/main/resources/lang/zh-CN.yml | 2 +- 16 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java index e750290612..d840409cfb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java @@ -263,7 +263,7 @@ public boolean execute(CommandSender sender, String label, String[] args) { if (!CommandsHelper.hasCommandAccess(command, sender)) { Log.debugResult(Debug.EXECUTE_COMMAND, "Return Missing Permission", command.getPermission()); - Message.NO_COMMAND_PERMISSION.send(sender, locale); + Message.NO_COMMAND_PERMISSION.send(sender, locale, command.getPermission()); return false; } @@ -333,7 +333,10 @@ public boolean execute(CommandSender sender, String label, String[] args) { } } - Message.NO_COMMAND_PERMISSION.send(sender, locale); + // We don't want to end up in an infinite loop + if (!"help".equalsIgnoreCase(executedSubCommand)) { + dispatchSubCommand(sender, "help"); + } return false; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java index 420cde4054..095c05d737 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java @@ -85,7 +85,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ if (!CommandsHelper.hasCommandAccess(command, sender)) { Log.debugResult(Debug.EXECUTE_COMMAND, "Return Missing Permission", command.getPermission()); - Message.NO_COMMAND_PERMISSION.send(sender, locale); + Message.NO_COMMAND_PERMISSION.send(sender, locale, command.getPermission()); return; } @@ -121,7 +121,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ .build(plugin.getCommands().getAdminSubCommands()); if (subCommands.isEmpty()) { - Message.NO_COMMAND_PERMISSION.send(sender, locale); + Message.NO_COMMAND_PERMISSION.send(sender, locale, getPermission()); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java index 83aa3ead5c..be90c0adbd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdHelp.java @@ -88,7 +88,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ .build(plugin.getCommands().getSubCommands()); if (subCommands.isEmpty()) { - Message.NO_COMMAND_PERMISSION.send(sender); + Message.NO_COMMAND_PERMISSION.send(sender, getPermission()); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java index 320bab178b..e41abdbc86 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdToggle.java @@ -57,7 +57,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ if (args[1].equalsIgnoreCase("border")) { if (!superiorPlayer.hasPermission("superior.island.toggle.border")) { - Message.NO_COMMAND_PERMISSION.send(sender); + Message.NO_COMMAND_PERMISSION.send(sender, "superior.island.toggle.border"); return; } @@ -76,7 +76,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ } } else if (args[1].equalsIgnoreCase("blocks")) { if (!superiorPlayer.hasPermission("superior.island.toggle.blocks")) { - Message.NO_COMMAND_PERMISSION.send(sender); + Message.NO_COMMAND_PERMISSION.send(sender, "superior.island.toggle.blocks"); return; } diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index a3aefea6a9..885b60d12a 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -707,7 +707,7 @@ NO_BAN_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler zu ba NO_CLOSE_BYPASS: '&c&lError | &7Diese Insel ist nicht für die Öffentlichkeit zugänglich.' NO_CLOSE_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um die Insel für die Öffentlichkeit zu schließen.' -NO_COMMAND_PERMISSION: '&fUnbekannter Befehl. Gebe "/is help" ein, um Hilfe zu erhalten.' +NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler als Koop-Mitglieder hinzuzufügen.' NO_DELETE_WARP_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Warps zu diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 50e0784b36..2a57dff965 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -568,7 +568,7 @@ NAME_TOO_SHORT: '&c&lError | &7Island names cannot be less than 3 chars long.' NO_BAN_PERMISSION: '&c&lError | &7You must be at least {0} in order to ban players.' NO_CLOSE_BYPASS: '&c&lError | &7This island is not opened to the public.' NO_CLOSE_PERMISSION: '&c&lError | &7You must be at least {0} in order to close the island to the public.' -NO_COMMAND_PERMISSION: '&fUnknown command. Type "/help" for help.' +NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lError | &7You must be at least {0} in order to add players as co-op members.' NO_DELETE_WARP_PERMISSION: '&c&lError | &7You must be at least {0} in order to delete warps.' NO_DEMOTE_PERMISSION: '&c&lError | &7You must be at least {0} in order to demote players.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 00efbe446b..f5a89f3825 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -568,7 +568,7 @@ NAME_TOO_SHORT: '&c&lError | &7Los nombres de las islas no pueden tener menos de NO_BAN_PERMISSION: '&c&lError | &7Debes ser al menos {0} para prohibir a los jugadores' NO_CLOSE_BYPASS: '&c&lError | &7Esta isla no está abierta al público.' NO_CLOSE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder cerrar la isla al público.' -NO_COMMAND_PERMISSION: '&fComando desconocido. Escriba "/help" para obtener ayuda.' +NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder agregar jugadores como miembros cooperativos.' NO_DELETE_WARP_PERMISSION: '&c&lError | &7Debes tener al menos {0} para eliminar warps.' NO_DEMOTE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para degradar jugadores.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 13880cb2e9..5b4a298aa6 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -571,7 +571,7 @@ NO_ISLANDS_TO_PURGE: '&c&lErreur | &7Il n''y a aucune îles à purger.' NO_BAN_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de bannir un joueur.' NO_CLOSE_BYPASS: '&c&lErreur | &7Cette île n''est pas ouverte au public.' NO_CLOSE_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de fermer cette.' -NO_COMMAND_PERMISSION: '&8&l» &eCommande inconnue. Fais &c/help &epour afficher l''assistance.' +NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin d''ajouter des coopérateurs à l''île.' NO_DELETE_WARP_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de supprimer des warps.' NO_DEMOTE_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de rétrograder des joueurs.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 4296dbee57..7c6a2baec6 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -576,7 +576,7 @@ NAME_TOO_SHORT: '&c&lErrore | &7I nomi delle isole non possono avere una lunghez NO_BAN_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per poter vietare i giocatori.' NO_CLOSE_BYPASS: '&c&lErrore | &7Quest''isola non è aperta al pubblico.' NO_CLOSE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per chiudere l''isola al pubblico.' -NO_COMMAND_PERMISSION: '&fComando sconosciuto. Digita "/help" se ti serve aiuto.' +NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per aggiungere giocatori come membri coop.' NO_DELETE_WARP_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per eliminare le warp.' NO_DEMOTE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per degradare i giocatori.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index df44078f93..7d238bbe8c 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -590,7 +590,7 @@ NAME_TOO_SHORT: '&c&lהאיגש | &7םיוות 3 מ תוחפ תויהל םילו NO_BAN_PERMISSION: '&c&lהאיגש | &7םינקחש קיחרהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_CLOSE_BYPASS: '&c&lהאיגש | &7רוביצל חותפ אל הזה יאה.' NO_CLOSE_PERMISSION: '&c&lהאיגש | &7רוביצל יאה תא רוגסל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' -NO_COMMAND_PERMISSION: '&fUnknown command. Type "/help" for help.' +NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lהאיגש | &7הלועפ יפתשמכ םינקחש ףיסוהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_DELETE_WARP_PERMISSION: '&c&lהאיגש | &7םימוקימ קוחמל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_DEMOTE_PERMISSION: '&c&lהאיגש | &7המרב םינקחש דירוהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 06f1b46325..e8cc27ebf3 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -568,7 +568,7 @@ NAME_TOO_SHORT: '&c&lBlad | &7Nazwy wysp nie moga miec mniej niz 3 znaki.' NO_BAN_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby blokowac graczy.' NO_CLOSE_BYPASS: '&c&lBlad | &7Ta wyspa nie jest otwarta dla publicznosci.' NO_CLOSE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zamknac wyspe dla publicznosci.' -NO_COMMAND_PERMISSION: '&fNieznane polecenie. Wpisz "/help", aby uzyskac pomoc.' +NO_COMMAND_PERMISSION: '&c&lBlad | &7Nie masz uprawnien do uzycia tego polecenia. ({0})' NO_COOP_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby dodawac graczy jako czlonków trybu wspólpracy.' NO_DELETE_WARP_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby usunac wypaczenia.' NO_DEMOTE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zdegradowac graczy.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 95df74b030..3990eac663 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -568,7 +568,7 @@ NAME_TOO_SHORT: '&c&lErro | &7Os nomes de ilhas não podem ter menos de 3 caract NO_BAN_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para banir jogadores.' NO_CLOSE_BYPASS: '&c&lErro | &7Esta ilha não está aberta ao público.' NO_CLOSE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para fechar a ilha ao público.' -NO_COMMAND_PERMISSION: '&fComando desconhecido. Digite "/help" para obter ajuda.' +NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para adicionar jogadores como membros cooperativos.' NO_DELETE_WARP_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para excluir warps.' NO_DEMOTE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para rebaixar jogadores.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 7a43635be1..0ef91b296b 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -568,7 +568,7 @@ NAME_TOO_SHORT: '&c&lОшибка | &7Имена островов не могу NO_BAN_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы забанить игроков.' NO_CLOSE_BYPASS: '&c&lОшибка | &7Этот остров не открыт для публики.' NO_CLOSE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы закрыть остров для публики.' -NO_COMMAND_PERMISSION: '&fНеизвестная команда. Введите "/help" для получения помощи.' +NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы добавлять игроков как соучастников.' NO_DELETE_WARP_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы удалять варпы.' NO_DEMOTE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы понижать игроков.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 776ce1e435..62a608df41 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -670,7 +670,7 @@ NAME_TOO_SHORT: '&c&lHata | &7Ada adları 3 karakterden kısa olamaz.' NO_BAN_PERMISSION: '&c&lHata | &7Oyuncuları yasaklayabilmek için en az {0} olmalısın.' NO_CLOSE_BYPASS: '&c&lHata | &7Bu ada halka açık değil.' NO_CLOSE_PERMISSION: '&c&lHata | &7Adanı halka kapatabilmek için en az {0} olmalısın.' -NO_COMMAND_PERMISSION: '&fBilinmeyen komut. Yardım için "/help" yaz.' +NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lHata | &7Oyuncuları co-op üyesi olarak ekleyebilmek için en az {0} olmalısın.' NO_DELETE_WARP_PERMISSION: '&c&lHata | &7Işınlanmaları silebilmek için en az {0} olmalısın.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 29deb17a1e..d344ab3c8d 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -632,7 +632,7 @@ NAME_TOO_SHORT: '&c&lLỗi | &7Tên đảo không thể ngắn hơn 3 ký tự.' NO_BAN_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để cấm người chơi.' NO_CLOSE_BYPASS: '&c&lLỗi | &7Hòn đảo này không mở cửa cho công cộng.' NO_CLOSE_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để đóng đảo với công cộng.' -NO_COMMAND_PERMISSION: '&fLệnh không xác định. Nhấn "/help" để được trợ giúp.' +NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&lLỗi | &7Bạn phải là {0} hoặc cao hơn để thêm người chơi với tư cách là thành viên co-op.' NO_DELETE_WARP_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để xóa khu vực.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 194583b107..3901a14d5c 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -568,7 +568,7 @@ NAME_TOO_SHORT: '&c&l错误 | &7岛屿名称不能短于 3 个字符.' NO_BAN_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可封禁玩家.' NO_CLOSE_BYPASS: '&c&l错误 | &7该岛屿不对公众开放.' NO_CLOSE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将岛屿对公众开放.' -NO_COMMAND_PERMISSION: '&f未知命令. 请输入 "/help" 获取帮助.' +NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' NO_COOP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将玩家添加为合作成员.' NO_DELETE_WARP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可删除传送点.' NO_DEMOTE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可降职玩家.' From 00f316686fb4506cf53c49d14053db95c68f0fca Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 22 Aug 2025 18:04:19 +0300 Subject: [PATCH 253/600] [CI SKIP] Move configurations of builtin modules to their own classes --- .../commands/admin/CmdAdminDisband.java | 6 +- .../commands/player/CmdDisband.java | 5 +- .../serialization/IslandsDeserializer.java | 29 +- .../core/menu/button/impl/DisbandButton.java | 5 +- .../superiorskyblock/island/SIsland.java | 51 +-- .../island/bank/SIslandBank.java | 5 +- .../module/BuiltinModule.java | 84 +++-- .../module/IModuleConfiguration.java | 7 + .../module/bank/BankModule.java | 148 +++++---- .../module/generators/GeneratorsModule.java | 68 ++-- .../listeners/GeneratorsListener.java | 14 +- .../module/missions/MissionsModule.java | 297 +++++++++--------- .../module/upgrades/UpgradesModule.java | 166 +++++----- 13 files changed, 484 insertions(+), 401 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/module/IModuleConfiguration.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDisband.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDisband.java index 23dc5e24ba..43f91e746a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDisband.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDisband.java @@ -72,10 +72,10 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab else Message.DISBANDED_ISLAND_OTHER.send(sender, targetPlayer.getName()); - if (BuiltinModules.BANK.disbandRefund > 0) { + if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) { + BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund(); Message.DISBAND_ISLAND_BALANCE_REFUND.send(island.getOwner(), - Formatters.NUMBER_FORMATTER.format(island.getIslandBank() - .getBalance().multiply(BigDecimal.valueOf(BuiltinModules.BANK.disbandRefund)))); + Formatters.NUMBER_FORMATTER.format(island.getIslandBank().getBalance().multiply(disbandRefund))); } island.disbandIsland(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java index 884b5cf6bb..79d6481157 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDisband.java @@ -79,9 +79,10 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer Message.DISBANDED_ISLAND.send(superiorPlayer); - if (BuiltinModules.BANK.disbandRefund > 0) { + if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) { + BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund(); Message.DISBAND_ISLAND_BALANCE_REFUND.send(island.getOwner(), Formatters.NUMBER_FORMATTER.format( - island.getIslandBank().getBalance().multiply(BigDecimal.valueOf(BuiltinModules.BANK.disbandRefund)))); + island.getIslandBank().getBalance().multiply(disbandRefund))); } if (plugin.getSettings().getDisbandCount() >= 0) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java index e66e9fc89d..e65a2b8279 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java @@ -29,7 +29,6 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; @@ -736,20 +735,22 @@ public static void deserializeIslandSettings(DatabaseBridge databaseBridge, Data } public static void deserializeBankTransactions(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { - if (BuiltinModules.BANK.bankLogs && BuiltinModules.BANK.cacheAllLogs) { - databaseBridge.loadAllObjects("bank_transactions", bankTransactionRow -> { - DatabaseResult bankTransaction = new DatabaseResult(bankTransactionRow); - - Optional uuid = bankTransaction.getUUID("island"); - if (!uuid.isPresent()) { - Log.warn("Cannot load bank transaction for null islands, skipping..."); - return; - } + if (!BuiltinModules.BANK.getConfiguration().isBankLogs() || + !BuiltinModules.BANK.getConfiguration().isCacheAllLogs()) + return; - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); - SBankTransaction.fromDatabase(bankTransaction).ifPresent(builder::addBankTransaction); - }); - } + databaseBridge.loadAllObjects("bank_transactions", bankTransactionRow -> { + DatabaseResult bankTransaction = new DatabaseResult(bankTransactionRow); + + Optional uuid = bankTransaction.getUUID("island"); + if (!uuid.isPresent()) { + Log.warn("Cannot load bank transaction for null islands, skipping..."); + return; + } + + Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + SBankTransaction.fromDatabase(bankTransaction).ifPresent(builder::addBankTransaction); + }); } public static void deserializePersistentDataContainer(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java index 3b1d71e1d5..a8cbfafecb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/DisbandButton.java @@ -43,9 +43,10 @@ public void onButtonClick(InventoryClickEvent clickEvent) { Message.DISBANDED_ISLAND.send(inventoryViewer); - if (BuiltinModules.BANK.disbandRefund > 0) { + if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) { + BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund(); Message.DISBAND_ISLAND_BALANCE_REFUND.send(targetIsland.getOwner(), Formatters.NUMBER_FORMATTER.format( - targetIsland.getIslandBank().getBalance().multiply(BigDecimal.valueOf(BuiltinModules.BANK.disbandRefund)))); + targetIsland.getIslandBank().getBalance().multiply(disbandRefund))); } if (plugin.getSettings().getDisbandCount() >= 0) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index d12e92dd94..99d473130b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -1790,9 +1790,10 @@ public void disbandIsland() { invitedPlayers.forEach(invitedPlayer -> invitedPlayer.removeInvite(this)); - if (BuiltinModules.BANK.disbandRefund > 0) - plugin.getProviders().depositMoney(getOwner(), islandBank.getBalance() - .multiply(BigDecimal.valueOf(BuiltinModules.BANK.disbandRefund))); + if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) { + BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund(); + plugin.getProviders().depositMoney(getOwner(), islandBank.getBalance().multiply(disbandRefund)); + } plugin.getMissions().getIslandMissions().forEach(this::resetMission); @@ -2311,14 +2312,17 @@ public boolean giveInterest(boolean checkOnlineOwner) { long currentTime = System.currentTimeMillis() / 1000; - if (checkOnlineOwner && BuiltinModules.BANK.bankInterestRecentActive > 0 && - currentTime - owner.getLastTimeStatus() > BuiltinModules.BANK.bankInterestRecentActive) { + int bankInterestRecentActive = BuiltinModules.BANK.getConfiguration().getBankInterestRecentActive(); + if (checkOnlineOwner && bankInterestRecentActive > 0 && + currentTime - owner.getLastTimeStatus() > bankInterestRecentActive) { Log.debugResult(Debug.GIVE_BANK_INTEREST, "Return Cooldown", owner.getName()); return false; } + int bankInterestPercentage = BuiltinModules.BANK.getConfiguration().getBankInterestPercentage(); + BigDecimal balance = islandBank.getBalance().max(BigDecimal.ONE); - BigDecimal balanceToGive = balance.multiply(new BigDecimal(BuiltinModules.BANK.bankInterestPercentage / 100D)); + BigDecimal balanceToGive = balance.multiply(new BigDecimal(bankInterestPercentage / 100D)); // If the money that will be given exceeds limit, we want to give money later. if (!islandBank.canDepositMoney(balanceToGive)) { @@ -2349,8 +2353,8 @@ public void setLastInterestTime(long lastInterest) { if (this.lastInterest == lastInterest) return; - if (BuiltinModules.BANK.bankInterestEnabled) { - long ticksToNextInterest = BuiltinModules.BANK.bankInterestInterval * 20L; + if (BuiltinModules.BANK.getConfiguration().isBankInterestEnabled()) { + long ticksToNextInterest = BuiltinModules.BANK.getConfiguration().getBankInterestInterval() * 20L; this.bankInterestTask.set(bankInterestTask -> { if (bankInterestTask != null) bankInterestTask.cancel(); @@ -2365,7 +2369,8 @@ public void setLastInterestTime(long lastInterest) { @Override public long getNextInterest() { long currentTime = System.currentTimeMillis() / 1000; - return BuiltinModules.BANK.bankInterestInterval - (currentTime - lastInterest); + int bankInterestInterval = BuiltinModules.BANK.getConfiguration().getBankInterestInterval(); + return bankInterestInterval - (currentTime - lastInterest); } /* @@ -2851,7 +2856,7 @@ public IslandBlocksTrackerAlgorithm getBlocksTracker() { @Override public BigDecimal getWorth() { - double bankWorthRate = BuiltinModules.BANK.bankWorthRate; + double bankWorthRate = BuiltinModules.BANK.getConfiguration().getBankWorthRate(); BigDecimal islandWorth = this.islandWorth.get(); BigDecimal islandBank = this.islandBank.getBalance(); @@ -4929,18 +4934,20 @@ private IslandChest[] createDefaultIslandChests() { } private void startBankInterest() { - if (BuiltinModules.BANK.bankInterestEnabled) { - long currentTime = System.currentTimeMillis() / 1000; - long ticksToNextInterest = (BuiltinModules.BANK.bankInterestInterval - (currentTime - this.lastInterest)) * 20; - if (ticksToNextInterest <= 0) { - giveInterest(true); - } else { - this.bankInterestTask.set(bankInterestTask -> { - if (bankInterestTask != null) - bankInterestTask.cancel(); - return BukkitExecutor.sync(() -> giveInterest(true), ticksToNextInterest); - }); - } + if (!BuiltinModules.BANK.getConfiguration().isBankInterestEnabled()) + return; + + int bankInterestInterval = BuiltinModules.BANK.getConfiguration().getBankInterestInterval(); + long currentTime = System.currentTimeMillis() / 1000; + long ticksToNextInterest = (bankInterestInterval - (currentTime - this.lastInterest)) * 20; + if (ticksToNextInterest <= 0) { + giveInterest(true); + } else { + this.bankInterestTask.set(bankInterestTask -> { + if (bankInterestTask != null) + bankInterestTask.cancel(); + return BukkitExecutor.sync(() -> giveInterest(true), ticksToNextInterest); + }); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java index c175261865..19d0223dd4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java @@ -51,7 +51,8 @@ public class SIslandBank implements IslandBank { public SIslandBank(Island island, Supplier isGiveInterestFailed) { this.island = island; this.isGiveInterestFailed = isGiveInterestFailed; - this.bankLogs = BuiltinModules.BANK.cacheAllLogs ? new CacheBankLogs() : new DatabaseBankLogs(island); + this.bankLogs = BuiltinModules.BANK.getConfiguration().isCacheAllLogs() ? + new CacheBankLogs() : new DatabaseBankLogs(island); } @Override @@ -284,7 +285,7 @@ public void loadTransaction(BankTransaction bankTransaction) { } private void addTransaction(BankTransaction bankTransaction, boolean save) { - if (!BuiltinModules.BANK.bankLogs) + if (!BuiltinModules.BANK.getConfiguration().isBankLogs()) return; UUID senderUUID = bankTransaction.getPlayer(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java index 3f6a96585b..8c2e2fed97 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java @@ -10,10 +10,11 @@ import org.bukkit.event.Listener; import java.io.File; +import java.util.Objects; -public abstract class BuiltinModule extends PluginModule { +public abstract class BuiltinModule extends PluginModule { - protected CommentedConfiguration config = null; + protected T configuration; public BuiltinModule(String moduleName) { super(moduleName, "Ome_R"); @@ -24,33 +25,54 @@ public final void onEnable(SuperiorSkyblock plugin) { onEnable((SuperiorSkyblockPlugin) plugin); } + protected abstract void onEnable(SuperiorSkyblockPlugin plugin); + @Override public final void onReload(SuperiorSkyblock plugin) { onReload((SuperiorSkyblockPlugin) plugin); } + protected void onReload(SuperiorSkyblockPlugin plugin) { + onPluginInit(plugin); + } + @Override public void onDisable(SuperiorSkyblock plugin) { onDisable((SuperiorSkyblockPlugin) plugin); } + protected abstract void onDisable(SuperiorSkyblockPlugin plugin); + + @Override public void loadData(SuperiorSkyblock plugin) { loadData((SuperiorSkyblockPlugin) plugin); } + protected abstract void loadData(SuperiorSkyblockPlugin plugin); + @Override public Listener[] getModuleListeners(SuperiorSkyblock plugin) { - return getModuleListeners((SuperiorSkyblockPlugin) plugin); + return !isEnabled() ? null : getModuleListeners((SuperiorSkyblockPlugin) plugin); } + protected abstract Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin); + @Override public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblock plugin) { - return getSuperiorCommands((SuperiorSkyblockPlugin) plugin); + return !isEnabled() ? null : getSuperiorCommands((SuperiorSkyblockPlugin) plugin); } + protected abstract SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin); + @Override public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblock plugin) { - return getSuperiorAdminCommands((SuperiorSkyblockPlugin) plugin); + return !isEnabled() ? null : getSuperiorAdminCommands((SuperiorSkyblockPlugin) plugin); + } + + protected abstract SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin); + + public final T getConfiguration() { + return Objects.requireNonNull(this.configuration); } @Override @@ -59,8 +81,24 @@ protected void onPluginInit(SuperiorSkyblock plugin) { } protected void onPluginInit(SuperiorSkyblockPlugin plugin) { - File configFile = createConfig(); - config = CommentedConfiguration.loadConfiguration(configFile); + File configFile = new File(getModuleFolder(), "config.yml"); + boolean firstTime = false; + + if (!configFile.exists()) { + Resources.saveResource("modules/" + getName() + "/config.yml"); + firstTime = true; + } + + CommentedConfiguration config = CommentedConfiguration.loadConfiguration(configFile); + + boolean commitChanges = onConfigCreate(plugin, config, firstTime); + if (commitChanges) { + try { + config.save(configFile); + } catch (Exception error) { + Log.error(error, "An error occurred while saving config file for module " + getName() + ":"); + } + } try { config.syncWithConfig(configFile, @@ -71,37 +109,19 @@ protected void onPluginInit(SuperiorSkyblockPlugin plugin) { Log.error(error, "An error occurred while loading config file:"); } - updateConfig(plugin); - } - - public File createConfig() { - File configFile = new File(getModuleFolder(), "config.yml"); - - if (!configFile.exists()) - Resources.saveResource("modules/" + getName() + "/config.yml"); - return configFile; + this.configuration = createConfigFile(config); } - public abstract void onEnable(SuperiorSkyblockPlugin plugin); - - public void onReload(SuperiorSkyblockPlugin plugin) { - onPluginInit(plugin); + protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) { + return false; } - public abstract void onDisable(SuperiorSkyblockPlugin plugin); - - public abstract void loadData(SuperiorSkyblockPlugin plugin); - - public abstract Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin); - - public abstract SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin); - - public abstract SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin); - - public abstract boolean isEnabled(); + public boolean isEnabled() { + return this.configuration.isEnabled() && isInitialized(); + } - protected abstract void updateConfig(SuperiorSkyblockPlugin plugin); + protected abstract T createConfigFile(CommentedConfiguration config); protected String[] getIgnoredSections() { return new String[0]; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/IModuleConfiguration.java b/src/main/java/com/bgsoftware/superiorskyblock/module/IModuleConfiguration.java new file mode 100644 index 0000000000..75cef37737 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/IModuleConfiguration.java @@ -0,0 +1,7 @@ +package com.bgsoftware.superiorskyblock.module; + +public interface IModuleConfiguration { + + boolean isEnabled(); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java index c1525b321d..5359382acf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java @@ -3,70 +3,53 @@ import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; -import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.module.BuiltinModule; +import com.bgsoftware.superiorskyblock.module.IModuleConfiguration; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminDeposit; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminWithdraw; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdBalance; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdBank; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdDeposit; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdWithdraw; -import com.bgsoftware.superiorskyblock.module.BuiltinModule; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.Listener; import java.io.File; +import java.math.BigDecimal; -public class BankModule extends BuiltinModule { - - public double bankWorthRate = 1000; - public double disbandRefund = 0; - public boolean bankLogs = true; - public boolean cacheAllLogs = false; - public boolean bankInterestEnabled = true; - public int bankInterestInterval = 86400; - public int bankInterestPercentage = 10; - public int bankInterestRecentActive = 86400; - private boolean enabled = true; +public class BankModule extends BuiltinModule { public BankModule() { super("bank"); } @Override - protected void onPluginInit(SuperiorSkyblockPlugin plugin) { - super.onPluginInit(plugin); - - File configFile = new File(plugin.getDataFolder(), "config.yml"); - CommentedConfiguration config = CommentedConfiguration.loadConfiguration(configFile); + protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) { + File oldConfigFile = new File(plugin.getDataFolder(), "config.yml"); + if (!oldConfigFile.exists()) + return false; + CommentedConfiguration oldConfig = CommentedConfiguration.loadConfiguration(oldConfigFile); boolean updatedConfig = false; - if (syncValues("bank-worth-rate", config)) + if (syncValues("bank-worth-rate", config, oldConfig)) updatedConfig = true; - if (syncValues("disband-refund", config)) + if (syncValues("disband-refund", config, oldConfig)) updatedConfig = true; - if (syncValues("bank-logs", config)) + if (syncValues("bank-logs", config, oldConfig)) updatedConfig = true; - if (syncValues("cache-logs", config)) + if (syncValues("cache-logs", config, oldConfig)) updatedConfig = true; - if (syncValues("bank-interest", config)) + if (syncValues("bank-interest", config, oldConfig)) updatedConfig = true; - if (updatedConfig) { - File moduleConfigFile = new File(getModuleFolder(), "config.yml"); + oldConfigFile.delete(); - try { - super.config.save(moduleConfigFile); - config.save(configFile); - } catch (Exception error) { - Log.entering("BankModule", "onPluginInit", "ENTER"); - Log.error(error, "An error occurred while saving config file:"); - } - } + return updatedConfig; } @Override @@ -91,41 +74,96 @@ public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) { @Override public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) { - return !enabled ? null : new SuperiorCommand[]{new CmdBalance(), new CmdBank(), new CmdDeposit(), new CmdWithdraw()}; + return new SuperiorCommand[]{new CmdBalance(), new CmdBank(), new CmdDeposit(), new CmdWithdraw()}; } @Override public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) { - return !enabled ? null : new SuperiorCommand[]{new CmdAdminDeposit(), new CmdAdminWithdraw()}; - } - - @Override - public boolean isEnabled() { - return enabled && isInitialized(); + return new SuperiorCommand[]{new CmdAdminDeposit(), new CmdAdminWithdraw()}; } @Override - protected void updateConfig(SuperiorSkyblockPlugin plugin) { - enabled = config.getBoolean("enabled"); - int bankWorthRate = config.getInt("bank-worth-rate", 1000); - this.bankWorthRate = bankWorthRate == 0 ? 0D : 1D / bankWorthRate; - disbandRefund = Math.max(0, Math.min(100, config.getDouble("disband-refund"))) / 100D; - bankLogs = config.getBoolean("bank-logs", true); - cacheAllLogs = config.getBoolean("cache-logs", true); - bankInterestEnabled = config.getBoolean("bank-interest.enabled", true); - bankInterestInterval = config.getInt("bank-interest.interval", 86400); - bankInterestPercentage = config.getInt("bank-interest.percentage", 10); - bankInterestRecentActive = config.getInt("bank-interest.recent-active", 86400); + protected Configuration createConfigFile(CommentedConfiguration config) { + return new Configuration(config); } - private boolean syncValues(String section, YamlConfiguration config) { - if (config.contains(section)) { - super.config.set(section, config.get(section)); - config.set(section, null); + private static boolean syncValues(String section, YamlConfiguration newConfig, YamlConfiguration oldConfig) { + if (oldConfig.contains(section)) { + newConfig.set(section, oldConfig.get(section)); return true; } return false; } + public static class Configuration implements IModuleConfiguration { + + private final boolean enabled; + private final double bankWorthRate; + private final boolean hasDisbandRefund; + private final BigDecimal disbandRefund; + private final boolean bankLogs; + private final boolean cacheAllLogs; + private final boolean bankInterestEnabled; + private final int bankInterestInterval; + private final int bankInterestPercentage; + private final int bankInterestRecentActive; + + Configuration(CommentedConfiguration config) { + this.enabled = config.getBoolean("enabled"); + int bankWorthRate = config.getInt("bank-worth-rate", 1000); + this.bankWorthRate = bankWorthRate == 0 ? 0D : 1D / bankWorthRate; + double disbandRefund = Math.max(0, Math.min(100, config.getDouble("disband-refund"))) / 100D; + this.hasDisbandRefund = disbandRefund > 0; + this.disbandRefund = BigDecimal.valueOf(disbandRefund); + this.bankLogs = config.getBoolean("bank-logs", true); + this.cacheAllLogs = config.getBoolean("cache-logs", true); + this.bankInterestEnabled = config.getBoolean("bank-interest.enabled", true); + this.bankInterestInterval = config.getInt("bank-interest.interval", 86400); + this.bankInterestPercentage = config.getInt("bank-interest.percentage", 10); + this.bankInterestRecentActive = config.getInt("bank-interest.recent-active", 86400); + } + + @Override + public boolean isEnabled() { + return this.enabled; + } + + public double getBankWorthRate() { + return bankWorthRate; + } + + public boolean hasDisbandRefund() { + return hasDisbandRefund; + } + + public BigDecimal getDisbandRefund() { + return disbandRefund; + } + + public boolean isBankLogs() { + return bankLogs; + } + + public boolean isCacheAllLogs() { + return cacheAllLogs; + } + + public boolean isBankInterestEnabled() { + return bankInterestEnabled; + } + + public int getBankInterestInterval() { + return bankInterestInterval; + } + + public int getBankInterestPercentage() { + return bankInterestPercentage; + } + + public int getBankInterestRecentActive() { + return bankInterestRecentActive; + } + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/GeneratorsModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/GeneratorsModule.java index 8bc43e4089..3c67cca8c6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/GeneratorsModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/GeneratorsModule.java @@ -3,47 +3,36 @@ import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; -import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.module.BuiltinModule; +import com.bgsoftware.superiorskyblock.module.IModuleConfiguration; import com.bgsoftware.superiorskyblock.module.generators.commands.CmdAdminAddGenerator; import com.bgsoftware.superiorskyblock.module.generators.commands.CmdAdminClearGenerator; import com.bgsoftware.superiorskyblock.module.generators.commands.CmdAdminSetGenerator; -import com.bgsoftware.superiorskyblock.module.BuiltinModule; import com.bgsoftware.superiorskyblock.module.generators.listeners.GeneratorsListener; import org.bukkit.event.Listener; import java.io.File; -public class GeneratorsModule extends BuiltinModule { - - private boolean enabled = true; - private boolean matchGeneratorWorld = true; +public class GeneratorsModule extends BuiltinModule { public GeneratorsModule() { super("generators"); } @Override - protected void onPluginInit(SuperiorSkyblockPlugin plugin) { - super.onPluginInit(plugin); - - File configFile = new File(plugin.getDataFolder(), "config.yml"); - CommentedConfiguration config = CommentedConfiguration.loadConfiguration(configFile); + protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) { + File oldConfigFile = new File(plugin.getDataFolder(), "config.yml"); + if (!oldConfigFile.exists()) + return false; - if (config.contains("generators")) { - super.config.set("enabled", config.getBoolean("generators")); - config.set("generators", null); + CommentedConfiguration oldConfig = CommentedConfiguration.loadConfiguration(oldConfigFile); + boolean updatedConfig = false; - File moduleConfigFile = new File(getModuleFolder(), "config.yml"); - - try { - super.config.save(moduleConfigFile); - config.save(configFile); - } catch (Exception error) { - Log.entering("GeneratorsModule", "onPluginInit", "ENTER"); - Log.error(error, "An error occurred while saving config file:"); - } + if (oldConfig.contains("generators")) { + config.set("enabled", oldConfig.getBoolean("generators")); } + return updatedConfig; } @Override @@ -63,7 +52,7 @@ public void loadData(SuperiorSkyblockPlugin plugin) { @Override public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) { - return !enabled ? null : new Listener[]{new GeneratorsListener(plugin, this)}; + return new Listener[]{new GeneratorsListener(plugin)}; } @Override @@ -73,22 +62,33 @@ public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) { @Override public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) { - return !enabled ? null : new SuperiorCommand[]{new CmdAdminAddGenerator(), new CmdAdminClearGenerator(), new CmdAdminSetGenerator()}; + return new SuperiorCommand[]{new CmdAdminAddGenerator(), new CmdAdminClearGenerator(), new CmdAdminSetGenerator()}; } @Override - public boolean isEnabled() { - return enabled && isInitialized(); + protected Configuration createConfigFile(CommentedConfiguration config) { + return new Configuration(config); } - @Override - protected void updateConfig(SuperiorSkyblockPlugin plugin) { - enabled = config.getBoolean("enabled"); - matchGeneratorWorld = config.getBoolean("match-generator-world"); - } + public static class Configuration implements IModuleConfiguration { + + private final boolean enabled; + private final boolean matchGeneratorWorld; + + Configuration(CommentedConfiguration config) { + this.enabled = config.getBoolean("enabled"); + this.matchGeneratorWorld = config.getBoolean("match-generator-world"); + } + + @Override + public boolean isEnabled() { + return this.enabled; + } + + public boolean isMatchGeneratorWorld() { + return this.matchGeneratorWorld; + } - public boolean isMatchGeneratorWorld() { - return matchGeneratorWorld; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java index 78d18de3d1..299f3f7683 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java @@ -6,7 +6,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.module.generators.GeneratorsModule; +import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.GeneratorType; import org.bukkit.Location; @@ -28,16 +28,14 @@ public class GeneratorsListener implements Listener { private static final Material LAVA_MATERIAL = EnumHelper.getEnum(Material.class, "STATIONARY_LAVA", "LAVA"); private final SuperiorSkyblockPlugin plugin; - private final GeneratorsModule module; - public GeneratorsListener(SuperiorSkyblockPlugin plugin, GeneratorsModule module) { + public GeneratorsListener(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - this.module = module; } @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBlockFormEvent(BlockFormEvent e) { - if (!module.isEnabled()) + if (!BuiltinModules.GENERATORS.isEnabled()) return; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { @@ -55,7 +53,7 @@ public void onBlockFormEvent(BlockFormEvent e) { return; Dimension dimension; - if (module.isMatchGeneratorWorld()) { + if (BuiltinModules.GENERATORS.getConfiguration().isMatchGeneratorWorld()) { dimension = Dimensions.NETHER; } else { World blockWorld = blockLocation.getWorld(); @@ -72,7 +70,7 @@ public void onBlockFormEvent(BlockFormEvent e) { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBlockFromToEvent(BlockFromToEvent e) { - if (!module.isEnabled()) + if (!BuiltinModules.GENERATORS.isEnabled()) return; Block block = e.getToBlock(); @@ -99,7 +97,7 @@ public void onBlockFromToEvent(BlockFromToEvent e) { return; Dimension dimension; - if (module.isMatchGeneratorWorld()) { + if (BuiltinModules.GENERATORS.getConfiguration().isMatchGeneratorWorld()) { dimension = generatorType == GeneratorType.BASALT ? Dimensions.NETHER : Dimensions.NORMAL; } else { dimension = Optional.ofNullable(plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(blockWorld)) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java index 3b46886c08..4925e814bf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java @@ -16,6 +16,7 @@ import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandMembers; import com.bgsoftware.superiorskyblock.mission.SMissionCategory; import com.bgsoftware.superiorskyblock.module.BuiltinModule; +import com.bgsoftware.superiorskyblock.module.IModuleConfiguration; import com.bgsoftware.superiorskyblock.module.missions.commands.CmdAdminMission; import com.bgsoftware.superiorskyblock.module.missions.commands.CmdMission; import com.bgsoftware.superiorskyblock.module.missions.commands.CmdMissions; @@ -32,82 +33,36 @@ import java.util.List; import java.util.Map; -public class MissionsModule extends BuiltinModule { +public class MissionsModule extends BuiltinModule { - private static final int MAX_MISSIONS_NAME_LENGTH = 255; - - private final List> missionsToLoad = new LinkedList<>(); + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private boolean enabled = true; + private static final String[] IGNORED_SECTIONS = new String[]{"categories"}; + private static final int MAX_MISSIONS_NAME_LENGTH = 255; public MissionsModule() { super("missions"); } - private void generateDefaultFiles() { - Resources.copyResource("modules/missions/BlocksMissions"); - Resources.copyResource("modules/missions/BrewingMissions"); - Resources.copyResource("modules/missions/CraftingMissions"); - Resources.copyResource("modules/missions/EnchantingMissions"); - Resources.copyResource("modules/missions/FarmingMissions"); - Resources.copyResource("modules/missions/FishingMissions"); - Resources.copyResource("modules/missions/IslandMissions"); - Resources.copyResource("modules/missions/ItemsMissions"); - Resources.copyResource("modules/missions/KillsMissions"); - Resources.copyResource("modules/missions/StatisticsMissions"); - - File categoriesFolder = new File(getModuleFolder(), "categories"); - - if ((!categoriesFolder.exists() || !categoriesFolder.isDirectory()) && categoriesFolder.mkdirs()) { - Resources.saveResource("modules/missions/categories/farmer/farmer_1.yml"); - Resources.saveResource("modules/missions/categories/farmer/farmer_2.yml"); - Resources.saveResource("modules/missions/categories/farmer/farmer_3.yml"); - Resources.saveResource("modules/missions/categories/farmer/farmer_4.yml"); - Resources.saveResource("modules/missions/categories/farmer/farmer_5.yml"); - Resources.saveResource("modules/missions/categories/miner/miner_1.yml"); - Resources.saveResource("modules/missions/categories/miner/miner_2.yml"); - Resources.saveResource("modules/missions/categories/miner/miner_3.yml"); - Resources.saveResource("modules/missions/categories/miner/miner_4.yml"); - Resources.saveResource("modules/missions/categories/miner/miner_5.yml"); - Resources.saveResource("modules/missions/categories/slayer/slayer_1.yml"); - Resources.saveResource("modules/missions/categories/slayer/slayer_2.yml"); - Resources.saveResource("modules/missions/categories/slayer/slayer_3.yml"); - Resources.saveResource("modules/missions/categories/slayer/slayer_4.yml"); - Resources.saveResource("modules/missions/categories/fisherman/fisherman_1.yml"); - Resources.saveResource("modules/missions/categories/fisherman/fisherman_2.yml"); - Resources.saveResource("modules/missions/categories/fisherman/fisherman_3.yml"); - Resources.saveResource("modules/missions/categories/explorer/explorer_1.yml"); - Resources.saveResource("modules/missions/categories/explorer/explorer_2.yml"); - } - } - @Override - protected void onPluginInit(SuperiorSkyblockPlugin plugin) { - File file = new File(getModuleFolder(), "config.yml"); - - if (!file.exists()) - Resources.saveResource("modules/missions/config.yml"); + protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) { + boolean updatedConfig = false; - config = CommentedConfiguration.loadConfiguration(file); + if (convertOldMissions(plugin, config)) + updatedConfig = true; + if (convertNonCategorizedMissions(plugin, config)) + updatedConfig = true; - convertOldMissions(plugin, file, config); - convertNonCategorizedMissions(plugin, file, config); - generateDefaultFiles(); - - try { - config.syncWithConfig(file, Resources.getResource("modules/missions/config.yml"), getIgnoredSections()); - } catch (Exception error) { - Log.entering("MissionsModule", "onPluginInit", "ENTER"); - Log.error(error, "An error occurred while saving config file:"); + if (firstTime) { + generateDefaultFiles(); } - updateConfig(plugin); + return updatedConfig; } @Override - public void onEnable(SuperiorSkyblockPlugin plugin) { - if (enabled) - loadMissionCategories(plugin); + protected void onEnable(SuperiorSkyblockPlugin plugin) { + // Do nothing } @Override @@ -122,12 +77,13 @@ public void onReload(SuperiorSkyblockPlugin plugin) { @Override public void onDisable(SuperiorSkyblockPlugin plugin) { - if (enabled) + if (isEnabled()) plugin.getMissions().saveMissionsData(); } @Override public void loadData(SuperiorSkyblockPlugin plugin) { + List> missionsToLoad = this.configuration.missionsToLoad; if (!missionsToLoad.isEmpty()) { plugin.getMissions().loadMissionsData(missionsToLoad); missionsToLoad.clear(); @@ -141,125 +97,139 @@ public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) { @Override public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) { - return !enabled ? null : new SuperiorCommand[]{new CmdMission(), new CmdMissions()}; + return new SuperiorCommand[]{new CmdMission(), new CmdMissions()}; } @Override public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) { - return !enabled ? null : new SuperiorCommand[]{new CmdAdminMission()}; + return new SuperiorCommand[]{new CmdAdminMission()}; } @Override - public boolean isEnabled() { - return enabled && isInitialized(); + protected String[] getIgnoredSections() { + return IGNORED_SECTIONS; } @Override - protected void updateConfig(SuperiorSkyblockPlugin plugin) { - enabled = config.getBoolean("enabled"); + protected Configuration createConfigFile(CommentedConfiguration config) { + return new Configuration(config); } - @Override - protected String[] getIgnoredSections() { - return new String[]{"categories"}; - } + public class Configuration implements IModuleConfiguration { + + private final boolean enabled; + private final List> missionsToLoad = new LinkedList<>(); + + Configuration(CommentedConfiguration config) { + this.enabled = config.getBoolean("enabled"); + if (this.enabled) { + loadMissionCategories(config); + } + } + + @Override + public boolean isEnabled() { + return this.enabled; + } - private void loadMissionCategories(SuperiorSkyblockPlugin plugin) { - ConfigurationSection categoriesSection = config.getConfigurationSection("categories"); + private void loadMissionCategories(CommentedConfiguration config) { + ConfigurationSection categoriesSection = config.getConfigurationSection("categories"); - if (categoriesSection != null) { - for (String categoryName : categoriesSection.getKeys(false)) { - ConfigurationSection categorySection = categoriesSection.getConfigurationSection(categoryName); + if (categoriesSection != null) { + for (String categoryName : categoriesSection.getKeys(false)) { + ConfigurationSection categorySection = categoriesSection.getConfigurationSection(categoryName); - if (categorySection == null) - continue; + if (categorySection == null) + continue; - List> categoryMissions = new LinkedList<>(); + List> categoryMissions = new LinkedList<>(); - if (!canLoadCategory(plugin, categoryName, categoryMissions)) - continue; + if (!canLoadCategory(categoryName, categoryMissions)) + continue; - int slot = categorySection.getInt("slot"); + int slot = categorySection.getInt("slot"); - String formattedCategoryName = categorySection.getString("name", categoryName); + String formattedCategoryName = categorySection.getString("name", categoryName); - plugin.getMissions().loadMissionCategory(new SMissionCategory(formattedCategoryName, slot, categoryMissions)); + plugin.getMissions().loadMissionCategory(new SMissionCategory(formattedCategoryName, slot, categoryMissions)); - missionsToLoad.addAll(categoryMissions); + missionsToLoad.addAll(categoryMissions); + } } } - } - private boolean canLoadCategory(SuperiorSkyblockPlugin plugin, String categoryName, List> categoryMissions) { - File categoryFolder = new File(getModuleFolder(), "categories/" + categoryName); + private boolean canLoadCategory(String categoryName, List> categoryMissions) { + File categoryFolder = new File(getModuleFolder(), "categories/" + categoryName); - if (!categoryFolder.exists()) { - Log.warn("The directory of the mission category ", categoryName, " doesn't exist, skipping..."); - return false; - } + if (!categoryFolder.exists()) { + Log.warn("The directory of the mission category ", categoryName, " doesn't exist, skipping..."); + return false; + } - if (!categoryFolder.isDirectory()) { - Log.warn("The directory of the mission category ", categoryName, " is not valid, skipping..."); - return false; - } + if (!categoryFolder.isDirectory()) { + Log.warn("The directory of the mission category ", categoryName, " is not valid, skipping..."); + return false; + } - File[] missionFiles = categoryFolder.listFiles(file -> - file.isFile() && file.getName().endsWith(".yml")); + File[] missionFiles = categoryFolder.listFiles(file -> + file.isFile() && file.getName().endsWith(".yml")); - if (missionFiles == null || missionFiles.length == 0) { - Log.warn("The mission category ", categoryName, " doesn't have missions, skipping..."); - return false; - } + if (missionFiles == null || missionFiles.length == 0) { + Log.warn("The mission category ", categoryName, " doesn't have missions, skipping..."); + return false; + } - Map, Integer> missionWeights = new ArrayMap<>(); + Map, Integer> missionWeights = new ArrayMap<>(); - try (FilesLookup filesLookup = FilesLookupFactory.getInstance().lookupFolder(getModuleFolder())) { - for (File missionFile : missionFiles) { - String missionName = missionFile.getName().replace(".yml", ""); + try (FilesLookup filesLookup = FilesLookupFactory.getInstance().lookupFolder(getModuleFolder())) { + for (File missionFile : missionFiles) { + String missionName = missionFile.getName().replace(".yml", ""); - if (missionName.length() > MAX_MISSIONS_NAME_LENGTH) - missionName = missionName.substring(0, MAX_MISSIONS_NAME_LENGTH); + if (missionName.length() > MAX_MISSIONS_NAME_LENGTH) + missionName = missionName.substring(0, MAX_MISSIONS_NAME_LENGTH); - YamlConfiguration missionConfigFile = new YamlConfiguration(); + YamlConfiguration missionConfigFile = new YamlConfiguration(); - try { - missionConfigFile.load(missionFile); - } catch (InvalidConfigurationException error) { - Log.error(error, "A format-error occurred while parsing the mission file ", missionFile.getName() + ":"); - continue; - } catch (IOException error) { - Log.error(error, "An unexpected error occurred while parsing the mission file ", missionFile.getName() + ":"); - continue; - } + try { + missionConfigFile.load(missionFile); + } catch (InvalidConfigurationException error) { + Log.error(error, "A format-error occurred while parsing the mission file ", missionFile.getName() + ":"); + continue; + } catch (IOException error) { + Log.error(error, "An unexpected error occurred while parsing the mission file ", missionFile.getName() + ":"); + continue; + } - ConfigurationSection missionSection = missionConfigFile.getConfigurationSection(""); + ConfigurationSection missionSection = missionConfigFile.getConfigurationSection(""); - Mission mission = plugin.getMissions().loadMission(missionName, categoryName, filesLookup, missionSection); + Mission mission = plugin.getMissions().loadMission(missionName, categoryName, filesLookup, missionSection); - if (mission != null) { - categoryMissions.add(mission); - missionWeights.put(mission, missionSection.getInt("weight", 0)); + if (mission != null) { + categoryMissions.add(mission); + missionWeights.put(mission, missionSection.getInt("weight", 0)); + } } } - } - if (categoryMissions.isEmpty()) { - Log.warn("The mission category ", categoryName, " doesn't have missions, skipping..."); - return false; - } + if (categoryMissions.isEmpty()) { + Log.warn("The mission category ", categoryName, " doesn't have missions, skipping..."); + return false; + } - // Sort missions by their names and weights. - categoryMissions.sort(new MissionsComparator(missionWeights)); + // Sort missions by their names and weights. + categoryMissions.sort(new MissionsComparator(missionWeights)); + + return true; + } - return true; } @SuppressWarnings("ResultOfMethodCallIgnored") - private void convertNonCategorizedMissions(SuperiorSkyblockPlugin plugin, File file, YamlConfiguration config) { + private boolean convertNonCategorizedMissions(SuperiorSkyblockPlugin plugin, YamlConfiguration config) { ConfigurationSection missionsSection = config.getConfigurationSection("missions"); if (missionsSection == null) - return; + return false; ConfigurationSection categoriesSection = config.createSection("categories"); @@ -267,7 +237,7 @@ private void convertNonCategorizedMissions(SuperiorSkyblockPlugin plugin, File f null); if (menuLoadResult == null) - return; + return false; MenuPatternSlots menuPatternSlots = menuLoadResult.getPatternSlots(); YamlConfiguration missionsMenuConfig = menuLoadResult.getConfig(); @@ -319,17 +289,15 @@ private void convertNonCategorizedMissions(SuperiorSkyblockPlugin plugin, File f config.set("missions", ""); - try { - config.save(file); - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while saving missions file:"); - } - copyOldMissionsMenuFile(plugin); + + return true; } @SuppressWarnings("ResultOfMethodCallIgnored") - private void convertOldMissions(SuperiorSkyblockPlugin plugin, File file, YamlConfiguration config) { + private boolean convertOldMissions(SuperiorSkyblockPlugin plugin, YamlConfiguration config) { + boolean updatedConfig = false; + File oldMissionsFolder = new File(plugin.getDataFolder(), "missions"); if (oldMissionsFolder.exists()) { File oldMissionsFile = new File(oldMissionsFolder, "missions.yml"); @@ -338,11 +306,7 @@ private void convertOldMissions(SuperiorSkyblockPlugin plugin, File file, YamlCo YamlConfiguration oldConfig = YamlConfiguration.loadConfiguration(oldMissionsFile); config.set("missions", oldConfig.getConfigurationSection("")); - try { - config.save(file); - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while saving old missions file ", file.getName(), ":"); - } + updatedConfig = true; oldMissionsFile.delete(); } @@ -357,6 +321,8 @@ private void convertOldMissions(SuperiorSkyblockPlugin plugin, File file, YamlCo Files.deleteDirectory(oldMissionsFolder); } + + return updatedConfig; } private void copyOldMissionsMenuFile(SuperiorSkyblockPlugin plugin) { @@ -379,6 +345,43 @@ private void copyOldMissionsMenuFile(SuperiorSkyblockPlugin plugin) { } } + private void generateDefaultFiles() { + Resources.copyResource("modules/missions/BlocksMissions"); + Resources.copyResource("modules/missions/BrewingMissions"); + Resources.copyResource("modules/missions/CraftingMissions"); + Resources.copyResource("modules/missions/EnchantingMissions"); + Resources.copyResource("modules/missions/FarmingMissions"); + Resources.copyResource("modules/missions/FishingMissions"); + Resources.copyResource("modules/missions/IslandMissions"); + Resources.copyResource("modules/missions/ItemsMissions"); + Resources.copyResource("modules/missions/KillsMissions"); + Resources.copyResource("modules/missions/StatisticsMissions"); + + File categoriesFolder = new File(getModuleFolder(), "categories"); + + if ((!categoriesFolder.exists() || !categoriesFolder.isDirectory()) && categoriesFolder.mkdirs()) { + Resources.saveResource("modules/missions/categories/farmer/farmer_1.yml"); + Resources.saveResource("modules/missions/categories/farmer/farmer_2.yml"); + Resources.saveResource("modules/missions/categories/farmer/farmer_3.yml"); + Resources.saveResource("modules/missions/categories/farmer/farmer_4.yml"); + Resources.saveResource("modules/missions/categories/farmer/farmer_5.yml"); + Resources.saveResource("modules/missions/categories/miner/miner_1.yml"); + Resources.saveResource("modules/missions/categories/miner/miner_2.yml"); + Resources.saveResource("modules/missions/categories/miner/miner_3.yml"); + Resources.saveResource("modules/missions/categories/miner/miner_4.yml"); + Resources.saveResource("modules/missions/categories/miner/miner_5.yml"); + Resources.saveResource("modules/missions/categories/slayer/slayer_1.yml"); + Resources.saveResource("modules/missions/categories/slayer/slayer_2.yml"); + Resources.saveResource("modules/missions/categories/slayer/slayer_3.yml"); + Resources.saveResource("modules/missions/categories/slayer/slayer_4.yml"); + Resources.saveResource("modules/missions/categories/fisherman/fisherman_1.yml"); + Resources.saveResource("modules/missions/categories/fisherman/fisherman_2.yml"); + Resources.saveResource("modules/missions/categories/fisherman/fisherman_3.yml"); + Resources.saveResource("modules/missions/categories/explorer/explorer_1.yml"); + Resources.saveResource("modules/missions/categories/explorer/explorer_2.yml"); + } + } + private static class MissionsComparator implements Comparator> { private final Map, Integer> missionWeights; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java index e7ada440de..6b55861cdc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java @@ -27,6 +27,7 @@ import com.bgsoftware.superiorskyblock.island.upgrade.UpgradeRequirement; import com.bgsoftware.superiorskyblock.island.upgrade.container.IslandUpgrades; import com.bgsoftware.superiorskyblock.module.BuiltinModule; +import com.bgsoftware.superiorskyblock.module.IModuleConfiguration; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminRankup; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetUpgrade; import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSyncUpgrades; @@ -47,6 +48,7 @@ import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -54,20 +56,35 @@ import java.util.Set; import java.util.stream.Collectors; -public class UpgradesModule extends BuiltinModule { +public class UpgradesModule extends BuiltinModule { + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final String[] IGNORED_SECTIONS = new String[]{"upgrades"}; private static final int MAX_UPGRADES_NAME_LENGTH = 255; - private final List enabledUpgrades = new LinkedList<>(); + private final Map, IUpgradeType> classToUpgrade = new IdentityHashMap<>(); public UpgradesModule() { super("upgrades"); } @Override - protected void onPluginInit(SuperiorSkyblockPlugin plugin) { - super.onPluginInit(plugin); - convertOldUpgradesFile(plugin); + protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) { + File oldUpgradesFile = new File(plugin.getDataFolder(), "upgrades.yml"); + if (!oldUpgradesFile.exists()) + return false; + + CommentedConfiguration oldConfig = CommentedConfiguration.loadConfiguration(oldUpgradesFile); + boolean updatedConfig = false; + + if (oldConfig.isConfigurationSection("upgrades")) { + config.set("upgrades", oldConfig.getConfigurationSection("upgrades")); + } + + oldUpgradesFile.delete(); + + return updatedConfig; } @Override @@ -87,12 +104,9 @@ public void loadData(SuperiorSkyblockPlugin plugin) { @Override public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) { - if (!isEnabled()) - return null; - List listenersList = new ArrayList<>(); - for (IUpgradeType upgradeType : enabledUpgrades) { + for (IUpgradeType upgradeType : this.configuration.enabledUpgrades) { listenersList.addAll(upgradeType.getListeners()); } @@ -106,10 +120,7 @@ public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) { @Override public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) { - if (!isEnabled()) - return null; - - List adminCommands = enabledUpgrades.stream() + List adminCommands = this.configuration.enabledUpgrades.stream() .map(IUpgradeType::getCommands) .flatMap(List::stream) .collect(Collectors.toList()); @@ -121,66 +132,84 @@ public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) return adminCommands.toArray(new SuperiorCommand[0]); } - @Override - public boolean isEnabled() { - return !enabledUpgrades.isEmpty() && isInitialized(); - } - @Override protected String[] getIgnoredSections() { - return new String[]{"upgrades"}; + return IGNORED_SECTIONS; } @Override - protected void updateConfig(SuperiorSkyblockPlugin plugin) { - enabledUpgrades.clear(); - - if (config.getBoolean("crop-growth", true)) - enabledUpgrades.add(new UpgradeTypeCropGrowth(plugin)); - if (config.getBoolean("mob-drops", true)) - enabledUpgrades.add(new UpgradeTypeMobDrops(plugin)); - if (config.getBoolean("island-effects", true)) - enabledUpgrades.add(new UpgradeTypeIslandEffects(plugin)); - if (config.getBoolean("spawner-rates", true)) - enabledUpgrades.add(new UpgradeTypeSpawnerRates(plugin)); - if (config.getBoolean("block-limits", true)) - enabledUpgrades.add(new UpgradeTypeBlockLimits(plugin)); - if (config.getBoolean("entity-limits", true)) - enabledUpgrades.add(new UpgradeTypeEntityLimits(plugin)); - - plugin.getUpgrades().clearUpgrades(); - - if (!enabledUpgrades.isEmpty()) { - ConfigurationSection upgrades = config.getConfigurationSection("upgrades"); - if (upgrades != null) { - for (String upgradeName : upgrades.getKeys(false)) { - if (upgradeName.length() > MAX_UPGRADES_NAME_LENGTH) - upgradeName = upgradeName.substring(0, MAX_UPGRADES_NAME_LENGTH); - - SUpgrade upgrade = new SUpgrade(upgradeName); - for (String _level : upgrades.getConfigurationSection(upgradeName).getKeys(false)) { - loadUpgradeLevelFromSection(plugin, upgrade, _level, upgrades.getConfigurationSection(upgradeName + "." + _level)); - } - - plugin.getUpgrades().addUpgrade(upgrade); - } - } + protected Configuration createConfigFile(CommentedConfiguration config) { + this.classToUpgrade.clear(); + Configuration configuration = new Configuration(config); + for (IUpgradeType enabledUpgrade : configuration.enabledUpgrades) { + this.classToUpgrade.put(enabledUpgrade.getClass(), enabledUpgrade); } - - IslandUpgrades.onUpgradesUpdate(); + return configuration; } @Nullable public T getEnabledUpgradeType(Class clazz) { - return enabledUpgrades.stream() - .filter(upgradeType -> upgradeType.getClass().equals(clazz)) - .findFirst().map(clazz::cast).orElse(null); + IUpgradeType enabledUpgrade = this.classToUpgrade.get(clazz); + return enabledUpgrade == null ? null : (T) enabledUpgrade; } public boolean isUpgradeTypeEnabled(Class clazz) { return getEnabledUpgradeType(clazz) != null; } + public class Configuration implements IModuleConfiguration { + + private final boolean enabled; + private final List enabledUpgrades = new LinkedList<>(); + + Configuration(CommentedConfiguration config) { + loadUpgrades(config); + this.enabled = !this.enabledUpgrades.isEmpty(); + } + + @Override + public boolean isEnabled() { + return this.enabled; + } + + private void loadUpgrades(CommentedConfiguration config) { + if (config.getBoolean("crop-growth", true)) + enabledUpgrades.add(new UpgradeTypeCropGrowth(plugin)); + if (config.getBoolean("mob-drops", true)) + enabledUpgrades.add(new UpgradeTypeMobDrops(plugin)); + if (config.getBoolean("island-effects", true)) + enabledUpgrades.add(new UpgradeTypeIslandEffects(plugin)); + if (config.getBoolean("spawner-rates", true)) + enabledUpgrades.add(new UpgradeTypeSpawnerRates(plugin)); + if (config.getBoolean("block-limits", true)) + enabledUpgrades.add(new UpgradeTypeBlockLimits(plugin)); + if (config.getBoolean("entity-limits", true)) + enabledUpgrades.add(new UpgradeTypeEntityLimits(plugin)); + + plugin.getUpgrades().clearUpgrades(); + + if (!enabledUpgrades.isEmpty()) { + ConfigurationSection upgrades = config.getConfigurationSection("upgrades"); + if (upgrades != null) { + for (String upgradeName : upgrades.getKeys(false)) { + if (upgradeName.length() > MAX_UPGRADES_NAME_LENGTH) + upgradeName = upgradeName.substring(0, MAX_UPGRADES_NAME_LENGTH); + + SUpgrade upgrade = new SUpgrade(upgradeName); + for (String _level : upgrades.getConfigurationSection(upgradeName).getKeys(false)) { + loadUpgradeLevelFromSection(plugin, upgrade, _level, upgrades.getConfigurationSection(upgradeName + "." + _level)); + } + + plugin.getUpgrades().addUpgrade(upgrade); + } + } + } + + IslandUpgrades.onUpgradesUpdate(); + } + + } + private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade upgrade, String sectionName, ConfigurationSection levelSection) { int level = Integer.parseInt(sectionName); @@ -278,27 +307,4 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade upgrade.addUpgradeLevel(level, upgradeLevel); } - @SuppressWarnings("ResultOfMethodCallIgnored") - private void convertOldUpgradesFile(SuperiorSkyblockPlugin plugin) { - File upgradesFile = new File(plugin.getDataFolder(), "upgrades.yml"); - - if (upgradesFile.exists()) { - CommentedConfiguration config = CommentedConfiguration.loadConfiguration(upgradesFile); - - super.config.set("upgrades", config.get("upgrades")); - - File moduleConfigFile = new File(getModuleFolder(), "config.yml"); - - try { - super.config.save(moduleConfigFile); - config.save(upgradesFile); - } catch (Exception error) { - Log.entering("UpgradesModule", "convertOldUpgradesFile", "ENTER"); - Log.error(error, "An error occurred while saving config file:"); - } - - upgradesFile.delete(); - } - } - } From ab9417f44df833c5f50af5e113cad80888a8d03b Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 22 Aug 2025 18:09:27 +0200 Subject: [PATCH 254/600] Added auto-reward-outside-islands option to missions module (#2600) --- .../superiorskyblock/api/missions/Mission.java | 4 ---- .../mission/MissionsManagerImpl.java | 16 +++++++++++++--- .../module/missions/MissionsModule.java | 6 ++++++ src/main/resources/modules/missions/config.yml | 5 +++++ 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/Mission.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/Mission.java index 518a2905f0..c25d80697d 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/Mission.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/Mission.java @@ -1,7 +1,6 @@ package com.bgsoftware.superiorskyblock.api.missions; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.google.common.base.Preconditions; import org.bukkit.configuration.ConfigurationSection; @@ -184,9 +183,6 @@ public int getProgressValue(SuperiorPlayer superiorPlayer) { */ public boolean canComplete(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); - if (!SuperiorSkyblockAPI.getSuperiorSkyblock().getGrid().isIslandsWorld(superiorPlayer.getWorld())) - return false; - return getProgress(superiorPlayer) >= 1.0; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java index dfc5fab977..d7fae25010 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java @@ -286,13 +286,23 @@ public void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, return; } - if (checkAutoReward && !isAutoReward(mission)) { - if (canCompleteAgain(superiorPlayer, mission)) { - Message.MISSION_NO_AUTO_REWARD.send(superiorPlayer, mission.getName()); + if (checkAutoReward) { + boolean shouldAutoReward = isAutoReward(mission); + if (shouldAutoReward && !BuiltinModules.MISSIONS.getConfiguration().isAutoRewardOutsideIslands() && + !plugin.getGrid().isIslandsWorld(superiorPlayer.getWorld())) { if (result != null) result.accept(false); return; } + + if (!shouldAutoReward) { + if (canCompleteAgain(superiorPlayer, mission)) { + Message.MISSION_NO_AUTO_REWARD.send(superiorPlayer, mission.getName()); + if (result != null) + result.accept(false); + return; + } + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java index 4925e814bf..b38a7eb1b5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java @@ -118,10 +118,12 @@ protected Configuration createConfigFile(CommentedConfiguration config) { public class Configuration implements IModuleConfiguration { private final boolean enabled; + private final boolean autoRewardOutsideIslands; private final List> missionsToLoad = new LinkedList<>(); Configuration(CommentedConfiguration config) { this.enabled = config.getBoolean("enabled"); + this.autoRewardOutsideIslands = config.getBoolean("auto-reward-outside-islands"); if (this.enabled) { loadMissionCategories(config); } @@ -132,6 +134,10 @@ public boolean isEnabled() { return this.enabled; } + public boolean isAutoRewardOutsideIslands() { + return this.autoRewardOutsideIslands; + } + private void loadMissionCategories(CommentedConfiguration config) { ConfigurationSection categoriesSection = config.getConfigurationSection("categories"); diff --git a/src/main/resources/modules/missions/config.yml b/src/main/resources/modules/missions/config.yml index 90f2c190ae..a33cf11f58 100644 --- a/src/main/resources/modules/missions/config.yml +++ b/src/main/resources/modules/missions/config.yml @@ -8,6 +8,11 @@ # Should missions be enabled on your server? enabled: true +# Should mission rewards be automatically claimed outside island worlds? +# When disabled, rewards for missions with auto-reward enabled will be +# automatically claimed only in island worlds. +auto-reward-outside-islands: false + # Settings related to mission categories. # A tutorial about configuring missions can be found here: # https://wiki.bg-software.com/superiorskyblock/missions From 85dbebcf1238fbc37ffa8d508aee4ee723605655 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 22 Aug 2025 21:28:36 +0300 Subject: [PATCH 255/600] Fix config file being deleted due to recent changes (#2606) --- .../com/bgsoftware/superiorskyblock/module/bank/BankModule.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java index 5359382acf..873406ddde 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java @@ -47,8 +47,6 @@ protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfigu if (syncValues("bank-interest", config, oldConfig)) updatedConfig = true; - oldConfigFile.delete(); - return updatedConfig; } From 08473f3153b8214d2d8e2c136d251454cfd2cf36 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 22 Aug 2025 21:06:33 +0200 Subject: [PATCH 256/600] Add balance and next interest placeholders to the bank menu (#2547) --- .../menu/button/impl/BankBalanceButton.java | 56 +++++++++++++++++++ .../menu/button/impl/BankDepositButton.java | 2 + .../menu/button/impl/BankWithdrawButton.java | 2 + .../core/menu/impl/MenuIslandBank.java | 4 ++ src/main/resources/menus/island-bank.yml | 4 +- src/main/resources/menus/island-bank1_12.yml | 4 +- src/main/resources/menus/island-bank1_13.yml | 4 +- 7 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankBalanceButton.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankBalanceButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankBalanceButton.java new file mode 100644 index 0000000000..8f835c137d --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankBalanceButton.java @@ -0,0 +1,56 @@ +package com.bgsoftware.superiorskyblock.core.menu.button.impl; + +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; +import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; +import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; +import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; +import com.bgsoftware.superiorskyblock.core.menu.view.impl.IslandMenuView; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.Date; + +public class BankBalanceButton extends AbstractMenuViewButton { + + private BankBalanceButton(AbstractMenuTemplateButton templateButton, IslandMenuView menuView) { + super(templateButton, menuView); + } + + @Override + public ItemStack createViewItem() { + Island island = menuView.getInventoryViewer().getIsland(); + SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); + ItemStack buttonItem = super.createViewItem(); + + return new ItemBuilder(buttonItem) + .replaceAll("{0}", island.getIslandBank().getBalance() + "") + .replaceAll("{1}", Formatters.NUMBER_FORMATTER.format(island.getIslandBank().getBalance())) + .replaceAll("{2}", Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandBank().getBalance(), inventoryViewer.getUserLocale())) + .replaceAll("{3}", island.getBankLimit() + "") + .replaceAll("{4}", Formatters.NUMBER_FORMATTER.format(island.getBankLimit())) + .replaceAll("{5}", Formatters.FANCY_NUMBER_FORMATTER.format(island.getBankLimit(), inventoryViewer.getUserLocale())) + .replaceAll("{6}", Formatters.DATE_FORMATTER.format(new Date(island.getLastInterestTime() * 1000L))) + .replaceAll("{7}", Formatters.DATE_FORMATTER.format(new Date(System.currentTimeMillis() + island.getNextInterest() * 1000L))) + .build(); + } + + @Override + public void onButtonClick(InventoryClickEvent clickEvent) { + // Dummy button + } + + public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { + + @Override + public MenuTemplateButton build() { + return new MenuTemplateButtonImpl<>(buttonItem, clickSound, commands, requiredPermission, + lackPermissionSound, BankBalanceButton.class, BankBalanceButton::new); + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java index bd89a0df66..460b5edcc5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java @@ -40,6 +40,8 @@ public void onButtonClick(InventoryClickEvent clickEvent) { BankTransaction bankTransaction = island.getIslandBank().depositMoney(clickedPlayer, amount); MenuActions.handleDeposit(clickedPlayer, island, bankTransaction, getTemplate().successSound, getTemplate().failSound, amount); + + menuView.refreshView(); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java index 4e6b744f54..0813a668cb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java @@ -40,6 +40,8 @@ public void onButtonClick(InventoryClickEvent clickEvent) { BankTransaction bankTransaction = island.getIslandBank().withdrawMoney(clickedPlayer, amount, getTemplate().withdrawCommands); MenuActions.handleWithdraw(clickedPlayer, island, bankTransaction, getTemplate().successSound, getTemplate().failSound, amount); + + menuView.refreshView(); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java index 62d4bd7382..8c20c1858c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; +import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankBalanceButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankCustomDepositButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankCustomWithdrawButton; import com.bgsoftware.superiorskyblock.core.menu.button.impl.BankDepositButton; @@ -90,6 +91,9 @@ public static MenuIslandBank createInstance() { } } + patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "balance", menuPatternSlots), + new BankBalanceButton.Builder()); + patternBuilder.mapButtons(MenuParserImpl.getInstance().parseButtonSlots(cfg, "logs", menuPatternSlots), new OpenBankLogsButton.Builder()); diff --git a/src/main/resources/menus/island-bank.yml b/src/main/resources/menus/island-bank.yml index 68581eef87..64c88c46ba 100644 --- a/src/main/resources/menus/island-bank.yml +++ b/src/main/resources/menus/island-bank.yml @@ -15,6 +15,7 @@ pattern: - '- @ $ @ @ @ & @ -' - '= - @ @ ~ @ @ - =' +balance: '*' logs: '~' items: @@ -70,7 +71,8 @@ items: type: PAPER name: '&6Balance' lore: - - '&7Your bank currently has $%superior_island_bank_format%' + - '&7Your bank currently has ${2}' + - '&7Next interest on {7}' '=': type: EMERALD_BLOCK name: '&f ' diff --git a/src/main/resources/menus/island-bank1_12.yml b/src/main/resources/menus/island-bank1_12.yml index 77aac7b961..ad72a5266a 100644 --- a/src/main/resources/menus/island-bank1_12.yml +++ b/src/main/resources/menus/island-bank1_12.yml @@ -15,6 +15,7 @@ pattern: - '- @ $ @ @ @ & @ -' - '= - @ @ ~ @ @ - =' +balance: '*' logs: '~' items: @@ -70,7 +71,8 @@ items: type: PAPER name: '&6Balance' lore: - - '&7Your bank currently has $%superior_island_bank_format%' + - '&7Your bank currently has ${2}' + - '&7Next interest on {7}' '=': type: EMERALD_BLOCK name: '&f ' diff --git a/src/main/resources/menus/island-bank1_13.yml b/src/main/resources/menus/island-bank1_13.yml index f6b5ebd9f2..813ce0e66c 100644 --- a/src/main/resources/menus/island-bank1_13.yml +++ b/src/main/resources/menus/island-bank1_13.yml @@ -15,6 +15,7 @@ pattern: - '- @ $ @ @ @ & @ -' - '= - @ @ ~ @ @ - =' +balance: '*' logs: '~' items: @@ -64,7 +65,8 @@ items: type: PAPER name: '&6Balance' lore: - - '&7Your bank currently has $%superior_island_bank_format%' + - '&7Your bank currently has ${2}' + - '&7Next interest on {7}' '=': type: EMERALD_BLOCK name: '&f ' From e56256a67b9efb3c2c0c3d085d393fe653969347 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 22 Aug 2025 22:11:19 +0300 Subject: [PATCH 257/600] Fixed bank menu is not refreshing when balance is updated --- .../core/menu/button/impl/BankCustomDepositButton.java | 2 -- .../core/menu/button/impl/BankCustomWithdrawButton.java | 2 -- .../core/menu/button/impl/BankDepositButton.java | 2 -- .../core/menu/button/impl/BankWithdrawButton.java | 2 -- .../com/bgsoftware/superiorskyblock/island/SIsland.java | 1 - .../superiorskyblock/island/bank/SIslandBank.java | 9 +++++---- 6 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java index 3bfca38fb2..25b2763565 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomDepositButton.java @@ -54,8 +54,6 @@ public void onButtonClick(InventoryClickEvent clickEvent) { PlayerChat.remove(player); - menuView.refreshView(); - return true; }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java index fcd7260c11..e9f1ab4d5b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankCustomWithdrawButton.java @@ -54,8 +54,6 @@ public void onButtonClick(InventoryClickEvent clickEvent) { PlayerChat.remove(player); - menuView.refreshView(); - return true; }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java index 460b5edcc5..bd89a0df66 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankDepositButton.java @@ -40,8 +40,6 @@ public void onButtonClick(InventoryClickEvent clickEvent) { BankTransaction bankTransaction = island.getIslandBank().depositMoney(clickedPlayer, amount); MenuActions.handleDeposit(clickedPlayer, island, bankTransaction, getTemplate().successSound, getTemplate().failSound, amount); - - menuView.refreshView(); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java index 0813a668cb..4e6b744f54 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/BankWithdrawButton.java @@ -40,8 +40,6 @@ public void onButtonClick(InventoryClickEvent clickEvent) { BankTransaction bankTransaction = island.getIslandBank().withdrawMoney(clickedPlayer, amount, getTemplate().withdrawCommands); MenuActions.handleWithdraw(clickedPlayer, island, bankTransaction, getTemplate().successSound, getTemplate().failSound, amount); - - menuView.refreshView(); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 99d473130b..8e01340dcd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -2336,7 +2336,6 @@ public boolean giveInterest(boolean checkOnlineOwner) { giveInterestFailed = false; islandBank.depositAdminMoney(Bukkit.getConsoleSender(), balanceToGive); - plugin.getMenus().refreshIslandBank(this); setLastInterestTime(currentTime); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java index 19d0223dd4..e16a9d4135 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java @@ -116,7 +116,7 @@ public BankTransaction depositMoney(SuperiorPlayer superiorPlayer, BigDecimal am Formatters.NUMBER_FORMATTER.format(amount)); plugin.getMenus().refreshBankLogs(island); - plugin.getMenus().refreshBankLogs(island); + plugin.getMenus().refreshIslandBank(island); } else { Log.debugResult(Debug.DEPOSIT_MONEY, "Return Failure", failureReason); bankTransaction = new SBankTransaction(superiorPlayer.getUniqueId(), BankAction.DEPOSIT_FAILED, position, @@ -157,7 +157,7 @@ public BankTransaction depositAdminMoney(CommandSender commandSender, BigDecimal increaseBalance(amount); plugin.getMenus().refreshBankLogs(island); - plugin.getMenus().refreshBankLogs(island); + plugin.getMenus().refreshIslandBank(island); return bankTransaction; } @@ -219,7 +219,8 @@ public BankTransaction withdrawMoney(SuperiorPlayer superiorPlayer, BigDecimal a Formatters.NUMBER_FORMATTER.format(withdrawAmount)); plugin.getMenus().refreshBankLogs(island); - plugin.getMenus().refreshBankLogs(island); + plugin.getMenus().refreshIslandBank(island); + } else { Log.debugResult(Debug.DEPOSIT_MONEY, "Return Failure", failureReason); bankTransaction = new SBankTransaction(superiorPlayer.getUniqueId(), BankAction.WITHDRAW_FAILED, position, System.currentTimeMillis(), failureReason, MONEY_FAILURE); @@ -259,7 +260,7 @@ public BankTransaction withdrawAdminMoney(CommandSender commandSender, BigDecima addTransaction(bankTransaction, true); plugin.getMenus().refreshBankLogs(island); - plugin.getMenus().refreshBankLogs(island); + plugin.getMenus().refreshIslandBank(island); return bankTransaction; } From 7f0fb2fe5d82e1b3af8496818cf53eff61263242 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 23 Aug 2025 10:27:32 +0200 Subject: [PATCH 258/600] Improved missions files (#2607) --- .../categories/explorer/explorer_1.yml | 8 +- .../categories/explorer/explorer_2.yml | 8 +- .../missions/categories/farmer/farmer_1.yml | 17 +-- .../categories/farmer/farmer_11_12.yml | 111 ++++++++++++++ .../missions/categories/farmer/farmer_2.yml | 30 ++-- .../categories/farmer/farmer_21_12.yml | 112 ++++++++++++++ .../missions/categories/farmer/farmer_3.yml | 14 +- .../categories/farmer/farmer_31_12.yml | 91 +++++++++++ .../missions/categories/farmer/farmer_4.yml | 35 ++--- .../categories/farmer/farmer_41_12.yml | 140 +++++++++++++++++ .../missions/categories/farmer/farmer_5.yml | 37 ++--- .../categories/farmer/farmer_51_12.yml | 144 ++++++++++++++++++ .../categories/fisherman/fisherman_1.yml | 10 +- .../categories/fisherman/fisherman_11_13.yml | 10 +- .../categories/fisherman/fisherman_2.yml | 15 +- .../categories/fisherman/fisherman_21_13.yml | 15 +- .../categories/fisherman/fisherman_3.yml | 15 +- .../categories/fisherman/fisherman_31_13.yml | 15 +- .../missions/categories/miner/miner_1.yml | 5 +- .../missions/categories/miner/miner_2.yml | 10 +- .../missions/categories/miner/miner_3.yml | 10 +- .../missions/categories/miner/miner_4.yml | 10 +- .../missions/categories/miner/miner_5.yml | 10 +- .../missions/categories/slayer/slayer_1.yml | 9 +- .../missions/categories/slayer/slayer_2.yml | 14 +- .../missions/categories/slayer/slayer_3.yml | 14 +- .../missions/categories/slayer/slayer_4.yml | 14 +- 27 files changed, 724 insertions(+), 199 deletions(-) create mode 100644 src/main/resources/modules/missions/categories/farmer/farmer_11_12.yml create mode 100644 src/main/resources/modules/missions/categories/farmer/farmer_21_12.yml create mode 100644 src/main/resources/modules/missions/categories/farmer/farmer_31_12.yml create mode 100644 src/main/resources/modules/missions/categories/farmer/farmer_41_12.yml create mode 100644 src/main/resources/modules/missions/categories/farmer/farmer_51_12.yml diff --git a/src/main/resources/modules/missions/categories/explorer/explorer_1.yml b/src/main/resources/modules/missions/categories/explorer/explorer_1.yml index 7a0c2f55f5..e61650f6d0 100644 --- a/src/main/resources/modules/missions/categories/explorer/explorer_1.yml +++ b/src/main/resources/modules/missions/categories/explorer/explorer_1.yml @@ -11,9 +11,6 @@ mission-file: IslandMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? -reset-after-finish: true - # Rewards given when completing the mission. rewards: commands: @@ -51,10 +48,7 @@ icons: - '&8 - &7$25,000' - '' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + glow: true completed: type: MAP name: '&aNether Explorer' diff --git a/src/main/resources/modules/missions/categories/explorer/explorer_2.yml b/src/main/resources/modules/missions/categories/explorer/explorer_2.yml index d9f068b309..389d356687 100644 --- a/src/main/resources/modules/missions/categories/explorer/explorer_2.yml +++ b/src/main/resources/modules/missions/categories/explorer/explorer_2.yml @@ -11,9 +11,6 @@ mission-file: IslandMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? -reset-after-finish: true - # Rewards given when completing the mission. rewards: commands: @@ -54,10 +51,7 @@ icons: - '&8 - &7$150,000' - '' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + glow: true completed: type: MAP name: '&aThe-End Explorer' diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_1.yml b/src/main/resources/modules/missions/categories/farmer/farmer_1.yml index 4b9f628fbb..ad93a0cab2 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_1.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_1.yml @@ -11,26 +11,23 @@ mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? +# Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. rewards: items: '1': - type: BEETROOT_SEEDS - amount: 1 - '2': type: PUMPKIN_SEEDS amount: 1 - '3': + '2': type: MELON_SEEDS amount: 1 commands: - 'eco give %player% 2500' - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer I!' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: @@ -59,7 +56,6 @@ icons: - '&8 - &7x10 Wheat' - '' - '&6Rewards:' - - '&8 - &7x1 Beetroot Seed' - '&8 - &7x1 Pumpkin Seed' - '&8 - &7x1 Melon Seed' - '&8 - &7$2,500' @@ -81,7 +77,6 @@ icons: - '&8 - &7x10 Wheat' - '' - '&6Rewards:' - - '&8 - &7x1 Beetroot Seed' - '&8 - &7x1 Pumpkin Seed' - '&8 - &7x1 Melon Seed' - '&8 - &7$2,500' @@ -91,10 +86,7 @@ icons: - '&6Grown Wheat: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + glow: true completed: type: MAP name: '&aFarmer I' @@ -102,7 +94,6 @@ icons: - '&7Plant a small farm.' - '' - '&6Rewards:' - - '&8 - &7x1 Beetroot Seed' - '&8 - &7x1 Pumpkin Seed' - '&8 - &7x1 Melon Seed' - '&8 - &7$2,500' diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_11_12.yml b/src/main/resources/modules/missions/categories/farmer/farmer_11_12.yml new file mode 100644 index 0000000000..108e3e3172 --- /dev/null +++ b/src/main/resources/modules/missions/categories/farmer/farmer_11_12.yml @@ -0,0 +1,111 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +# The mission file to use +mission-file: FarmingMissions + +# Whether the mission should be given when completing all requirements. +auto-reward: true + +# Should plant counts of players get reset when completing the mission? +reset-after-finish: true + +# Rewards given when completing the mission. +rewards: + items: + '1': + type: BEETROOT_SEEDS + amount: 1 + '2': + type: PUMPKIN_SEEDS + amount: 1 + '3': + type: MELON_SEEDS + amount: 1 + commands: + - 'eco give %player% 2500' + - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer I!' + +# List of all required plants must be gathered in order to complete the mission. +required-plants: + '1': + types: + - 'CARROT' + amount: 10 + '2': + types: + - 'POTATO' + amount: 10 + '3': + types: + - 'WHEAT' + amount: 10 + +# Icons used in the menus. +icons: + not-completed: + type: PAPER + name: '&aFarmer I' + lore: + - '&7Plant a small farm.' + - '' + - '&6Required Plants:' + - '&8 - &7x10 Carrots' + - '&8 - &7x10 Potatoes' + - '&8 - &7x10 Wheat' + - '' + - '&6Rewards:' + - '&8 - &7x1 Beetroot Seed' + - '&8 - &7x1 Pumpkin Seed' + - '&8 - &7x1 Melon Seed' + - '&8 - &7$2,500' + - '' + - '&6Grown Carrots: &7{value_carrot}/10' + - '&6Grown Potatoes: &7{value_potato}/10' + - '&6Grown Wheat: &7{value_wheat}/10' + - '&6Progress: &7{0}%' + - '&c&l ✘ &7Not Completed' + can-complete: + type: PAPER + name: '&aFarmer I' + lore: + - '&7Plant a small farm.' + - '' + - '&6Required Plants:' + - '&8 - &7x10 Carrots' + - '&8 - &7x10 Potatoes' + - '&8 - &7x10 Wheat' + - '' + - '&6Rewards:' + - '&8 - &7x1 Beetroot Seed' + - '&8 - &7x1 Pumpkin Seed' + - '&8 - &7x1 Melon Seed' + - '&8 - &7$2,500' + - '' + - '&6Grown Carrots: &710/10' + - '&6Grown Potatoes: &710/10' + - '&6Grown Wheat: &710/10' + - '&6Progress: &7100%' + - '&a&l ✔ &7Click to redeem your reward.' + glow: true + completed: + type: MAP + name: '&aFarmer I' + lore: + - '&7Plant a small farm.' + - '' + - '&6Rewards:' + - '&8 - &7x1 Beetroot Seed' + - '&8 - &7x1 Pumpkin Seed' + - '&8 - &7x1 Melon Seed' + - '&8 - &7$2,500' + - '' + - '&6Grown Carrots: &710/10' + - '&6Grown Potatoes: &710/10' + - '&6Grown Wheat: &710/10' + - '&6Progress: &7100%' + - '&a&l ✔ &7Already Claimed.' \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_2.yml b/src/main/resources/modules/missions/categories/farmer/farmer_2.yml index efb437cb4d..789f0e59ff 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_2.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_2.yml @@ -11,7 +11,7 @@ mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? +# Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. @@ -31,17 +31,13 @@ rewards: required-missions: - 'farmer_1' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required plants must be gathered in order to complete the mission. required-plants: '1': - types: - - 'BEETROOT' - amount: 10 - '2': types: - 'PUMPKIN' amount: 10 - '3': + '2': types: - 'MELON' amount: 10 @@ -52,10 +48,9 @@ icons: type: PAPER name: '&aFarmer II' lore: - - '&7Expand your farm with beetroots, pumpkin and melons.' + - '&7Expand your farm with pumpkins and melons.' - '' - '&6Required Plants:' - - '&8 - &7x10 Beetroots' - '&8 - &7x10 Pumpkins' - '&8 - &7x10 Melons' - '' @@ -64,16 +59,16 @@ icons: - '&8 - &7x1 Cactus' - '&8 - &7$5,000' - '' - - '&6Grown Beetroots: &7{value_beetroot}/10' - '&6Grown Pumpkins: &7{value_pumpkin}/10' - '&6Grown Melons: &7{value_melon}/10' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 2 can-complete: type: PAPER name: '&aFarmer II' lore: - - '&7Expand your farm with beetroots, pumpkin and melons.' + - '&7Expand your farm with pumpkins and melons.' - '' - '&6Required Plants:' - '&8 - &7x10 Beetroots' @@ -85,28 +80,25 @@ icons: - '&8 - &7x1 Cactus' - '&8 - &7$5,000' - '' - - '&6Grown Beetroots: &710/10' - '&6Grown Pumpkins: &710/10' - '&6Grown Melons: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 2 + glow: true completed: type: MAP name: '&aFarmer II' lore: - - '&7Expand your farm with beetroots, pumpkin and melons.' + - '&7Expand your farm with pumpkins and melons.' - '' - '&6Rewards:' - '&8 - &7x1 Sugar Cane' - '&8 - &7x1 Cactus' - '&8 - &7$5,000' - '' - - '&6Grown Beetroots: &710/10' - '&6Grown Pumpkins: &710/10' - '&6Grown Melons: &710/10' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 2 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_21_12.yml b/src/main/resources/modules/missions/categories/farmer/farmer_21_12.yml new file mode 100644 index 0000000000..700e599b98 --- /dev/null +++ b/src/main/resources/modules/missions/categories/farmer/farmer_21_12.yml @@ -0,0 +1,112 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +# The mission file to use +mission-file: FarmingMissions + +# Whether the mission should be given when completing all requirements. +auto-reward: true + +# Should plant counts of players get reset when completing the mission? +reset-after-finish: true + +# Rewards given when completing the mission. +rewards: + items: + '1': + type: SUGAR_CANE + amount: 1 + '2': + type: CACTUS + amount: 1 + commands: + - 'eco give %player% 5000' + - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer II!' + +# List of required missions that must be completed before completing this one. +required-missions: + - 'farmer_1' + +# List of all required plants must be gathered in order to complete the mission. +required-plants: + '1': + types: + - 'BEETROOT' + amount: 10 + '2': + types: + - 'PUMPKIN' + amount: 10 + '3': + types: + - 'MELON' + amount: 10 + +# Icons used in the menus. +icons: + not-completed: + type: PAPER + name: '&aFarmer II' + lore: + - '&7Expand your farm with beetroots, pumpkins and melons.' + - '' + - '&6Required Plants:' + - '&8 - &7x10 Beetroots' + - '&8 - &7x10 Pumpkins' + - '&8 - &7x10 Melons' + - '' + - '&6Rewards:' + - '&8 - &7x1 Sugar Cane' + - '&8 - &7x1 Cactus' + - '&8 - &7$5,000' + - '' + - '&6Grown Beetroots: &7{value_beetroot}/10' + - '&6Grown Pumpkins: &7{value_pumpkin}/10' + - '&6Grown Melons: &7{value_melon}/10' + - '&6Progress: &7{0}%' + - '&c&l ✘ &7Not Completed' + amount: 2 + can-complete: + type: PAPER + name: '&aFarmer II' + lore: + - '&7Expand your farm with beetroots, pumpkins and melons.' + - '' + - '&6Required Plants:' + - '&8 - &7x10 Beetroots' + - '&8 - &7x10 Pumpkins' + - '&8 - &7x10 Melons' + - '' + - '&6Rewards:' + - '&8 - &7x1 Sugar Cane' + - '&8 - &7x1 Cactus' + - '&8 - &7$5,000' + - '' + - '&6Grown Beetroots: &710/10' + - '&6Grown Pumpkins: &710/10' + - '&6Grown Melons: &710/10' + - '&6Progress: &7100%' + - '&a&l ✔ &7Click to redeem your reward.' + amount: 2 + glow: true + completed: + type: MAP + name: '&aFarmer II' + lore: + - '&7Expand your farm with beetroots, pumpkins and melons.' + - '' + - '&6Rewards:' + - '&8 - &7x1 Sugar Cane' + - '&8 - &7x1 Cactus' + - '&8 - &7$5,000' + - '' + - '&6Grown Beetroots: &710/10' + - '&6Grown Pumpkins: &710/10' + - '&6Grown Melons: &710/10' + - '&6Progress: &7100%' + - '&a&l ✔ &7Already Claimed.' + amount: 2 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_3.yml b/src/main/resources/modules/missions/categories/farmer/farmer_3.yml index 18b6ee2e32..3af54aad28 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_3.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_3.yml @@ -11,7 +11,7 @@ mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? +# Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. @@ -25,7 +25,7 @@ required-missions: - 'farmer_1' - 'farmer_2' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: @@ -55,6 +55,7 @@ icons: - '&6Grown Cactus: &7{value_cactus}/10' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 3 can-complete: type: PAPER name: '&aFarmer III' @@ -72,10 +73,8 @@ icons: - '&6Grown Cactus: &710/10' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 3 + glow: true completed: type: MAP name: '&aFarmer III' @@ -88,4 +87,5 @@ icons: - '&6Grown Sugar Canes: &710/10' - '&6Grown Cactus: &710/10' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 3 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_31_12.yml b/src/main/resources/modules/missions/categories/farmer/farmer_31_12.yml new file mode 100644 index 0000000000..3af54aad28 --- /dev/null +++ b/src/main/resources/modules/missions/categories/farmer/farmer_31_12.yml @@ -0,0 +1,91 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +# The mission file to use +mission-file: FarmingMissions + +# Whether the mission should be given when completing all requirements. +auto-reward: true + +# Should plant counts of players get reset when completing the mission? +reset-after-finish: true + +# Rewards given when completing the mission. +rewards: + commands: + - 'is admin rankup %player% crop-growth' + - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer III!' + +# List of required missions that must be completed before completing this one. +required-missions: + - 'farmer_1' + - 'farmer_2' + +# List of all required plants must be gathered in order to complete the mission. +required-plants: + '1': + types: + - 'SUGAR_CANE' + amount: 10 + '2': + types: + - 'CACTUS' + amount: 10 + +# Icons used in the menus. +icons: + not-completed: + type: PAPER + name: '&aFarmer III' + lore: + - '&7Expand your farm with sugar canes and cactus.' + - '' + - '&6Required Plants:' + - '&8 - &7x10 Sugar Canes' + - '&8 - &7x10 Cactus' + - '' + - '&6Rewards:' + - '&8 - &7Crops Upgrade' + - '' + - '&6Grown Sugar Canes: &7{value_sugar_cane}/10' + - '&6Grown Cactus: &7{value_cactus}/10' + - '&6Progress: &7{0}%' + - '&c&l ✘ &7Not Completed' + amount: 3 + can-complete: + type: PAPER + name: '&aFarmer III' + lore: + - '&7Expand your farm with sugar canes and cactus.' + - '' + - '&6Required Plants:' + - '&8 - &7x10 Sugar Canes' + - '&8 - &7x10 Cactus' + - '' + - '&6Rewards:' + - '&8 - &7Crops Upgrade' + - '' + - '&6Grown Sugar Canes: &710/10' + - '&6Grown Cactus: &710/10' + - '&6Progress: &7100%' + - '&a&l ✔ &7Click to redeem your reward.' + amount: 3 + glow: true + completed: + type: MAP + name: '&aFarmer III' + lore: + - '&7Expand your farm with sugar canes and cactus.' + - '' + - '&6Rewards:' + - '&8 - &7Crops Upgrade' + - '' + - '&6Grown Sugar Canes: &710/10' + - '&6Grown Cactus: &710/10' + - '&6Progress: &7100%' + - '&a&l ✔ &7Already Claimed.' + amount: 3 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_4.yml b/src/main/resources/modules/missions/categories/farmer/farmer_4.yml index 24acf6d1ee..52b4e0fdde 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_4.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_4.yml @@ -11,7 +11,7 @@ mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? +# Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. @@ -26,7 +26,7 @@ required-missions: - 'farmer_2' - 'farmer_3' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: @@ -41,22 +41,18 @@ required-plants: - 'WHEAT' amount: 64 '4': - types: - - 'BEETROOT' - amount: 64 - '5': types: - 'PUMPKIN' amount: 64 - '6': + '5': types: - 'MELON' amount: 64 - '7': + '6': types: - 'SUGAR_CANE' amount: 64 - '8': + '7': types: - 'CACTUS' amount: 64 @@ -72,8 +68,8 @@ icons: - '&7Plant x64 of each crop.' - '' - '&6Required Plants:' - - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' - - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' + - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins' + - '&8 - &7Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$25,000' @@ -81,13 +77,13 @@ icons: - '&6Grown Carrots: &7{value_carrot}/64' - '&6Grown Potatoes: &7{value_potato}/64' - '&6Grown Wheat: &7{value_wheat}/64' - - '&6Grown Beetroots: &7{value_beetroot}/64' - '&6Grown Pumpkins: &7{value_pumpkin}/64' - '&6Grown Melons: &7{value_melon}/64' - '&6Grown Sugar Canes: &7{value_sugar_cane}/64' - '&6Grown Cactus: &7{value_cactus}/64' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 4 can-complete: type: PAPER name: '&aFarmer IV' @@ -97,8 +93,8 @@ icons: - '&7Plant x64 of each crop.' - '' - '&6Required Plants:' - - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' - - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' + - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins' + - '&8 - &7Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$25,000' @@ -106,17 +102,14 @@ icons: - '&6Grown Carrots: &764/64' - '&6Grown Potatoes: &764/64' - '&6Grown Wheat: &764/64' - - '&6Grown Beetroots: &764/64' - '&6Grown Pumpkins: &764/64' - '&6Grown Melons: &764/64' - '&6Grown Sugar Canes: &764/64' - '&6Grown Cactus: &764/64' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 4 + glow: true completed: type: MAP name: '&aFarmer IV' @@ -131,10 +124,10 @@ icons: - '&6Grown Carrots: &764/64' - '&6Grown Potatoes: &764/64' - '&6Grown Wheat: &764/64' - - '&6Grown Beetroots: &764/64' - '&6Grown Pumpkins: &764/64' - '&6Grown Melons: &764/64' - '&6Grown Sugar Canes: &764/64' - '&6Grown Cactus: &764/64' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 4 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_41_12.yml b/src/main/resources/modules/missions/categories/farmer/farmer_41_12.yml new file mode 100644 index 0000000000..429280c1cf --- /dev/null +++ b/src/main/resources/modules/missions/categories/farmer/farmer_41_12.yml @@ -0,0 +1,140 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +# The mission file to use +mission-file: FarmingMissions + +# Whether the mission should be given when completing all requirements. +auto-reward: true + +# Should plant counts of players get reset when completing the mission? +reset-after-finish: true + +# Rewards given when completing the mission. +rewards: + commands: + - 'eco give %player% 25000' + - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer IV!' + +# List of required missions that must be completed before completing this one. +required-missions: + - 'farmer_1' + - 'farmer_2' + - 'farmer_3' + +# List of all required plants must be gathered in order to complete the mission. +required-plants: + '1': + types: + - 'CARROT' + amount: 64 + '2': + types: + - 'POTATO' + amount: 64 + '3': + types: + - 'WHEAT' + amount: 64 + '4': + types: + - 'BEETROOT' + amount: 64 + '5': + types: + - 'PUMPKIN' + amount: 64 + '6': + types: + - 'MELON' + amount: 64 + '7': + types: + - 'SUGAR_CANE' + amount: 64 + '8': + types: + - 'CACTUS' + amount: 64 + +# Icons used in the menus. +icons: + not-completed: + type: PAPER + name: '&aFarmer IV' + lore: + - '&7Now that you are a professional farmer,' + - '&7let''s get the hands dirty.' + - '&7Plant x64 of each crop.' + - '' + - '&6Required Plants:' + - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' + - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' + - '' + - '&6Rewards:' + - '&8 - &7$25,000' + - '' + - '&6Grown Carrots: &7{value_carrot}/64' + - '&6Grown Potatoes: &7{value_potato}/64' + - '&6Grown Wheat: &7{value_wheat}/64' + - '&6Grown Beetroots: &7{value_beetroot}/64' + - '&6Grown Pumpkins: &7{value_pumpkin}/64' + - '&6Grown Melons: &7{value_melon}/64' + - '&6Grown Sugar Canes: &7{value_sugar_cane}/64' + - '&6Grown Cactus: &7{value_cactus}/64' + - '&6Progress: &7{0}%' + - '&c&l ✘ &7Not Completed' + amount: 4 + can-complete: + type: PAPER + name: '&aFarmer IV' + lore: + - '&7Now that you are a professional farmer,' + - '&7let''s get the hands dirty.' + - '&7Plant x64 of each crop.' + - '' + - '&6Required Plants:' + - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' + - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' + - '' + - '&6Rewards:' + - '&8 - &7$25,000' + - '' + - '&6Grown Carrots: &764/64' + - '&6Grown Potatoes: &764/64' + - '&6Grown Wheat: &764/64' + - '&6Grown Beetroots: &764/64' + - '&6Grown Pumpkins: &764/64' + - '&6Grown Melons: &764/64' + - '&6Grown Sugar Canes: &764/64' + - '&6Grown Cactus: &764/64' + - '&6Progress: &7100%' + - '&a&l ✔ &7Click to redeem your reward.' + amount: 4 + glow: true + completed: + type: MAP + name: '&aFarmer IV' + lore: + - '&7Now that you are a professional farmer,' + - '&7let''s get the hands dirty.' + - '&7Plant x64 of each crop.' + - '' + - '&6Rewards:' + - '&8 - &7$25,000' + - '' + - '&6Grown Carrots: &764/64' + - '&6Grown Potatoes: &764/64' + - '&6Grown Wheat: &764/64' + - '&6Grown Beetroots: &764/64' + - '&6Grown Pumpkins: &764/64' + - '&6Grown Melons: &764/64' + - '&6Grown Sugar Canes: &764/64' + - '&6Grown Cactus: &764/64' + - '&6Progress: &7100%' + - '&a&l ✔ &7Already Claimed.' + amount: 4 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_5.yml b/src/main/resources/modules/missions/categories/farmer/farmer_5.yml index e1536f8833..f79386b302 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_5.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_5.yml @@ -11,7 +11,7 @@ mission-file: FarmingMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? +# Should plant counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. @@ -21,7 +21,7 @@ rewards: - 'is admin rankup %player% crop-growth' - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer V!' - 'is admin msg %player% &e&lFarmer | &7There is nothing you don''t know how to grow.' - - 'is admin msg %player% &e&lFarmer | &7&oYou are now a professional Framer, congratz!' + - 'is admin msg %player% &e&lFarmer | &7&oYou are now a professional Farmer, congratz!' # List of required missions that must be completed before completing this one. required-missions: @@ -30,7 +30,7 @@ required-missions: - 'farmer_3' - 'farmer_4' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required plants must be gathered in order to complete the mission. required-plants: '1': types: @@ -45,22 +45,18 @@ required-plants: - 'WHEAT' amount: 320 '4': - types: - - 'BEETROOT' - amount: 320 - '5': types: - 'PUMPKIN' amount: 320 - '6': + '5': types: - 'MELON' amount: 320 - '7': + '6': types: - 'SUGAR_CANE' amount: 320 - '8': + '7': types: - 'CACTUS' amount: 320 @@ -75,8 +71,8 @@ icons: - '&7Plant 5 stacks of each crop.' - '' - '&6Required Plants:' - - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' - - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' + - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins' + - '&8 - &7Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$1,000,000' @@ -85,13 +81,13 @@ icons: - '&6Grown Carrots: &7{value_carrot}/320' - '&6Grown Potatoes: &7{value_potato}/320' - '&6Grown Wheat: &7{value_wheat}/320' - - '&6Grown Beetroots: &7{value_beetroot}/320' - '&6Grown Pumpkins: &7{value_pumpkin}/320' - '&6Grown Melons: &7{value_melon}/320' - '&6Grown Sugar Canes: &7{value_sugar_cane}/320' - '&6Grown Cactus: &7{value_cactus}/320' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 5 can-complete: type: PAPER name: '&aFarmer V' @@ -100,8 +96,8 @@ icons: - '&7Plant 5 stacks of each crop.' - '' - '&6Required Plants:' - - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' - - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' + - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins' + - '&8 - &7Melons, Sugar Canes, Cactus' - '' - '&6Rewards:' - '&8 - &7$1,000,000' @@ -110,17 +106,14 @@ icons: - '&6Grown Carrots: &7320/320' - '&6Grown Potatoes: &7320/320' - '&6Grown Wheat: &7320/320' - - '&6Grown Beetroots: &7320/320' - '&6Grown Pumpkins: &7320/320' - '&6Grown Melons: &7320/320' - '&6Grown Sugar Canes: &7320/320' - '&6Grown Cactus: &7320/320' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 5 + glow: true completed: type: MAP name: '&aFarmer V' @@ -135,10 +128,10 @@ icons: - '&6Grown Carrots: &7320/320' - '&6Grown Potatoes: &7320/320' - '&6Grown Wheat: &7320/320' - - '&6Grown Beetroots: &7320/320' - '&6Grown Pumpkins: &7320/320' - '&6Grown Melons: &7320/320' - '&6Grown Sugar Canes: &7320/320' - '&6Grown Cactus: &7320/320' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 5 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_51_12.yml b/src/main/resources/modules/missions/categories/farmer/farmer_51_12.yml new file mode 100644 index 0000000000..1f70e014a1 --- /dev/null +++ b/src/main/resources/modules/missions/categories/farmer/farmer_51_12.yml @@ -0,0 +1,144 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +# The mission file to use +mission-file: FarmingMissions + +# Whether the mission should be given when completing all requirements. +auto-reward: true + +# Should plant counts of players get reset when completing the mission? +reset-after-finish: true + +# Rewards given when completing the mission. +rewards: + commands: + - 'eco give %player% 1000000' + - 'is admin rankup %player% crop-growth' + - 'is admin msg %player% &e&lFarmer | &7Successfully finished the mission Farmer V!' + - 'is admin msg %player% &e&lFarmer | &7There is nothing you don''t know how to grow.' + - 'is admin msg %player% &e&lFarmer | &7&oYou are now a professional Farmer, congratz!' + +# List of required missions that must be completed before completing this one. +required-missions: + - 'farmer_1' + - 'farmer_2' + - 'farmer_3' + - 'farmer_4' + +# List of all required plants must be gathered in order to complete the mission. +required-plants: + '1': + types: + - 'CARROT' + amount: 320 + '2': + types: + - 'POTATO' + amount: 320 + '3': + types: + - 'WHEAT' + amount: 320 + '4': + types: + - 'BEETROOT' + amount: 320 + '5': + types: + - 'PUMPKIN' + amount: 320 + '6': + types: + - 'MELON' + amount: 320 + '7': + types: + - 'SUGAR_CANE' + amount: 320 + '8': + types: + - 'CACTUS' + amount: 320 + +# Icons used in the menus. +icons: + not-completed: + type: PAPER + name: '&aFarmer V' + lore: + - '&7Let''s go one step further,' + - '&7Plant 5 stacks of each crop.' + - '' + - '&6Required Plants:' + - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' + - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' + - '' + - '&6Rewards:' + - '&8 - &7$1,000,000' + - '&8 - &7Crops Upgrade' + - '' + - '&6Grown Carrots: &7{value_carrot}/320' + - '&6Grown Potatoes: &7{value_potato}/320' + - '&6Grown Wheat: &7{value_wheat}/320' + - '&6Grown Beetroots: &7{value_beetroot}/320' + - '&6Grown Pumpkins: &7{value_pumpkin}/320' + - '&6Grown Melons: &7{value_melon}/320' + - '&6Grown Sugar Canes: &7{value_sugar_cane}/320' + - '&6Grown Cactus: &7{value_cactus}/320' + - '&6Progress: &7{0}%' + - '&c&l ✘ &7Not Completed' + amount: 5 + can-complete: + type: PAPER + name: '&aFarmer V' + lore: + - '&7Let''s go one step further,' + - '&7Plant 5 stacks of each crop.' + - '' + - '&6Required Plants:' + - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' + - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' + - '' + - '&6Rewards:' + - '&8 - &7$1,000,000' + - '&8 - &7Crops Upgrade' + - '' + - '&6Grown Carrots: &7320/320' + - '&6Grown Potatoes: &7320/320' + - '&6Grown Wheat: &7320/320' + - '&6Grown Beetroots: &7320/320' + - '&6Grown Pumpkins: &7320/320' + - '&6Grown Melons: &7320/320' + - '&6Grown Sugar Canes: &7320/320' + - '&6Grown Cactus: &7320/320' + - '&6Progress: &7100%' + - '&a&l ✔ &7Click to redeem your reward.' + amount: 5 + glow: true + completed: + type: MAP + name: '&aFarmer V' + lore: + - '&7Let''s go one step further,' + - '&7Plant 5 stacks of each crop.' + - '' + - '&6Rewards:' + - '&8 - &7$1,000,000' + - '&8 - &7Crops Upgrade' + - '' + - '&6Grown Carrots: &7320/320' + - '&6Grown Potatoes: &7320/320' + - '&6Grown Wheat: &7320/320' + - '&6Grown Beetroots: &7320/320' + - '&6Grown Pumpkins: &7320/320' + - '&6Grown Melons: &7320/320' + - '&6Grown Sugar Canes: &7320/320' + - '&6Grown Cactus: &7320/320' + - '&6Progress: &7100%' + - '&a&l ✔ &7Already Claimed.' + amount: 5 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/fisherman/fisherman_1.yml b/src/main/resources/modules/missions/categories/fisherman/fisherman_1.yml index 993af94681..e1ea301f49 100644 --- a/src/main/resources/modules/missions/categories/fisherman/fisherman_1.yml +++ b/src/main/resources/modules/missions/categories/fisherman/fisherman_1.yml @@ -11,9 +11,6 @@ mission-file: FishingMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? -reset-after-finish: true - # Rewards given when completing the mission. rewards: commands: @@ -22,7 +19,7 @@ rewards: - 'is admin msg %player% &e&lFisherman | &7I heard you can find other items as well...' - 'is admin msg %player% &e&lFisherman | &7&oFor more information about the next mission, checkout /is missions' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required caughts must be gathered in order to complete the mission. required-caughts: '1': types: @@ -63,10 +60,7 @@ icons: - '&6Fish Caught: &75/5' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + glow: true completed: type: MAP name: '&aFisherman I' diff --git a/src/main/resources/modules/missions/categories/fisherman/fisherman_11_13.yml b/src/main/resources/modules/missions/categories/fisherman/fisherman_11_13.yml index f569a680ff..185c44ea9b 100644 --- a/src/main/resources/modules/missions/categories/fisherman/fisherman_11_13.yml +++ b/src/main/resources/modules/missions/categories/fisherman/fisherman_11_13.yml @@ -11,9 +11,6 @@ mission-file: FishingMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? -reset-after-finish: true - # Rewards given when completing the mission. rewards: commands: @@ -22,7 +19,7 @@ rewards: - 'is admin msg %player% &e&lFisherman | &7I heard you can find other items as well...' - 'is admin msg %player% &e&lFisherman | &7&oFor more information about the next mission, checkout /is missions' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required caughts must be gathered in order to complete the mission. required-caughts: '1': types: @@ -87,10 +84,7 @@ icons: - '&6Pufferfish Caught: &71/1' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + glow: true completed: type: MAP name: '&aFisherman I' diff --git a/src/main/resources/modules/missions/categories/fisherman/fisherman_2.yml b/src/main/resources/modules/missions/categories/fisherman/fisherman_2.yml index 6d6406f5b2..1f1b69fa78 100644 --- a/src/main/resources/modules/missions/categories/fisherman/fisherman_2.yml +++ b/src/main/resources/modules/missions/categories/fisherman/fisherman_2.yml @@ -11,9 +11,6 @@ mission-file: FishingMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? -reset-after-finish: true - # Rewards given when completing the mission. rewards: commands: @@ -26,7 +23,7 @@ rewards: required-missions: - 'fisherman_1' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required caughts must be gathered in order to complete the mission. required-caughts: '1': types: @@ -66,6 +63,7 @@ icons: - '&6Items: &7{1}/5' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 2 can-complete: type: PAPER name: '&aFisherman II' @@ -82,10 +80,8 @@ icons: - '&6Items: &75/5' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 2 + glow: true completed: type: MAP name: '&aFisherman II' @@ -98,4 +94,5 @@ icons: - '' - '&6Items: &75/5' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 2 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/fisherman/fisherman_21_13.yml b/src/main/resources/modules/missions/categories/fisherman/fisherman_21_13.yml index c0a2befd3b..0156f0fe97 100644 --- a/src/main/resources/modules/missions/categories/fisherman/fisherman_21_13.yml +++ b/src/main/resources/modules/missions/categories/fisherman/fisherman_21_13.yml @@ -11,9 +11,6 @@ mission-file: FishingMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? -reset-after-finish: true - # Rewards given when completing the mission. rewards: commands: @@ -26,7 +23,7 @@ rewards: required-missions: - 'fisherman_1' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required caughts must be gathered in order to complete the mission. required-caughts: '1': types: @@ -67,6 +64,7 @@ icons: - '&6Items: &7{1}/5' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 2 can-complete: type: PAPER name: '&aFisherman II' @@ -83,10 +81,8 @@ icons: - '&6Items: &75/5' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 2 + glow: true completed: type: MAP name: '&aFisherman II' @@ -99,4 +95,5 @@ icons: - '' - '&6Items: &75/5' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 2 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/fisherman/fisherman_3.yml b/src/main/resources/modules/missions/categories/fisherman/fisherman_3.yml index 191c96c1eb..14519920fb 100644 --- a/src/main/resources/modules/missions/categories/fisherman/fisherman_3.yml +++ b/src/main/resources/modules/missions/categories/fisherman/fisherman_3.yml @@ -11,9 +11,6 @@ mission-file: FishingMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? -reset-after-finish: true - # Rewards given when completing the mission. rewards: commands: @@ -27,7 +24,7 @@ required-missions: - 'fisherman_1' - 'fisherman_2' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required caughts must be gathered in order to complete the mission. required-caughts: '1': types: @@ -56,6 +53,7 @@ icons: - '&6Treasure Items: &7{1}/3' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 3 can-complete: type: PAPER name: '&aFisherman III' @@ -72,10 +70,8 @@ icons: - '&6Treasure Items: &73/3' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 3 + glow: true completed: type: MAP name: '&aFisherman III' @@ -88,4 +84,5 @@ icons: - '' - '&6Treasure Items: &73/3' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 3 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/fisherman/fisherman_31_13.yml b/src/main/resources/modules/missions/categories/fisherman/fisherman_31_13.yml index 94c2002397..869bc15cfd 100644 --- a/src/main/resources/modules/missions/categories/fisherman/fisherman_31_13.yml +++ b/src/main/resources/modules/missions/categories/fisherman/fisherman_31_13.yml @@ -11,9 +11,6 @@ mission-file: FishingMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? -reset-after-finish: true - # Rewards given when completing the mission. rewards: commands: @@ -27,7 +24,7 @@ required-missions: - 'fisherman_1' - 'fisherman_2' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required caughts must be gathered in order to complete the mission. required-caughts: '1': types: @@ -57,6 +54,7 @@ icons: - '&6Treasure Items: &7{1}/3' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 3 can-complete: type: PAPER name: '&aFisherman III' @@ -73,10 +71,8 @@ icons: - '&6Treasure Items: &73/3' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 3 + glow: true completed: type: MAP name: '&aFisherman III' @@ -89,4 +85,5 @@ icons: - '' - '&6Treasure Items: &73/3' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 3 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/miner/miner_1.yml b/src/main/resources/modules/missions/categories/miner/miner_1.yml index d33a6047cd..f2ae34bded 100644 --- a/src/main/resources/modules/missions/categories/miner/miner_1.yml +++ b/src/main/resources/modules/missions/categories/miner/miner_1.yml @@ -76,10 +76,7 @@ icons: - '&6Coal Ore Mined: &716/16' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + glow: true completed: type: MAP name: '&aMiner I' diff --git a/src/main/resources/modules/missions/categories/miner/miner_2.yml b/src/main/resources/modules/missions/categories/miner/miner_2.yml index 66dff22a22..66cc5a7748 100644 --- a/src/main/resources/modules/missions/categories/miner/miner_2.yml +++ b/src/main/resources/modules/missions/categories/miner/miner_2.yml @@ -69,6 +69,7 @@ icons: - '&6Iron Ore Mined: &7{value_iron_ore}/16' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 2 can-complete: type: PAPER name: '&aMiner II' @@ -90,10 +91,8 @@ icons: - '&6Iron Ore Mined: &716/16' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 2 + glow: true completed: type: MAP name: '&aMiner II' @@ -109,4 +108,5 @@ icons: - '&6Coal Ore Mined: &732/32' - '&6Iron Ore Mined: &716/16' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 2 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/miner/miner_3.yml b/src/main/resources/modules/missions/categories/miner/miner_3.yml index d63dee1518..fa82b30dab 100644 --- a/src/main/resources/modules/missions/categories/miner/miner_3.yml +++ b/src/main/resources/modules/missions/categories/miner/miner_3.yml @@ -61,6 +61,7 @@ icons: - '&6Iron Ore Mined: &7{value_iron_ore}/64' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 3 can-complete: type: PAPER name: '&aMiner III' @@ -79,10 +80,8 @@ icons: - '&6Iron Ore Mined: &764/64' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 3 + glow: true completed: type: MAP name: '&aMiner III' @@ -96,4 +95,5 @@ icons: - '&6Coal Ore Mined: &764/64' - '&6Iron Ore Mined: &764/64' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 3 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/miner/miner_4.yml b/src/main/resources/modules/missions/categories/miner/miner_4.yml index f09ed87a11..c8cad70682 100644 --- a/src/main/resources/modules/missions/categories/miner/miner_4.yml +++ b/src/main/resources/modules/missions/categories/miner/miner_4.yml @@ -62,6 +62,7 @@ icons: - '&6Iron Ore Mined: &7{value_iron_ore}/320' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 4 can-complete: type: PAPER name: '&aMiner IV' @@ -80,10 +81,8 @@ icons: - '&6Iron Ore Mined: &7320/320' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 4 + glow: true completed: type: MAP name: '&aMiner IV' @@ -97,4 +96,5 @@ icons: - '&6Coal Ore Mined: &7192/192' - '&6Iron Ore Mined: &7320/320' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 4 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/miner/miner_5.yml b/src/main/resources/modules/missions/categories/miner/miner_5.yml index a4a7fb3d93..69009a1981 100644 --- a/src/main/resources/modules/missions/categories/miner/miner_5.yml +++ b/src/main/resources/modules/missions/categories/miner/miner_5.yml @@ -57,6 +57,7 @@ icons: - '&6Diamond Ore Mined: &7{1}/32' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 5 can-complete: type: PAPER name: '&aMiner V' @@ -73,10 +74,8 @@ icons: - '&6Diamond Ore Mined: &732/32' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 5 + glow: true completed: type: MAP name: '&aMiner V' @@ -89,4 +88,5 @@ icons: - '' - '&6Diamond Ore Mined: &732/32' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 5 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/slayer/slayer_1.yml b/src/main/resources/modules/missions/categories/slayer/slayer_1.yml index cc1c78507e..5a909400ae 100644 --- a/src/main/resources/modules/missions/categories/slayer/slayer_1.yml +++ b/src/main/resources/modules/missions/categories/slayer/slayer_1.yml @@ -11,7 +11,7 @@ mission-file: KillsMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? +# Should entity counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. @@ -22,7 +22,7 @@ rewards: - 'is admin msg %player% &e&lSlayer | &7Your sword hasn''t seen blood yet... Kill more mobs!' - 'is admin msg %player% &e&lSlayer | &7&oFor more information about the next mission, checkout /is missions' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required entities must be gathered in order to complete the mission. required-entities: '1': types: @@ -64,10 +64,7 @@ icons: - '&6Hostiles Killed: &75/5' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + glow: true completed: type: MAP name: '&aSlayer I' diff --git a/src/main/resources/modules/missions/categories/slayer/slayer_2.yml b/src/main/resources/modules/missions/categories/slayer/slayer_2.yml index bd66febc39..2699cffed7 100644 --- a/src/main/resources/modules/missions/categories/slayer/slayer_2.yml +++ b/src/main/resources/modules/missions/categories/slayer/slayer_2.yml @@ -11,7 +11,7 @@ mission-file: KillsMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? +# Should entity counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. @@ -27,7 +27,7 @@ rewards: required-missions: - 'slayer_1' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required entities must be gathered in order to complete the mission. required-entities: '1': types: @@ -71,6 +71,7 @@ icons: - '&6Creepers Killed: &7{value_creeper}/24' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 2 can-complete: type: PAPER name: '&aSlayer II' @@ -94,10 +95,8 @@ icons: - '&6Creepers Killed: &724/24' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 2 + glow: true completed: type: MAP name: '&aSlayer II' @@ -114,4 +113,5 @@ icons: - '&6Spiders Killed: &732/32' - '&6Creepers Killed: &724/24' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 2 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/slayer/slayer_3.yml b/src/main/resources/modules/missions/categories/slayer/slayer_3.yml index 03803d1b14..718477cd69 100644 --- a/src/main/resources/modules/missions/categories/slayer/slayer_3.yml +++ b/src/main/resources/modules/missions/categories/slayer/slayer_3.yml @@ -11,7 +11,7 @@ mission-file: KillsMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? +# Should entity counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. @@ -27,7 +27,7 @@ required-missions: - 'slayer_1' - 'slayer_2' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required entities must be gathered in order to complete the mission. required-entities: '1': types: @@ -64,6 +64,7 @@ icons: - '&6Endermans Killed: &7{value_enderman}/24' - '&6Progress: &7{0}%' - '&c&l ✘ &7Not Completed' + amount: 3 can-complete: type: PAPER name: '&aSlayer III' @@ -84,10 +85,8 @@ icons: - '&6Endermans Killed: &724/24' - '&6Progress: &7100%' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 3 + glow: true completed: type: MAP name: '&aSlayer III' @@ -102,4 +101,5 @@ icons: - '&6Wither Skeletons Killed: &712/12' - '&6Endermans Killed: &724/24' - '&6Progress: &7100%' - - '&a&l ✔ &7Already Claimed.' \ No newline at end of file + - '&a&l ✔ &7Already Claimed.' + amount: 3 \ No newline at end of file diff --git a/src/main/resources/modules/missions/categories/slayer/slayer_4.yml b/src/main/resources/modules/missions/categories/slayer/slayer_4.yml index ffc90f950d..aac8ab46a1 100644 --- a/src/main/resources/modules/missions/categories/slayer/slayer_4.yml +++ b/src/main/resources/modules/missions/categories/slayer/slayer_4.yml @@ -11,7 +11,7 @@ mission-file: KillsMissions # Whether the mission should be given when completing all requirements. auto-reward: true -# Should block counts of players get reset when completing the mission? +# Should entity counts of players get reset when completing the mission? reset-after-finish: true # Rewards given when completing the mission. @@ -29,7 +29,7 @@ required-missions: - 'slayer_2' - 'slayer_3' -# List of all required blocks must be gathered in order to complete the mission. +# List of all required entities must be gathered in order to complete the mission. required-entities: '1': types: @@ -53,6 +53,7 @@ icons: - '&8 - &7Unlock The End' - '' - '&6Wither Killed: &c&l ✘' + amount: 4 can-complete: type: PAPER name: '&aSlayer IV' @@ -69,10 +70,8 @@ icons: - '' - '&6Wither Killed: &a&l ✔' - '&a&l ✔ &7Click to redeem your reward.' - enchants: - DURABILITY: 1 - flags: - - HIDE_ENCHANTS + amount: 4 + glow: true completed: type: MAP name: '&aSlayer IV' @@ -85,4 +84,5 @@ icons: - '&8 - &7Unlock The End' - '' - '&6Wither Killed: &a&l ✔' - - '&a&l ✔ &7Click to redeem your reward.' \ No newline at end of file + - '&a&l ✔ &7Click to redeem your reward.' + amount: 4 \ No newline at end of file From abff6176f8f3259387df356ee0e70a5cced64de4 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 23 Aug 2025 10:30:50 +0200 Subject: [PATCH 259/600] Added placeholders and reorganized the placeholder file for better readability (#2532) --- .../placeholders/PlaceholdersServiceImpl.java | 643 ++++++++++++++---- 1 file changed, 501 insertions(+), 142 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index b73efdbab8..a48bfa6f06 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -6,26 +6,35 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.service.placeholders.IslandPlaceholderParser; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlayerPlaceholderParser; +import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; +import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.values.BlockValue; import com.bgsoftware.superiorskyblock.external.placeholders.PlaceholdersProvider; +import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.service.IService; +import com.bgsoftware.superiorskyblock.world.Dimensions; import com.google.common.collect.ImmutableMap; import org.bukkit.Location; import org.bukkit.OfflinePlayer; +import org.bukkit.potion.PotionEffectType; +import java.math.BigDecimal; import java.time.Duration; import java.util.Date; import java.util.HashMap; @@ -45,13 +54,32 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { private static final Pattern ISLAND_PLACEHOLDER_PATTERN = Pattern.compile("island_(.+)"); private static final Pattern PLAYER_PLACEHOLDER_PATTERN = Pattern.compile("player_(.+)"); + + private static final Pattern BLOCK_COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_block_count_(.+)"); + private static final Pattern BLOCK_LEVEL_PLACEHOLDER_PATTERN = Pattern.compile("island_block_level_(.+)"); + private static final Pattern BLOCK_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile("island_block_limit_(.+)"); + private static final Pattern BLOCK_TOTAL_LEVEL_PLACEHOLDER_PATTERN = Pattern.compile("island_block_total_level_(.+)"); + private static final Pattern BLOCK_TOTAL_WORTH_PLACEHOLDER_PATTERN = Pattern.compile("island_block_total_worth_(.+)"); + private static final Pattern BLOCK_WORTH_PLACEHOLDER_PATTERN = Pattern.compile("island_block_worth_(.+)"); + private static final Pattern COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_block_count_(.+)"); + private static final Pattern DATA_PLACEHOLDER_PATTERN = Pattern.compile("island_data_(.+)"); + private static final Pattern EFFECT_PLACEHOLDER_PATTERN = Pattern.compile("island_effect_(.+)"); + private static final Pattern ENTITY_COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_entity_count_(.+)"); + private static final Pattern ENTITY_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile("island_entity_limit_(.+)"); + private static final Pattern FLAG_PLACEHOLDER_PATTERN = Pattern.compile("flag_(.+)"); + private static final Pattern GENERATOR_AMOUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_generator_amount_(.+)"); + private static final Pattern GENERATOR_PERCENTAGE_PLACEHOLDER_PATTERN = Pattern.compile("island_generator_percentage_(.+)"); + private static final Pattern GENERATOR_NORMAL_PLACEHOLDER_PATTERN = Pattern.compile("normal_(.+)"); + private static final Pattern GENERATOR_NETHER_PLACEHOLDER_PATTERN = Pattern.compile("nether_(.+)"); + private static final Pattern GENERATOR_END_PLACEHOLDER_PATTERN = Pattern.compile("end_(.+)"); + private static final Pattern MEMBER_PLACEHOLDER_PATTERN = Pattern.compile("member_(.+)"); + private static final Pattern MISSIONS_COMPLETED_PATTERN = Pattern.compile("missions_completed_(.+)"); + private static final Pattern MISSION_STATUS_PATTERN = Pattern.compile("mission_status_(.+)"); private static final Pattern PERMISSION_PLACEHOLDER_PATTERN = Pattern.compile("island_permission_(.+)"); private static final Pattern PERMISSION_ROLE_PLACEHOLDER_PATTERN = Pattern.compile("island_permission_role_(.+)"); + private static final Pattern ROLE_COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_role_count_(.+)"); + private static final Pattern ROLE_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile("island_role_limit_(.+)"); private static final Pattern UPGRADE_PLACEHOLDER_PATTERN = Pattern.compile("island_upgrade_(.+)"); - private static final Pattern COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_count_(.+)"); - private static final Pattern BLOCK_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile("island_block_limit_(.+)"); - private static final Pattern ENTITY_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile("island_entity_limit_(.+)"); - private static final Pattern ENTITY_COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_entity_count_(.+)"); private static final Pattern TOP_PLACEHOLDER_PATTERN = Pattern.compile("island_top_(.+)"); private static final Pattern TOP_WORTH_PLACEHOLDER_PATTERN = Pattern.compile("worth_(.+)"); private static final Pattern TOP_LEVEL_PLACEHOLDER_PATTERN = Pattern.compile("level_(.+)"); @@ -62,51 +90,247 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { private static final Pattern TOP_VALUE_PLACEHOLDER_PATTERN = Pattern.compile("value_(.+)"); private static final Pattern TOP_LEADER_PLACEHOLDER_PATTERN = Pattern.compile("leader_(.+)"); private static final Pattern TOP_CUSTOM_PLACEHOLDER_PATTERN = Pattern.compile("(\\d+)_(.+)"); - private static final Pattern MEMBER_PLACEHOLDER_PATTERN = Pattern.compile("member_(.+)"); private static final Pattern VISITOR_LAST_JOIN_PLACEHOLDER_PATTERN = Pattern.compile("visitor_last_join_(.+)"); - private static final Pattern ISLAND_FLAG_PLACEHOLDER_PATTERN = Pattern.compile("flag_(.+)"); - private static final Pattern MISSIONS_COMPLETED_PATTERN = Pattern.compile("missions_completed_(.+)"); - private static final Pattern MISSION_STATUS_PATTERN = Pattern.compile("mission_status_(.+)"); private static final Map PLAYER_PARSES = new ImmutableMap.Builder() - .put("texture", SuperiorPlayer::getTextureValue) - .put("role", superiorPlayer -> superiorPlayer.getPlayerRole().toString()) - .put("role_display", superiorPlayer -> superiorPlayer.getPlayerRole().getDisplayName()) - .put("locale", superiorPlayer -> Formatters.LOCALE_FORMATTER.format(superiorPlayer.getUserLocale())) - .put("world_border", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasWorldBorderEnabled(), superiorPlayer.getUserLocale())) - .put("blocks_stacker", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasBlocksStackerEnabled(), superiorPlayer.getUserLocale())) - .put("schematics", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasSchematicModeEnabled(), superiorPlayer.getUserLocale())) - .put("team_chat", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasTeamChatEnabled(), superiorPlayer.getUserLocale())) - .put("bypass", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasBypassModeEnabled(), superiorPlayer.getUserLocale())) - .put("disbands", superiorPlayer -> superiorPlayer.getDisbands() + "") - .put("panel", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasToggledPanel(), superiorPlayer.getUserLocale())) - .put("fly", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasIslandFlyEnabled(), superiorPlayer.getUserLocale())) - .put("chat_spy", superiorPlayer -> Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasAdminSpyEnabled(), superiorPlayer.getUserLocale())) + .put("blocks_stacker", superiorPlayer -> + Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasBlocksStackerEnabled(), superiorPlayer.getUserLocale())) .put("border_color", superiorPlayer -> Formatters.BORDER_COLOR_FORMATTER.format(superiorPlayer.getBorderColor(), superiorPlayer.getUserLocale())) - .put("missions_completed", superiorPlayer -> superiorPlayer.getCompletedMissions().size() + "") + .put("bypass", superiorPlayer -> + Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasBypassModeEnabled(), superiorPlayer.getUserLocale())) + .put("chat_spy", superiorPlayer -> + Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasAdminSpyEnabled(), superiorPlayer.getUserLocale())) + .put("disbands", superiorPlayer -> + superiorPlayer.getDisbands() + "") + .put("fly", superiorPlayer -> + Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasIslandFlyEnabled(), superiorPlayer.getUserLocale())) + .put("locale", superiorPlayer -> + Formatters.LOCALE_FORMATTER.format(superiorPlayer.getUserLocale())) + .put("missions_completed", superiorPlayer -> + superiorPlayer.getCompletedMissions().size() + "") + .put("panel", superiorPlayer -> + Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasToggledPanel(), superiorPlayer.getUserLocale())) + .put("role", superiorPlayer -> + superiorPlayer.getPlayerRole().toString()) + .put("role_display", superiorPlayer -> + superiorPlayer.getPlayerRole().getDisplayName()) + .put("schematics", superiorPlayer -> + Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasSchematicModeEnabled(), superiorPlayer.getUserLocale())) + .put("team_chat", superiorPlayer -> + Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasTeamChatEnabled(), superiorPlayer.getUserLocale())) + .put("texture", SuperiorPlayer::getTextureValue) + .put("world_border", superiorPlayer -> + Formatters.BOOLEAN_FORMATTER.format(superiorPlayer.hasWorldBorderEnabled(), superiorPlayer.getUserLocale())) .build(); @SuppressWarnings("ConstantConditions") private static final Map ISLAND_PARSES = new ImmutableMap.Builder() + // Island Placeholders + .put("bank", (island, superiorPlayer) -> + Formatters.NUMBER_FORMATTER.format(island.getIslandBank().getBalance())) + .put("bank_format", (island, superiorPlayer) -> + Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandBank().getBalance(), superiorPlayer.getUserLocale())) + .put("bank_int", (island, superiorPlayer) -> + island.getIslandBank().getBalance().toBigInteger().toString()) + .put("bank_raw", (island, superiorPlayer) -> + island.getIslandBank().getBalance().toString()) + .put("bank_limit", (island, superiorPlayer) -> + Formatters.NUMBER_FORMATTER.format(island.getBankLimit())) + .put("bank_limit_format", (island, superiorPlayer) -> + Formatters.FANCY_NUMBER_FORMATTER.format(island.getBankLimit(), superiorPlayer.getUserLocale())) + .put("bank_limit_int", (island, superiorPlayer) -> + island.getBankLimit().toBigInteger().toString()) + .put("bank_limit_raw", (island, superiorPlayer) -> + island.getBankLimit().toString()) + .put("bank_last_interest", (island, superiorPlayer) -> + Formatters.TIME_FORMATTER.format(Duration.ofSeconds(island.getLastInterestTime()), superiorPlayer.getUserLocale())) + .put("bank_next_interest", (island, superiorPlayer) -> + Formatters.TIME_FORMATTER.format(Duration.ofSeconds(island.getNextInterest()), superiorPlayer.getUserLocale())) + .put("bans_count", (island, superiorPlayer) -> + island.getBannedPlayers().size() + "") + .put("bans_list", (island, superiorPlayer) -> { + StringBuilder teamBuilder = new StringBuilder(); + List players = island.getBannedPlayers(); + if (players.isEmpty()) { + return ""; + } + for (SuperiorPlayer player : players) { + teamBuilder.append(", ").append(player.getName()); + } + return teamBuilder.substring(2); + }) + .put("biome", (island, superiorPlayer) -> + Formatters.CAPITALIZED_FORMATTER.format(island.getBiome().name())) + .put("bonus_level", (island, superiorPlayer) -> + Formatters.NUMBER_FORMATTER.format(island.getBonusLevel())) + .put("bonus_level_format", (island, superiorPlayer) -> + Formatters.FANCY_NUMBER_FORMATTER.format(island.getBonusLevel(), superiorPlayer.getUserLocale())) + .put("bonus_level_int", (island, superiorPlayer) -> + island.getBonusLevel().toBigInteger().toString()) + .put("bonus_level_raw", (island, superiorPlayer) -> + island.getBonusLevel().toString()) + .put("bonus_worth", (island, superiorPlayer) -> + Formatters.NUMBER_FORMATTER.format(island.getBonusWorth())) + .put("bonus_worth_format", (island, superiorPlayer) -> + Formatters.FANCY_NUMBER_FORMATTER.format(island.getBonusWorth(), superiorPlayer.getUserLocale())) + .put("bonus_worth_int", (island, superiorPlayer) -> + island.getBonusWorth().toBigInteger().toString()) + .put("bonus_worth_raw", (island, superiorPlayer) -> + island.getBonusWorth().toString()) .put("center", (island, superiorPlayer) -> Formatters.BLOCK_POSITION_FORMATTER.format(island.getCenterPosition(), getDefaultWorldInfo(island))) - .put("x", (island, superiorPlayer) -> + .put("center_x", (island, superiorPlayer) -> island.getCenterPosition().getX() + "") - .put("y", (island, superiorPlayer) -> + .put("center_y", (island, superiorPlayer) -> island.getCenterPosition().getY() + "") - .put("z", (island, superiorPlayer) -> + .put("center_z", (island, superiorPlayer) -> island.getCenterPosition().getZ() + "") - .put("world", (island, superiorPlayer) -> getDefaultWorldInfo(island).getName()) - .put("schematic", (island, superiorPlayer) -> island.getSchematicName()) - .put("team_size", (island, superiorPlayer) -> island.getIslandMembers(true).size() + "") - .put("team_size_online", (island, superiorPlayer) -> - island.getIslandMembers(true).stream().filter(SuperiorPlayer::isShownAsOnline).count() + "") - .put("team_limit", (island, superiorPlayer) -> island.getTeamLimit() + "") - .put("coop_limit", (island, superiorPlayer) -> island.getCoopLimit() + "") - .put("leader", (island, superiorPlayer) -> island.getOwner().getName()) + .put("chest_size", (island, superiorPlayer) -> + island.getChestSize() + "") + .put("coop_limit", (island, superiorPlayer) -> + island.getCoopLimit() + "") + .put("coop_list", (island, superiorPlayer) -> { + StringBuilder teamBuilder = new StringBuilder(); + List players = island.getCoopPlayers(); + if (players.isEmpty()) { + return ""; + } + for (SuperiorPlayer player : players) { + teamBuilder.append(", ").append(player.getName()); + } + return teamBuilder.substring(2); + }) + .put("coop_size", (island, superiorPlayer) -> + island.getCoopPlayers().size() + "") + .put("creation_time", (island, superiorPlayer) -> + island.getCreationTimeDate()) + .put("crops_multiplier", (island, superiorPlayer) -> + island.getCropGrowthMultiplier() + "") + .put("description", (island, superiorPlayer) -> + island.getDescription()) + .put("discord", (island, superiorPlayer) -> + island.hasPermission(superiorPlayer, IslandPrivileges.DISCORD_SHOW) ? island.getDiscord() : "None") + .put("discord_all", (island, superiorPlayer) -> + island.getDiscord()) + .put("drops_multiplier", (island, superiorPlayer) -> + island.getMobDropsMultiplier() + "") + .put("end_unlocked", (island, superiorPlayer) -> + Formatters.BOOLEAN_FORMATTER.format(island.isEndEnabled(), superiorPlayer.getUserLocale())) + .put("exists", (island, superiorPlayer) -> + Formatters.BOOLEAN_FORMATTER.format(island != null, superiorPlayer.getUserLocale())) + .put("home", (island, superiorPlayer) -> + Formatters.LOCATION_FORMATTER.format(island.getIslandHome(getDefaultWorldInfo(island).getDimension()))) + .put("home_x", (island, superiorPlayer) -> + island.getIslandHome(getDefaultWorldInfo(island).getDimension()).getBlockX() + "") + .put("home_y", (island, superiorPlayer) -> + island.getIslandHome(getDefaultWorldInfo(island).getDimension()).getBlockY() + "") + .put("home_z", (island, superiorPlayer) -> + island.getIslandHome(getDefaultWorldInfo(island).getDimension()).getBlockZ() + "") + .put("is_coop", (island, superiorPlayer) -> + Formatters.BOOLEAN_FORMATTER.format(island.isCoop(superiorPlayer), superiorPlayer.getUserLocale())) + .put("is_leader", (island, superiorPlayer) -> + Formatters.BOOLEAN_FORMATTER.format(island.getOwner().equals(superiorPlayer), superiorPlayer.getUserLocale())) + .put("is_member", (island, superiorPlayer) -> + Formatters.BOOLEAN_FORMATTER.format(island.isMember(superiorPlayer), superiorPlayer.getUserLocale())) + .put("is_visitor", (island, superiorPlayer) -> + Formatters.BOOLEAN_FORMATTER.format(island.isVisitor(superiorPlayer, true), superiorPlayer.getUserLocale())) + .put("last_time_updated", (island, superiorPlayer) -> + Formatters.TIME_FORMATTER.format(Duration.ofSeconds(island.getLastTimeUpdate()), superiorPlayer.getUserLocale())) + .put("leader", (island, superiorPlayer) -> + island.getOwner().getName()) + .put("level", (island, superiorPlayer) -> + Formatters.NUMBER_FORMATTER.format(island.getIslandLevel())) + .put("level_format", (island, superiorPlayer) -> + Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandLevel(), superiorPlayer.getUserLocale())) + .put("level_int", (island, superiorPlayer) -> + island.getIslandLevel().toBigInteger().toString()) + .put("level_raw", (island, superiorPlayer) -> + island.getIslandLevel().toString()) + .put("locked", (island, superiorPlayer) -> + Formatters.BOOLEAN_FORMATTER.format(island.isLocked(), superiorPlayer.getUserLocale())) + .put("name", (island, superiorPlayer) -> + plugin.getSettings().getIslandNames().isColorSupport() ? + Formatters.COLOR_FORMATTER.format(island.getName()) : island.getName()) + .put("name_leader", (island, superiorPlayer) -> + island.getName().isEmpty() ? island.getOwner().getName() : + plugin.getSettings().getIslandNames().isColorSupport() ? + Formatters.COLOR_FORMATTER.format(island.getName()) : island.getName()) + .put("nether_unlocked", (island, superiorPlayer) -> + Formatters.BOOLEAN_FORMATTER.format(island.isNetherEnabled(), superiorPlayer.getUserLocale())) + .put("normal_unlocked", (island, superiorPlayer) -> + Formatters.BOOLEAN_FORMATTER.format(island.isNormalEnabled(), superiorPlayer.getUserLocale())) + .put("paypal", (island, superiorPlayer) -> + island.hasPermission(superiorPlayer, IslandPrivileges.PAYPAL_SHOW) ? island.getPaypal() : "None") + .put("paypal_all", (island, superiorPlayer) -> + island.getPaypal()) + .put("players_count", (island, superiorPlayer) -> + island.getAllPlayersInside().size() + "") + .put("players_list", (island, superiorPlayer) -> { + StringBuilder teamBuilder = new StringBuilder(); + List players = island.getAllPlayersInside(); + if (players.isEmpty()) { + return ""; + } + for (SuperiorPlayer player : players) { + teamBuilder.append(", ").append(player.getName()); + } + return teamBuilder.substring(2); + }) + .put("radius", (island, superiorPlayer) -> + island.getIslandSize() + "") + .put("rating", (island, superiorPlayer) -> + island.getTotalRating() + "") + .put("rating_amount", (island, superiorPlayer) -> + island.getRatingAmount() + "") + .put("rating_stars", (island, superiorPlayer) -> + Formatters.RATING_FORMATTER.format(island.getTotalRating(), superiorPlayer.getUserLocale())) + .put("raw_bank_limit", (island, superiorPlayer) -> + Formatters.NUMBER_FORMATTER.format(island.getBankLimitRaw())) + .put("raw_bank_limit_format", (island, superiorPlayer) -> + Formatters.FANCY_NUMBER_FORMATTER.format(island.getBankLimitRaw(), superiorPlayer.getUserLocale())) + .put("raw_bank_limit_int", (island, superiorPlayer) -> + island.getBankLimitRaw().toBigInteger().toString()) + .put("raw_bank_limit_raw", (island, superiorPlayer) -> + island.getBankLimitRaw().toString()) + .put("raw_coop_limit", (island, superiorPlayer) -> + island.getCoopLimitRaw() + "") + .put("raw_crops_multiplier", (island, superiorPlayer) -> + island.getCropGrowthRaw() + "") + .put("raw_drops_multiplier", (island, superiorPlayer) -> + island.getMobDropsRaw() + "") + .put("raw_level", (island, superiorPlayer) -> + Formatters.NUMBER_FORMATTER.format(island.getRawLevel())) + .put("raw_level_format", (island, superiorPlayer) -> + Formatters.FANCY_NUMBER_FORMATTER.format(island.getRawLevel(), superiorPlayer.getUserLocale())) + .put("raw_level_int", (island, superiorPlayer) -> + island.getRawLevel().toBigInteger().toString()) + .put("raw_level_raw", (island, superiorPlayer) -> + island.getRawLevel().toString()) + .put("raw_radius", (island, superiorPlayer) -> + island.getIslandSizeRaw() + "") + .put("raw_spawners_multiplier", (island, superiorPlayer) -> + island.getSpawnerRatesRaw() + "") + .put("raw_team_limit", (island, superiorPlayer) -> + island.getTeamLimitRaw() + "") + .put("raw_warps_limit", (island, superiorPlayer) -> + island.getWarpsLimitRaw() + "") + .put("raw_worth", (island, superiorPlayer) -> + Formatters.NUMBER_FORMATTER.format(island.getRawWorth())) + .put("raw_worth_format", (island, superiorPlayer) -> + Formatters.FANCY_NUMBER_FORMATTER.format(island.getRawWorth(), superiorPlayer.getUserLocale())) + .put("raw_worth_int", (island, superiorPlayer) -> + island.getRawWorth().toBigInteger().toString()) + .put("raw_worth_raw", (island, superiorPlayer) -> + island.getRawWorth().toString()) + .put("schematic", (island, superiorPlayer) -> + island.getSchematicName()) + .put("size", (island, superiorPlayer) -> { + int size = island.getIslandSize() * 2 + 1; + return size + " x " + size; + }) .put("size_format", (island, superiorPlayer) -> { int size = island.getIslandSize() * 2 + 1; int rounded = 5 * (Math.round(size / 5.0F)); @@ -114,80 +338,107 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { size = rounded; return size + " x " + size; }) - .put("size", (island, superiorPlayer) -> { - int size = island.getIslandSize() * 2 + 1; - return size + " x " + size; + .put("spawners_multiplier", (island, superiorPlayer) -> + island.getSpawnerRatesMultiplier() + "") + .put("team_limit", (island, superiorPlayer) -> + island.getTeamLimit() + "") + .put("team_list", (island, superiorPlayer) -> { + StringBuilder teamBuilder = new StringBuilder(); + List players = island.getIslandMembers(true); + if (players.isEmpty()) { + return ""; + } + for (SuperiorPlayer player : players) { + teamBuilder.append(", ").append(player.getName()); + } + return teamBuilder.substring(2); }) - .put("radius", (island, superiorPlayer) -> island.getIslandSize() + "") - .put("biome", (island, superiorPlayer) -> Formatters.CAPITALIZED_FORMATTER.format(island.getBiome().name())) - .put("level", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getIslandLevel())) - .put("level_raw", (island, superiorPlayer) -> island.getIslandLevel().toString()) - .put("level_format", (island, superiorPlayer) -> - Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandLevel(), superiorPlayer.getUserLocale())) - .put("level_int", (island, superiorPlayer) -> island.getIslandLevel().toBigInteger().toString()) - .put("worth", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getWorth())) - .put("worth_raw", (island, superiorPlayer) -> island.getWorth().toString()) - .put("worth_format", (island, superiorPlayer) -> - Formatters.FANCY_NUMBER_FORMATTER.format(island.getWorth(), superiorPlayer.getUserLocale())) - .put("worth_int", (island, superiorPlayer) -> island.getWorth().toBigInteger().toString()) - .put("raw_worth", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getRawWorth())) - .put("raw_worth_format", (island, superiorPlayer) -> - Formatters.FANCY_NUMBER_FORMATTER.format(island.getRawWorth(), superiorPlayer.getUserLocale())) - .put("bank", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getIslandBank().getBalance())) - .put("bank_raw", (island, superiorPlayer) -> island.getIslandBank().getBalance().toString()) - .put("bank_format", (island, superiorPlayer) -> - Formatters.FANCY_NUMBER_FORMATTER.format(island.getIslandBank().getBalance(), superiorPlayer.getUserLocale())) - .put("bank_next_interest", (island, superiorPlayer) -> - Formatters.TIME_FORMATTER.format(Duration.ofSeconds(island.getNextInterest()), superiorPlayer.getUserLocale())) - .put("hoppers_limit", (island, superiorPlayer) -> island.getBlockLimit(ConstantKeys.HOPPER) + "") - .put("crops_multiplier", (island, superiorPlayer) -> island.getCropGrowthMultiplier() + "") - .put("spawners_multiplier", (island, superiorPlayer) -> island.getSpawnerRatesMultiplier() + "") - .put("drops_multiplier", (island, superiorPlayer) -> island.getMobDropsMultiplier() + "") - .put("discord", (island, superiorPlayer) -> - island.hasPermission(superiorPlayer, IslandPrivileges.DISCORD_SHOW) ? island.getDiscord() : "None") - .put("paypal", (island, superiorPlayer) -> - island.hasPermission(superiorPlayer, IslandPrivileges.PAYPAL_SHOW) ? island.getPaypal() : "None") - .put("discord_all", (island, superiorPlayer) -> island.getDiscord()) - .put("paypal_all", (island, superiorPlayer) -> island.getPaypal()) - .put("exists", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island != null, superiorPlayer.getUserLocale())) - .put("locked", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isLocked(), superiorPlayer.getUserLocale())) - .put("name", (island, superiorPlayer) -> { - return plugin.getSettings().getIslandNames().isColorSupport() ? - Formatters.COLOR_FORMATTER.format(island.getName()) : island.getName(); + .put("team_size", (island, superiorPlayer) -> + island.getIslandMembers(true).size() + "") + .put("team_size_online", (island, superiorPlayer) -> + island.getIslandMembers(true).stream().filter(SuperiorPlayer::isShownAsOnline).count() + "") + .put("unique_visitors_count", (island, superiorPlayer) -> + island.getUniqueVisitors().size() + "") + .put("unique_visitors_list", (island, superiorPlayer) -> { + StringBuilder teamBuilder = new StringBuilder(); + List players = island.getUniqueVisitors(); + if (players.isEmpty()) { + return ""; + } + for (SuperiorPlayer player : players) { + teamBuilder.append(", ").append(player.getName()); + } + return teamBuilder.substring(2); }) - .put("name_leader", (island, superiorPlayer) -> { - return island.getName().isEmpty() ? island.getOwner().getName() : - plugin.getSettings().getIslandNames().isColorSupport() ? - Formatters.COLOR_FORMATTER.format(island.getName()) : island.getName(); + .put("uuid", (island, superiorPlayer) -> + island.getUniqueId() + "") + .put("visitors_count", (island, superiorPlayer) -> + island.getIslandVisitors(false).size() + "") + .put("visitors_list", (island, superiorPlayer) -> { + StringBuilder teamBuilder = new StringBuilder(); + List players = island.getIslandVisitors(); + if (players.isEmpty()) { + return ""; + } + for (SuperiorPlayer player : players) { + teamBuilder.append(", ").append(player.getName()); + } + return teamBuilder.substring(2); }) - .put("is_leader", (island, superiorPlayer) -> - Formatters.BOOLEAN_FORMATTER.format(island.getOwner().equals(superiorPlayer), superiorPlayer.getUserLocale())) - .put("is_member", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isMember(superiorPlayer), superiorPlayer.getUserLocale())) - .put("is_coop", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isCoop(superiorPlayer), superiorPlayer.getUserLocale())) - .put("rating", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getTotalRating())) - .put("rating_amount", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getRatingAmount())) - .put("rating_stars", (island, superiorPlayer) -> - Formatters.RATING_FORMATTER.format(island.getTotalRating(), superiorPlayer.getUserLocale())) - .put("warps_limit", (island, superiorPlayer) -> island.getWarpsLimit() + "") - .put("warps", (island, superiorPlayer) -> island.getIslandWarps().size() + "") - .put("creation_time", (island, superiorPlayer) -> island.getCreationTimeDate()) - .put("total_worth", (island, superiorPlayer) -> - Formatters.NUMBER_FORMATTER.format(plugin.getGrid().getTotalWorth())) - .put("total_worth_format", (island, superiorPlayer) -> - Formatters.FANCY_NUMBER_FORMATTER.format(plugin.getGrid().getTotalWorth(), superiorPlayer.getUserLocale())) + .put("visitors_location", (island, superiorPlayer) -> + Formatters.LOCATION_FORMATTER.format(island.getVisitorsLocation(getDefaultWorldInfo(island).getDimension()))) + .put("visitors_location_x", (island, superiorPlayer) -> + island.getVisitorsLocation(getDefaultWorldInfo(island).getDimension()).getBlockX() + "") + .put("visitors_location_y", (island, superiorPlayer) -> + island.getVisitorsLocation(getDefaultWorldInfo(island).getDimension()).getBlockY() + "") + .put("visitors_location_z", (island, superiorPlayer) -> + island.getVisitorsLocation(getDefaultWorldInfo(island).getDimension()).getBlockZ() + "") + .put("warps", (island, superiorPlayer) -> + island.getIslandWarps().size() + "") + .put("warps_limit", (island, superiorPlayer) -> + island.getWarpsLimit() + "") + .put("world", (island, superiorPlayer) -> + getDefaultWorldInfo(island).getName()) + .put("worth", (island, superiorPlayer) -> + Formatters.NUMBER_FORMATTER.format(island.getWorth())) + .put("worth_format", (island, superiorPlayer) -> + Formatters.FANCY_NUMBER_FORMATTER.format(island.getWorth(), superiorPlayer.getUserLocale())) + .put("worth_int", (island, superiorPlayer) -> + island.getWorth().toBigInteger().toString()) + .put("worth_raw", (island, superiorPlayer) -> + island.getWorth().toString()) + // Renamed Island Placeholders + .put("hoppers_limit", (island, superiorPlayer) -> + island.getBlockLimit(ConstantKeys.HOPPER) + "") + .put("x", (island, superiorPlayer) -> + island.getCenterPosition().getX() + "") + .put("y", (island, superiorPlayer) -> + island.getCenterPosition().getY() + "") + .put("z", (island, superiorPlayer) -> + island.getCenterPosition().getZ() + "") + // Global Placeholders + .put("total_count", (island, superiorPlayer) -> + Formatters.NUMBER_FORMATTER.format(plugin.getGrid().getIslands().size())) + .put("total_count_format", (island, superiorPlayer) -> + Formatters.FANCY_NUMBER_FORMATTER.format(plugin.getGrid().getIslands().size(), superiorPlayer.getUserLocale())) + .put("total_count_raw", (island, superiorPlayer) -> + plugin.getGrid().getIslands().size() + "") .put("total_level", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(plugin.getGrid().getTotalLevel())) .put("total_level_format", (island, superiorPlayer) -> Formatters.FANCY_NUMBER_FORMATTER.format(plugin.getGrid().getTotalLevel(), superiorPlayer.getUserLocale())) - .put("nether_unlocked", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isNetherEnabled(), superiorPlayer.getUserLocale())) - .put("end_unlocked", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isEndEnabled(), superiorPlayer.getUserLocale())) - .put("visitors_count", (island, superiorPlayer) -> { - return island.getIslandVisitors(false).size() + ""; - }) - .put("bank_limit", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(island.getBankLimit())) - .put("bank_limit_format", (island, superiorPlayer) -> - Formatters.FANCY_NUMBER_FORMATTER.format(island.getBankLimit(), superiorPlayer.getUserLocale())) - .put("uuid", (island, superiorPlayer) -> island.getUniqueId() + "") + .put("total_level_int", (island, superiorPlayer) -> + plugin.getGrid().getTotalLevel().toBigInteger().toString()) + .put("total_level_raw", (island, superiorPlayer) -> + plugin.getGrid().getTotalLevel().toString()) + .put("total_worth", (island, superiorPlayer) -> + Formatters.NUMBER_FORMATTER.format(plugin.getGrid().getTotalWorth())) + .put("total_worth_format", (island, superiorPlayer) -> + Formatters.FANCY_NUMBER_FORMATTER.format(plugin.getGrid().getTotalWorth(), superiorPlayer.getUserLocale())) + .put("total_worth_int", (island, superiorPlayer) -> + plugin.getGrid().getTotalWorth().toBigInteger().toString()) + .put("total_worth_raw", (island, superiorPlayer) -> + plugin.getGrid().getTotalWorth().toString()) .build(); private static final Map> TOP_VALUE_FORMAT_FUNCTIONS = @@ -279,9 +530,11 @@ public String handlePluginPlaceholder(@Nullable OfflinePlayer offlinePlayer, Str } else if ((matcher = ISLAND_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String subPlaceholder = matcher.group(1).toLowerCase(Locale.ENGLISH); Island island; + boolean isLocationPlaceholder = false; if (superiorPlayer == null) { island = null; } else if (subPlaceholder.startsWith("location_")) { + isLocationPlaceholder = true; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(superiorPlayer.getLocation(wrapper.getHandle())); } @@ -289,8 +542,8 @@ public String handlePluginPlaceholder(@Nullable OfflinePlayer offlinePlayer, Str island = superiorPlayer.getIsland(); } placeholderResult = parsePlaceholdersForIsland(island, superiorPlayer, - placeholder.replace("location_", ""), - subPlaceholder.replace("location_", "")); + isLocationPlaceholder ? placeholder.substring(9) : placeholder, + isLocationPlaceholder ? subPlaceholder.substring(9) : subPlaceholder); } } @@ -343,8 +596,12 @@ private static Optional parsePlaceholdersForIsland(@Nullable Island isla Matcher matcher; if (island != null) { - if ((matcher = PERMISSION_ROLE_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { - return handlePermissionRolesPlaceholder(island, matcher.group(1)); + if ((matcher = GENERATOR_AMOUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + return handleGeneratorAmountsPlaceholder(island, matcher.group(1)); + } + + if ((matcher = GENERATOR_PERCENTAGE_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + return handleGeneratorPercentagesPlaceholder(island, matcher.group(1)); } if ((matcher = MISSIONS_COMPLETED_PATTERN.matcher(subPlaceholder)).matches()) { @@ -363,28 +620,89 @@ private static Optional parsePlaceholdersForIsland(@Nullable Island isla return Optional.of(Formatters.BOOLEAN_FORMATTER.format(completedMission, superiorPlayer.getUserLocale())); } + if ((matcher = PERMISSION_ROLE_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + return handlePermissionRolesPlaceholder(island, matcher.group(1)); + } + if (superiorPlayer != null) { - if ((matcher = PERMISSION_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { - return handlePermissionsPlaceholder(island, superiorPlayer, matcher.group(1)); - } else if ((matcher = UPGRADE_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { - String upgradeName = matcher.group(1); - return Optional.of(island.getUpgradeLevel(plugin.getUpgrades() - .getUpgrade(upgradeName)).getLevel() + ""); - } else if ((matcher = COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + if ((matcher = BLOCK_COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + String keyName = matcher.group(1); + return Optional.of(island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName)) + ""); + } else if ((matcher = BLOCK_LEVEL_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); - return Optional.of(Formatters.NUMBER_FORMATTER.format(island - .getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName)))); + BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName)); + return Optional.of(blockValue.getLevel() + ""); } else if ((matcher = BLOCK_LIMIT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); return Optional.of(island.getBlockLimit(Keys.ofMaterialAndData(keyName)) + ""); - } else if ((matcher = ENTITY_LIMIT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + } else if ((matcher = BLOCK_TOTAL_LEVEL_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); - return Optional.of(island.getEntityLimit(Keys.ofEntityType(keyName)) + ""); + BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName)); + BigDecimal amount = new BigDecimal(island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName))); + return Optional.of(blockValue.getLevel().multiply(amount) + ""); + } else if ((matcher = BLOCK_TOTAL_WORTH_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + String keyName = matcher.group(1); + BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName)); + BigDecimal amount = new BigDecimal(island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName))); + return Optional.of(blockValue.getWorth().multiply(amount) + ""); + } else if ((matcher = BLOCK_WORTH_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + String keyName = matcher.group(1); + BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName)); + return Optional.of(blockValue.getWorth() + ""); + } else if ((matcher = COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + String keyName = matcher.group(1); + return Optional.of(island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName)) + ""); + } else if ((matcher = DATA_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + String keyName = matcher.group(1); + Object data = island.getPersistentDataContainer().get(keyName); + if (data == null) { + return Optional.empty(); + } + return Optional.of(data.toString()); + } else if ((matcher = EFFECT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + String effectName = matcher.group(1); + PotionEffectType potionEffectType = PotionEffectType.getByName(effectName); + if (potionEffectType == null) { + return Optional.empty(); + } + return Optional.of(island.getPotionEffectLevel(potionEffectType) + ""); } else if ((matcher = ENTITY_COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); - return Optional.of(Formatters.NUMBER_FORMATTER.format(island.getEntitiesTracker().getEntityCount(Keys.ofEntityType(keyName)))); + return Optional.of(island.getEntitiesTracker().getEntityCount(Keys.ofEntityType(keyName)) + ""); + } else if ((matcher = ENTITY_LIMIT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + String keyName = matcher.group(1); + return Optional.of(island.getEntityLimit(Keys.ofEntityType(keyName)) + ""); + } else if ((matcher = FLAG_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { + return handleFlagsPlaceholder(island, superiorPlayer, matcher.group(1)); } else if ((matcher = MEMBER_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { return handleMembersPlaceholder(island, matcher.group(1)); + } else if ((matcher = PERMISSION_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + return handlePermissionsPlaceholder(island, superiorPlayer, matcher.group(1)); + } else if ((matcher = ROLE_COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + String roleName = matcher.group(1); + PlayerRole playerRole; + try { + playerRole = SPlayerRole.of(roleName); + } catch (IllegalArgumentException error) { + return Optional.empty(); + } + return Optional.of(island.getIslandMembers(playerRole).size() + ""); + } else if ((matcher = ROLE_LIMIT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + String roleName = matcher.group(1); + PlayerRole playerRole; + try { + playerRole = SPlayerRole.of(roleName); + } catch (IllegalArgumentException error) { + return Optional.empty(); + } + return Optional.of(island.getRoleLimit(playerRole) + ""); + } else if ((matcher = UPGRADE_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + String upgradeName = matcher.group(1); + Upgrade upgrade = plugin.getUpgrades().getUpgrade(upgradeName); + if (upgrade == null) { + return Optional.empty(); + } + return Optional.of(island.getUpgradeLevel(upgrade).getLevel() + ""); } else if ((matcher = VISITOR_LAST_JOIN_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { String visitorName = matcher.group(1); return Optional.of(island.getUniqueVisitorsWithTimes().stream() @@ -392,8 +710,6 @@ private static Optional parsePlaceholdersForIsland(@Nullable Island isla .findFirst() .map(Pair::getValue).map(value -> Formatters.DATE_FORMATTER.format(new Date(value))) .orElse("Haven't Joined")); - } else if ((matcher = ISLAND_FLAG_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { - return handleIslandFlagsPlaceholder(island, matcher.group(1)); } } } @@ -412,31 +728,90 @@ private static Optional parsePlaceholdersForIsland(@Nullable Island isla return Optional.empty(); } - private static Optional handlePermissionRolesPlaceholder(@NotNull Island island, - String placeholder) { + private static Optional handleFlagsPlaceholder(@NotNull Island island, + @NotNull SuperiorPlayer superiorPlayer, + String placeholder) { try { - IslandPrivilege islandPrivilege = IslandPrivilege.getByName(placeholder); - return Optional.of(island.getRequiredPlayerRole(islandPrivilege).getDisplayName()); + IslandFlag islandFlag = IslandFlag.getByName(placeholder); + return Optional.of(Formatters.BOOLEAN_FORMATTER.format(island.hasSettingsEnabled(islandFlag), + superiorPlayer.getUserLocale())); } catch (NullPointerException ex) { return Optional.empty(); } } + private static Optional handleGeneratorAmountsPlaceholder(@Nullable Island island, String placeholder) { + Matcher matcher; + Dimension dimension = null; + + if ((matcher = GENERATOR_NORMAL_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + dimension = Dimensions.NORMAL; + } else if ((matcher = GENERATOR_NETHER_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + dimension = Dimensions.NETHER; + } else if ((matcher = GENERATOR_END_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + dimension = Dimensions.THE_END; + } + + if (dimension == null) + return Optional.empty(); + + String keyName = matcher.group(1); + + return Optional.of(island.getGeneratorAmount(Keys.ofMaterialAndData(keyName), dimension) + ""); + } + + private static Optional handleGeneratorPercentagesPlaceholder(@Nullable Island island, String placeholder) { + Matcher matcher; + Dimension dimension = null; + + if ((matcher = GENERATOR_NORMAL_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + dimension = Dimensions.NORMAL; + } else if ((matcher = GENERATOR_NETHER_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + dimension = Dimensions.NETHER; + } else if ((matcher = GENERATOR_END_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + dimension = Dimensions.THE_END; + } + + if (dimension == null) + return Optional.empty(); + + String keyName = matcher.group(1); + + return Optional.of(IslandUtils.getGeneratorPercentageDecimal(island, Keys.ofMaterialAndData(keyName), dimension) + ""); + } + + private static Optional handleMembersPlaceholder(@NotNull Island island, String placeholder) { + List members = island.getIslandMembers(false); + + int targetMemberIndex = -1; + + try { + targetMemberIndex = Integer.parseInt(placeholder) - 1; + } catch (NumberFormatException ignored) { + } + + if (targetMemberIndex < 0 || targetMemberIndex >= members.size()) + return Optional.empty(); + + return Optional.of(members.get(targetMemberIndex).getName()); + } + private static Optional handlePermissionsPlaceholder(@NotNull Island island, @NotNull SuperiorPlayer superiorPlayer, String placeholder) { try { IslandPrivilege islandPrivilege = IslandPrivilege.getByName(placeholder); - return Optional.of(island.hasPermission(superiorPlayer, islandPrivilege) + ""); + return Optional.of(Formatters.BOOLEAN_FORMATTER.format(island.hasPermission(superiorPlayer, islandPrivilege), + superiorPlayer.getUserLocale())); } catch (NullPointerException ex) { return Optional.empty(); } } - private static Optional handleIslandFlagsPlaceholder(@NotNull Island island, String placeholder) { + private static Optional handlePermissionRolesPlaceholder(@NotNull Island island, String placeholder) { try { - IslandFlag islandFlag = IslandFlag.getByName(placeholder); - return Optional.of(island.hasSettingsEnabled(islandFlag) + ""); + IslandPrivilege islandPrivilege = IslandPrivilege.getByName(placeholder); + return Optional.of(island.getRequiredPlayerRole(islandPrivilege).getDisplayName()); } catch (NullPointerException ex) { return Optional.empty(); } @@ -506,22 +881,6 @@ private static Optional handleTopIslandsPlaceholder(@Nullable Island isl return Optional.ofNullable(targetIsland).map(getValueFunction); } - private static Optional handleMembersPlaceholder(@NotNull Island island, String placeholder) { - List members = island.getIslandMembers(false); - - int targetMemberIndex = -1; - - try { - targetMemberIndex = Integer.parseInt(placeholder) - 1; - } catch (NumberFormatException ignored) { - } - - if (targetMemberIndex < 0 || targetMemberIndex >= members.size()) - return Optional.empty(); - - return Optional.of(members.get(targetMemberIndex).getName()); - } - private static WorldInfo getDefaultWorldInfo(Island island) { return plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension()); } From 87fdd2d1a258436cf350fce953e184d28762ca2e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 23 Aug 2025 11:57:59 +0300 Subject: [PATCH 260/600] Fixed blocks fading to other blocks is not detected (#2608) --- .../listener/BlockChangesListener.java | 17 ++++++++++++++++- .../listener/BukkitEventsListener.java | 9 +++++++++ .../platform/event/GameEventType.java | 1 + .../platform/event/args/GameEventArgs.java | 7 ++++++- 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index a7bcbe2d55..05e05dc934 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -35,7 +35,6 @@ import org.bukkit.entity.TNTPrimed; import org.bukkit.event.block.Action; import org.bukkit.inventory.ItemStack; -import org.bukkit.metadata.FixedMetadataValue; import java.util.Collection; import java.util.concurrent.TimeUnit; @@ -294,6 +293,21 @@ private void onBlockFromTo(GameEvent e) { } } + private void onBlockFade(GameEvent e) { + BlockState newState = e.getArgs().newState; + if (newState.getType() == Material.AIR) { + this.worldRecordService.get().recordBlockBreak(e.getArgs().block, REGULAR_RECORD_FLAGS); + } else { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockPlace(Keys.of(newState), + newState.getLocation(wrapper.getHandle()), + 1, + e.getArgs().block.getState(), + REGULAR_RECORD_FLAGS); + } + } + } + private void onEntityExplode(GameEvent e) { Entity entity = e.getArgs().entity; @@ -360,6 +374,7 @@ private void registerListeners() { registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.MONITOR, this::onPistonExtend); registerCallback(GameEventType.LEAVES_DECAY_EVENT, GameEventPriority.MONITOR, this::onLeavesDecay); registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.MONITOR, this::onBlockFromTo); + registerCallback(GameEventType.BLOCK_FADE_EVENT, GameEventPriority.MONITOR, this::onBlockFade); registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.MONITOR, this::onEntityExplode); registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.MONITOR, this::onChorusHit); registerCallback(GameEventType.SPONGE_ABSORB_EVENT, GameEventPriority.MONITOR, this::onSpongeAbsorb); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index f44c523826..dc2a65da4d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -32,6 +32,7 @@ import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockDispenseEvent; +import org.bukkit.event.block.BlockFadeEvent; import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockFromToEvent; import org.bukkit.event.block.BlockGrowEvent; @@ -183,6 +184,7 @@ public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { createEventListener(GameEventType.PROJECTILE_HIT_EVENT, ProjectileHitEvent.class, this::createGameEvent); createEventListener(GameEventType.SIGN_CHANGE_EVENT, SignChangeEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_PHYSICS_EVENT, BlockPhysicsEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_FADE_EVENT, BlockFadeEvent.class, this::createGameEvent); try { Class.forName("org.bukkit.event.block.SpongeAbsorbEvent"); @@ -768,6 +770,13 @@ private GameEvent createGameEvent(GameEventType return eventType.createEvent(blockPhysicsEvent); } + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockFadeEvent e) { + GameEventArgs.BlockFadeEvent blockFadeEvent = new GameEventArgs.BlockFadeEvent(); + blockFadeEvent.block = e.getBlock(); + blockFadeEvent.newState = e.getNewState(); + return eventType.createEvent(blockFadeEvent); + } + private void cancelVehicleCreateEvent(VehicleCreateEvent bukkitEvent, GameEvent gameEvent) { if (gameEvent.isCancelled()) bukkitEvent.getVehicle().remove(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java index e63fcfda64..af52e84ba2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java @@ -75,6 +75,7 @@ public class GameEventType extends EventType RAID_TRIGGER_EVENT = register(RaidTriggerEvent.class); public static final GameEventType SIGN_CHANGE_EVENT = register(SignChangeEvent.class); public static final GameEventType BLOCK_PHYSICS_EVENT = register(BlockPhysicsEvent.class); + public static final GameEventType BLOCK_FADE_EVENT = register(BlockFadeEvent.class); private GameEventType() { } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java index 263b528c56..f21dcf618a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java @@ -314,7 +314,6 @@ public static class EntityBlockFormEvent extends BlockFormEvent { } - public static class BlockDispenseEvent extends BlockEvent { public ItemStack dispensedItem; @@ -322,6 +321,12 @@ public static class BlockDispenseEvent extends BlockEvent { } + public static class BlockFadeEvent extends BlockEvent { + + public BlockState newState; + + } + public static class PlayerItemConsumeEvent extends PlayerEvent { From 51f65c2f6c5af02ea41585ee5f4380d52bffccc7 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 23 Aug 2025 12:31:35 +0300 Subject: [PATCH 261/600] [CI SKIP] Reformat event classes for better readability --- .../listener/BukkitEventsListener.java | 798 +++++++++--------- .../platform/event/GameEventType.java | 95 ++- 2 files changed, 466 insertions(+), 427 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index dc2a65da4d..41dbc5ee98 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -88,7 +88,6 @@ import org.bukkit.event.player.PlayerUnleashEntityEvent; import org.bukkit.event.vehicle.VehicleCreateEvent; import org.bukkit.event.vehicle.VehicleDamageEvent; -import org.bukkit.event.vehicle.VehicleDestroyEvent; import org.bukkit.event.vehicle.VehicleEnterEvent; import org.bukkit.event.vehicle.VehicleEntityCollisionEvent; import org.bukkit.event.vehicle.VehicleMoveEvent; @@ -120,72 +119,81 @@ public class BukkitEventsListener implements Listener { public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - createEventListener(GameEventType.PLAYER_JOIN_EVENT, PlayerJoinEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_QUIT_EVENT, PlayerQuitEvent.class, this::createGameEvent); - createEventListener(GameEventType.BLOCK_PLACE_EVENT, BlockPlaceEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_EMPTY_BUCKET_EVENT, PlayerBucketEmptyEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_FILL_BUCKET_EVENT, PlayerBucketFillEvent.class, this::createGameEvent); - createEventListener(GameEventType.STRUCTURE_GROW_EVENT, StructureGrowEvent.class, this::createGameEvent); - createEventListener(GameEventType.BLOCK_GROW_EVENT, BlockGrowEvent.class, this::createGameEvent); + // Block Events + createEventListener(GameEventType.BLOCK_BREAK_EVENT, BlockBreakEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_BURN_EVENT, BlockBurnEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_DISPENSE_EVENT, BlockDispenseEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_FADE_EVENT, BlockFadeEvent.class, this::createGameEvent); createEventListener(GameEventType.BLOCK_FORM_EVENT, BlockFormEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_FROM_TO_EVENT, BlockFromToEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_GROW_EVENT, BlockGrowEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_IGNITE_EVENT, BlockIgniteEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_PHYSICS_EVENT, BlockPhysicsEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_PLACE_EVENT, BlockPlaceEvent.class, this::createGameEvent); + createEventListener(GameEventType.BLOCK_REDSTONE_EVENT, BlockRedstoneEvent.class, this::createGameEvent, this::cancelBlockRedstoneEvent); createEventListener(GameEventType.BLOCK_SPREAD_EVENT, BlockSpreadEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_SPAWN_EVENT, VehicleCreateEvent.class, this::createGameEvent, this::cancelVehicleCreateEvent); - createEventListener(GameEventType.ENTITY_SPAWN_EVENT, HangingPlaceEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_SPAWN_EVENT, CreatureSpawnEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, EntityChangeBlockEvent.class, this::createGameEvent); - createEventListener(GameEventType.BLOCK_BREAK_EVENT, BlockBreakEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_SPAWN_EVENT, ItemSpawnEvent.class, this::createGameEvent); + createEventListener(GameEventType.LEAVES_DECAY_EVENT, LeavesDecayEvent.class, this::createGameEvent); createEventListener(GameEventType.PISTON_EXTEND_EVENT, BlockPistonExtendEvent.class, this::createGameEvent); createEventListener(GameEventType.PISTON_RETRACT_EVENT, BlockPistonRetractEvent.class, this::createGameEvent); - createEventListener(GameEventType.LEAVES_DECAY_EVENT, LeavesDecayEvent.class, this::createGameEvent); - createEventListener(GameEventType.BLOCK_FROM_TO_EVENT, BlockFromToEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_EXPLODE_EVENT, EntityExplodeEvent.class, this::createGameEvent); -// createEventListener(GameEventType.ENTITY_DEATH_EVENT, VehicleDestroyEvent.class, this::createGameEvent); + + // World Events createEventListener(GameEventType.CHUNK_LOAD_EVENT, ChunkLoadEvent.class, this::createGameEvent); createEventListener(GameEventType.CHUNK_UNLOAD_EVENT, ChunkUnloadEvent.class, this::createGameEvent); + createEventListener(GameEventType.SIGN_CHANGE_EVENT, SignChangeEvent.class, this::createGameEvent); + createEventListener(GameEventType.STRUCTURE_GROW_EVENT, StructureGrowEvent.class, this::createGameEvent); createEventListener(GameEventType.WORLD_UNLOAD_EVENT, WorldUnloadEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_COMMAND_EVENT, PlayerCommandPreprocessEvent.class, this::createGameEvent); - createEventListener(GameEventType.HANGING_BREAK_EVENT, HangingBreakByEntityEvent.class, this::createGameEvent); + + // Entity Events + createEventListener(GameEventType.ENTITY_BLOCK_FORM_EVENT, EntityBlockFormEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, EntityChangeBlockEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_COLLISION_EVENT, VehicleEntityCollisionEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, EntityDamageByEntityEvent.class, this::createGameEvent); - createEventListener(GameEventType.BLOCK_BURN_EVENT, BlockBurnEvent.class, this::createGameEvent); - createEventListener(GameEventType.BLOCK_IGNITE_EVENT, BlockIgniteEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractAtEntityEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractEntityEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_RIDE_EVENT, VehicleEnterEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_MOVE_EVENT, VehicleMoveEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, VehicleDamageEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_ENTER_PORTAL_EVENT, EntityPortalEnterEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_EXPLODE_EVENT, EntityExplodeEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_MOVE_EVENT, PlayerMoveEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_MOVE_EVENT, VehicleMoveEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_PORTAL_EVENT, EntityPortalEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_PORTAL_EVENT, PlayerPortalEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_RIDE_EVENT, VehicleEnterEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_SPAWN_EVENT, CreatureSpawnEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_SPAWN_EVENT, HangingPlaceEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_SPAWN_EVENT, ItemSpawnEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_SPAWN_EVENT, VehicleCreateEvent.class, this::createGameEvent, this::cancelVehicleCreateEvent); + createEventListener(GameEventType.ENTITY_TARGET_EVENT, EntityTargetEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_TELEPORT_EVENT, EntityTeleportEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_TELEPORT_EVENT, PlayerTeleportEvent.class, this::createGameEvent); - createEventListener(GameEventType.BLOCK_REDSTONE_EVENT, BlockRedstoneEvent.class, this::createGameEvent, this::cancelBlockRedstoneEvent); + createEventListener(GameEventType.HANGING_BREAK_EVENT, HangingBreakByEntityEvent.class, this::createGameEvent); + createEventListener(GameEventType.HANGING_PLACE_EVENT, HangingPlaceEvent.class, this::createGameEvent2); + createEventListener(GameEventType.PROJECTILE_HIT_EVENT, ProjectileHitEvent.class, this::createGameEvent); + createEventListener(GameEventType.PROJECTILE_LAUNCH_EVENT, ProjectileLaunchEvent.class, this::createGameEvent); + + // Inventory Events createEventListener(GameEventType.INVENTORY_CLICK_EVENT, InventoryClickEvent.class, this::createGameEvent); createEventListener(GameEventType.INVENTORY_CLOSE_EVENT, InventoryCloseEvent.class, this::createGameEvent); createEventListener(GameEventType.INVENTORY_OPEN_EVENT, InventoryOpenEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_LOGIN_EVENT, PlayerLoginEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_GAMEMODE_CHANGE, PlayerGameModeChangeEvent.class, this::createGameEvent); + + // Player Events createEventListener(GameEventType.PLAYER_CHANGED_WORLD_EVENT, PlayerChangedWorldEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_RESPAWN_EVENT, PlayerRespawnEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_PORTAL_EVENT, PlayerPortalEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_PORTAL_EVENT, EntityPortalEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_ENTER_PORTAL_EVENT, EntityPortalEnterEvent.class, this::createGameEvent); - createEventListener(GameEventType.PROJECTILE_LAUNCH_EVENT, ProjectileLaunchEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_BLOCK_FORM_EVENT, EntityBlockFormEvent.class, this::createGameEvent); - createEventListener(GameEventType.BLOCK_DISPENSE_EVENT, BlockDispenseEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_COMMAND_EVENT, PlayerCommandPreprocessEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_DROP_ITEM_EVENT, PlayerDropItemEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_EMPTY_BUCKET_EVENT, PlayerBucketEmptyEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_FILL_BUCKET_EVENT, PlayerBucketFillEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_GAMEMODE_CHANGE, PlayerGameModeChangeEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractAtEntityEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractEntityEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_INTERACT_EVENT, PlayerInteractEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_ITEM_CONSUME_EVENT, PlayerItemConsumeEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_SHEAR_ENTITY_EVENT, PlayerShearEntityEvent.class, this::createGameEvent); - createEventListener(GameEventType.HANGING_PLACE_EVENT, HangingPlaceEvent.class, this::createGameEvent2); - createEventListener(GameEventType.ENTITY_TARGET_EVENT, EntityTargetEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_JOIN_EVENT, PlayerJoinEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_LEASH_ENTITY_EVENT, PlayerLeashEntityEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_UNLEASH_ENTITY_EVENT, PlayerUnleashEntityEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, VehicleDamageEvent.class, this::createGameEvent); - createEventListener(GameEventType.ENTITY_COLLISION_EVENT, VehicleEntityCollisionEvent.class, this::createGameEvent); - createEventListener(GameEventType.PLAYER_DROP_ITEM_EVENT, PlayerDropItemEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_LOGIN_EVENT, PlayerLoginEvent.class, this::createGameEvent); createEventListener(GameEventType.PLAYER_PICKUP_ITEM_EVENT, PlayerPickupItemEvent.class, this::createGameEvent); - createEventListener(GameEventType.PROJECTILE_HIT_EVENT, ProjectileHitEvent.class, this::createGameEvent); - createEventListener(GameEventType.SIGN_CHANGE_EVENT, SignChangeEvent.class, this::createGameEvent); - createEventListener(GameEventType.BLOCK_PHYSICS_EVENT, BlockPhysicsEvent.class, this::createGameEvent); - createEventListener(GameEventType.BLOCK_FADE_EVENT, BlockFadeEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_QUIT_EVENT, PlayerQuitEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_RESPAWN_EVENT, PlayerRespawnEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_SHEAR_ENTITY_EVENT, PlayerShearEntityEvent.class, this::createGameEvent); + createEventListener(GameEventType.PLAYER_UNLEASH_ENTITY_EVENT, PlayerUnleashEntityEvent.class, this::createGameEvent); + // Special Events (per version) try { Class.forName("org.bukkit.event.block.SpongeAbsorbEvent"); createEventListener(GameEventType.SPONGE_ABSORB_EVENT, org.bukkit.event.block.SpongeAbsorbEvent.class, new SpongeAbsorbEventFunction()); @@ -244,58 +252,36 @@ public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { } } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerJoinEvent e) { - GameEventArgs.PlayerJoinEvent playerJoinEvent = new GameEventArgs.PlayerJoinEvent(); - playerJoinEvent.player = e.getPlayer(); - return eventType.createEvent(playerJoinEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerQuitEvent e) { - GameEventArgs.PlayerQuitEvent playerQuitEvent = new GameEventArgs.PlayerQuitEvent(); - playerQuitEvent.player = e.getPlayer(); - return eventType.createEvent(playerQuitEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPlaceEvent e) { - GameEventArgs.BlockPlaceEvent blockPlaceEvent = new GameEventArgs.BlockPlaceEvent(); - blockPlaceEvent.block = e.getBlock(); - blockPlaceEvent.player = e.getPlayer(); - blockPlaceEvent.againstBlock = e.getBlockAgainst(); - blockPlaceEvent.replacedState = e.getBlockReplacedState(); - blockPlaceEvent.usedHand = BukkitItems.getHand(e); - blockPlaceEvent.usedItem = getHandItem(e.getPlayer(), blockPlaceEvent.usedHand, true, () -> e.getItemInHand()); - return eventType.createEvent(blockPlaceEvent); - } + /* + * BLOCK EVENTS + */ - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerBucketEmptyEvent e) { - GameEventArgs.PlayerEmptyBucketEvent playerEmptyBucketEvent = new GameEventArgs.PlayerEmptyBucketEvent(); - playerEmptyBucketEvent.player = e.getPlayer(); - playerEmptyBucketEvent.bucket = e.getBucket(); - playerEmptyBucketEvent.clickedBlock = e.getBlockClicked(); - return eventType.createEvent(playerEmptyBucketEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockBreakEvent e) { + GameEventArgs.BlockBreakEvent blockBreakEvent = new GameEventArgs.BlockBreakEvent(); + blockBreakEvent.block = e.getBlock(); + blockBreakEvent.player = e.getPlayer(); + return eventType.createEvent(blockBreakEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerBucketFillEvent e) { - GameEventArgs.PlayerFillBucketEvent playerFillBucketEvent = new GameEventArgs.PlayerFillBucketEvent(); - playerFillBucketEvent.player = e.getPlayer(); - playerFillBucketEvent.bucket = e.getBucket(); - playerFillBucketEvent.clickedBlock = e.getBlockClicked(); - return eventType.createEvent(playerFillBucketEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockBurnEvent e) { + GameEventArgs.BlockBurnEvent blockBurnEvent = new GameEventArgs.BlockBurnEvent(); + blockBurnEvent.block = e.getBlock(); + return eventType.createEvent(blockBurnEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, StructureGrowEvent e) { - GameEventArgs.StructureGrowEvent structureGrowEvent = new GameEventArgs.StructureGrowEvent(); - structureGrowEvent.world = e.getWorld(); - structureGrowEvent.location = e.getLocation(); - structureGrowEvent.blocks = e.getBlocks(); - return eventType.createEvent(structureGrowEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockDispenseEvent e) { + GameEventArgs.BlockDispenseEvent blockDispenseEvent = new GameEventArgs.BlockDispenseEvent(); + blockDispenseEvent.block = e.getBlock(); + blockDispenseEvent.dispensedItem = e.getItem(); + blockDispenseEvent.velocity = e.getVelocity(); + return eventType.createEvent(blockDispenseEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockGrowEvent e) { - GameEventArgs.BlockGrowEvent blockGrowEvent = new GameEventArgs.BlockGrowEvent(); - blockGrowEvent.block = e.getBlock(); - blockGrowEvent.newState = e.getNewState(); - return eventType.createEvent(blockGrowEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockFadeEvent e) { + GameEventArgs.BlockFadeEvent blockFadeEvent = new GameEventArgs.BlockFadeEvent(); + blockFadeEvent.block = e.getBlock(); + blockFadeEvent.newState = e.getNewState(); + return eventType.createEvent(blockFadeEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockFormEvent e) { @@ -305,98 +291,67 @@ private GameEvent createGameEvent(GameEventType createGameEvent(GameEventType eventType, GameEventPriority priority, BlockSpreadEvent e) { - GameEventArgs.BlockSpreadEvent blockSpreadEvent = new GameEventArgs.BlockSpreadEvent(); - blockSpreadEvent.block = e.getBlock(); - blockSpreadEvent.newState = e.getNewState(); - blockSpreadEvent.source = e.getSource(); - return eventType.createEvent(blockSpreadEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleCreateEvent e) { - GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); - entitySpawnEvent.entity = e.getVehicle(); - entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT; - return eventType.createEvent(entitySpawnEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockFromToEvent e) { + GameEventArgs.BlockFromToEvent blockFromToEvent = new GameEventArgs.BlockFromToEvent(); + blockFromToEvent.block = e.getBlock(); + blockFromToEvent.toBlock = e.getToBlock(); + return eventType.createEvent(blockFromToEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, HangingPlaceEvent e) { - GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); - entitySpawnEvent.entity = e.getEntity(); - entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT; - return eventType.createEvent(entitySpawnEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockGrowEvent e) { + GameEventArgs.BlockGrowEvent blockGrowEvent = new GameEventArgs.BlockGrowEvent(); + blockGrowEvent.block = e.getBlock(); + blockGrowEvent.newState = e.getNewState(); + return eventType.createEvent(blockGrowEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, CreatureSpawnEvent e) { - if (this.shouldFireAttemptEntitySpawnEvent) { - GameEventArgs.AttemptEntitySpawnEvent attemptEntitySpawnEvent = new GameEventArgs.AttemptEntitySpawnEvent(); - attemptEntitySpawnEvent.entityType = e.getEntityType(); - attemptEntitySpawnEvent.spawnLocation = e.getLocation(); - attemptEntitySpawnEvent.spawnReason = e.getSpawnReason(); - GameEvent gameEvent = GameEventType.ATTEMPT_ENTITY_SPAWN_EVENT - .createEvent(attemptEntitySpawnEvent); - plugin.getGameEventsDispatcher().onGameEvent(gameEvent, priority); - if (gameEvent.isCancelled()) { - e.getEntity().remove(); - return null; - } - } - - GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); - entitySpawnEvent.entity = e.getEntity(); - entitySpawnEvent.spawnReason = e.getSpawnReason(); - return eventType.createEvent(entitySpawnEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockIgniteEvent e) { + GameEventArgs.BlockIgniteEvent blockIgniteEvent = new GameEventArgs.BlockIgniteEvent(); + blockIgniteEvent.block = e.getBlock(); + blockIgniteEvent.igniteCause = e.getCause(); + return eventType.createEvent(blockIgniteEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ItemSpawnEvent e) { - GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); - entitySpawnEvent.entity = e.getEntity(); - entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT; - return eventType.createEvent(entitySpawnEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPhysicsEvent e) { + GameEventArgs.BlockPhysicsEvent blockPhysicsEvent = new GameEventArgs.BlockPhysicsEvent(); + blockPhysicsEvent.block = e.getBlock(); + return eventType.createEvent(blockPhysicsEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerInteractEvent e) { - GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent(); - playerInteractEvent.player = e.getPlayer(); - playerInteractEvent.action = e.getAction(); - playerInteractEvent.usedHand = BukkitItems.getHand(e); - playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, () -> e.getItem()); - playerInteractEvent.clickedBlock = e.getClickedBlock(); - return eventType.createEvent(playerInteractEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPlaceEvent e) { + GameEventArgs.BlockPlaceEvent blockPlaceEvent = new GameEventArgs.BlockPlaceEvent(); + blockPlaceEvent.block = e.getBlock(); + blockPlaceEvent.player = e.getPlayer(); + blockPlaceEvent.againstBlock = e.getBlockAgainst(); + blockPlaceEvent.replacedState = e.getBlockReplacedState(); + blockPlaceEvent.usedHand = BukkitItems.getHand(e); + blockPlaceEvent.usedItem = getHandItem(e.getPlayer(), blockPlaceEvent.usedHand, true, () -> e.getItemInHand()); + return eventType.createEvent(blockPlaceEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityChangeBlockEvent e) { - GameEventArgs.EntityChangeBlockEvent entityChangeBlockEvent = new GameEventArgs.EntityChangeBlockEvent(); - - entityChangeBlockEvent.entity = e.getEntity(); - entityChangeBlockEvent.block = e.getBlock(); - if (ServerVersion.isLegacy()) { - // noinspection deprecated - entityChangeBlockEvent.newType = Keys.of(e.getTo(), e.getData()); - } else { - entityChangeBlockEvent.newType = Keys.of(e.getTo(), (byte) 0); - } - - return eventType.createEvent(entityChangeBlockEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockRedstoneEvent e) { + GameEventArgs.BlockRedstoneEvent blockRedstoneEvent = new GameEventArgs.BlockRedstoneEvent(); + blockRedstoneEvent.block = e.getBlock(); + return eventType.createEvent(blockRedstoneEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockBreakEvent e) { - GameEventArgs.BlockBreakEvent blockBreakEvent = new GameEventArgs.BlockBreakEvent(); - blockBreakEvent.block = e.getBlock(); - blockBreakEvent.player = e.getPlayer(); - return eventType.createEvent(blockBreakEvent); + private void cancelBlockRedstoneEvent(BlockRedstoneEvent bukkitEvent, GameEvent gameEvent) { + if (gameEvent.isCancelled()) + bukkitEvent.setNewCurrent(0); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityDeathEvent e) { - GameEventArgs.EntityDeathEvent entityDeathEvent = new GameEventArgs.EntityDeathEvent(); - entityDeathEvent.entity = e.getEntity(); - return eventType.createEvent(entityDeathEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockSpreadEvent e) { + GameEventArgs.BlockSpreadEvent blockSpreadEvent = new GameEventArgs.BlockSpreadEvent(); + blockSpreadEvent.block = e.getBlock(); + blockSpreadEvent.newState = e.getNewState(); + blockSpreadEvent.source = e.getSource(); + return eventType.createEvent(blockSpreadEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleDestroyEvent e) { - GameEventArgs.EntityDeathEvent entityDeathEvent = new GameEventArgs.EntityDeathEvent(); - entityDeathEvent.entity = e.getVehicle(); - return eventType.createEvent(entityDeathEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, LeavesDecayEvent e) { + GameEventArgs.LeavesDecayEvent leavesDecayEvent = new GameEventArgs.LeavesDecayEvent(); + leavesDecayEvent.block = e.getBlock(); + return eventType.createEvent(leavesDecayEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPistonExtendEvent e) { @@ -415,35 +370,21 @@ private GameEvent createGameEvent(GameEventTyp return eventType.createEvent(pistonRetractEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, LeavesDecayEvent e) { - GameEventArgs.LeavesDecayEvent leavesDecayEvent = new GameEventArgs.LeavesDecayEvent(); - leavesDecayEvent.block = e.getBlock(); - return eventType.createEvent(leavesDecayEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockFromToEvent e) { - GameEventArgs.BlockFromToEvent blockFromToEvent = new GameEventArgs.BlockFromToEvent(); - blockFromToEvent.block = e.getBlock(); - blockFromToEvent.toBlock = e.getToBlock(); - return eventType.createEvent(blockFromToEvent); - } + /* + * WORLD EVENTS + */ - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityExplodeEvent e) { - GameEventArgs.EntityExplodeEvent entityExplodeEvent = new GameEventArgs.EntityExplodeEvent(); - entityExplodeEvent.entity = e.getEntity(); - entityExplodeEvent.blocks = e.blockList(); - entityExplodeEvent.isSoftExplosion = e.getEntityType() == WIND_CHARGE || e.getEntityType() == BREEZE_WIND_CHARGE; - return eventType.createEvent(entityExplodeEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ChunkLoadEvent e) { + GameEventArgs.ChunkLoadEvent chunkLoadEvent = new GameEventArgs.ChunkLoadEvent(); + chunkLoadEvent.chunk = e.getChunk(); + chunkLoadEvent.isNewChunk = e.isNewChunk(); + return eventType.createEvent(chunkLoadEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ProjectileHitEvent e) { - GameEventArgs.ProjectileHitEvent projectileHitEvent = new GameEventArgs.ProjectileHitEvent(); - projectileHitEvent.entity = e.getEntity(); - if (PROJECTILE_HIT_TARGET_ENTITY.isValid()) - projectileHitEvent.hitEntity = PROJECTILE_HIT_TARGET_ENTITY.invoke(e); - if (PROJECTILE_HIT_EVENT_TARGET_BLOCK.isValid()) - projectileHitEvent.hitBlock = PROJECTILE_HIT_EVENT_TARGET_BLOCK.invoke(e); - return eventType.createEvent(projectileHitEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ChunkUnloadEvent e) { + GameEventArgs.ChunkUnloadEvent chunkUnloadEvent = new GameEventArgs.ChunkUnloadEvent(); + chunkUnloadEvent.chunk = e.getChunk(); + return eventType.createEvent(chunkUnloadEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, SignChangeEvent e) { @@ -454,17 +395,12 @@ private GameEvent createGameEvent(GameEventType createGameEvent(GameEventType eventType, GameEventPriority priority, ChunkLoadEvent e) { - GameEventArgs.ChunkLoadEvent chunkLoadEvent = new GameEventArgs.ChunkLoadEvent(); - chunkLoadEvent.chunk = e.getChunk(); - chunkLoadEvent.isNewChunk = e.isNewChunk(); - return eventType.createEvent(chunkLoadEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ChunkUnloadEvent e) { - GameEventArgs.ChunkUnloadEvent chunkUnloadEvent = new GameEventArgs.ChunkUnloadEvent(); - chunkUnloadEvent.chunk = e.getChunk(); - return eventType.createEvent(chunkUnloadEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, StructureGrowEvent e) { + GameEventArgs.StructureGrowEvent structureGrowEvent = new GameEventArgs.StructureGrowEvent(); + structureGrowEvent.world = e.getWorld(); + structureGrowEvent.location = e.getLocation(); + structureGrowEvent.blocks = e.getBlocks(); + return eventType.createEvent(structureGrowEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, WorldUnloadEvent e) { @@ -473,19 +409,38 @@ private GameEvent createGameEvent(GameEventType< return eventType.createEvent(worldUnloadEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerCommandPreprocessEvent e) { - GameEventArgs.PlayerCommandEvent playerCommandEvent = new GameEventArgs.PlayerCommandEvent(); - playerCommandEvent.player = e.getPlayer(); - playerCommandEvent.command = e.getMessage(); - return eventType.createEvent(playerCommandEvent); + /* + * ENTITY EVENTS + */ + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityBlockFormEvent e) { + GameEventArgs.EntityBlockFormEvent entityBlockFormEvent = new GameEventArgs.EntityBlockFormEvent(); + entityBlockFormEvent.block = e.getBlock(); + entityBlockFormEvent.newState = e.getNewState(); + entityBlockFormEvent.entity = e.getEntity(); + return eventType.createEvent(entityBlockFormEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, HangingBreakByEntityEvent e) { - GameEventArgs.HangingBreakEvent hangingBreakEvent = new GameEventArgs.HangingBreakEvent(); - hangingBreakEvent.entity = e.getEntity(); - hangingBreakEvent.remover = e.getRemover(); - hangingBreakEvent.removeCause = e.getCause(); - return eventType.createEvent(hangingBreakEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityChangeBlockEvent e) { + GameEventArgs.EntityChangeBlockEvent entityChangeBlockEvent = new GameEventArgs.EntityChangeBlockEvent(); + + entityChangeBlockEvent.entity = e.getEntity(); + entityChangeBlockEvent.block = e.getBlock(); + if (ServerVersion.isLegacy()) { + // noinspection deprecated + entityChangeBlockEvent.newType = Keys.of(e.getTo(), e.getData()); + } else { + entityChangeBlockEvent.newType = Keys.of(e.getTo(), (byte) 0); + } + + return eventType.createEvent(entityChangeBlockEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleEntityCollisionEvent e) { + GameEventArgs.EntityCollisionEvent entityCollisionEvent = new GameEventArgs.EntityCollisionEvent(); + entityCollisionEvent.entity = e.getEntity(); + entityCollisionEvent.target = e.getVehicle(); + return eventType.createEvent(entityCollisionEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityDamageByEntityEvent e) { @@ -496,47 +451,30 @@ private GameEvent createGameEvent(GameEventType return eventType.createEvent(entityDamageEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockBurnEvent e) { - GameEventArgs.BlockBurnEvent blockBurnEvent = new GameEventArgs.BlockBurnEvent(); - blockBurnEvent.block = e.getBlock(); - return eventType.createEvent(blockBurnEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockIgniteEvent e) { - GameEventArgs.BlockIgniteEvent blockIgniteEvent = new GameEventArgs.BlockIgniteEvent(); - blockIgniteEvent.block = e.getBlock(); - blockIgniteEvent.igniteCause = e.getCause(); - return eventType.createEvent(blockIgniteEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerInteractAtEntityEvent e) { - GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent(); - playerInteractEvent.player = e.getPlayer(); - playerInteractEvent.action = Action.RIGHT_CLICK_AIR; - playerInteractEvent.usedHand = BukkitItems.getHand(e); - playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, null); - playerInteractEvent.clickedEntity = e.getRightClicked(); - return eventType.createEvent(playerInteractEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleDamageEvent e) { + GameEventArgs.EntityDamageEvent entityDamageEvent = new GameEventArgs.EntityDamageEvent(); + entityDamageEvent.entity = e.getVehicle(); + entityDamageEvent.damager = e.getAttacker(); + entityDamageEvent.damageCause = EntityDamageEvent.DamageCause.ENTITY_ATTACK; + return eventType.createEvent(entityDamageEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerInteractEntityEvent e) { - GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent(); - playerInteractEvent.player = e.getPlayer(); - playerInteractEvent.action = Action.RIGHT_CLICK_AIR; - playerInteractEvent.usedHand = BukkitItems.getHand(e); - playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, null); - playerInteractEvent.clickedEntity = e.getRightClicked(); - return eventType.createEvent(playerInteractEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityPortalEnterEvent e) { + GameEventArgs.EntityEnterPortalEvent entityEnterPortalEvent = new GameEventArgs.EntityEnterPortalEvent(); + entityEnterPortalEvent.entity = e.getEntity(); + entityEnterPortalEvent.portalLocation = e.getLocation(); + return eventType.createEvent(entityEnterPortalEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleEnterEvent e) { - GameEventArgs.EntityRideEvent entityRideEvent = new GameEventArgs.EntityRideEvent(); - entityRideEvent.entity = e.getEntered(); - entityRideEvent.vehicle = e.getVehicle(); - return eventType.createEvent(entityRideEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityExplodeEvent e) { + GameEventArgs.EntityExplodeEvent entityExplodeEvent = new GameEventArgs.EntityExplodeEvent(); + entityExplodeEvent.entity = e.getEntity(); + entityExplodeEvent.blocks = e.blockList(); + entityExplodeEvent.isSoftExplosion = e.getEntityType() == WIND_CHARGE || e.getEntityType() == BREEZE_WIND_CHARGE; + return eventType.createEvent(entityExplodeEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleMoveEvent e) { + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerMoveEvent e) { Location from = e.getFrom(); Location to = e.getTo(); @@ -544,13 +482,13 @@ private GameEvent createGameEvent(GameEventType createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerMoveEvent e) { + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleMoveEvent e) { Location from = e.getFrom(); Location to = e.getTo(); @@ -558,12 +496,96 @@ private GameEvent createGameEvent(GameEventType createGameEvent(GameEventType eventType, GameEventPriority priority, EntityPortalEvent e) { + GameEventArgs.EntityPortalEvent entityPortalEvent = new GameEventArgs.EntityPortalEvent(); + entityPortalEvent.entity = e.getEntity(); + entityPortalEvent.cause = e.getTo().getWorld().getEnvironment() == World.Environment.THE_END || + e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ? + PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL; + entityPortalEvent.from = e.getFrom(); + entityPortalEvent.to = e.getTo(); + return eventType.createEvent(entityPortalEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerPortalEvent e) { + GameEventArgs.EntityPortalEvent entityPortalEvent = new GameEventArgs.EntityPortalEvent(); + entityPortalEvent.entity = e.getPlayer(); + entityPortalEvent.cause = e.getTo() == null ? e.getCause() : + e.getTo().getWorld().getEnvironment() == World.Environment.THE_END || + e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ? + PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL; + entityPortalEvent.from = e.getFrom(); + entityPortalEvent.to = e.getTo(); + return eventType.createEvent(entityPortalEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleEnterEvent e) { + GameEventArgs.EntityRideEvent entityRideEvent = new GameEventArgs.EntityRideEvent(); + entityRideEvent.entity = e.getEntered(); + entityRideEvent.vehicle = e.getVehicle(); + return eventType.createEvent(entityRideEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, CreatureSpawnEvent e) { + if (this.shouldFireAttemptEntitySpawnEvent) { + GameEventArgs.AttemptEntitySpawnEvent attemptEntitySpawnEvent = new GameEventArgs.AttemptEntitySpawnEvent(); + attemptEntitySpawnEvent.entityType = e.getEntityType(); + attemptEntitySpawnEvent.spawnLocation = e.getLocation(); + attemptEntitySpawnEvent.spawnReason = e.getSpawnReason(); + GameEvent gameEvent = GameEventType.ATTEMPT_ENTITY_SPAWN_EVENT + .createEvent(attemptEntitySpawnEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, priority); + if (gameEvent.isCancelled()) { + e.getEntity().remove(); + return null; + } + } + + GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); + entitySpawnEvent.entity = e.getEntity(); + entitySpawnEvent.spawnReason = e.getSpawnReason(); + return eventType.createEvent(entitySpawnEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, HangingPlaceEvent e) { + GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); + entitySpawnEvent.entity = e.getEntity(); + entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT; + return eventType.createEvent(entitySpawnEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ItemSpawnEvent e) { + GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); + entitySpawnEvent.entity = e.getEntity(); + entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT; + return eventType.createEvent(entitySpawnEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleCreateEvent e) { + GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); + entitySpawnEvent.entity = e.getVehicle(); + entitySpawnEvent.spawnReason = CreatureSpawnEvent.SpawnReason.DEFAULT; + return eventType.createEvent(entitySpawnEvent); + } + + private void cancelVehicleCreateEvent(VehicleCreateEvent bukkitEvent, GameEvent gameEvent) { + if (gameEvent.isCancelled()) + bukkitEvent.getVehicle().remove(); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityTargetEvent e) { + GameEventArgs.EntityTargetEvent entityTargetEvent = new GameEventArgs.EntityTargetEvent(); + entityTargetEvent.entity = e.getEntity(); + entityTargetEvent.target = e.getTarget(); + return eventType.createEvent(entityTargetEvent); + } + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityTeleportEvent e) { GameEventArgs.EntityTeleportEvent entityTeleportEvent = new GameEventArgs.EntityTeleportEvent(); entityTeleportEvent.entity = e.getEntity(); @@ -582,12 +604,47 @@ private GameEvent createGameEvent(GameEventTy return eventType.createEvent(entityTeleportEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockRedstoneEvent e) { - GameEventArgs.BlockRedstoneEvent blockRedstoneEvent = new GameEventArgs.BlockRedstoneEvent(); - blockRedstoneEvent.block = e.getBlock(); - return eventType.createEvent(blockRedstoneEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, HangingBreakByEntityEvent e) { + GameEventArgs.HangingBreakEvent hangingBreakEvent = new GameEventArgs.HangingBreakEvent(); + hangingBreakEvent.entity = e.getEntity(); + hangingBreakEvent.remover = e.getRemover(); + hangingBreakEvent.removeCause = e.getCause(); + return eventType.createEvent(hangingBreakEvent); + } + + private GameEvent createGameEvent2(GameEventType eventType, GameEventPriority priority, HangingPlaceEvent e) { + GameEventArgs.HangingPlaceEvent hangingPlaceEvent = new GameEventArgs.HangingPlaceEvent(); + hangingPlaceEvent.entity = e.getEntity(); + hangingPlaceEvent.player = e.getPlayer(); + return eventType.createEvent(hangingPlaceEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ProjectileHitEvent e) { + GameEventArgs.ProjectileHitEvent projectileHitEvent = new GameEventArgs.ProjectileHitEvent(); + projectileHitEvent.entity = e.getEntity(); + if (PROJECTILE_HIT_TARGET_ENTITY.isValid()) + projectileHitEvent.hitEntity = PROJECTILE_HIT_TARGET_ENTITY.invoke(e); + if (PROJECTILE_HIT_EVENT_TARGET_BLOCK.isValid()) + projectileHitEvent.hitBlock = PROJECTILE_HIT_EVENT_TARGET_BLOCK.invoke(e); + return eventType.createEvent(projectileHitEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ProjectileLaunchEvent e) { + GameEventArgs.ProjectileLaunchEvent projectileLaunchEvent = new GameEventArgs.ProjectileLaunchEvent(); + projectileLaunchEvent.entity = e.getEntity(); + return eventType.createEvent(projectileLaunchEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityDeathEvent e) { + GameEventArgs.EntityDeathEvent entityDeathEvent = new GameEventArgs.EntityDeathEvent(); + entityDeathEvent.entity = e.getEntity(); + return eventType.createEvent(entityDeathEvent); } + /* + * INVENTORY EVENTS + */ + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, InventoryClickEvent e) { GameEventArgs.InventoryClickEvent inventoryClickEvent = new GameEventArgs.InventoryClickEvent(); inventoryClickEvent.bukkitEvent = e; @@ -606,18 +663,9 @@ private GameEvent createGameEvent(GameEventTyp return eventType.createEvent(inventoryOpenEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerLoginEvent e) { - GameEventArgs.PlayerLoginEvent playerLoginEvent = new GameEventArgs.PlayerLoginEvent(); - playerLoginEvent.player = e.getPlayer(); - return eventType.createEvent(playerLoginEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerGameModeChangeEvent e) { - GameEventArgs.PlayerGamemodeChangeEvent playerGamemodeChangeEvent = new GameEventArgs.PlayerGamemodeChangeEvent(); - playerGamemodeChangeEvent.player = e.getPlayer(); - playerGamemodeChangeEvent.newGamemode = e.getNewGameMode(); - return eventType.createEvent(playerGamemodeChangeEvent); - } + /* + * PLAYER EVENTS + */ private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerChangedWorldEvent e) { GameEventArgs.PlayerChangedWorldEvent playerChangedWorldEvent = new GameEventArgs.PlayerChangedWorldEvent(); @@ -626,40 +674,71 @@ private GameEvent createGameEvent(GameEve return eventType.createEvent(playerChangedWorldEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerRespawnEvent e) { - GameEventArgs.PlayerRespawnEvent playerRespawnEvent = new GameEventArgs.PlayerRespawnEvent(); - playerRespawnEvent.player = e.getPlayer(); - playerRespawnEvent.bukkitEvent = e; - return eventType.createEvent(playerRespawnEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerCommandPreprocessEvent e) { + GameEventArgs.PlayerCommandEvent playerCommandEvent = new GameEventArgs.PlayerCommandEvent(); + playerCommandEvent.player = e.getPlayer(); + playerCommandEvent.command = e.getMessage(); + return eventType.createEvent(playerCommandEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityPortalEnterEvent e) { - GameEventArgs.EntityEnterPortalEvent entityEnterPortalEvent = new GameEventArgs.EntityEnterPortalEvent(); - entityEnterPortalEvent.entity = e.getEntity(); - entityEnterPortalEvent.portalLocation = e.getLocation(); - return eventType.createEvent(entityEnterPortalEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerDropItemEvent e) { + GameEventArgs.PlayerDropItemEvent playerDropItemEvent = new GameEventArgs.PlayerDropItemEvent(); + playerDropItemEvent.player = e.getPlayer(); + playerDropItemEvent.droppedItem = e.getItemDrop(); + return eventType.createEvent(playerDropItemEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, ProjectileLaunchEvent e) { - GameEventArgs.ProjectileLaunchEvent projectileLaunchEvent = new GameEventArgs.ProjectileLaunchEvent(); - projectileLaunchEvent.entity = e.getEntity(); - return eventType.createEvent(projectileLaunchEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerBucketEmptyEvent e) { + GameEventArgs.PlayerEmptyBucketEvent playerEmptyBucketEvent = new GameEventArgs.PlayerEmptyBucketEvent(); + playerEmptyBucketEvent.player = e.getPlayer(); + playerEmptyBucketEvent.bucket = e.getBucket(); + playerEmptyBucketEvent.clickedBlock = e.getBlockClicked(); + return eventType.createEvent(playerEmptyBucketEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityBlockFormEvent e) { - GameEventArgs.EntityBlockFormEvent entityBlockFormEvent = new GameEventArgs.EntityBlockFormEvent(); - entityBlockFormEvent.block = e.getBlock(); - entityBlockFormEvent.newState = e.getNewState(); - entityBlockFormEvent.entity = e.getEntity(); - return eventType.createEvent(entityBlockFormEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerBucketFillEvent e) { + GameEventArgs.PlayerFillBucketEvent playerFillBucketEvent = new GameEventArgs.PlayerFillBucketEvent(); + playerFillBucketEvent.player = e.getPlayer(); + playerFillBucketEvent.bucket = e.getBucket(); + playerFillBucketEvent.clickedBlock = e.getBlockClicked(); + return eventType.createEvent(playerFillBucketEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockDispenseEvent e) { - GameEventArgs.BlockDispenseEvent blockDispenseEvent = new GameEventArgs.BlockDispenseEvent(); - blockDispenseEvent.block = e.getBlock(); - blockDispenseEvent.dispensedItem = e.getItem(); - blockDispenseEvent.velocity = e.getVelocity(); - return eventType.createEvent(blockDispenseEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerGameModeChangeEvent e) { + GameEventArgs.PlayerGamemodeChangeEvent playerGamemodeChangeEvent = new GameEventArgs.PlayerGamemodeChangeEvent(); + playerGamemodeChangeEvent.player = e.getPlayer(); + playerGamemodeChangeEvent.newGamemode = e.getNewGameMode(); + return eventType.createEvent(playerGamemodeChangeEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerInteractAtEntityEvent e) { + GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent(); + playerInteractEvent.player = e.getPlayer(); + playerInteractEvent.action = Action.RIGHT_CLICK_AIR; + playerInteractEvent.usedHand = BukkitItems.getHand(e); + playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, null); + playerInteractEvent.clickedEntity = e.getRightClicked(); + return eventType.createEvent(playerInteractEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerInteractEntityEvent e) { + GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent(); + playerInteractEvent.player = e.getPlayer(); + playerInteractEvent.action = Action.RIGHT_CLICK_AIR; + playerInteractEvent.usedHand = BukkitItems.getHand(e); + playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, null); + playerInteractEvent.clickedEntity = e.getRightClicked(); + return eventType.createEvent(playerInteractEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerInteractEvent e) { + GameEventArgs.PlayerInteractEvent playerInteractEvent = new GameEventArgs.PlayerInteractEvent(); + playerInteractEvent.player = e.getPlayer(); + playerInteractEvent.action = e.getAction(); + playerInteractEvent.usedHand = BukkitItems.getHand(e); + playerInteractEvent.usedItem = getHandItem(e.getPlayer(), playerInteractEvent.usedHand, true, () -> e.getItem()); + playerInteractEvent.clickedBlock = e.getClickedBlock(); + return eventType.createEvent(playerInteractEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerItemConsumeEvent e) { @@ -669,25 +748,10 @@ private GameEvent createGameEvent(GameEven return eventType.createEvent(playerItemConsumeEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerShearEntityEvent e) { - GameEventArgs.PlayerShearEntityEvent playerShearEntityEvent = new GameEventArgs.PlayerShearEntityEvent(); - playerShearEntityEvent.player = e.getPlayer(); - playerShearEntityEvent.entity = e.getEntity(); - return eventType.createEvent(playerShearEntityEvent); - } - - private GameEvent createGameEvent2(GameEventType eventType, GameEventPriority priority, HangingPlaceEvent e) { - GameEventArgs.HangingPlaceEvent hangingPlaceEvent = new GameEventArgs.HangingPlaceEvent(); - hangingPlaceEvent.entity = e.getEntity(); - hangingPlaceEvent.player = e.getPlayer(); - return eventType.createEvent(hangingPlaceEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityTargetEvent e) { - GameEventArgs.EntityTargetEvent entityTargetEvent = new GameEventArgs.EntityTargetEvent(); - entityTargetEvent.entity = e.getEntity(); - entityTargetEvent.target = e.getTarget(); - return eventType.createEvent(entityTargetEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerJoinEvent e) { + GameEventArgs.PlayerJoinEvent playerJoinEvent = new GameEventArgs.PlayerJoinEvent(); + playerJoinEvent.player = e.getPlayer(); + return eventType.createEvent(playerJoinEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerLeashEntityEvent e) { @@ -697,33 +761,10 @@ private GameEvent createGameEvent(GameEven return eventType.createEvent(playerLeashEntityEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerUnleashEntityEvent e) { - GameEventArgs.PlayerUnleashEntityEvent playerUnleashEntityEvent = new GameEventArgs.PlayerUnleashEntityEvent(); - playerUnleashEntityEvent.player = e.getPlayer(); - playerUnleashEntityEvent.entity = e.getEntity(); - return eventType.createEvent(playerUnleashEntityEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleDamageEvent e) { - GameEventArgs.EntityDamageEvent entityDamageEvent = new GameEventArgs.EntityDamageEvent(); - entityDamageEvent.entity = e.getVehicle(); - entityDamageEvent.damager = e.getAttacker(); - entityDamageEvent.damageCause = EntityDamageEvent.DamageCause.ENTITY_ATTACK; - return eventType.createEvent(entityDamageEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleEntityCollisionEvent e) { - GameEventArgs.EntityCollisionEvent entityCollisionEvent = new GameEventArgs.EntityCollisionEvent(); - entityCollisionEvent.entity = e.getEntity(); - entityCollisionEvent.target = e.getVehicle(); - return eventType.createEvent(entityCollisionEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerDropItemEvent e) { - GameEventArgs.PlayerDropItemEvent playerDropItemEvent = new GameEventArgs.PlayerDropItemEvent(); - playerDropItemEvent.player = e.getPlayer(); - playerDropItemEvent.droppedItem = e.getItemDrop(); - return eventType.createEvent(playerDropItemEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerLoginEvent e) { + GameEventArgs.PlayerLoginEvent playerLoginEvent = new GameEventArgs.PlayerLoginEvent(); + playerLoginEvent.player = e.getPlayer(); + return eventType.createEvent(playerLoginEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerPickupItemEvent e) { @@ -733,27 +774,31 @@ private GameEvent createGameEvent(GameEvent return eventType.createEvent(playerPickupItemEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerPortalEvent e) { - GameEventArgs.EntityPortalEvent entityPortalEvent = new GameEventArgs.EntityPortalEvent(); - entityPortalEvent.entity = e.getPlayer(); - entityPortalEvent.cause = e.getTo() == null ? e.getCause() : - e.getTo().getWorld().getEnvironment() == World.Environment.THE_END || - e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ? - PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL; - entityPortalEvent.from = e.getFrom(); - entityPortalEvent.to = e.getTo(); - return eventType.createEvent(entityPortalEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerQuitEvent e) { + GameEventArgs.PlayerQuitEvent playerQuitEvent = new GameEventArgs.PlayerQuitEvent(); + playerQuitEvent.player = e.getPlayer(); + return eventType.createEvent(playerQuitEvent); } - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityPortalEvent e) { - GameEventArgs.EntityPortalEvent entityPortalEvent = new GameEventArgs.EntityPortalEvent(); - entityPortalEvent.entity = e.getEntity(); - entityPortalEvent.cause = e.getTo().getWorld().getEnvironment() == World.Environment.THE_END || - e.getFrom().getWorld().getEnvironment() == World.Environment.THE_END ? - PlayerTeleportEvent.TeleportCause.END_PORTAL : PlayerTeleportEvent.TeleportCause.NETHER_PORTAL; - entityPortalEvent.from = e.getFrom(); - entityPortalEvent.to = e.getTo(); - return eventType.createEvent(entityPortalEvent); + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerRespawnEvent e) { + GameEventArgs.PlayerRespawnEvent playerRespawnEvent = new GameEventArgs.PlayerRespawnEvent(); + playerRespawnEvent.player = e.getPlayer(); + playerRespawnEvent.bukkitEvent = e; + return eventType.createEvent(playerRespawnEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerShearEntityEvent e) { + GameEventArgs.PlayerShearEntityEvent playerShearEntityEvent = new GameEventArgs.PlayerShearEntityEvent(); + playerShearEntityEvent.player = e.getPlayer(); + playerShearEntityEvent.entity = e.getEntity(); + return eventType.createEvent(playerShearEntityEvent); + } + + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerUnleashEntityEvent e) { + GameEventArgs.PlayerUnleashEntityEvent playerUnleashEntityEvent = new GameEventArgs.PlayerUnleashEntityEvent(); + playerUnleashEntityEvent.player = e.getPlayer(); + playerUnleashEntityEvent.entity = e.getEntity(); + return eventType.createEvent(playerUnleashEntityEvent); } private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, AsyncPlayerChatEvent e) { @@ -764,28 +809,9 @@ private GameEvent createGameEvent(GameEventType createGameEvent(GameEventType eventType, GameEventPriority priority, BlockPhysicsEvent e) { - GameEventArgs.BlockPhysicsEvent blockPhysicsEvent = new GameEventArgs.BlockPhysicsEvent(); - blockPhysicsEvent.block = e.getBlock(); - return eventType.createEvent(blockPhysicsEvent); - } - - private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, BlockFadeEvent e) { - GameEventArgs.BlockFadeEvent blockFadeEvent = new GameEventArgs.BlockFadeEvent(); - blockFadeEvent.block = e.getBlock(); - blockFadeEvent.newState = e.getNewState(); - return eventType.createEvent(blockFadeEvent); - } - - private void cancelVehicleCreateEvent(VehicleCreateEvent bukkitEvent, GameEvent gameEvent) { - if (gameEvent.isCancelled()) - bukkitEvent.getVehicle().remove(); - } - - private void cancelBlockRedstoneEvent(BlockRedstoneEvent bukkitEvent, GameEvent gameEvent) { - if (gameEvent.isCancelled()) - bukkitEvent.setNewCurrent(0); - } + /* + * INTERNALS + */ private void createEventListener(GameEventType eventType, Class bukkitEventClass, @@ -866,6 +892,10 @@ private interface ApplyBukkitEventFunction { } + /* + * SPECIAL EVENTS + */ + private static class SpongeAbsorbEventFunction implements GameEventCreator { @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java index af52e84ba2..2340b936df 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java @@ -14,68 +14,77 @@ public class GameEventType extends EventType> ALL_TYPES = new LinkedList<>(); - public static final GameEventType PLAYER_JOIN_EVENT = register(PlayerJoinEvent.class); - public static final GameEventType PLAYER_QUIT_EVENT = register(PlayerQuitEvent.class); - public static final GameEventType BLOCK_PLACE_EVENT = register(BlockPlaceEvent.class); - public static final GameEventType PLAYER_EMPTY_BUCKET_EVENT = register(PlayerEmptyBucketEvent.class); - public static final GameEventType PLAYER_FILL_BUCKET_EVENT = register(PlayerFillBucketEvent.class); - public static final GameEventType STRUCTURE_GROW_EVENT = register(StructureGrowEvent.class); - public static final GameEventType BLOCK_GROW_EVENT = register(BlockGrowEvent.class); - public static final GameEventType BLOCK_FORM_EVENT = register(BlockFormEvent.class); - public static final GameEventType BLOCK_SPREAD_EVENT = register(BlockSpreadEvent.class); - public static final GameEventType PLAYER_INTERACT_EVENT = register(PlayerInteractEvent.class); - public static final GameEventType ENTITY_CHANGE_BLOCK_EVENT = register(EntityChangeBlockEvent.class); + // Block Events public static final GameEventType BLOCK_BREAK_EVENT = register(BlockBreakEvent.class); + public static final GameEventType BLOCK_BURN_EVENT = register(BlockBurnEvent.class); public static final GameEventType BLOCK_DESTROY_EVENT = register(BlockDestroyEvent.class); - public static final GameEventType ENTITY_DEATH_EVENT = register(EntityDeathEvent.class); + public static final GameEventType BLOCK_DISPENSE_EVENT = register(BlockDispenseEvent.class); + public static final GameEventType BLOCK_FADE_EVENT = register(BlockFadeEvent.class); + public static final GameEventType BLOCK_FORM_EVENT = register(BlockFormEvent.class); + public static final GameEventType BLOCK_FROM_TO_EVENT = register(BlockFromToEvent.class); + public static final GameEventType BLOCK_GROW_EVENT = register(BlockGrowEvent.class); + public static final GameEventType BLOCK_IGNITE_EVENT = register(BlockIgniteEvent.class); + public static final GameEventType BLOCK_PHYSICS_EVENT = register(BlockPhysicsEvent.class); + public static final GameEventType BLOCK_PLACE_EVENT = register(BlockPlaceEvent.class); + public static final GameEventType BLOCK_REDSTONE_EVENT = register(BlockRedstoneEvent.class); + public static final GameEventType BLOCK_SPREAD_EVENT = register(BlockSpreadEvent.class); + public static final GameEventType LEAVES_DECAY_EVENT = register(LeavesDecayEvent.class); public static final GameEventType PISTON_EXTEND_EVENT = register(PistonExtendEvent.class); public static final GameEventType PISTON_RETRACT_EVENT = register(PistonRetractEvent.class); - public static final GameEventType LEAVES_DECAY_EVENT = register(LeavesDecayEvent.class); - public static final GameEventType BLOCK_FROM_TO_EVENT = register(BlockFromToEvent.class); - public static final GameEventType ENTITY_EXPLODE_EVENT = register(EntityExplodeEvent.class); - public static final GameEventType PROJECTILE_HIT_EVENT = register(ProjectileHitEvent.class); - public static final GameEventType PROJECTILE_LAUNCH_EVENT = register(ProjectileLaunchEvent.class); - public static final GameEventType SPONGE_ABSORB_EVENT = register(SpongeAbsorbEvent.class); + + // World Events public static final GameEventType CHUNK_LOAD_EVENT = register(ChunkLoadEvent.class); public static final GameEventType CHUNK_UNLOAD_EVENT = register(ChunkUnloadEvent.class); + public static final GameEventType SIGN_CHANGE_EVENT = register(SignChangeEvent.class); + public static final GameEventType SPONGE_ABSORB_EVENT = register(SpongeAbsorbEvent.class); + public static final GameEventType STRUCTURE_GROW_EVENT = register(StructureGrowEvent.class); public static final GameEventType WORLD_UNLOAD_EVENT = register(WorldUnloadEvent.class); - public static final GameEventType ENTITY_SPAWN_EVENT = register(EntitySpawnEvent.class); + + // Entity Events public static final GameEventType ATTEMPT_ENTITY_SPAWN_EVENT = register(AttemptEntitySpawnEvent.class); - public static final GameEventType PLAYER_COMMAND_EVENT = register(PlayerCommandEvent.class); - public static final GameEventType HANGING_BREAK_EVENT = register(HangingBreakEvent.class); + public static final GameEventType ENTITY_BLOCK_FORM_EVENT = register(EntityBlockFormEvent.class); + public static final GameEventType ENTITY_CHANGE_BLOCK_EVENT = register(EntityChangeBlockEvent.class); + public static final GameEventType ENTITY_COLLISION_EVENT = register(EntityCollisionEvent.class); public static final GameEventType ENTITY_DAMAGE_EVENT = register(EntityDamageEvent.class); - public static final GameEventType BLOCK_BURN_EVENT = register(BlockBurnEvent.class); - public static final GameEventType BLOCK_IGNITE_EVENT = register(BlockIgniteEvent.class); - public static final GameEventType ENTITY_RIDE_EVENT = register(EntityRideEvent.class); + public static final GameEventType ENTITY_DEATH_EVENT = register(EntityDeathEvent.class); + public static final GameEventType ENTITY_ENTER_PORTAL_EVENT = register(EntityEnterPortalEvent.class); + public static final GameEventType ENTITY_EXPLODE_EVENT = register(EntityExplodeEvent.class); public static final GameEventType ENTITY_MOVE_EVENT = register(EntityMoveEvent.class); + public static final GameEventType ENTITY_PORTAL_EVENT = register(EntityPortalEvent.class); + public static final GameEventType ENTITY_RIDE_EVENT = register(EntityRideEvent.class); + public static final GameEventType ENTITY_SPAWN_EVENT = register(EntitySpawnEvent.class); + public static final GameEventType ENTITY_TARGET_EVENT = register(EntityTargetEvent.class); public static final GameEventType ENTITY_TELEPORT_EVENT = register(EntityTeleportEvent.class); - public static final GameEventType BLOCK_REDSTONE_EVENT = register(BlockRedstoneEvent.class); + public static final GameEventType HANGING_BREAK_EVENT = register(HangingBreakEvent.class); + public static final GameEventType HANGING_PLACE_EVENT = register(HangingPlaceEvent.class); + public static final GameEventType PROJECTILE_HIT_EVENT = register(ProjectileHitEvent.class); + public static final GameEventType PROJECTILE_LAUNCH_EVENT = register(ProjectileLaunchEvent.class); + public static final GameEventType RAID_TRIGGER_EVENT = register(RaidTriggerEvent.class); + + // Inventory Events public static final GameEventType INVENTORY_CLICK_EVENT = register(InventoryClickEvent.class); public static final GameEventType INVENTORY_CLOSE_EVENT = register(InventoryCloseEvent.class); public static final GameEventType INVENTORY_OPEN_EVENT = register(InventoryOpenEvent.class); - public static final GameEventType PLAYER_LOGIN_EVENT = register(PlayerLoginEvent.class); - public static final GameEventType PLAYER_GAMEMODE_CHANGE = register(PlayerGamemodeChangeEvent.class); + + // Player Events public static final GameEventType PLAYER_CHANGED_WORLD_EVENT = register(PlayerChangedWorldEvent.class); - public static final GameEventType PLAYER_RESPAWN_EVENT = register(PlayerRespawnEvent.class); public static final GameEventType PLAYER_CHAT_EVENT = register(PlayerChatEvent.class); - public static final GameEventType ENTITY_PORTAL_EVENT = register(EntityPortalEvent.class); - public static final GameEventType ENTITY_ENTER_PORTAL_EVENT = register(EntityEnterPortalEvent.class); - public static final GameEventType ENTITY_BLOCK_FORM_EVENT = register(EntityBlockFormEvent.class); - public static final GameEventType BLOCK_DISPENSE_EVENT = register(BlockDispenseEvent.class); + public static final GameEventType PLAYER_COMMAND_EVENT = register(PlayerCommandEvent.class); + public static final GameEventType PLAYER_DROP_ITEM_EVENT = register(PlayerDropItemEvent.class); + public static final GameEventType PLAYER_EMPTY_BUCKET_EVENT = register(PlayerEmptyBucketEvent.class); + public static final GameEventType PLAYER_FILL_BUCKET_EVENT = register(PlayerFillBucketEvent.class); + public static final GameEventType PLAYER_GAMEMODE_CHANGE = register(PlayerGamemodeChangeEvent.class); + public static final GameEventType PLAYER_INTERACT_EVENT = register(PlayerInteractEvent.class); public static final GameEventType PLAYER_ITEM_CONSUME_EVENT = register(PlayerItemConsumeEvent.class); - public static final GameEventType PLAYER_SHEAR_ENTITY_EVENT = register(PlayerShearEntityEvent.class); - public static final GameEventType HANGING_PLACE_EVENT = register(HangingPlaceEvent.class); - public static final GameEventType ENTITY_TARGET_EVENT = register(EntityTargetEvent.class); + public static final GameEventType PLAYER_JOIN_EVENT = register(PlayerJoinEvent.class); public static final GameEventType PLAYER_LEASH_ENTITY_EVENT = register(PlayerLeashEntityEvent.class); - public static final GameEventType PLAYER_UNLEASH_ENTITY_EVENT = register(PlayerUnleashEntityEvent.class); - public static final GameEventType ENTITY_COLLISION_EVENT = register(EntityCollisionEvent.class); - public static final GameEventType PLAYER_DROP_ITEM_EVENT = register(PlayerDropItemEvent.class); - public static final GameEventType PLAYER_PICKUP_ITEM_EVENT = register(PlayerPickupItemEvent.class); + public static final GameEventType PLAYER_LOGIN_EVENT = register(PlayerLoginEvent.class); public static final GameEventType PLAYER_PICKUP_ARROW_EVENT = register(PlayerPickupArrowEvent.class); - public static final GameEventType RAID_TRIGGER_EVENT = register(RaidTriggerEvent.class); - public static final GameEventType SIGN_CHANGE_EVENT = register(SignChangeEvent.class); - public static final GameEventType BLOCK_PHYSICS_EVENT = register(BlockPhysicsEvent.class); - public static final GameEventType BLOCK_FADE_EVENT = register(BlockFadeEvent.class); + public static final GameEventType PLAYER_PICKUP_ITEM_EVENT = register(PlayerPickupItemEvent.class); + public static final GameEventType PLAYER_QUIT_EVENT = register(PlayerQuitEvent.class); + public static final GameEventType PLAYER_RESPAWN_EVENT = register(PlayerRespawnEvent.class); + public static final GameEventType PLAYER_SHEAR_ENTITY_EVENT = register(PlayerShearEntityEvent.class); + public static final GameEventType PLAYER_UNLEASH_ENTITY_EVENT = register(PlayerUnleashEntityEvent.class); private GameEventType() { } From d67e162f624014c6ba341282d33f7c1825066615 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 23 Aug 2025 12:36:21 +0300 Subject: [PATCH 262/600] Cache entity categories per entity type (#2594) --- .../world/BukkitEntities.java | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java index ed9769baa3..78a5031859 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java @@ -35,6 +35,7 @@ import java.util.Arrays; import java.util.Collections; +import java.util.EnumMap; import java.util.EnumSet; import java.util.LinkedList; import java.util.List; @@ -54,6 +55,20 @@ public class BukkitEntities { @Nullable private static final EntityType CAMEL_TYPE = EnumHelper.getEnum(EntityType.class, "CAMEL"); + private static final EnumMap ENTITY_CATEGORIES_CACHE = new EnumMap<>(EntityType.class); + + static { + outerLoop: + for (EntityType entityType : EntityType.values()) { + for (EntityCategory entityCategory : EntityCategory.values()) { + if (entityCategory.isFromCategory(entityType)) { + ENTITY_CATEGORIES_CACHE.put(entityType, entityCategory); + continue outerLoop; + } + } + } + } + private BukkitEntities() { } @@ -159,12 +174,7 @@ public static boolean canBypassEntityLimit(Entity entity, boolean checkProviders } public static EntityCategory getCategory(EntityType entityType) { - for (EntityCategory entityCategory : EntityCategory.values()) { - if (entityCategory.isFromCategory(entityType)) - return entityCategory; - } - - return EntityCategory.UNKNOWN; + return ENTITY_CATEGORIES_CACHE.getOrDefault(entityType, EntityCategory.UNKNOWN); } public static boolean isHorse(Entity entity) { From 849fe2d100d93bbb4c29a2819f2f4a2be7f5dada Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 23 Aug 2025 13:11:41 +0300 Subject: [PATCH 263/600] Optimized the position to island cache (#2594) --- .../superiorskyblock/core/IslandPosition.java | 39 +- .../collections/IslandPosition2ObjectMap.java | 394 ++++++++++++++++++ .../container/DefaultIslandsContainer.java | 56 ++- 3 files changed, 463 insertions(+), 26 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/collections/IslandPosition2ObjectMap.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java index 1ef1dfd56b..031e5e7010 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java @@ -13,17 +13,21 @@ public class IslandPosition implements ObjectsPool.Releasable, AutoCloseable { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @Nullable - private String worldName; - private int x; - private int z; + protected String worldName; + protected int x; + protected int z; - private IslandPosition() { + @Nullable + protected Long cachedPackedPos = null; + + protected IslandPosition() { } private IslandPosition initialize(@Nullable String worldName, int x, int z) { this.worldName = worldName; this.x = x; this.z = z; + this.cachedPackedPos = null; return this; } @@ -46,6 +50,15 @@ public static IslandPosition of(String worldName, int locX, int locZ, boolean fr locX < 0 ? -x : x, locZ < 0 ? -z : z); } + public String getWorldName() { + return worldName; + } + + public long pack() { + return this.cachedPackedPos != null ? this.cachedPackedPos : + (this.cachedPackedPos = IslandPosition.calculatePackedPos(this)); + } + @Override public void release() { this.worldName = null; @@ -75,4 +88,22 @@ public String toString() { return "IslandPosition{x=" + x + ",z=" + z + "}"; } + public static long calculatePackedPos(IslandPosition islandPosition) { + return calculatePackedPos(islandPosition.x, islandPosition.z); + } + + public static long calculatePackedPos(int posX, int posZ) { + long posXLong = (long) posX & 0xFFFFFFFFL; + long posZLong = (long) posZ & 0xFFFFFFFFL; + return (posXLong) | (posZLong << 32); + } + + public static int getXFromPacked(long packedPos) { + return (int) (packedPos & 0xFFFFFFFFL); + } + + public static int getZFromPacked(long packedPos) { + return (int) ((packedPos >>> 32) & 0xFFFFFFFFL); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/IslandPosition2ObjectMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/IslandPosition2ObjectMap.java new file mode 100644 index 0000000000..925660d7a3 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/IslandPosition2ObjectMap.java @@ -0,0 +1,394 @@ +package com.bgsoftware.superiorskyblock.core.collections; + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.core.IslandPosition; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; + +import java.util.AbstractCollection; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.function.Supplier; + +public class IslandPosition2ObjectMap extends AbstractMap { + + @Nullable + private KeySet keySet; + @Nullable + private Values values; + @Nullable + private EntrySet entrySet; + + private final Map> backendMap = new LinkedHashMap<>(); + private int size = 0; + + @Override + public int size() { + return this.size; + } + + @Override + public boolean isEmpty() { + return this.size == 0; + } + + @Override + public boolean containsKey(Object key) { + return get(key) != null; + } + + @Override + public boolean containsValue(Object value) { + return value != null && super.containsValue(value); + } + + @Override + public V get(Object key) { + return key instanceof IslandPosition ? get((IslandPosition) key) : null; + } + + @Nullable + public V get(IslandPosition islandPosition) { + return get(islandPosition.getWorldName(), islandPosition.pack()); + } + + @Nullable + public V get(String worldName, long packedPos) { + Long2ObjectMapView worldBackendData = this.backendMap.get(worldName); + if (worldBackendData == null) + return null; + + return worldBackendData.get(packedPos); + } + + public V computeIfAbsent(String worldName, long packedPos, Supplier newValue) { + Long2ObjectMapView worldBackendData = this.backendMap.computeIfAbsent(worldName, n -> + CollectionsFactory.createLong2ObjectLinkedHashMap()); + + return worldBackendData.computeIfAbsent(packedPos, p -> { + ++IslandPosition2ObjectMap.this.size; + return newValue.get(); + }); + } + + @Nullable + @Override + public V put(IslandPosition islandPosition, V value) { + return put(islandPosition.getWorldName(), islandPosition.pack(), value); + } + + @Nullable + public V put(String worldName, long packedPos, V value) { + Long2ObjectMapView worldBackendData = this.backendMap.computeIfAbsent(worldName, n -> + CollectionsFactory.createLong2ObjectLinkedHashMap()); + + V oldValue = worldBackendData.put(packedPos, value); + + if (oldValue == null) + ++this.size; + + return oldValue; + } + + @Override + public V remove(Object key) { + return key instanceof IslandPosition ? remove((IslandPosition) key) : null; + } + + @Nullable + public V remove(IslandPosition islandPosition) { + return remove(islandPosition.getWorldName(), islandPosition.pack()); + } + + @Nullable + public V remove(String worldName, long packedPos) { + Long2ObjectMapView worldBackendData = this.backendMap.get(worldName); + if (worldBackendData == null) + return null; + + V oldValue = onRemove(worldBackendData.remove(packedPos)); + if (oldValue == null) + return null; + + if (worldBackendData.isEmpty()) + IslandPosition2ObjectMap.this.backendMap.remove(worldName); + + return oldValue; + } + + @Nullable + private V onRemove(@Nullable V removedValue) { + if (removedValue != null) + --this.size; + return removedValue; + } + + @Override + public void clear() { + this.backendMap.clear(); + this.size = 0; + } + + @NotNull + @Override + public Set keySet() { + return this.keySet == null ? (this.keySet = new KeySet()) : this.keySet; + } + + @NotNull + @Override + public Collection values() { + return this.values == null ? (this.values = new Values()) : this.values; + } + + @NotNull + @Override + public Set> entrySet() { + return this.entrySet == null ? (this.entrySet = new EntrySet()) : this.entrySet; + } + + private class KeySet extends AbstractSet { + + @Override + public int size() { + return IslandPosition2ObjectMap.this.size(); + } + + @Override + public boolean isEmpty() { + return IslandPosition2ObjectMap.this.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return IslandPosition2ObjectMap.this.containsKey(o); + } + + @NotNull + @Override + public Iterator iterator() { + return new KeySetItr(); + } + + @Override + public void clear() { + IslandPosition2ObjectMap.this.clear(); + } + + private class KeySetItr extends Itr { + + private final MutableIslandPosition mutableIslandPosition = new MutableIslandPosition(); + + @Override + protected IslandPosition getNext() { + return this.mutableIslandPosition.reset(this.currentWorld, this.currentPosition); + } + } + + } + + private class Values extends AbstractCollection { + + @Override + public int size() { + return IslandPosition2ObjectMap.this.size(); + } + + @Override + public boolean isEmpty() { + return IslandPosition2ObjectMap.this.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return IslandPosition2ObjectMap.this.containsValue(o); + } + + @NotNull + @Override + public Iterator iterator() { + return new ValuesItr(); + } + + @Override + public void clear() { + IslandPosition2ObjectMap.this.clear(); + } + + private class ValuesItr extends Itr { + + @Override + protected V getNext() { + return this.currentValue; + } + + } + + } + + private class EntrySet extends AbstractSet> { + + @Override + public int size() { + return IslandPosition2ObjectMap.this.size(); + } + + @Override + public boolean isEmpty() { + return IslandPosition2ObjectMap.this.isEmpty(); + } + + @Override + public boolean contains(Object o) { + IslandPosition key = null; + + if (o instanceof Entry) { + o = ((Entry) o).getKey(); + } + + if (o instanceof IslandPosition) + key = (IslandPosition) o; + + return key != null && IslandPosition2ObjectMap.this.containsKey(o); + } + + @NotNull + @Override + public Iterator> iterator() { + return new EntrySetItr(); + } + + @Override + public void clear() { + IslandPosition2ObjectMap.this.clear(); + } + + private class EntrySetItr extends Itr> { + + private final MutableIslandPosition mutableIslandPosition = new MutableIslandPosition(); + private final EntryImpl mutableEntry = new EntryImpl(); + + @Override + protected Entry getNext() { + return mutableEntry.reset( + this.mutableIslandPosition.reset(this.currentWorld, this.currentPosition), + this.currentValue); + } + + private class EntryImpl implements Entry { + + private IslandPosition islandPosition; + private V cachedValue; + + EntryImpl() { + + } + + EntryImpl reset(IslandPosition islandPosition, V value) { + this.islandPosition = islandPosition; + this.cachedValue = value; + return this; + } + + @Override + public IslandPosition getKey() { + return this.islandPosition; + } + + @Override + public V getValue() { + return this.cachedValue; + } + + @Override + public V setValue(V v) { + V oldValue = this.cachedValue; + this.cachedValue = v; + + Long2ObjectMapView worldBackendData = IslandPosition2ObjectMap.this.backendMap + .get(this.islandPosition.getWorldName()); + + worldBackendData.put(this.islandPosition.pack(), this.cachedValue); + + return oldValue; + } + } + + } + + } + + private abstract class Itr implements Iterator { + + protected final Iterator>> worldsIterator; + protected Iterator> currentWorldIterator = Collections.emptyIterator(); + protected String currentWorld; + protected long currentPosition; + protected V currentValue; + + protected Itr() { + this.worldsIterator = IslandPosition2ObjectMap.this.backendMap.entrySet().iterator(); + } + + @Override + public final boolean hasNext() { + return this.currentWorldIterator.hasNext() || this.worldsIterator.hasNext(); + } + + @Override + public final T next() { + if (!this.currentWorldIterator.hasNext()) { + if (!this.worldsIterator.hasNext()) { + throw new NoSuchElementException(); + } + + Entry> nextWorld = this.worldsIterator.next(); + this.currentWorldIterator = nextWorld.getValue().entryIterator(); + this.currentWorld = nextWorld.getKey(); + } + + Long2ObjectMapView.Entry nextPosition = this.currentWorldIterator.next(); + this.currentPosition = nextPosition.getKey(); + this.currentValue = nextPosition.getValue(); + + return getNext(); + } + + protected abstract T getNext(); + + @Override + public final void remove() { + Long2ObjectMapView worldBackendData = IslandPosition2ObjectMap.this.backendMap.get(this.currentWorld); + + this.currentWorldIterator.remove(); + IslandPosition2ObjectMap.this.onRemove(this.currentValue); + + if (worldBackendData.isEmpty()) + this.worldsIterator.remove(); + } + } + + private static class MutableIslandPosition extends IslandPosition { + + public MutableIslandPosition() { + super(); + } + + public MutableIslandPosition reset(String worldName, long packedPos) { + this.worldName = worldName; + this.x = IslandPosition.getXFromPacked(packedPos); + this.z = IslandPosition.getZFromPacked(packedPos); + this.cachedPackedPos = packedPos; + return this; + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index e3bbb42274..47c4d03fef 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.core.IslandPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; +import com.bgsoftware.superiorskyblock.core.collections.IslandPosition2ObjectMap; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; @@ -33,7 +34,7 @@ public class DefaultIslandsContainer implements IslandsContainer { - private final Map islandsByPositions = new ConcurrentHashMap<>(); + private final Synchronized> islandsByPositions = Synchronized.of(new IslandPosition2ObjectMap<>()); private final Map islandsByUUID = new ConcurrentHashMap<>(); private final Map>> sortedIslands = new ConcurrentHashMap<>(); @@ -55,18 +56,23 @@ public void addIsland(Island island) { Preconditions.checkNotNull(defaultWorld, "Default world information cannot be null!"); - this.islandsByPositions.put(IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ(), false), island); + this.islandsByPositions.write(islandsByPositions -> { + try (IslandPosition islandPosition = IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ())) { + islandsByPositions.put(islandPosition, island); + } - if (plugin.getProviders().hasCustomWorldsSupport()) { - // We don't know the logic of the custom worlds support, therefore we add a position - // for every possible world, so there won't be issues with detecting islands later. - for (Dimension dimension : Dimension.values()) { - if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { - runWithCustomWorld(defaultWorld, center, island, dimension, - islandPosition -> this.islandsByPositions.put(islandPosition, island)); + if (plugin.getProviders().hasCustomWorldsSupport()) { + // We don't know the logic of the custom worlds support, therefore we add a position + // for every possible world, so there won't be issues with detecting islands later. + for (Dimension dimension : Dimension.values()) { + if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { + runWithCustomWorld(defaultWorld, center, island, dimension, + islandPosition -> islandsByPositions.put(islandPosition, island)); + } } } - } + }); + this.islandsByUUID.put(island.getUniqueId(), island); @@ -83,18 +89,20 @@ public void removeIsland(Island island) { Preconditions.checkNotNull(defaultWorld, "Default world information cannot be null!"); - try (IslandPosition islandPosition = IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ())) { - this.islandsByPositions.remove(islandPosition, island); - } + this.islandsByPositions.write(islandsByPositions -> { + try (IslandPosition islandPosition = IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ())) { + islandsByPositions.remove(islandPosition, island); + } - if (plugin.getProviders().hasCustomWorldsSupport()) { - for (Dimension dimension : Dimension.values()) { - if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { - runWithCustomWorld(defaultWorld, center, island, dimension, - islandPosition -> this.islandsByPositions.remove(islandPosition, island)); + if (plugin.getProviders().hasCustomWorldsSupport()) { + for (Dimension dimension : Dimension.values()) { + if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { + runWithCustomWorld(defaultWorld, center, island, dimension, + islandPosition -> islandsByPositions.remove(islandPosition, island)); + } } } - } + }); islandsByUUID.remove(island.getUniqueId()); @@ -136,7 +144,8 @@ public int getIslandsAmount() { public Island getIslandAt(Location location) { Island island; try (IslandPosition islandPosition = IslandPosition.of(location)) { - island = this.islandsByPositions.get(islandPosition); + island = this.islandsByPositions.readAndGet(islandsByPositions -> + islandsByPositions.get(islandPosition)); } return island == null || !island.isInside(location) ? null : island; } @@ -244,8 +253,11 @@ else if (sortingType == SortingTypes.BY_RATING) private void runWithCustomWorld(WorldInfo defaultWorld, BlockPosition center, Island island, Dimension dimension, Consumer consumer) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); - if (worldInfo != null && !worldInfo.equals(defaultWorld)) - consumer.accept(IslandPosition.of(worldInfo.getName(), center.getX(), center.getZ(), false)); + if (worldInfo != null && !worldInfo.equals(defaultWorld)) { + try (IslandPosition islandPosition = IslandPosition.of(worldInfo.getName(), center.getX(), center.getZ())) { + consumer.accept(islandPosition); + } + } } } From 7f9e519ce65ee13fb587efea47f6a59023f6d43a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 23 Aug 2025 13:23:40 +0300 Subject: [PATCH 264/600] Optimized islands world detection (#2594) --- .../superiorskyblock/island/SIsland.java | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 8e01340dcd..865cd5ba61 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -1463,28 +1463,15 @@ public boolean isInsideRange(Chunk chunk) { } } - private boolean isIslandWorld(@Nullable World world) { - if (world == null) - return false; - - Dimension dimension = plugin.getGrid().getIslandsWorldDimension(world); - if (dimension == null) - return false; - - WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); - return worldInfo.getName().equals(world.getName()); + private static boolean isIslandWorld(@Nullable World world) { + return world != null && plugin.getProviders().getWorldsProvider().isIslandsWorld(world); } private boolean isIslandWorld(@Nullable WorldInfo worldInfo) { if (worldInfo == null) return false; - Dimension dimension = worldInfo.getDimension(); - if (dimension == null) - return false; - - WorldInfo realWorldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); - return realWorldInfo.getName().equals(worldInfo.getName()); + return plugin.getGrid().getIslandsWorldInfo(this, worldInfo.getName()) != null; } @Override From b162e8c1e72ef956c451ab18beea72c6c14cf1a4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 23 Aug 2025 18:01:29 +0300 Subject: [PATCH 265/600] Fixed errors when loading the plugin due to recent commits --- .../world/BukkitEntities.java | 127 ---------------- .../world/EntityCategory.java | 138 ++++++++++++++++++ 2 files changed, 138 insertions(+), 127 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/EntityCategory.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java index 78a5031859..b4ac1535b8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java @@ -3,30 +3,23 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.EntitiesProvider; -import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import org.bukkit.Material; import org.bukkit.entity.AbstractHorse; -import org.bukkit.entity.Ambient; import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Creature; import org.bukkit.entity.Donkey; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; -import org.bukkit.entity.Flying; import org.bukkit.entity.Hanging; import org.bukkit.entity.Horse; import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Monster; import org.bukkit.entity.Mule; import org.bukkit.entity.Pig; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; -import org.bukkit.entity.Slime; import org.bukkit.entity.Vehicle; import org.bukkit.inventory.AbstractHorseInventory; import org.bukkit.inventory.HorseInventory; @@ -36,22 +29,17 @@ import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; -import java.util.EnumSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Predicate; public class BukkitEntities { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Map> entityContent = new ConcurrentHashMap<>(); - private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); - private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); - private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); @Nullable private static final EntityType CAMEL_TYPE = EnumHelper.getEnum(EntityType.class, "CAMEL"); @@ -182,119 +170,4 @@ public static boolean isHorse(Entity entity) { (ServerVersion.isAtLeast(ServerVersion.v1_11) && (entity instanceof Mule || entity instanceof Donkey)); } - private static EnumSet createEntityTypesSet(Predicate predicate) { - EnumSet entityTypes = EnumSet.noneOf(EntityType.class); - for (EntityType entityType : EntityType.values()) { - if (predicate.test(entityType)) - entityTypes.add(entityType); - } - return entityTypes; - } - - public enum EntityCategory { - - MONSTER(IslandPrivileges.MONSTER_DAMAGE, IslandPrivileges.MONSTER_SPAWN) { - - private final EnumSet MONSTER_TYPES = createEntityTypesSet(entityType -> { - Class entityClass = entityType.getEntityClass(); - return entityClass != null && (Monster.class.isAssignableFrom(entityClass) || - // Checks for slimes & magma cubes - Slime.class.isAssignableFrom(entityClass) || - // Checks for ghasts and phantoms - Flying.class.isAssignableFrom(entityClass) || - // In Bukkit, Hoglins are considered as Animals for no reason. - // We want to explicitly tell the plugin its monster type. - entityClass == HOGLIN_CLASS || - // In Bukkit, Skeleton and Zombie horses are considered Horses, - // and therefore they are animals. We want to explicit tell the plugin - // they are monsters. - entityClass == SKELETON_HORSE_CLASS || entityClass == ZOMBIE_HORSE_CLASS - ); - }); - - @Override - boolean isFromCategory(EntityType entityType) { - return MONSTER_TYPES.contains(entityType); - } - }, - // !!!Never put this above Monster category!!! - ANIMAL(IslandPrivileges.ANIMAL_DAMAGE, IslandPrivileges.ANIMAL_SPAWN) { - - private final EnumSet ANIMAL_TYPES = createEntityTypesSet(entityType -> { - Class entityClass = entityType.getEntityClass(); - // This call is done after Monster category is checked. - // Therefore, the checks below are enough. - return entityClass != null && - // We check that the entity type is whether a Creature or an Ambient - (Creature.class.isAssignableFrom(entityClass) || Ambient.class.isAssignableFrom(entityClass)) && - // We make sure this is not Hoglin; In Bukkit, they are considered Animals. - entityClass != HOGLIN_CLASS && - // We make sure this is not Skeleton/Zombie horses; In Bukkit, they are considered Animals. - entityClass != SKELETON_HORSE_CLASS && entityClass != ZOMBIE_HORSE_CLASS; - }); - - @Override - boolean isFromCategory(EntityType entityType) { - return ANIMAL_TYPES.contains(entityType); - } - }, - PAINTING(IslandPrivileges.PAINTING, IslandPrivileges.BUILD) { - @Override - boolean isFromCategory(EntityType entityType) { - return entityType == EntityType.PAINTING; - } - }, - ITEM_FRAME(IslandPrivileges.ITEM_FRAME, IslandPrivileges.BUILD) { - @Override - boolean isFromCategory(EntityType entityType) { - return entityType == EntityType.ITEM_FRAME; - } - }, - VEHICLE(IslandPrivileges.MINECART_DAMAGE, IslandPrivileges.MINECART_PLACE) { - - private final EnumSet VEHICLE_TYPES = createEntityTypesSet(entityType -> { - Class entityClass = entityType.getEntityClass(); - return entityClass != null && Vehicle.class.isAssignableFrom(entityClass); - }); - - @Override - boolean isFromCategory(EntityType entityType) { - return VEHICLE_TYPES.contains(entityType); - } - }, - UNKNOWN(IslandPrivileges.BREAK, IslandPrivileges.BUILD) { - @Override - boolean isFromCategory(EntityType entityType) { - return true; - } - }; - - private final IslandPrivilege damagePrivilege; - private final IslandPrivilege spawnPrivilege; - - EntityCategory(IslandPrivilege damagePrivilege, IslandPrivilege spawnPrivilege) { - this.damagePrivilege = damagePrivilege; - this.spawnPrivilege = spawnPrivilege; - } - - public IslandPrivilege getDamagePrivilege() { - return damagePrivilege; - } - - public IslandPrivilege getSpawnPrivilege() { - return spawnPrivilege; - } - - abstract boolean isFromCategory(EntityType entityType); - - } - - private static Class getEntityTypeClass(String clazz) { - try { - return Class.forName(clazz); - } catch (ClassNotFoundException error) { - return null; - } - } - } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityCategory.java b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityCategory.java new file mode 100644 index 0000000000..1245d20f9d --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityCategory.java @@ -0,0 +1,138 @@ +package com.bgsoftware.superiorskyblock.world; + +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import org.bukkit.entity.Ambient; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Flying; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Slime; +import org.bukkit.entity.Vehicle; + +import java.util.EnumSet; +import java.util.function.Predicate; + +public enum EntityCategory { + + MONSTER(IslandPrivileges.MONSTER_DAMAGE, IslandPrivileges.MONSTER_SPAWN) { + + private final EnumSet MONSTER_TYPES = createEntityTypesSet(EntityCategory::isMonsterType); + + @Override + boolean isFromCategory(EntityType entityType) { + return MONSTER_TYPES.contains(entityType); + } + }, + // !!!Never put this above Monster category!!! + ANIMAL(IslandPrivileges.ANIMAL_DAMAGE, IslandPrivileges.ANIMAL_SPAWN) { + + private final EnumSet ANIMAL_TYPES = createEntityTypesSet(EntityCategory::isAnimalType); + + @Override + boolean isFromCategory(EntityType entityType) { + return ANIMAL_TYPES.contains(entityType); + } + }, + PAINTING(IslandPrivileges.PAINTING, IslandPrivileges.BUILD) { + @Override + boolean isFromCategory(EntityType entityType) { + return entityType == EntityType.PAINTING; + } + }, + ITEM_FRAME(IslandPrivileges.ITEM_FRAME, IslandPrivileges.BUILD) { + @Override + boolean isFromCategory(EntityType entityType) { + return entityType == EntityType.ITEM_FRAME; + } + }, + VEHICLE(IslandPrivileges.MINECART_DAMAGE, IslandPrivileges.MINECART_PLACE) { + + private final EnumSet VEHICLE_TYPES = createEntityTypesSet(entityType -> { + Class entityClass = entityType.getEntityClass(); + return entityClass != null && Vehicle.class.isAssignableFrom(entityClass); + }); + + @Override + boolean isFromCategory(EntityType entityType) { + return VEHICLE_TYPES.contains(entityType); + } + }, + UNKNOWN(IslandPrivileges.BREAK, IslandPrivileges.BUILD) { + @Override + boolean isFromCategory(EntityType entityType) { + return true; + } + }; + + private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); + private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); + private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); + + private final IslandPrivilege damagePrivilege; + private final IslandPrivilege spawnPrivilege; + + EntityCategory(IslandPrivilege damagePrivilege, IslandPrivilege spawnPrivilege) { + this.damagePrivilege = damagePrivilege; + this.spawnPrivilege = spawnPrivilege; + } + + public IslandPrivilege getDamagePrivilege() { + return damagePrivilege; + } + + public IslandPrivilege getSpawnPrivilege() { + return spawnPrivilege; + } + + abstract boolean isFromCategory(EntityType entityType); + + private static boolean isAnimalType(EntityType entityType) { + Class entityClass = entityType.getEntityClass(); + // This call is done after Monster category is checked. + // Therefore, the checks below are enough. + return entityClass != null && + // We check that the entity type is whether a Creature or an Ambient + (Creature.class.isAssignableFrom(entityClass) || Ambient.class.isAssignableFrom(entityClass)) && + // We make sure this is not Hoglin; In Bukkit, they are considered Animals. + entityClass != HOGLIN_CLASS && + // We make sure this is not Skeleton/Zombie horses; In Bukkit, they are considered Animals. + entityClass != SKELETON_HORSE_CLASS && entityClass != ZOMBIE_HORSE_CLASS; + } + + private static boolean isMonsterType(EntityType entityType) { + Class entityClass = entityType.getEntityClass(); + return entityClass != null && (Monster.class.isAssignableFrom(entityClass) || + // Checks for slimes & magma cubes + Slime.class.isAssignableFrom(entityClass) || + // Checks for ghasts and phantoms + Flying.class.isAssignableFrom(entityClass) || + // In Bukkit, Hoglins are considered as Animals for no reason. + // We want to explicitly tell the plugin its monster type. + entityClass == HOGLIN_CLASS || + // In Bukkit, Skeleton and Zombie horses are considered Horses, + // and therefore they are animals. We want to explicit tell the plugin + // they are monsters. + entityClass == SKELETON_HORSE_CLASS || entityClass == ZOMBIE_HORSE_CLASS + ); + } + + private static EnumSet createEntityTypesSet(Predicate predicate) { + EnumSet entityTypes = EnumSet.noneOf(EntityType.class); + for (EntityType entityType : EntityType.values()) { + if (predicate.test(entityType)) + entityTypes.add(entityType); + } + return entityTypes; + } + + private static Class getEntityTypeClass(String clazz) { + try { + return Class.forName(clazz); + } catch (ClassNotFoundException error) { + return null; + } + } + +} From 875ae571a071e044eeeb90f996316cd9a37f5352 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 23 Aug 2025 18:07:09 +0300 Subject: [PATCH 266/600] Use DatabaseBridge instead of local implementation --- build.gradle | 4 +- .../SuperiorSkyblockPlugin.java | 5 - .../core/database/loader/sql/SQLDatabase.java | 336 +++++++++--------- .../loader/sql/SQLDatabaseLoader.java | 57 +-- .../sql/upgrade/v0/DatabaseConverter.java | 36 +- .../sql/upgrade/v0/DatabaseUpgrade_V0.java | 28 +- .../sql/upgrade/v1/DatabaseUpgrade_V1.java | 4 +- .../sql/upgrade/v2/DatabaseUpgrade_V2.java | 16 +- .../core/database/sql/DBSession.java | 178 ++++++++++ .../core/database/sql/SQLDatabaseBridge.java | 21 +- .../core/database/sql/SQLHelper.java | 114 ------ .../database/sql/SQLTransactionProcessor.java | 121 ------- .../database/sql/session/QueryResult.java | 49 --- .../sql/session/RemoteSQLSession.java | 172 --------- .../core/database/sql/session/SQLSession.java | 36 -- .../sql/session/impl/MariaDBSession.java | 70 ---- .../sql/session/impl/MySQLSession.java | 62 ---- .../sql/session/impl/SQLiteSession.java | 208 ----------- .../CustomSQLDatabaseTransaction.java | 16 - .../DeleteSQLDatabaseTransaction.java | 24 -- .../InsertSQLDatabaseTransaction.java | 32 -- .../transaction/SQLDatabaseTransaction.java | 74 ---- .../UpdateSQLDatabaseTransaction.java | 34 -- .../DatabaseTransactionsExecutor.java | 147 -------- .../transaction/IDatabaseTransaction.java | 5 - 25 files changed, 424 insertions(+), 1425 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/DBSession.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLHelper.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLTransactionProcessor.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/QueryResult.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/RemoteSQLSession.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/SQLSession.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/impl/MariaDBSession.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/impl/MySQLSession.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/impl/SQLiteSession.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/CustomSQLDatabaseTransaction.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/DeleteSQLDatabaseTransaction.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/InsertSQLDatabaseTransaction.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/SQLDatabaseTransaction.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/UpdateSQLDatabaseTransaction.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/transaction/DatabaseTransactionsExecutor.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/transaction/IDatabaseTransaction.java diff --git a/build.gradle b/build.gradle index c34c8ac910..2868a4c8f5 100644 --- a/build.gradle +++ b/build.gradle @@ -73,9 +73,8 @@ dependencies { implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b14' + implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b1' - implementation 'com.zaxxer:HikariCP:4.0.3' - implementation 'org.slf4j:slf4j-api:2.0.5' implementation 'org.bstats:bstats-bukkit:3.0.0' // Spigot jars @@ -105,7 +104,6 @@ processResources { shadowJar { dependsOn(jar) - relocate 'com.zaxxer.hikari', 'com.bgsoftware.superiorskyblock.libs.com.zaxxer.hikari' relocate 'org.bstats', 'com.bgsoftware.superiorskyblock.libs.org.bstats' relocate 'com.bgsoftware.common', 'com.bgsoftware.superiorskyblock.libs.com.bgsoftware.common' diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index 26bf8c54fd..52855bd9ad 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -22,7 +22,6 @@ import com.bgsoftware.superiorskyblock.core.PluginLoadingStage; import com.bgsoftware.superiorskyblock.core.PluginReloadReason; import com.bgsoftware.superiorskyblock.core.database.DataManager; -import com.bgsoftware.superiorskyblock.core.database.transaction.DatabaseTransactionsExecutor; import com.bgsoftware.superiorskyblock.core.engine.EnginesFactory; import com.bgsoftware.superiorskyblock.core.engine.NashornEngineDownloader; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; @@ -196,8 +195,6 @@ public void onLoad() { client.start(); loadingStage = PluginLoadingStage.LOADED; - - DatabaseTransactionsExecutor.init(); } @Override @@ -377,8 +374,6 @@ public void onDisable() { if (loadingStage.isAtLeast(PluginLoadingStage.START_ENABLE)) { Log.info("Shutting down executor"); BukkitExecutor.close(); - Log.info("Shutting down database executor"); - DatabaseTransactionsExecutor.stop(); } if (loadingStage.isAtLeast(PluginLoadingStage.MANAGERS_INITIALIZED)) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java index ecc8367544..d7c11af4ef 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java @@ -1,11 +1,11 @@ package com.bgsoftware.superiorskyblock.core.database.loader.sql; -import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.common.databasebridge.sql.query.Column; +import com.bgsoftware.common.databasebridge.sql.query.QueryResult; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.DatabaseUpgrade_V0; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v1.DatabaseUpgrade_V1; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v2.DatabaseUpgrade_V2; -import com.bgsoftware.superiorskyblock.core.database.sql.SQLHelper; -import com.bgsoftware.superiorskyblock.core.database.sql.session.QueryResult; +import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; import com.bgsoftware.superiorskyblock.core.mutable.MutableInt; import java.sql.ResultSet; @@ -34,7 +34,7 @@ public static void initializeDatabase() { public static UpgradeResult upgradeDatabase() { MutableInt databaseVersionMutable = new MutableInt(0); - SQLHelper.select("ssb_metadata", "", new QueryResult() + DBSession.select("ssb_metadata", "", new QueryResult() .onSuccess(result -> databaseVersionMutable.set(result.getInt("version"))) .onFail(error -> { })); @@ -51,250 +51,244 @@ public static int getCurrentDatabaseVersion() { return DATABASE_UPGRADES.length; } - @SuppressWarnings("unchecked") private static void createMetadataTable() { MutableInt databaseVersion = new MutableInt(0); // We check if "islands" table exists. If not, it's a new database, // therefore the DB version should be latest. Otherwise, 0. - SQLHelper.select("islands", "", new QueryResult() + DBSession.select("islands", "", new QueryResult() .onFail(error -> databaseVersion.set(getCurrentDatabaseVersion()))); - SQLHelper.createTable("ssb_metadata", - new Pair<>("version", "INTEGER DEFAULT " + databaseVersion.get()) + DBSession.createTable("ssb_metadata", + new Column("version", "INTEGER DEFAULT " + databaseVersion.get()) ); } - @SuppressWarnings("unchecked") private static void createIslandsTable() { - SQLHelper.createTable("islands", - new Pair<>("uuid", "UUID PRIMARY KEY"), - new Pair<>("owner", "UUID"), - new Pair<>("center", "TEXT"), - new Pair<>("creation_time", "BIGINT"), - new Pair<>("island_type", "TEXT"), - new Pair<>("discord", "TEXT"), - new Pair<>("paypal", "TEXT"), - new Pair<>("worth_bonus", "BIG_DECIMAL"), - new Pair<>("levels_bonus", "BIG_DECIMAL"), - new Pair<>("locked", "BOOLEAN"), - new Pair<>("ignored", "BOOLEAN"), - new Pair<>("name", "TEXT"), - new Pair<>("description", "TEXT"), - new Pair<>("generated_schematics", "INTEGER"), - new Pair<>("unlocked_worlds", "INTEGER"), - new Pair<>("last_time_updated", "BIGINT"), - new Pair<>("dirty_chunks", "LONGTEXT"), - new Pair<>("block_counts", "LONGTEXT"), - new Pair<>("entity_counts", "LONGTEXT") + DBSession.createTable("islands", + new Column("uuid", "UUID PRIMARY KEY"), + new Column("owner", "UUID"), + new Column("center", "TEXT"), + new Column("creation_time", "BIGINT"), + new Column("island_type", "TEXT"), + new Column("discord", "TEXT"), + new Column("paypal", "TEXT"), + new Column("worth_bonus", "BIG_DECIMAL"), + new Column("levels_bonus", "BIG_DECIMAL"), + new Column("locked", "BOOLEAN"), + new Column("ignored", "BOOLEAN"), + new Column("name", "TEXT"), + new Column("description", "TEXT"), + new Column("generated_schematics", "INTEGER"), + new Column("unlocked_worlds", "INTEGER"), + new Column("last_time_updated", "BIGINT"), + new Column("dirty_chunks", "LONGTEXT"), + new Column("block_counts", "LONGTEXT"), + new Column("entity_counts", "LONGTEXT") ); - SQLHelper.createTable("islands_banks", - new Pair<>("island", "UUID PRIMARY KEY"), - new Pair<>("balance", "BIG_DECIMAL"), - new Pair<>("last_interest_time", "BIGINT") + DBSession.createTable("islands_banks", + new Column("island", "UUID PRIMARY KEY"), + new Column("balance", "BIG_DECIMAL"), + new Column("last_interest_time", "BIGINT") ); - SQLHelper.createTable("islands_bans", - new Pair<>("island", "UUID"), - new Pair<>("player", "UUID"), - new Pair<>("banned_by", "UUID"), - new Pair<>("banned_time", "BIGINT") + DBSession.createTable("islands_bans", + new Column("island", "UUID"), + new Column("player", "UUID"), + new Column("banned_by", "UUID"), + new Column("banned_time", "BIGINT") ); - SQLHelper.createTable("islands_block_limits", - new Pair<>("island", "UUID"), - new Pair<>("block", "UNIQUE_TEXT"), - new Pair<>("`limit`", "INTEGER") + DBSession.createTable("islands_block_limits", + new Column("island", "UUID"), + new Column("block", "UNIQUE_TEXT"), + new Column("`limit`", "INTEGER") ); - SQLHelper.createTable("islands_chests", - new Pair<>("island", "UUID"), - new Pair<>("`index`", "INTEGER"), - new Pair<>("contents", "LONGBLOB") + DBSession.createTable("islands_chests", + new Column("island", "UUID"), + new Column("`index`", "INTEGER"), + new Column("contents", "LONGBLOB") ); - SQLHelper.createTable("islands_custom_data", - new Pair<>("island", "UUID PRIMARY KEY"), - new Pair<>("data", "BLOB") + DBSession.createTable("islands_custom_data", + new Column("island", "UUID PRIMARY KEY"), + new Column("data", "BLOB") ); - SQLHelper.createTable("islands_effects", - new Pair<>("island", "UUID"), - new Pair<>("effect_type", "UNIQUE_TEXT"), - new Pair<>("level", "INTEGER") + DBSession.createTable("islands_effects", + new Column("island", "UUID"), + new Column("effect_type", "UNIQUE_TEXT"), + new Column("level", "INTEGER") ); - SQLHelper.createTable("islands_entity_limits", - new Pair<>("island", "UUID"), - new Pair<>("entity", "UNIQUE_TEXT"), - new Pair<>("`limit`", "INTEGER") + DBSession.createTable("islands_entity_limits", + new Column("island", "UUID"), + new Column("entity", "UNIQUE_TEXT"), + new Column("`limit`", "INTEGER") ); - SQLHelper.createTable("islands_flags", - new Pair<>("island", "UUID"), - new Pair<>("name", "UNIQUE_TEXT"), - new Pair<>("status", "INTEGER") + DBSession.createTable("islands_flags", + new Column("island", "UUID"), + new Column("name", "UNIQUE_TEXT"), + new Column("status", "INTEGER") ); - SQLHelper.createTable("islands_generators", - new Pair<>("island", "UUID"), - new Pair<>("environment", "VARCHAR(7)"), - new Pair<>("block", "UNIQUE_TEXT"), - new Pair<>("rate", "INTEGER") + DBSession.createTable("islands_generators", + new Column("island", "UUID"), + new Column("environment", "VARCHAR(7)"), + new Column("block", "UNIQUE_TEXT"), + new Column("rate", "INTEGER") ); - SQLHelper.createTable("islands_homes", - new Pair<>("island", "UUID"), - new Pair<>("environment", "VARCHAR(7)"), - new Pair<>("location", "TEXT") + DBSession.createTable("islands_homes", + new Column("island", "UUID"), + new Column("environment", "VARCHAR(7)"), + new Column("location", "TEXT") ); - SQLHelper.createTable("islands_members", - new Pair<>("island", "UUID"), - new Pair<>("player", "UUID"), - new Pair<>("role", "INTEGER"), - new Pair<>("join_time", "BIGINT") + DBSession.createTable("islands_members", + new Column("island", "UUID"), + new Column("player", "UUID"), + new Column("role", "INTEGER"), + new Column("join_time", "BIGINT") ); - SQLHelper.createTable("islands_missions", - new Pair<>("island", "UUID"), - new Pair<>("name", "LONG_UNIQUE_TEXT"), - new Pair<>("finish_count", "INTEGER") + DBSession.createTable("islands_missions", + new Column("island", "UUID"), + new Column("name", "LONG_UNIQUE_TEXT"), + new Column("finish_count", "INTEGER") ); - SQLHelper.createTable("islands_player_permissions", - new Pair<>("island", "UUID"), - new Pair<>("player", "UUID"), - new Pair<>("permission", "UNIQUE_TEXT"), - new Pair<>("status", "BOOLEAN") + DBSession.createTable("islands_player_permissions", + new Column("island", "UUID"), + new Column("player", "UUID"), + new Column("permission", "UNIQUE_TEXT"), + new Column("status", "BOOLEAN") ); - SQLHelper.createTable("islands_ratings", - new Pair<>("island", "UUID"), - new Pair<>("player", "UUID"), - new Pair<>("rating", "INTEGER"), - new Pair<>("rating_time", "BIGINT") + DBSession.createTable("islands_ratings", + new Column("island", "UUID"), + new Column("player", "UUID"), + new Column("rating", "INTEGER"), + new Column("rating_time", "BIGINT") ); - SQLHelper.createTable("islands_role_limits", - new Pair<>("island", "UUID"), - new Pair<>("role", "INTEGER"), - new Pair<>("`limit`", "INTEGER") + DBSession.createTable("islands_role_limits", + new Column("island", "UUID"), + new Column("role", "INTEGER"), + new Column("`limit`", "INTEGER") ); - SQLHelper.createTable("islands_role_permissions", - new Pair<>("island", "UUID"), - new Pair<>("role", "INTEGER"), - new Pair<>("permission", "UNIQUE_TEXT") + DBSession.createTable("islands_role_permissions", + new Column("island", "UUID"), + new Column("role", "INTEGER"), + new Column("permission", "UNIQUE_TEXT") ); - SQLHelper.createTable("islands_settings", - new Pair<>("island", "UUID PRIMARY KEY"), - new Pair<>("size", "INTEGER"), - new Pair<>("bank_limit", "BIG_DECIMAL"), - new Pair<>("coops_limit", "INTEGER"), - new Pair<>("members_limit", "INTEGER"), - new Pair<>("warps_limit", "INTEGER"), - new Pair<>("crop_growth_multiplier", "DECIMAL"), - new Pair<>("spawner_rates_multiplier", "DECIMAL"), - new Pair<>("mob_drops_multiplier", "DECIMAL") + DBSession.createTable("islands_settings", + new Column("island", "UUID PRIMARY KEY"), + new Column("size", "INTEGER"), + new Column("bank_limit", "BIG_DECIMAL"), + new Column("coops_limit", "INTEGER"), + new Column("members_limit", "INTEGER"), + new Column("warps_limit", "INTEGER"), + new Column("crop_growth_multiplier", "DECIMAL"), + new Column("spawner_rates_multiplier", "DECIMAL"), + new Column("mob_drops_multiplier", "DECIMAL") ); - SQLHelper.createTable("islands_upgrades", - new Pair<>("island", "UUID"), - new Pair<>("upgrade", "LONG_UNIQUE_TEXT"), - new Pair<>("level", "INTEGER") + DBSession.createTable("islands_upgrades", + new Column("island", "UUID"), + new Column("upgrade", "LONG_UNIQUE_TEXT"), + new Column("level", "INTEGER") ); - SQLHelper.createTable("islands_visitor_homes", - new Pair<>("island", "UUID"), - new Pair<>("environment", "VARCHAR(7)"), - new Pair<>("location", "TEXT") + DBSession.createTable("islands_visitor_homes", + new Column("island", "UUID"), + new Column("environment", "VARCHAR(7)"), + new Column("location", "TEXT") ); - SQLHelper.createTable("islands_visitors", - new Pair<>("island", "UUID"), - new Pair<>("player", "UUID"), - new Pair<>("visit_time", "BIGINT") + DBSession.createTable("islands_visitors", + new Column("island", "UUID"), + new Column("player", "UUID"), + new Column("visit_time", "BIGINT") ); - SQLHelper.createTable("islands_warp_categories", - new Pair<>("island", "UUID"), - new Pair<>("name", "LONG_UNIQUE_TEXT"), - new Pair<>("slot", "INTEGER"), - new Pair<>("icon", "TEXT") + DBSession.createTable("islands_warp_categories", + new Column("island", "UUID"), + new Column("name", "LONG_UNIQUE_TEXT"), + new Column("slot", "INTEGER"), + new Column("icon", "TEXT") ); - SQLHelper.createTable("islands_warps", - new Pair<>("island", "UUID"), - new Pair<>("name", "LONG_UNIQUE_TEXT"), - new Pair<>("category", "TEXT"), - new Pair<>("location", "TEXT"), - new Pair<>("private", "BOOLEAN"), - new Pair<>("icon", "TEXT") + DBSession.createTable("islands_warps", + new Column("island", "UUID"), + new Column("name", "LONG_UNIQUE_TEXT"), + new Column("category", "TEXT"), + new Column("location", "TEXT"), + new Column("private", "BOOLEAN"), + new Column("icon", "TEXT") ); } - @SuppressWarnings("unchecked") private static void createPlayersTable() { - SQLHelper.createTable("players", - new Pair<>("uuid", "UUID PRIMARY KEY"), - new Pair<>("last_used_name", "TEXT"), - new Pair<>("last_used_skin", "TEXT"), - new Pair<>("disbands", "INTEGER"), - new Pair<>("last_time_updated", "BIGINT") + DBSession.createTable("players", + new Column("uuid", "UUID PRIMARY KEY"), + new Column("last_used_name", "TEXT"), + new Column("last_used_skin", "TEXT"), + new Column("disbands", "INTEGER"), + new Column("last_time_updated", "BIGINT") ); - SQLHelper.createTable("players_custom_data", - new Pair<>("player", "UUID PRIMARY KEY"), - new Pair<>("data", "BLOB") + DBSession.createTable("players_custom_data", + new Column("player", "UUID PRIMARY KEY"), + new Column("data", "BLOB") ); - SQLHelper.createTable("players_missions", - new Pair<>("player", "UUID"), - new Pair<>("name", "LONG_UNIQUE_TEXT"), - new Pair<>("finish_count", "INTEGER") + DBSession.createTable("players_missions", + new Column("player", "UUID"), + new Column("name", "LONG_UNIQUE_TEXT"), + new Column("finish_count", "INTEGER") ); - SQLHelper.createTable("players_settings", - new Pair<>("player", "UUID PRIMARY KEY"), - new Pair<>("language", "TEXT"), - new Pair<>("toggled_panel", "BOOLEAN"), - new Pair<>("border_color", "TEXT"), - new Pair<>("toggled_border", "BOOLEAN"), - new Pair<>("island_fly", "BOOLEAN") + DBSession.createTable("players_settings", + new Column("player", "UUID PRIMARY KEY"), + new Column("language", "TEXT"), + new Column("toggled_panel", "BOOLEAN"), + new Column("border_color", "TEXT"), + new Column("toggled_border", "BOOLEAN"), + new Column("island_fly", "BOOLEAN") ); } - @SuppressWarnings("unchecked") private static void createGridTable() { - SQLHelper.createTable("grid", - new Pair<>("last_island", "TEXT"), - new Pair<>("max_island_size", "INTEGER"), - new Pair<>("world", "TEXT") + DBSession.createTable("grid", + new Column("last_island", "TEXT"), + new Column("max_island_size", "INTEGER"), + new Column("world", "TEXT") ); } - @SuppressWarnings("unchecked") private static void createBankTransactionsTable() { - SQLHelper.createTable("bank_transactions", - new Pair<>("island", "UUID"), - new Pair<>("player", "UUID"), - new Pair<>("bank_action", "TEXT"), - new Pair<>("position", "INTEGER"), - new Pair<>("time", "BIGINT"), - new Pair<>("failure_reason", "TEXT"), - new Pair<>("amount", "TEXT") + DBSession.createTable("bank_transactions", + new Column("island", "UUID"), + new Column("player", "UUID"), + new Column("bank_action", "TEXT"), + new Column("position", "INTEGER"), + new Column("time", "BIGINT"), + new Column("failure_reason", "TEXT"), + new Column("amount", "TEXT") ); } - @SuppressWarnings("unchecked") private static void createStackedBlocksTable() { - SQLHelper.createTable("stacked_blocks", - new Pair<>("location", "LONG_UNIQUE_TEXT PRIMARY KEY"), - new Pair<>("block_type", "TEXT"), - new Pair<>("amount", "INTEGER") + DBSession.createTable("stacked_blocks", + new Column("location", "LONG_UNIQUE_TEXT PRIMARY KEY"), + new Column("block_type", "TEXT"), + new Column("amount", "INTEGER") ); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabaseLoader.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabaseLoader.java index cc830f4fcf..7b51e49f8c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabaseLoader.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabaseLoader.java @@ -1,10 +1,10 @@ package com.bgsoftware.superiorskyblock.core.database.loader.sql; +import com.bgsoftware.common.databasebridge.sql.query.QueryResult; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.database.bridge.GridDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.loader.MachineStateDatabaseLoader; -import com.bgsoftware.superiorskyblock.core.database.sql.SQLHelper; -import com.bgsoftware.superiorskyblock.core.database.sql.session.QueryResult; +import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import java.sql.ResultSet; @@ -25,13 +25,13 @@ public void setState(State state) throws ManagerLoadException { @Override protected void handleInitialize() throws ManagerLoadException { - if (!SQLHelper.createConnection(plugin)) { + if (!DBSession.createConnection(plugin)) { throw new ManagerLoadException("Couldn't connect to the database.\nMake sure all information is correct.", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } try { - SQLHelper.select("ssb_metadata", "", new QueryResult().onSuccess(resultSet -> { + DBSession.select("ssb_metadata", "", new QueryResult().onSuccess(resultSet -> { int databaseVersion = resultSet.getInt("version"); if (databaseVersion > SQLDatabase.getCurrentDatabaseVersion()) @@ -49,86 +49,87 @@ protected void handleInitialize() throws ManagerLoadException { if (databaseUpgradeResult.isUpgraded()) GridDatabaseBridge.updateVersion(plugin.getGrid(), databaseUpgradeResult.getDatabaseVersion()); - SQLHelper.select("grid", "", new QueryResult() + DBSession.select("grid", "", new QueryResult() .onFail(error -> GridDatabaseBridge.insertGrid(plugin.getGrid()))); } @Override protected void handlePostInitialize() { - SQLHelper.createIndex("islands_bans_index", "islands_bans", + DBSession.createIndex("islands_bans_index", "islands_bans", "island", "player"); - SQLHelper.createIndex("block_limits_index", "islands_block_limits", + DBSession.createIndex("block_limits_index", "islands_block_limits", "island", "block"); - SQLHelper.createIndex("islands_chests_index", "islands_chests", + DBSession.createIndex("islands_chests_index", "islands_chests", "island", "`index`"); - SQLHelper.createIndex("islands_effects_index", "islands_effects", + DBSession.createIndex("islands_effects_index", "islands_effects", "island", "effect_type"); - SQLHelper.createIndex("entity_limits_index", "islands_entity_limits", + DBSession.createIndex("entity_limits_index", "islands_entity_limits", "island", "entity"); - SQLHelper.createIndex("islands_flags_index", "islands_flags", + DBSession.createIndex("islands_flags_index", "islands_flags", "island", "name"); - SQLHelper.createIndex("islands_generators_index", "islands_generators", + DBSession.createIndex("islands_generators_index", "islands_generators", "island", "environment", "block"); - SQLHelper.createIndex("islands_homes_index", "islands_homes", + DBSession.createIndex("islands_homes_index", "islands_homes", "island", "environment"); - SQLHelper.createIndex("islands_members_index", "islands_members", + DBSession.createIndex("islands_members_index", "islands_members", "island", "player"); - SQLHelper.createIndex("islands_missions_index", "islands_missions", + DBSession.createIndex("islands_missions_index", "islands_missions", "island", "name"); - SQLHelper.createIndex("player_permissions_index", "islands_player_permissions", + DBSession.createIndex("player_permissions_index", "islands_player_permissions", "island", "player", "permission"); - SQLHelper.createIndex("islands_ratings_index", "islands_ratings", + DBSession.createIndex("islands_ratings_index", "islands_ratings", "island", "player"); - SQLHelper.createIndex("role_limits_index", "islands_role_limits", + DBSession.createIndex("role_limits_index", "islands_role_limits", "island", "role"); - SQLHelper.createIndex("role_permissions_index", "islands_role_permissions", + DBSession.createIndex("role_permissions_index", "islands_role_permissions", "island", "permission"); - SQLHelper.createIndex("islands_upgrades_index", "islands_upgrades", + DBSession.createIndex("islands_upgrades_index", "islands_upgrades", "island", "upgrade"); - SQLHelper.createIndex("visitor_homes_index", "islands_visitor_homes", + DBSession.createIndex("visitor_homes_index", "islands_visitor_homes", "island", "environment"); - SQLHelper.createIndex("islands_visitors_index", "islands_visitors", + DBSession.createIndex("islands_visitors_index", "islands_visitors", "island", "player"); - SQLHelper.createIndex("warp_categories_index", "islands_warp_categories", + DBSession.createIndex("warp_categories_index", "islands_warp_categories", "island", "name"); - SQLHelper.createIndex("islands_warps_index", "islands_warps", + DBSession.createIndex("islands_warps_index", "islands_warps", "island", "name"); - SQLHelper.createIndex("players_missions_index", "players_missions", + DBSession.createIndex("players_missions_index", "players_missions", "player", "name"); } @Override protected void handlePreLoadData() { - SQLHelper.setJournalMode("MEMORY", QueryResult.EMPTY_QUERY_RESULT); + DBSession.setJournalMode("MEMORY", QueryResult.EMPTY_QUERY_RESULT); } @Override protected void handlePostLoadData() { - SQLHelper.setJournalMode("DELETE", QueryResult.EMPTY_QUERY_RESULT); + DBSession.setJournalMode("DELETE", QueryResult.EMPTY_QUERY_RESULT); } @Override protected void handleShutdown() { - SQLHelper.close(); + + DBSession.close(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseConverter.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseConverter.java index 30b405e80f..d5dc5046de 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseConverter.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseConverter.java @@ -1,5 +1,7 @@ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0; +import com.bgsoftware.common.databasebridge.sql.query.QueryResult; +import com.bgsoftware.common.databasebridge.sql.transaction.CustomSQLDatabaseTransaction; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.enums.Rating; @@ -9,7 +11,6 @@ import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.database.transaction.DatabaseTransactionsExecutor; import com.bgsoftware.superiorskyblock.core.database.loader.sql.SQLDatabase; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.BankTransactionsAttributes; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.attributes.GridAttributes; @@ -24,10 +25,8 @@ import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.JsonDeserializer; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.MultipleDeserializer; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.deserializer.RawDeserializer; +import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; import com.bgsoftware.superiorskyblock.core.database.sql.ResultSetMapBridge; -import com.bgsoftware.superiorskyblock.core.database.sql.SQLHelper; -import com.bgsoftware.superiorskyblock.core.database.sql.session.QueryResult; -import com.bgsoftware.superiorskyblock.core.database.sql.transaction.CustomSQLDatabaseTransaction; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; @@ -80,7 +79,7 @@ public static void tryConvertDatabase() { private static void convertDatabase() { Log.info("[Database-Converter] Detected old database - starting to convert data..."); - SQLHelper.select("players", "", new QueryResult().onSuccess(resultSet -> { + DBSession.select("players", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { loadedPlayers.add(loadPlayer(new ResultSetMapBridge(resultSet))); } @@ -88,7 +87,7 @@ private static void convertDatabase() { Log.info("[Database-Converter] Found ", loadedPlayers.size(), " players in the database."); - SQLHelper.select("islands", "", new QueryResult().onSuccess(resultSet -> { + DBSession.select("islands", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { loadedIslands.add(loadIsland(new ResultSetMapBridge(resultSet))); } @@ -96,7 +95,7 @@ private static void convertDatabase() { Log.info("[Database-Converter] Found ", loadedIslands.size(), " islands in the database."); - SQLHelper.select("stackedBlocks", "", new QueryResult().onSuccess(resultSet -> { + DBSession.select("stackedBlocks", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { loadedBlocks.add(loadStackedBlock(new ResultSetMapBridge(resultSet))); } @@ -106,7 +105,7 @@ private static void convertDatabase() { // Ignoring errors as the bankTransactions table may not exist. AtomicBoolean foundBankTransaction = new AtomicBoolean(false); - SQLHelper.select("bankTransactions", "", new QueryResult().onSuccess(resultSet -> { + DBSession.select("bankTransactions", "", new QueryResult().onSuccess(resultSet -> { foundBankTransaction.set(true); while (resultSet.next()) { loadedBankTransactions.add(loadBankTransaction(new ResultSetMapBridge(resultSet))); @@ -117,7 +116,7 @@ private static void convertDatabase() { Log.info("[Database-Converter] Found ", loadedBankTransactions.size(), " bank transactions in the database."); } - SQLHelper.select("grid", "", new QueryResult().onSuccess(resultSet -> { + DBSession.select("grid", "", new QueryResult().onSuccess(resultSet -> { if (resultSet.next()) { gridAttributes = new GridAttributes() .setValue(GridAttributes.Field.LAST_ISLAND, resultSet.getString("lastIsland")) @@ -129,11 +128,11 @@ private static void convertDatabase() { MutableObject failedBackupError = new MutableObject<>(null); if (!isRemoteDatabase) { - SQLHelper.close(); + DBSession.close(); if (!databaseFile.renameTo(new File(databaseFile.getParentFile(), "database-bkp.db"))) { failedBackupError.setValue(new RuntimeException("Failed to rename file to database-bkp.db")); } else { - SQLHelper.createConnection(plugin); + DBSession.createConnection(plugin); SQLDatabase.initializeDatabase(); } } @@ -165,7 +164,7 @@ private static boolean isDatabaseOldFormat() { AtomicBoolean isOldFormat = new AtomicBoolean(true); - SQLHelper.select("stackedBlocks", "", new QueryResult().onFail(error -> { + DBSession.select("stackedBlocks", "", new QueryResult().onFail(error -> { isOldFormat.set(false); })); @@ -198,8 +197,7 @@ private static void savePlayers() { } try { - DatabaseTransactionsExecutor.addTransactions(playersTransaction, - playersMissionsTransaction, playersSettingsTransaction).get(); + DBSession.execute(playersMissionsTransaction, playersSettingsTransaction).get(); } catch (InterruptedException | ExecutionException error) { error.printStackTrace(); } @@ -265,7 +263,7 @@ private static void saveIslands() { } try { - DatabaseTransactionsExecutor.addTransactions( + DBSession.execute( islandsTransaction, islandsBanksTransaction, islandsBansTransaction, @@ -309,7 +307,7 @@ private static void saveStackedBlocks() { } try { - stackedBlocksTransaction.execute().get(); + DBSession.execute(stackedBlocksTransaction).get(); } catch (InterruptedException | ExecutionException error) { error.printStackTrace(); } @@ -334,7 +332,7 @@ private static void saveBankTransactions() { } try { - bankTransactionsTransaction.execute().get(); + DBSession.execute(bankTransactionsTransaction).get(); } catch (InterruptedException | ExecutionException error) { error.printStackTrace(); } @@ -348,7 +346,7 @@ private static void saveGrid() { CustomSQLDatabaseTransaction deleteGridTransaction = new CustomSQLDatabaseTransaction("DELETE FROM {prefix}grid;"); try { - deleteGridTransaction.execute().get(); + DBSession.execute(deleteGridTransaction).get(); } catch (InterruptedException | ExecutionException error) { error.printStackTrace(); } @@ -360,7 +358,7 @@ private static void saveGrid() { .bindObject(gridAttributes.getValue(GridAttributes.Field.MAX_ISLAND_SIZE)) .bindObject(gridAttributes.getValue(GridAttributes.Field.WORLD)); try { - insertGridTransaction.execute().get(); + DBSession.execute(insertGridTransaction).get(); } catch (InterruptedException | ExecutionException error) { error.printStackTrace(); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseUpgrade_V0.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseUpgrade_V0.java index 9b6e32b77e..0894d89c51 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseUpgrade_V0.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseUpgrade_V0.java @@ -1,6 +1,6 @@ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0; -import com.bgsoftware.superiorskyblock.core.database.sql.SQLHelper; +import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; public class DatabaseUpgrade_V0 implements Runnable { @@ -19,31 +19,31 @@ public void run() { } private void upgradeIslandsTables() { - SQLHelper.modifyColumnType("islands", "dirty_chunks", "LONGTEXT"); - SQLHelper.modifyColumnType("islands", "block_counts", "LONGTEXT"); + DBSession.modifyColumnType("islands", "dirty_chunks", "LONGTEXT"); + DBSession.modifyColumnType("islands", "block_counts", "LONGTEXT"); - SQLHelper.modifyColumnType("islands_chests", "contents", "LONGBLOB"); + DBSession.modifyColumnType("islands_chests", "contents", "LONGBLOB"); - SQLHelper.modifyColumnType("islands_missions", "name", "LONG_UNIQUE_TEXT"); + DBSession.modifyColumnType("islands_missions", "name", "LONG_UNIQUE_TEXT"); // Up to 1.9.0.574, decimals would not be saved correctly in MySQL // This occurred because the field type was DECIMAL(10,0) instead of DECIMAL(10,2) // Updating the column types to "DECIMAL" again should fix the issue. // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/1021 - SQLHelper.modifyColumnType("islands_settings", "crop_growth_multiplier", "DECIMAL"); - SQLHelper.modifyColumnType("islands_settings", "spawner_rates_multiplier", "DECIMAL"); - SQLHelper.modifyColumnType("islands_settings", "mob_drops_multiplier", "DECIMAL"); + DBSession.modifyColumnType("islands_settings", "crop_growth_multiplier", "DECIMAL"); + DBSession.modifyColumnType("islands_settings", "spawner_rates_multiplier", "DECIMAL"); + DBSession.modifyColumnType("islands_settings", "mob_drops_multiplier", "DECIMAL"); - SQLHelper.modifyColumnType("islands_upgrades", "upgrade", "LONG_UNIQUE_TEXT"); - SQLHelper.removePrimaryKey("islands_upgrades", "island"); + DBSession.modifyColumnType("islands_upgrades", "upgrade", "LONG_UNIQUE_TEXT"); + DBSession.removePrimaryKey("islands_upgrades", "island"); - SQLHelper.modifyColumnType("islands_warp_categories", "name", "LONG_UNIQUE_TEXT"); + DBSession.modifyColumnType("islands_warp_categories", "name", "LONG_UNIQUE_TEXT"); - SQLHelper.modifyColumnType("islands_warps", "name", "LONG_UNIQUE_TEXT"); + DBSession.modifyColumnType("islands_warps", "name", "LONG_UNIQUE_TEXT"); } private void upgradePlayersTables() { - SQLHelper.modifyColumnType("players_missions", "name", "LONG_UNIQUE_TEXT"); + DBSession.modifyColumnType("players_missions", "name", "LONG_UNIQUE_TEXT"); } private void upgradeStackedBlocksTables() { @@ -51,7 +51,7 @@ private void upgradeStackedBlocksTables() { // In order to make sure all tables keep the large number, we modify the column to 255-chars long // each time the plugin attempts to create the table. // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/730 - SQLHelper.modifyColumnType("stacked_blocks", "location", "LONG_UNIQUE_TEXT"); + DBSession.modifyColumnType("stacked_blocks", "location", "LONG_UNIQUE_TEXT"); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v1/DatabaseUpgrade_V1.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v1/DatabaseUpgrade_V1.java index a654dd9901..e1c0a30871 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v1/DatabaseUpgrade_V1.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v1/DatabaseUpgrade_V1.java @@ -1,6 +1,6 @@ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v1; -import com.bgsoftware.superiorskyblock.core.database.sql.SQLHelper; +import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; public class DatabaseUpgrade_V1 implements Runnable { @@ -12,7 +12,7 @@ private DatabaseUpgrade_V1() { @Override public void run() { - SQLHelper.addColumn("islands", "entity_counts", "LONGTEXT"); + DBSession.addColumn("islands", "entity_counts", "LONGTEXT"); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v2/DatabaseUpgrade_V2.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v2/DatabaseUpgrade_V2.java index b6e8e2312b..bc6a3752b3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v2/DatabaseUpgrade_V2.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v2/DatabaseUpgrade_V2.java @@ -1,10 +1,10 @@ package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v2; +import com.bgsoftware.common.databasebridge.sql.query.QueryResult; +import com.bgsoftware.common.databasebridge.sql.transaction.CustomSQLDatabaseTransaction; import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; import com.bgsoftware.superiorskyblock.core.database.sql.ResultSetMapBridge; -import com.bgsoftware.superiorskyblock.core.database.sql.SQLHelper; -import com.bgsoftware.superiorskyblock.core.database.sql.session.QueryResult; -import com.bgsoftware.superiorskyblock.core.database.sql.transaction.CustomSQLDatabaseTransaction; +import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import org.bukkit.inventory.ItemStack; @@ -35,7 +35,7 @@ private static void updateWarpsIcons() { MutableBoolean isFailed = new MutableBoolean(false); - SQLHelper.select("islands_warps", "", new QueryResult().onSuccess(resultSet -> { + DBSession.select("islands_warps", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { DatabaseResult databaseResult = new DatabaseResult(new ResultSetMapBridge(resultSet)); @@ -69,7 +69,7 @@ private static void updateWarpCategoriesIcons() { MutableBoolean isFailed = new MutableBoolean(false); - SQLHelper.select("islands_warp_categories", "", new QueryResult().onSuccess(resultSet -> { + DBSession.select("islands_warp_categories", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { DatabaseResult databaseResult = new DatabaseResult(new ResultSetMapBridge(resultSet)); @@ -103,7 +103,7 @@ private static void updateIslandChests() { MutableBoolean isFailed = new MutableBoolean(false); - SQLHelper.select("islands_chests", "", new QueryResult().onSuccess(resultSet -> { + DBSession.select("islands_chests", "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { DatabaseResult databaseResult = new DatabaseResult(new ResultSetMapBridge(resultSet)); @@ -139,7 +139,7 @@ private static void updateIslandChests() { } try { - updateTransaction.execute().get(); + DBSession.execute(updateTransaction).get(); } catch (InterruptedException | ExecutionException ignored) { } } @@ -155,7 +155,7 @@ private static void updateManyItems(List items, } try { - updateTransaction.execute().get(); + DBSession.execute(updateTransaction).get(); } catch (InterruptedException | ExecutionException ignored) { } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/DBSession.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/DBSession.java new file mode 100644 index 0000000000..40fe03633d --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/DBSession.java @@ -0,0 +1,178 @@ +package com.bgsoftware.superiorskyblock.core.database.sql; + +import com.bgsoftware.common.databasebridge.DatabaseSessionFactory; +import com.bgsoftware.common.databasebridge.logger.ILogger; +import com.bgsoftware.common.databasebridge.session.IDatabaseSession; +import com.bgsoftware.common.databasebridge.sql.query.Column; +import com.bgsoftware.common.databasebridge.sql.query.QueryResult; +import com.bgsoftware.common.databasebridge.sql.session.MariaDBDatabaseSession; +import com.bgsoftware.common.databasebridge.sql.session.MySQLDatabaseSession; +import com.bgsoftware.common.databasebridge.sql.session.SQLDatabaseSession; +import com.bgsoftware.common.databasebridge.sql.session.SQLiteDatabaseSession; +import com.bgsoftware.common.databasebridge.transaction.IDatabaseTransaction; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.config.SettingsManager; +import com.bgsoftware.superiorskyblock.api.data.DatabaseFilter; +import com.bgsoftware.superiorskyblock.core.logging.Debug; +import com.bgsoftware.superiorskyblock.core.logging.Log; + +import java.io.File; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +public class DBSession { + + private static final ILogger LOGGER = new ILogger() { + @Override + public void error(String message, Throwable error) { + Log.error(error, message); + } + + @Override + public boolean hasDebugEnabled() { + return Log.isDebugged(Debug.DATABASE_QUERY); + } + + @Override + public void debug(String message) { + if (hasDebugEnabled()) + Log.debug(Debug.DATABASE_QUERY, message); + } + + @Override + public void info(String message) { + Log.info(message); + } + }; + + private static SQLDatabaseSession globalSession = null; + + private DBSession() { + + } + + public static boolean isReady() { + return globalSession != null; + } + + public static void waitForConnection() { + if (isReady()) + globalSession.waitForConnection(); + } + + public static boolean createConnection(SuperiorSkyblockPlugin plugin) { + SQLDatabaseSession session = createSessionInternal(plugin, true); + + if (session.connect()) { + globalSession = session; + return true; + } + + return false; + } + + public static CompletableFuture execute(IDatabaseTransaction transaction) { + return globalSession.execute(transaction); + } + + public static CompletableFuture execute(IDatabaseTransaction... transactions) { + return globalSession.execute(transactions); + } + + public static CompletableFuture execute(Collection transactions) { + return globalSession.execute(transactions); + } + + public static void createTable(String tableName, Column... columns) { + if (isReady()) + globalSession.createTable(tableName, columns, QueryResult.EMPTY_VOID_QUERY_RESULT); + } + + public static void createIndex(String indexName, String tableName, String... columns) { + if (isReady()) + globalSession.createIndex(indexName, tableName, columns, QueryResult.EMPTY_VOID_QUERY_RESULT); + } + + public static void modifyColumnType(String tableName, String columnName, String newType) { + if (isReady()) + globalSession.modifyColumnType(tableName, columnName, newType, QueryResult.EMPTY_VOID_QUERY_RESULT); + } + + public static void addColumn(String tableName, String columnName, String type) { + if (isReady()) + globalSession.addColumn(tableName, columnName, type, QueryResult.EMPTY_VOID_QUERY_RESULT); + } + + public static void removePrimaryKey(String tableName, String columnName) { + if (isReady()) + globalSession.removePrimaryKey(tableName, columnName, QueryResult.EMPTY_VOID_QUERY_RESULT); + } + + public static void select(String tableName, String filters, QueryResult queryResult) { + if (isReady()) + globalSession.select(tableName, filters, queryResult); + } + + public static void setJournalMode(String jounralMode, QueryResult queryResult) { + if (isReady()) + globalSession.setJournalMode(jounralMode, queryResult); + } + + public static void customQuery(String query, QueryResult queryResult) { + if (isReady()) + globalSession.customQuery(query, queryResult); + } + + public static void close() { + if (isReady()) + globalSession.close(); + } + + public static String getColumnFilter(DatabaseFilter filter) { + StringBuilder columnIdentifier = new StringBuilder(); + if (filter != null) { + filter.forEach((column, value) -> { + if (columnIdentifier.length() == 0) { + columnIdentifier.append(String.format(" WHERE %s=?", column)); + } else { + columnIdentifier.append(String.format(" AND %s=?", column)); + } + }); + } + return columnIdentifier.toString(); + } + + private static SQLDatabaseSession createSessionInternal(SuperiorSkyblockPlugin plugin, boolean logging) { + SettingsManager.Database database = plugin.getSettings().getDatabase(); + + IDatabaseSession.Args args; + switch (database.getType()) { + case "MYSQL": + args = new MySQLDatabaseSession.Args(database.getAddress(), database.getPort(), database.getDBName(), + database.getUsername(), database.getPassword(), database.getPrefix(), database.hasSSL(), + database.hasPublicKeyRetrieval(), database.getWaitTimeout(), database.getMaxLifetime(), + "SuperiorSkyblock Database Thread", LOGGER); + break; + case "MARIADB": + args = new MariaDBDatabaseSession.Args(database.getAddress(), database.getPort(), database.getDBName(), + database.getUsername(), database.getPassword(), database.getPrefix(), database.hasSSL(), + database.hasPublicKeyRetrieval(), database.getWaitTimeout(), database.getMaxLifetime(), + "SuperiorSkyblock Database Thread", LOGGER); + break; + default: + File databaseFile = new File(plugin.getDataFolder(), "datastore/database.db"); + args = new SQLiteDatabaseSession.Args(databaseFile, + "SuperiorSkyblock Database Thread", LOGGER); + break; + } + + SQLDatabaseSession session = (SQLDatabaseSession) DatabaseSessionFactory.createSession(args); + if (logging) + session.setLogging(true); + return session; + } + +} + diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLDatabaseBridge.java index e7f56245fd..cf40e51655 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLDatabaseBridge.java @@ -1,16 +1,15 @@ package com.bgsoftware.superiorskyblock.core.database.sql; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.databasebridge.sql.query.QueryResult; +import com.bgsoftware.common.databasebridge.sql.transaction.DeleteSQLDatabaseTransaction; +import com.bgsoftware.common.databasebridge.sql.transaction.InsertSQLDatabaseTransaction; +import com.bgsoftware.common.databasebridge.sql.transaction.UpdateSQLDatabaseTransaction; +import com.bgsoftware.common.databasebridge.transaction.IDatabaseTransaction; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.data.DatabaseFilter; import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.database.sql.session.QueryResult; -import com.bgsoftware.superiorskyblock.core.database.sql.transaction.DeleteSQLDatabaseTransaction; -import com.bgsoftware.superiorskyblock.core.database.sql.transaction.InsertSQLDatabaseTransaction; -import com.bgsoftware.superiorskyblock.core.database.sql.transaction.UpdateSQLDatabaseTransaction; -import com.bgsoftware.superiorskyblock.core.database.transaction.DatabaseTransactionsExecutor; -import com.bgsoftware.superiorskyblock.core.database.transaction.IDatabaseTransaction; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; @@ -31,7 +30,7 @@ public SQLDatabaseBridge() { @Override public void loadAllObjects(String table, Consumer> resultConsumer) { - SQLHelper.select(table, "", new QueryResult().onSuccess(resultSet -> { + DBSession.select(table, "", new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { try { resultConsumer.accept(new ResultSetMapBridge(resultSet)); @@ -48,7 +47,7 @@ public void batchOperations(boolean batchOperations) { if (batchOperations) { batchTransactions = new LinkedList<>(); } else if (batchTransactions != null) { - DatabaseTransactionsExecutor.addTransactions(batchTransactions); + DBSession.execute(batchTransactions); batchTransactions = null; } } @@ -120,14 +119,14 @@ public void deleteObject(String table, @Nullable DatabaseFilter filter) { @Override public void loadObject(String table, DatabaseFilter filter, Consumer> resultConsumer) { - MutableObject columnFilter = new MutableObject<>(SQLHelper.getColumnFilter(filter)); + MutableObject columnFilter = new MutableObject<>(DBSession.getColumnFilter(filter)); filter.forEach((column, value) -> { columnFilter.setValue(columnFilter.getValue().replaceFirst("\\?", value instanceof String ? String.format("'%s'", value) : value.toString())); }); - SQLHelper.select(table, columnFilter.getValue(), new QueryResult().onSuccess(resultSet -> { + DBSession.select(table, columnFilter.getValue(), new QueryResult().onSuccess(resultSet -> { while (resultSet.next()) { try { resultConsumer.accept(new ResultSetMapBridge(resultSet)); @@ -153,7 +152,7 @@ private void submitTransaction(IDatabaseTransaction transaction) { if (batchTransactions != null) { batchTransactions.add(transaction); } else { - DatabaseTransactionsExecutor.addTransaction(transaction); + DBSession.execute(transaction); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLHelper.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLHelper.java deleted file mode 100644 index 22ca5eb573..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLHelper.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.data.DatabaseFilter; -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.database.sql.session.QueryResult; -import com.bgsoftware.superiorskyblock.core.database.sql.session.SQLSession; -import com.bgsoftware.superiorskyblock.core.database.sql.session.impl.MariaDBSession; -import com.bgsoftware.superiorskyblock.core.database.sql.session.impl.MySQLSession; -import com.bgsoftware.superiorskyblock.core.database.sql.session.impl.SQLiteSession; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; - -public class SQLHelper { - - private static SQLSession globalSession = null; - - private SQLHelper() { - - } - - public static boolean isReady() { - return globalSession != null; - } - - public static void waitForConnection() { - if (isReady()) - globalSession.waitForConnection(); - } - - public static SQLSession createSession(SuperiorSkyblockPlugin plugin, boolean logging) { - switch (plugin.getSettings().getDatabase().getType()) { - case "MYSQL": - return new MySQLSession(plugin, logging); - case "MARIADB": - return new MariaDBSession(plugin, logging); - default: - return new SQLiteSession(plugin, logging); - } - } - - public static boolean createConnection(SuperiorSkyblockPlugin plugin) { - SQLSession session = createSession(plugin, true); - - if (session.createConnection()) { - globalSession = session; - return true; - } - - return false; - } - - public static void createTable(String tableName, Pair... columns) { - if (isReady()) - globalSession.createTable(tableName, columns, QueryResult.EMPTY_VOID_QUERY_RESULT); - } - - public static void createIndex(String indexName, String tableName, String... columns) { - if (isReady()) - globalSession.createIndex(indexName, tableName, columns, QueryResult.EMPTY_VOID_QUERY_RESULT); - } - - public static void modifyColumnType(String tableName, String columnName, String newType) { - if (isReady()) - globalSession.modifyColumnType(tableName, columnName, newType, QueryResult.EMPTY_VOID_QUERY_RESULT); - } - - public static void addColumn(String tableName, String columnName, String type) { - if (isReady()) - globalSession.addColumn(tableName, columnName, type, QueryResult.EMPTY_VOID_QUERY_RESULT); - } - - public static void removePrimaryKey(String tableName, String columnName) { - if (isReady()) - globalSession.removePrimaryKey(tableName, columnName, QueryResult.EMPTY_VOID_QUERY_RESULT); - } - - public static void select(String tableName, String filters, QueryResult queryResult) { - if (isReady()) - globalSession.select(tableName, filters, queryResult); - } - - public static void setJournalMode(String jounralMode, QueryResult queryResult) { - if (isReady()) - globalSession.setJournalMode(jounralMode, queryResult); - } - - public static void customQuery(String query, QueryResult queryResult) { - if (isReady()) - globalSession.customQuery(query, queryResult); - } - - public static void close() { - if (isReady()) - globalSession.closeConnection(); - } - - public static String getColumnFilter(DatabaseFilter filter) { - StringBuilder columnIdentifier = new StringBuilder(); - if (filter != null) { - filter.forEach((column, value) -> { - if (columnIdentifier.length() == 0) { - columnIdentifier.append(String.format(" WHERE %s=?", column)); - } else { - columnIdentifier.append(String.format(" AND %s=?", column)); - } - }); - } - return columnIdentifier.toString(); - } - -} - diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLTransactionProcessor.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLTransactionProcessor.java deleted file mode 100644 index 6d792f0f1a..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/SQLTransactionProcessor.java +++ /dev/null @@ -1,121 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.database.sql.session.QueryResult; -import com.bgsoftware.superiorskyblock.core.database.sql.transaction.SQLDatabaseTransaction; -import com.bgsoftware.superiorskyblock.core.database.transaction.IDatabaseTransaction; -import com.bgsoftware.superiorskyblock.core.logging.Debug; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.core.mutable.MutableInt; -import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; -import com.google.common.base.Preconditions; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class SQLTransactionProcessor { - - private static final Pattern QUERY_VALUE_PATTERN = Pattern.compile("\\?"); - - public SQLTransactionProcessor() { - - } - - public void processTransaction(IDatabaseTransaction transaction) { - Preconditions.checkArgument(transaction instanceof SQLDatabaseTransaction, - "Transaction is not SQL transaction: " + transaction); - - SQLDatabaseTransaction sqlTransaction = (SQLDatabaseTransaction) transaction; - - String query = sqlTransaction.buildQuery(); - - MutableObject fullQuery = new MutableObject<>(query); - - executeQuery(query, new QueryResult().onSuccess(preparedStatement -> { - List allBatchValues = sqlTransaction.getValues(); - if (allBatchValues.size() > 1) { - executeBatchTransaction(preparedStatement, allBatchValues, query); - } else if (allBatchValues.size() == 1) { - executeTransaction(preparedStatement, allBatchValues.iterator().next(), query); - } - }).onFail(error -> { - Log.error(error, "An unexpected error occurred while executing query `", fullQuery.getValue(), "`:"); - })); - } - - private static void executeBatchTransaction(PreparedStatement preparedStatement, - List allBatchValues, - String query) throws SQLException { - MutableObject fullQuery = Log.isDebugged(Debug.DATABASE_QUERY) ? new MutableObject<>(query) : null; - - Connection connection = preparedStatement.getConnection(); - - try { - connection.setAutoCommit(false); - - for (SQLDatabaseTransaction.DatabaseValues batchValues : allBatchValues) { - if (fullQuery != null) - fullQuery.setValue(query); - - populateStatement(preparedStatement, batchValues, fullQuery); - - if (fullQuery != null) - Log.debug(Debug.DATABASE_QUERY, fullQuery.getValue()); - - preparedStatement.addBatch(); - } - - preparedStatement.executeBatch(); - - try { - connection.commit(); - } catch (Throwable ignored) { - } - } finally { - connection.setAutoCommit(true); - } - } - - private static void executeTransaction(PreparedStatement preparedStatement, - SQLDatabaseTransaction.DatabaseValues values, - String query) throws SQLException { - MutableObject fullQuery = Log.isDebugged(Debug.DATABASE_QUERY) ? new MutableObject<>(query) : null; - - populateStatement(preparedStatement, values, fullQuery); - - if (fullQuery != null) - Log.debug(Debug.DATABASE_QUERY, fullQuery.getValue()); - - preparedStatement.executeUpdate(); - } - - private static void populateStatement(PreparedStatement preparedStatement, - SQLDatabaseTransaction.DatabaseValues values, - @Nullable MutableObject fullQuery) throws SQLException { - MutableInt index = new MutableInt(1); - for (Object value : values.values) { - addObject(preparedStatement, index, value, fullQuery); - } - } - - private static void addObject(PreparedStatement preparedStatement, MutableInt index, Object value, - @Nullable MutableObject fullQuery) throws SQLException { - int curr = index.get(); - preparedStatement.setObject(curr, value); - index.set(curr + 1); - if (fullQuery != null) { - fullQuery.setValue(QUERY_VALUE_PATTERN.matcher(fullQuery.getValue()) - .replaceFirst(Matcher.quoteReplacement(value + ""))); - } - } - - private static void executeQuery(String query, QueryResult callback) { - SQLHelper.waitForConnection(); - SQLHelper.customQuery(query, callback); - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/QueryResult.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/QueryResult.java deleted file mode 100644 index b63ef2f194..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/QueryResult.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql.session; - -import com.bgsoftware.common.annotations.Nullable; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.function.Consumer; - -public class QueryResult { - - public static final Consumer PRINT_ERROR = Throwable::printStackTrace; - public static final QueryResult EMPTY_QUERY_RESULT = new QueryResult<>(); - public static final QueryResult EMPTY_VOID_QUERY_RESULT = new QueryResult<>(); - - @Nullable - private QueryConsumer onSuccess; - private Consumer onFail; - - public QueryResult() { - - } - - public QueryResult onSuccess(QueryConsumer onSuccess) { - this.onSuccess = onSuccess; - return this; - } - - public QueryResult onFail(Consumer onFail) { - this.onFail = onFail; - return this; - } - - public void complete(T success) throws SQLException { - if (onSuccess != null) - onSuccess.accept(success); - } - - public void fail(Throwable error) { - if (onFail != null) - onFail.accept(error); - } - - public interface QueryConsumer { - - void accept(T value) throws SQLException; - - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/RemoteSQLSession.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/RemoteSQLSession.java deleted file mode 100644 index 25db09317d..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/RemoteSQLSession.java +++ /dev/null @@ -1,172 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql.session; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.logging.Debug; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.google.common.base.Preconditions; -import com.zaxxer.hikari.HikariDataSource; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.concurrent.CompletableFuture; - -public abstract class RemoteSQLSession implements SQLSession { - - protected final CompletableFuture ready = new CompletableFuture<>(); - protected final SuperiorSkyblockPlugin plugin; - - @Nullable - protected HikariDataSource dataSource; - protected boolean logging; - - protected RemoteSQLSession(SuperiorSkyblockPlugin plugin, boolean logging) { - this.plugin = plugin; - setLogging(logging); - } - - @Override - public void setLogging(boolean logging) { - this.logging = logging; - } - - @Override - public abstract boolean createConnection(); - - @Override - public void closeConnection() { - Preconditions.checkNotNull(this.dataSource, "Session was not initialized."); - dataSource.close(); - } - - @Override - public void waitForConnection() { - try { - ready.get(); - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while waiting for connection:"); - } - } - - @Override - public void createTable(String tableName, Pair[] columns, QueryResult queryResult) { - StringBuilder columnsSection = new StringBuilder(); - for (Pair column : columns) { - columnsSection.append(",") - .append(column.getKey()) - .append(" ") - .append(column.getValue()); - } - - String prefix = plugin.getSettings().getDatabase().getPrefix(); - - executeUpdate(String.format("CREATE TABLE IF NOT EXISTS %s%s (%s);", - prefix, tableName, columnsSection.substring(1)), queryResult); - } - - @Override - public void renameTable(String tableName, String newName, QueryResult queryResult) { - String prefix = plugin.getSettings().getDatabase().getPrefix(); - executeUpdate(String.format("RENAME TABLE %s%s TO %s%s;", prefix, tableName, prefix, newName), queryResult); - } - - @Override - public void createIndex(String indexName, String tableName, String[] columns, QueryResult queryResult) { - StringBuilder columnsSection = new StringBuilder(); - for (String column : columns) { - columnsSection.append(",").append(column); - } - - String prefix = plugin.getSettings().getDatabase().getPrefix(); - - executeUpdate(String.format("CREATE UNIQUE INDEX %s ON %s%s (%s);", - indexName, prefix, tableName, columnsSection.substring(1)), queryResult); - } - - @Override - public void modifyColumnType(String tableName, String columnName, String newType, QueryResult queryResult) { - String prefix = plugin.getSettings().getDatabase().getPrefix(); - executeUpdate(String.format("ALTER TABLE %s%s MODIFY COLUMN %s %s;", - prefix, tableName, columnName, newType), queryResult); - } - - @Override - public void addColumn(String tableName, String columnName, String type, QueryResult queryResult) { - String prefix = plugin.getSettings().getDatabase().getPrefix(); - executeUpdate(String.format("ALTER TABLE %s%s ADD COLUMN %s %s;", - prefix, tableName, columnName, type), queryResult); - } - - @Override - public void removePrimaryKey(String tableName, String columnName, QueryResult queryResult) { - String prefix = plugin.getSettings().getDatabase().getPrefix(); - executeUpdate(String.format("ALTER TABLE %s%s DROP PRIMARY KEY;", prefix, tableName), queryResult); - } - - @Override - public void select(String tableName, String filters, QueryResult queryResult) { - String prefix = plugin.getSettings().getDatabase().getPrefix(); - executeQuery(String.format("SELECT * FROM %s%s%s;", prefix, tableName, filters), queryResult); - } - - @Override - public void setJournalMode(String jounralMode, QueryResult queryResult) { - executeQuery(String.format("PRAGMA journal_mode=%s;", jounralMode), queryResult); - } - - @Override - public void customQuery(String statement, QueryResult queryResult) { - Preconditions.checkNotNull(this.dataSource, "Session was not initialized."); - - String prefix = plugin.getSettings().getDatabase().getPrefix(); - String query = statement.replace("{prefix}", prefix); - - Log.debug(Debug.DATABASE_QUERY, query); - - try (Connection conn = this.dataSource.getConnection(); - PreparedStatement preparedStatement = conn.prepareStatement(query)) { - queryResult.complete(preparedStatement); - } catch (SQLException error) { - queryResult.fail(error); - } - } - - private void executeUpdate(String statement, QueryResult queryResult) { - Preconditions.checkNotNull(this.dataSource, "Session was not initialized."); - - String query = statement - .replace("BIG_DECIMAL", "TEXT") - .replace("DECIMAL", "DECIMAL(10, 2)") - .replace("UUID", "VARCHAR(36)") - .replace("LONG_UNIQUE_TEXT", "VARCHAR(255)") - .replace("UNIQUE_TEXT", "VARCHAR(30)"); - - Log.debug(Debug.DATABASE_QUERY, query); - - try (Connection conn = this.dataSource.getConnection(); - PreparedStatement preparedStatement = conn.prepareStatement(query)) { - preparedStatement.executeUpdate(); - queryResult.complete(null); - } catch (SQLException error) { - queryResult.fail(error); - } - } - - private void executeQuery(String query, QueryResult queryResult) { - Preconditions.checkNotNull(this.dataSource, "Session was not initialized."); - - Log.debug(Debug.DATABASE_QUERY, query); - - try (Connection conn = this.dataSource.getConnection(); - PreparedStatement preparedStatement = conn.prepareStatement(query); - ResultSet resultSet = preparedStatement.executeQuery()) { - queryResult.complete(resultSet); - } catch (SQLException error) { - queryResult.fail(error); - } - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/SQLSession.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/SQLSession.java deleted file mode 100644 index 536af7b89a..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/SQLSession.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql.session; - -import com.bgsoftware.superiorskyblock.api.objects.Pair; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; - -public interface SQLSession { - - void setLogging(boolean logging); - - boolean createConnection(); - - void closeConnection(); - - void waitForConnection(); - - void createTable(String tableName, Pair[] columns, QueryResult queryResult); - - void renameTable(String tableName, String newName, QueryResult queryResult); - - void createIndex(String indexName, String tableName, String[] columns, QueryResult queryResult); - - void modifyColumnType(String tableName, String columnName, String newType, QueryResult queryResult); - - void addColumn(String tableName, String columnName, String type, QueryResult queryResult); - - void removePrimaryKey(String tableName, String columnName, QueryResult queryResult); - - void select(String tableName, String filters, QueryResult queryResult); - - void setJournalMode(String jounralMode, QueryResult queryResult); - - void customQuery(String query, QueryResult queryResult); - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/impl/MariaDBSession.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/impl/MariaDBSession.java deleted file mode 100644 index 2432d2fcb8..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/impl/MariaDBSession.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql.session.impl; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.database.sql.session.QueryResult; -import com.bgsoftware.superiorskyblock.core.database.sql.session.RemoteSQLSession; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; - -import java.sql.ResultSet; - -public class MariaDBSession extends RemoteSQLSession { - - public MariaDBSession(SuperiorSkyblockPlugin plugin, boolean logging) { - super(plugin, logging); - } - - @Override - public boolean createConnection() { - if (logging) Log.info("Trying to connect to remote database (MariaDB)..."); - - try { - HikariConfig config = new HikariConfig(); - config.setConnectionTestQuery("SELECT 1"); - config.setPoolName("SuperiorSkyblock Pool"); - - config.setDriverClassName("com.mysql.jdbc.Driver"); - - String address = plugin.getSettings().getDatabase().getAddress(); - String dbName = plugin.getSettings().getDatabase().getDBName(); - String userName = plugin.getSettings().getDatabase().getUsername(); - String password = plugin.getSettings().getDatabase().getPassword(); - int port = plugin.getSettings().getDatabase().getPort(); - - boolean useSSL = plugin.getSettings().getDatabase().hasSSL(); - boolean publicKeyRetrieval = plugin.getSettings().getDatabase().hasPublicKeyRetrieval(); - - config.setJdbcUrl("jdbc:mysql://" + address + ":" + port + "/" + dbName + "?useSSL=" + useSSL); - config.setJdbcUrl(String.format("jdbc:mysql://%s:%d/%s?useSSL=%b&allowPublicKeyRetrieval=%b", - address, port, dbName, useSSL, publicKeyRetrieval)); - config.setUsername(userName); - config.setPassword(password); - config.setMinimumIdle(5); - config.setMaximumPoolSize(50); - config.setConnectionTimeout(10000); - config.setIdleTimeout(plugin.getSettings().getDatabase().getWaitTimeout()); - config.setMaxLifetime(plugin.getSettings().getDatabase().getMaxLifetime()); - config.addDataSourceProperty("characterEncoding", "utf8"); - config.addDataSourceProperty("useUnicode", "true"); - - dataSource = new HikariDataSource(config); - - if (logging) Log.info("Successfully established connection with remote database!"); - - ready.complete(null); - - return true; - } catch (Throwable error) { - Log.error(error, "An unexpected error occurred while connecting to the MariaDB database:"); - } - - return false; - } - - @Override - public void setJournalMode(String jounralMode, QueryResult queryResult) { - queryResult.fail(new UnsupportedOperationException("Cannot change journal mode in maria-db")); - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/impl/MySQLSession.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/impl/MySQLSession.java deleted file mode 100644 index f3c73eb205..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/impl/MySQLSession.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql.session.impl; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.database.sql.session.RemoteSQLSession; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; - -public class MySQLSession extends RemoteSQLSession { - - public MySQLSession(SuperiorSkyblockPlugin plugin, boolean logging) { - super(plugin, logging); - } - - @Override - public boolean createConnection() { - if (logging) Log.info("Trying to connect to remote database (MySQL)..."); - - try { - HikariConfig config = new HikariConfig(); - config.setConnectionTestQuery("SELECT 1"); - config.setPoolName("SuperiorSkyblock Pool"); - - config.setDriverClassName("com.mysql.jdbc.Driver"); - - String address = plugin.getSettings().getDatabase().getAddress(); - String dbName = plugin.getSettings().getDatabase().getDBName(); - String userName = plugin.getSettings().getDatabase().getUsername(); - String password = plugin.getSettings().getDatabase().getPassword(); - int port = plugin.getSettings().getDatabase().getPort(); - - boolean useSSL = plugin.getSettings().getDatabase().hasSSL(); - boolean publicKeyRetrieval = plugin.getSettings().getDatabase().hasPublicKeyRetrieval(); - - config.setJdbcUrl("jdbc:mysql://" + address + ":" + port + "/" + dbName + "?useSSL=" + useSSL); - config.setJdbcUrl(String.format("jdbc:mysql://%s:%d/%s?useSSL=%b&allowPublicKeyRetrieval=%b", - address, port, dbName, useSSL, publicKeyRetrieval)); - config.setUsername(userName); - config.setPassword(password); - config.setMinimumIdle(5); - config.setMaximumPoolSize(50); - config.setConnectionTimeout(10000); - config.setIdleTimeout(plugin.getSettings().getDatabase().getWaitTimeout()); - config.setMaxLifetime(plugin.getSettings().getDatabase().getMaxLifetime()); - config.addDataSourceProperty("characterEncoding", "utf8"); - config.addDataSourceProperty("useUnicode", "true"); - - dataSource = new HikariDataSource(config); - - if (logging) Log.info("Successfully established connection with remote database!"); - - ready.complete(null); - - return true; - } catch (Throwable error) { - Log.error(error, "An unexpected error occurred while connecting to MySQL database:"); - } - - return false; - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/impl/SQLiteSession.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/impl/SQLiteSession.java deleted file mode 100644 index 35305b664b..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/session/impl/SQLiteSession.java +++ /dev/null @@ -1,208 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql.session.impl; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.database.sql.session.QueryResult; -import com.bgsoftware.superiorskyblock.core.database.sql.session.SQLSession; -import com.bgsoftware.superiorskyblock.core.logging.Debug; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.google.common.base.Preconditions; - -import java.io.File; -import java.io.IOException; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.concurrent.CompletableFuture; - -public class SQLiteSession implements SQLSession { - - private final CompletableFuture ready = new CompletableFuture<>(); - private final SuperiorSkyblockPlugin plugin; - - @Nullable - private Connection conn; - private boolean logging; - - public SQLiteSession(SuperiorSkyblockPlugin plugin, boolean logging) { - this.plugin = plugin; - - setLogging(logging); - } - - @Override - public void setLogging(boolean logging) { - this.logging = logging; - } - - @Override - public boolean createConnection() { - if (logging) Log.info("Trying to connect to local database (SQLite)..."); - - File file = new File(plugin.getDataFolder(), "datastore/database.db"); - - if (!file.exists()) { - file.getParentFile().mkdirs(); - try { - if (!file.createNewFile()) { - Log.error("Failed to create SQLite database file."); - return false; - } - } catch (IOException error) { - Log.error(error, "An unexpected error occurred while creating the database file:"); - return false; - } - } - - String jdbcUrl = "jdbc:sqlite:" + file.getAbsolutePath().replace("\\", "/"); - - try { - Class.forName("org.sqlite.JDBC"); - - conn = DriverManager.getConnection(jdbcUrl); - - if (logging) Log.info("Successfully established connection with local database!"); - - ready.complete(null); - - return true; - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while connecting to SQLite database:"); - } - - return false; - } - - @Override - public void closeConnection() { - Preconditions.checkNotNull(this.conn, "Session was not initialized."); - - try { - conn.close(); - } catch (SQLException error) { - Log.error(error, "An unexpected error occurred while closing connection to SQLite database:"); - } - } - - @Override - public void waitForConnection() { - try { - ready.get(); - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while waiting for connection:"); - } - } - - @Override - public void createTable(String tableName, Pair[] columns, QueryResult queryResult) { - StringBuilder columnsSection = new StringBuilder(); - for (Pair column : columns) { - columnsSection.append(",") - .append(column.getKey()) - .append(" ") - .append(column.getValue()); - } - - executeUpdate(String.format("CREATE TABLE IF NOT EXISTS %s (%s);", - tableName, columnsSection.substring(1)), queryResult); - } - - @Override - public void renameTable(String tableName, String newName, QueryResult queryResult) { - executeUpdate(String.format("ALTER TABLE %s RENAME TO %s;", tableName, newName), queryResult); - } - - @Override - public void createIndex(String indexName, String tableName, String[] columns, QueryResult queryResult) { - StringBuilder columnsSection = new StringBuilder(); - for (String column : columns) { - columnsSection.append(",").append(column); - } - - executeUpdate(String.format("CREATE UNIQUE INDEX %s ON %s (%s);", - indexName, tableName, columnsSection.substring(1)), queryResult); - } - - @Override - public void modifyColumnType(String tableName, String columnName, String newType, QueryResult queryResult) { - executeUpdate(String.format("ALTER TABLE %s MODIFY COLUMN %s %s;", - tableName, columnName, newType), queryResult); - } - - @Override - public void addColumn(String tableName, String columnName, String type, QueryResult queryResult) { - executeUpdate(String.format("ALTER TABLE %s ADD COLUMN %s %s;", tableName, columnName, type), queryResult); - } - - @Override - public void removePrimaryKey(String tableName, String columnName, QueryResult queryResult) { - executeQuery(String.format("PRAGMA table_info('%s')", tableName), new QueryResult() - .onSuccess(resultSet -> { - if (resultSet.next() && resultSet.getInt("pk") == 1) { - resultSet.close(); - executeUpdate(String.format("DROP TABLE %s_copy;", tableName), QueryResult.EMPTY_VOID_QUERY_RESULT); - executeUpdate(String.format("CREATE TABLE %s_copy AS SELECT * FROM %s;", tableName, tableName), queryResult); - executeUpdate(String.format("DROP TABLE %s;", tableName), queryResult); - renameTable(tableName + "_copy", tableName, queryResult); - } - }).onFail(queryResult::fail)); - } - - @Override - public void select(String tableName, String filters, QueryResult queryResult) { - executeQuery(String.format("SELECT * FROM %s%s;", tableName, filters), queryResult); - } - - @Override - public void setJournalMode(String jounralMode, QueryResult queryResult) { - executeQuery(String.format("PRAGMA journal_mode=%s;", jounralMode), queryResult); - } - - @Override - public void customQuery(String query, QueryResult queryResult) { - Preconditions.checkNotNull(this.conn, "Session was not initialized."); - - try (PreparedStatement preparedStatement = - this.conn.prepareStatement(query.replace("{prefix}", ""))) { - queryResult.complete(preparedStatement); - } catch (SQLException error) { - queryResult.fail(error); - } - } - - private void executeUpdate(String statement, QueryResult queryResult) { - Preconditions.checkNotNull(this.conn, "Session was not initialized."); - - String query = statement - .replace("BIG_DECIMAL", "TEXT") - .replace("UUID", "VARCHAR(36)") - .replace("LONG_UNIQUE_TEXT", "VARCHAR(255)") - .replace("UNIQUE_TEXT", "VARCHAR(30)"); - - Log.debug(Debug.DATABASE_QUERY, query); - - try (PreparedStatement preparedStatement = this.conn.prepareStatement(query)) { - preparedStatement.executeUpdate(); - queryResult.complete(null); - } catch (SQLException error) { - queryResult.fail(error); - } - } - - private void executeQuery(String query, QueryResult queryResult) { - Preconditions.checkNotNull(this.conn, "Session was not initialized."); - - Log.debug(Debug.DATABASE_QUERY, query); - - try (PreparedStatement preparedStatement = this.conn.prepareStatement(query); - ResultSet resultSet = preparedStatement.executeQuery()) { - queryResult.complete(resultSet); - } catch (SQLException error) { - queryResult.fail(error); - } - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/CustomSQLDatabaseTransaction.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/CustomSQLDatabaseTransaction.java deleted file mode 100644 index a762a18899..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/CustomSQLDatabaseTransaction.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql.transaction; - -public class CustomSQLDatabaseTransaction extends SQLDatabaseTransaction { - - private final String query; - - public CustomSQLDatabaseTransaction(String query) { - this.query = query; - } - - @Override - public String buildQuery() { - return this.query; - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/DeleteSQLDatabaseTransaction.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/DeleteSQLDatabaseTransaction.java deleted file mode 100644 index dfed3f1ab9..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/DeleteSQLDatabaseTransaction.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql.transaction; - -import com.bgsoftware.common.annotations.Nullable; - -import java.util.List; - -public class DeleteSQLDatabaseTransaction extends SQLDatabaseTransaction { - - protected final String tableName; - @Nullable - private final List filteredColumns; - - public DeleteSQLDatabaseTransaction(String tableName, @Nullable List filteredColumns) { - this.tableName = tableName; - this.filteredColumns = filteredColumns; - } - - @Override - public String buildQuery() { - String columnFilter = getColumnsFilter(filteredColumns); - return String.format("DELETE FROM {prefix}%s%s;", tableName, columnFilter); - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/InsertSQLDatabaseTransaction.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/InsertSQLDatabaseTransaction.java deleted file mode 100644 index f8571bae78..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/InsertSQLDatabaseTransaction.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql.transaction; - -import java.util.List; - -public class InsertSQLDatabaseTransaction extends SQLDatabaseTransaction { - - protected final String tableName; - private final List columnNames; - - public InsertSQLDatabaseTransaction(String tableName, List columnNames) { - this.tableName = tableName; - this.columnNames = columnNames; - } - - @Override - public String buildQuery() { - StringBuilder columnsBuilder = new StringBuilder(); - StringBuilder valuesBuilder = new StringBuilder(); - - for (String columnName : this.columnNames) { - if (columnsBuilder.length() != 0) - columnsBuilder.append(","); - if (valuesBuilder.length() != 0) - valuesBuilder.append(","); - columnsBuilder.append("`").append(columnName).append("`"); - valuesBuilder.append("?"); - } - - return String.format("REPLACE INTO {prefix}%s (%s) VALUES(%s);", this.tableName, columnsBuilder, valuesBuilder); - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/SQLDatabaseTransaction.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/SQLDatabaseTransaction.java deleted file mode 100644 index 7c9669720f..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/SQLDatabaseTransaction.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql.transaction; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.database.transaction.DatabaseTransactionsExecutor; -import com.bgsoftware.superiorskyblock.core.database.transaction.IDatabaseTransaction; - -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.CompletableFuture; - -public abstract class SQLDatabaseTransaction> implements IDatabaseTransaction { - - protected final List values = new LinkedList<>(); - protected DatabaseValues currentValues; - - protected SQLDatabaseTransaction() { - } - - public abstract String buildQuery(); - - public T bindObject(Object value) { - ensureDatabaseValues(); - currentValues.values.add(value); - return (T) this; - } - - public T bindObjects(List values) { - ensureDatabaseValues(); - currentValues.values.addAll(values); - return (T) this; - } - - public T newBatch() { - currentValues = null; - return (T) this; - } - - public List getValues() { - return values; - } - - private void ensureDatabaseValues() { - if (currentValues == null) { - currentValues = new DatabaseValues(); - values.add(currentValues); - } - } - - public CompletableFuture execute() { - return DatabaseTransactionsExecutor.addTransaction(this); - } - - protected static String getColumnsFilter(@Nullable List columnNames) { - if (columnNames == null || columnNames.isEmpty()) - return ""; - - StringBuilder columnIdentifier = new StringBuilder(); - for (String columnName : columnNames) { - if (columnIdentifier.length() == 0) { - columnIdentifier.append(String.format(" WHERE %s=?", columnName)); - } else { - columnIdentifier.append(String.format(" AND %s=?", columnName)); - } - } - return columnIdentifier.toString(); - } - - public static class DatabaseValues { - - public final List values = new LinkedList<>(); - - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/UpdateSQLDatabaseTransaction.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/UpdateSQLDatabaseTransaction.java deleted file mode 100644 index 6a5c742ac5..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/transaction/UpdateSQLDatabaseTransaction.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.sql.transaction; - -import com.bgsoftware.common.annotations.Nullable; - -import java.util.List; - -public class UpdateSQLDatabaseTransaction extends SQLDatabaseTransaction { - - private final String tableName; - private final List columnNames; - @Nullable - private final List filteredColumns; - - public UpdateSQLDatabaseTransaction(String tableName, List columnNames, @Nullable List filteredColumns) { - this.tableName = tableName; - this.columnNames = columnNames; - this.filteredColumns = filteredColumns; - } - - @Override - public String buildQuery() { - StringBuilder columnsBuilder = new StringBuilder(); - - for (String columnName : columnNames) { - if (columnsBuilder.length() != 0) - columnsBuilder.append(","); - columnsBuilder.append(columnName).append("=?"); - } - - String columnFilter = getColumnsFilter(filteredColumns); - return String.format("UPDATE {prefix}%s SET %s%s;", tableName, columnsBuilder, columnFilter); - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/transaction/DatabaseTransactionsExecutor.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/transaction/DatabaseTransactionsExecutor.java deleted file mode 100644 index 6eac021ca3..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/transaction/DatabaseTransactionsExecutor.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.transaction; - -import com.bgsoftware.superiorskyblock.core.database.sql.SQLTransactionProcessor; -import com.google.common.base.Preconditions; -import com.google.common.util.concurrent.ThreadFactoryBuilder; - -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -public class DatabaseTransactionsExecutor { - - private static final SQLTransactionProcessor PROCESSOR = new SQLTransactionProcessor(); - - private static final BlockingQueue pendingTransactions = new LinkedBlockingQueue<>(); - private static final AtomicBoolean IS_RUNNING = new AtomicBoolean(true); - private static final CompletableFuture STOP_CONDITION = new CompletableFuture<>(); - - - private DatabaseTransactionsExecutor() { - - } - - public static CompletableFuture addTransaction(IDatabaseTransaction transaction) { - Preconditions.checkState(IS_RUNNING.get(), "Database Executor is not running"); - return addPendingTransaction(new PendingTransaction(transaction)); - } - - public static CompletableFuture addTransactions(Collection transactions) { - Preconditions.checkState(IS_RUNNING.get(), "Database Executor is not running"); - - if (transactions.isEmpty()) - return CompletableFuture.completedFuture(null); - - return addPendingTransaction(new PendingTransaction(new MultipleDatabaseTransactions(transactions))); - } - - public static CompletableFuture addTransactions(IDatabaseTransaction... transactions) { - Preconditions.checkState(IS_RUNNING.get(), "Database Executor is not running"); - - if (transactions.length == 0) - return CompletableFuture.completedFuture(null); - - if (transactions.length == 1) - return addTransaction(transactions[0]); - - List transactionList = new LinkedList<>(); - Collections.addAll(transactionList, transactions); - return addTransactions(transactionList); - } - - private static CompletableFuture addPendingTransaction(PendingTransaction pendingTransaction) { - pendingTransactions.add(pendingTransaction); - return pendingTransaction.waitable; - } - - public static void init() { - Thread thread = new ThreadFactoryBuilder() - .setNameFormat("SuperiorSkyblock Database Thread") - .build() - .newThread(DatabaseTransactionsExecutor::transactionsHandler); - thread.start(); - } - - public static void stop() { - IS_RUNNING.set(false); - try { - STOP_CONDITION.get(); - } catch (ExecutionException | InterruptedException ignored) { - } - } - - private static void transactionsHandler() { - while (IS_RUNNING.get()) { - try { - handleNextTransactionSafe(); - } catch (Throwable error) { - error.printStackTrace(); - } - } - - // Handle all pending transactions - while (!pendingTransactions.isEmpty()) - handleNextTransactionSafe(); - - STOP_CONDITION.complete(null); - } - - private static void handleNextTransactionSafe() { - PendingTransaction transaction; - try { - transaction = pendingTransactions.poll(1, TimeUnit.SECONDS); - } catch (InterruptedException error) { - return; - } - - if (transaction != null) { - processTransaction(transaction); - } - } - - private static void processTransaction(PendingTransaction pendingTransaction) { - IDatabaseTransaction transaction = pendingTransaction.transaction; - if (transaction instanceof MultipleDatabaseTransactions) { - for (IDatabaseTransaction innerTransaction : ((MultipleDatabaseTransactions) transaction).getTransactions()) - PROCESSOR.processTransaction(innerTransaction); - } else { - PROCESSOR.processTransaction(transaction); - } - pendingTransaction.waitable.complete(null); - } - - private static class MultipleDatabaseTransactions implements IDatabaseTransaction { - - private final List transactions; - - MultipleDatabaseTransactions(Collection transactions) { - this.transactions = new LinkedList<>(transactions); - } - - List getTransactions() { - return transactions; - } - - } - - private static class PendingTransaction { - - private final IDatabaseTransaction transaction; - private final CompletableFuture waitable; - - PendingTransaction(IDatabaseTransaction transaction) { - this.transaction = transaction; - this.waitable = new CompletableFuture<>(); - } - - } - - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/transaction/IDatabaseTransaction.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/transaction/IDatabaseTransaction.java deleted file mode 100644 index 50f202539d..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/transaction/IDatabaseTransaction.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.bgsoftware.superiorskyblock.core.database.transaction; - -public interface IDatabaseTransaction { - -} From fcb19de70a080023d08b6fae7ae7c472af1d4132 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 25 Aug 2025 21:43:54 +0300 Subject: [PATCH 267/600] Fixed saving of fishing missions progress causing errors (#2595) --- .../modules/missions/FishingMissions | Bin 21712 -> 21737 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/modules/missions/FishingMissions b/src/main/resources/modules/missions/FishingMissions index 0d2acf64b1f3e40e568f01dc6a1558f2cdec2acb..76bde4aeea700729f5f90f0ee71084eed966c07e 100644 GIT binary patch delta 6760 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 delta 6652 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 b Date: Thu, 28 Aug 2025 21:58:41 +0300 Subject: [PATCH 268/600] Fixed requiring SADDLE_ENTITY in order to shear sheep (#2614) --- .../superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java | 5 +++++ .../com/bgsoftware/superiorskyblock/nms/NMSEntities.java | 5 +++++ .../service/region/RegionManagerServiceImpl.java | 5 +---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java index e41062769e..f119931de5 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java @@ -10,6 +10,7 @@ import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.entity.Animals; +import org.bukkit.entity.Steerable; import org.bukkit.entity.minecart.PoweredMinecart; import org.bukkit.inventory.EntityEquipment; import org.bukkit.inventory.ItemStack; @@ -49,4 +50,8 @@ public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } + @Override + public boolean canShearSaddleFromEntity(org.bukkit.entity.Entity entity) { + return entity instanceof Steerable steerable && steerable.hasSaddle(); + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSEntities.java index 9a9fd7f69f..1bda0a272d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSEntities.java @@ -16,4 +16,9 @@ public interface NMSEntities { int getPortalTicks(Entity entity); + default boolean canShearSaddleFromEntity(Entity entity) { + // Not implemented for most versions + return false; + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index b609437cb8..da130966ed 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -87,9 +87,6 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService @Nullable private static final EntityType HAPPY_GHAST_TYPE = EnumHelper.getEnum(EntityType.class, "HAPPY_GHAST"); - // Shearing saddles introduced in 1.21.6, when Happy Ghast was added as well. - private static final boolean HAS_SHEARING_SADDLE_SUPPORT = HAPPY_GHAST_TYPE != null; - private static final int MAX_PICKUP_DISTANCE = 1; private static EnumerateSet WORLD_PERMISSIONS_CACHE; private static KeySet INTERACTABLES_CACHE; @@ -264,7 +261,7 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent islandPrivilege = IslandPrivileges.NAME_ENTITY; } else if (usedItemType == Material.SADDLE || (entityType == LLAMA_TYPE && Materials.isCarpet(usedItemType)) || (entityType == HAPPY_GHAST_TYPE && Materials.isHarness(usedItemType)) || - (HAS_SHEARING_SADDLE_SUPPORT && usedItemType == Material.SHEARS)) { + (usedItemType == Material.SHEARS && plugin.getNMSEntities().canShearSaddleFromEntity(entity))) { islandPrivilege = IslandPrivileges.SADDLE_ENTITY; } else if (entity instanceof Villager) { islandPrivilege = IslandPrivileges.VILLAGER_TRADING; From 6e389c2ce661f2c5e98bb19ab7a1eba798e78e33 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Thu, 28 Aug 2025 21:03:35 +0200 Subject: [PATCH 269/600] Restrict types when loading data from config files (#2613) --- .../config/SettingsContainer.java | 4 +- .../config/SettingsManagerImpl.java | 50 +++++++++---------- .../core/io/MenuParserImpl.java | 46 ++++++++--------- .../core/menu/impl/MenuBankLogs.java | 2 +- .../core/menu/impl/MenuBiomes.java | 16 +++--- .../core/menu/impl/MenuBorderColor.java | 4 +- .../core/menu/impl/MenuConfirmDisband.java | 2 +- .../core/menu/impl/MenuControlPanel.java | 2 +- .../core/menu/impl/MenuGlobalWarps.java | 6 +-- .../core/menu/impl/MenuIslandBank.java | 4 +- .../core/menu/impl/MenuIslandCreation.java | 10 ++-- .../core/menu/impl/MenuIslandFlags.java | 2 +- .../core/menu/impl/MenuIslandMembers.java | 2 +- .../core/menu/impl/MenuIslandPrivileges.java | 2 +- .../core/menu/impl/MenuIslandRate.java | 2 +- .../core/menu/impl/MenuIslandRatings.java | 2 +- .../core/menu/impl/MenuIslandUpgrades.java | 6 +-- .../core/menu/impl/MenuIslandValues.java | 12 ++--- .../core/menu/impl/MenuIslandVisitors.java | 2 +- .../core/menu/impl/MenuMemberManage.java | 2 +- .../core/menu/impl/MenuMemberRole.java | 5 +- .../core/menu/impl/MenuMissions.java | 7 ++- .../core/menu/impl/MenuPlayerLanguage.java | 2 +- .../core/menu/impl/MenuTopIslands.java | 28 +++++------ .../core/menu/impl/MenuWarpCategories.java | 14 +++--- .../core/menu/impl/MenuWarps.java | 2 +- .../core/menu/impl/internal/MenuCustom.java | 2 +- .../superiorskyblock/mission/MissionData.java | 2 +- .../mission/MissionsManagerImpl.java | 5 +- 29 files changed, 119 insertions(+), 126 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index c7244242ff..db89222bc0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -439,7 +439,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config blockedVisitorsCommands = Collections.unmodifiableList(config.getStringList("blocked-visitors-commands")); defaultContainersEnabled = config.getBoolean("default-containers.enabled", false); Map defaultContainersContents = new EnumMap<>(InventoryType.class); - if (config.contains("default-containers.containers")) { + if (config.isConfigurationSection("default-containers.containers")) { for (String container : config.getConfigurationSection("default-containers.containers").getKeys(false)) { try { InventoryType containerType = InventoryType.valueOf(container.toUpperCase(Locale.ENGLISH)); @@ -476,7 +476,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config defaultSignLines = Collections.unmodifiableList( Formatters.formatList(config.getStringList("default-signs"), Formatters.COLOR_FORMATTER)); Map> eventCommands = new HashMap<>(); - if (config.contains("event-commands")) { + if (config.isConfigurationSection("event-commands")) { for (String eventName : config.getConfigurationSection("event-commands").getKeys(false)) { eventCommands.put(eventName.toLowerCase(Locale.ENGLISH), config.getStringList("event-commands." + eventName)); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index b1518d7544..e810855918 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -661,15 +661,15 @@ private void loadContainerFromConfig(YamlConfiguration cfg) throws ManagerLoadEx } private void convertData(YamlConfiguration cfg) { - if (cfg.contains("disband-count")) { + if (cfg.isInt("disband-count")) { cfg.set("default-disband-count", cfg.getInt("disband-count") == 0 ? -1 : cfg.getInt("disband-count")); cfg.set("disband-count", null); } - if (cfg.contains("default-hoppers-limit")) { + if (cfg.isInt("default-hoppers-limit")) { cfg.set("default-limits", Collections.singletonList("HOPPER:" + cfg.getInt("default-hoppers-limit"))); cfg.set("default-hoppers-limit", null); } - if (cfg.contains("default-permissions")) { + if (cfg.isConfigurationSection("default-permissions")) { cfg.set("island-roles.guest.name", "Guest"); cfg.set("island-roles.guest.permissions", cfg.getStringList("default-permissions.guest")); cfg.set("island-roles.ladder.member.name", "Member"); @@ -685,45 +685,45 @@ private void convertData(YamlConfiguration cfg) { cfg.set("island-roles.ladder.leader.weight", 3); cfg.set("island-roles.ladder.leader.permissions", cfg.getStringList("default-permissions.leader")); } - if (cfg.contains("spawn-location")) + if (cfg.isString("spawn-location")) cfg.set("spawn.location", cfg.getString("spawn-location")); - if (cfg.contains("spawn-protection")) + if (cfg.isBoolean("spawn-protection")) cfg.set("spawn.protection", cfg.getBoolean("spawn-protection")); if (cfg.getBoolean("spawn-pvp", false)) cfg.set("spawn.settings", Collections.singletonList("PVP")); - if (cfg.contains("island-world")) + if (cfg.isString("island-world")) cfg.set("worlds.normal-world", cfg.getString("island-world")); - if (cfg.contains("welcome-sign-line")) + if (cfg.isString("welcome-sign-line")) cfg.set("visitors-sign.line", cfg.getString("welcome-sign-line")); - if (cfg.contains("island-roles.ladder")) { + if (cfg.isConfigurationSection("island-roles.ladder")) { for (String name : cfg.getConfigurationSection("island-roles.ladder").getKeys(false)) { - if (!cfg.contains("island-roles.ladder." + name + ".id")) + if (!cfg.isInt("island-roles.ladder." + name + ".id")) cfg.set("island-roles.ladder." + name + ".id", cfg.getInt("island-roles.ladder." + name + ".weight")); } } - if (cfg.contains("default-island-size")) + if (cfg.isInt("default-island-size")) cfg.set("default-values.island-size", cfg.getInt("default-island-size")); - if (cfg.contains("default-limits")) + if (cfg.isList("default-limits")) cfg.set("default-values.block-limits", cfg.getStringList("default-limits")); - if (cfg.contains("default-entity-limits")) + if (cfg.isList("default-entity-limits")) cfg.set("default-values.entity-limits", cfg.getStringList("default-entity-limits")); - if (cfg.contains("default-warps-limit")) + if (cfg.isInt("default-warps-limit")) cfg.set("default-values.warps-limit", cfg.getInt("default-warps-limit")); - if (cfg.contains("default-team-limit")) + if (cfg.isInt("default-team-limit")) cfg.set("default-values.team-limit", cfg.getInt("default-team-limit")); - if (cfg.contains("default-crop-growth")) + if (cfg.isInt("default-crop-growth")) cfg.set("default-values.crop-growth", cfg.getInt("default-crop-growth")); - if (cfg.contains("default-spawner-rates")) + if (cfg.isInt("default-spawner-rates")) cfg.set("default-values.spawner-rates", cfg.getInt("default-spawner-rates")); - if (cfg.contains("default-mob-drops")) + if (cfg.isInt("default-mob-drops")) cfg.set("default-values.mob-drops", cfg.getInt("default-mob-drops")); - if (cfg.contains("default-island-height")) + if (cfg.isInt("default-island-height")) cfg.set("islands-height", cfg.getInt("default-island-height")); - if (cfg.contains("starter-chest")) { + if (cfg.isConfigurationSection("starter-chest")) { cfg.set("default-containers.enabled", cfg.getBoolean("starter-chest.enabled")); cfg.set("default-containers.containers.chest", cfg.getConfigurationSection("starter-chest.contents")); } - if (cfg.contains("default-generator")) + if (cfg.isList("default-generator")) cfg.set("default-values.generator", cfg.getStringList("default-generator")); if (cfg.isBoolean("void-teleport")) { boolean voidTeleport = cfg.getBoolean("void-teleport"); @@ -732,27 +732,27 @@ private void convertData(YamlConfiguration cfg) { } if (cfg.isBoolean("sync-worth")) cfg.set("sync-worth", cfg.getBoolean("sync-worth") ? "BUY" : "NONE"); - if (!cfg.contains("worlds.nether")) { + if (!cfg.isConfigurationSection("worlds.nether")) { cfg.set("worlds.nether.enabled", cfg.getBoolean("worlds.nether-world")); cfg.set("worlds.nether.unlock", cfg.getBoolean("worlds.nether-unlock")); } - if (!cfg.contains("worlds.end")) { + if (!cfg.isConfigurationSection("worlds.end")) { cfg.set("worlds.end.enabled", cfg.getBoolean("worlds.end-world")); cfg.set("worlds.end.unlock", cfg.getBoolean("worlds.end-unlock")); } - if (cfg.contains("worlds.normal-world")) { + if (cfg.isString("worlds.normal-world")) { cfg.set("worlds.world-name", cfg.getString("worlds.normal-world")); cfg.set("worlds.normal-world", null); } if (cfg.isBoolean("worlds.end.dragon-fight")) { cfg.set("worlds.end.dragon-fight.enabled", cfg.getBoolean("worlds.end.dragon-fight")); } - if (!cfg.contains("default-values.island-effects")) + if (!cfg.isConfigurationSection("default-values.island-effects")) cfg.createSection("default-values.island-effects"); } private void convertInteractables(SuperiorSkyblockPlugin plugin, YamlConfiguration cfg) { - if (!cfg.contains("interactables")) + if (!cfg.isList("interactables")) return; File file = new File(plugin.getDataFolder(), "interactables.yml"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java index 15a30babb6..c67237c312 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java @@ -285,7 +285,7 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec if (sourceItem != null) { templateItem = getItemStackUnsafe(fileName, section.getRoot().getConfigurationSection(sourceItem)); } else { - if (!section.contains("type")) + if (!section.isString("type")) return null; Material type; @@ -307,7 +307,7 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec data = (short) section.getInt("data"); } } catch (IllegalArgumentException error) { - throw new MenuParseException("Couldn't convert " + section.getCurrentPath() + " into an itemstack. Check type & data sections!"); + throw new MenuParseException("Couldn't convert " + section.getCurrentPath() + " into an item stack. Check type & data sections!"); } templateItem = new TemplateItem(new ItemBuilder(type, data)); @@ -315,28 +315,28 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec ItemBuilder itemBuilder = templateItem.getEditableBuilder(); - if (section.contains("name")) + if (section.isString("name")) itemBuilder.withName(Formatters.COLOR_FORMATTER.format(section.getString("name"))); - if (section.contains("lore")) + if (section.isList("lore")) itemBuilder.withLore(section.getStringList("lore")); if (section.isInt("amount")) itemBuilder.withAmount(section.getInt("amount")); - if (section.contains("enchants")) { - for (String _enchantment : section.getConfigurationSection("enchants").getKeys(false)) { + if (section.isConfigurationSection("enchants")) { + for (String enchantmentName : section.getConfigurationSection("enchants").getKeys(false)) { Enchantment enchantment; try { - enchantment = getMinecraftEnum(Enchantment.class, _enchantment, Enchantment::getByName); + enchantment = getMinecraftEnum(Enchantment.class, enchantmentName, Enchantment::getByName); } catch (IllegalArgumentException ex) { Log.warnFromFile(fileName, "Couldn't convert ", section.getCurrentPath(), - ".enchants.", _enchantment.toUpperCase(Locale.ENGLISH), " into an enchantment, skipping..."); + ".enchants.", enchantmentName.toUpperCase(Locale.ENGLISH), " into an enchantment, skipping..."); continue; } - itemBuilder.withEnchant(enchantment, section.getInt("enchants." + _enchantment)); + itemBuilder.withEnchant(enchantment, section.getInt("enchants." + enchantmentName)); } } @@ -344,19 +344,19 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec itemBuilder.makeItemGlow(); } - if (section.contains("flags")) { + if (section.isList("flags")) { for (String flag : section.getStringList("flags")) { String flagName = flag.toUpperCase(Locale.ENGLISH); try { itemBuilder.withFlags(ItemFlag.valueOf(flagName)); } catch (IllegalArgumentException error) { Log.warnFromFile(fileName, "Couldn't convert ", section.getCurrentPath(), - " (", flagName, ") into an ItemFlag, skipping..."); + " (", flagName, ") into an item flag, skipping..."); } } } - if (section.contains("skull")) { + if (section.isString("skull")) { itemBuilder.asSkullOf(section.getString("skull")); } @@ -364,25 +364,25 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec itemBuilder.setUnbreakable(); } - if (section.contains("effects")) { + if (section.isConfigurationSection("effects")) { ConfigurationSection effectsSection = section.getConfigurationSection("effects"); - for (String _effect : effectsSection.getKeys(false)) { + for (String effectName : effectsSection.getKeys(false)) { PotionEffectType potionEffectType; try { - potionEffectType = getMinecraftEnum(PotionEffectType.class, _effect, PotionEffectType::getByName); + potionEffectType = getMinecraftEnum(PotionEffectType.class, effectName, PotionEffectType::getByName); } catch (IllegalArgumentException error) { Log.warnFromFile(fileName, "Couldn't convert ", effectsSection.getCurrentPath(), - ".", _effect.toUpperCase(Locale.ENGLISH), " into a potion effect, skipping..."); + ".", effectName.toUpperCase(Locale.ENGLISH), " into a potion effect type, skipping..."); continue; } - int duration = effectsSection.getInt(_effect + ".duration", -1); - int amplifier = effectsSection.getInt(_effect + ".amplifier", 0); + int duration = effectsSection.getInt(effectName + ".duration", -1); + int amplifier = effectsSection.getInt(effectName + ".amplifier", 0); if (duration == -1) { Log.warnFromFile(fileName, "Potion effect ", effectsSection.getCurrentPath(), - ".", _effect, " is missing duration, skipping..."); + ".", effectName, " is missing duration, skipping..."); continue; } @@ -390,7 +390,7 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec } } - if (section.contains("entity")) { + if (section.isString("entity")) { String entity = section.getString("entity"); try { itemBuilder.withEntityType(getMinecraftEnum(EntityType.class, entity)); @@ -399,11 +399,11 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec } } - if (section.contains("customModel")) { + if (section.isInt("customModel")) { itemBuilder.withCustomModel(section.getInt("customModel")); } - if (section.contains("leatherColor")) { + if (section.isString("leatherColor")) { String leatherColor = section.getString("leatherColor"); if (leatherColor.startsWith("#")) leatherColor = leatherColor.substring(1); @@ -419,7 +419,7 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec } public List parseButtonSlots(ConfigurationSection section, String key, MenuPatternSlots menuPatternSlots) { - return !section.contains(key) ? Collections.emptyList() : menuPatternSlots.getSlots(section.getString(key)); + return !section.isString(key) ? Collections.emptyList() : menuPatternSlots.getSlots(section.getString(key)); } private static T getMinecraftEnum(Class type, String name) throws IllegalArgumentException { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java index 33812bf616..81603dfe95 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java @@ -167,7 +167,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("members-panel.fill-items")) { + if (cfg.isConfigurationSection("members-panel.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("members-panel.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java index f082bd1cd3..99652a2eb7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java @@ -80,27 +80,27 @@ public static MenuBiomes createInstance() { BiomeButton.Builder buttonBuilder = new BiomeButton.Builder(biome); - if (itemSection.contains("access")) { + if (itemSection.isConfigurationSection("access")) { buttonBuilder.setAccessItem(MenuParserImpl.getInstance().getItemStack("menus/biomes.yml", itemSection.getConfigurationSection("access"))); } - if (itemSection.contains("no-access")) { + if (itemSection.isConfigurationSection("no-access")) { buttonBuilder.setNoAccessItem(MenuParserImpl.getInstance().getItemStack("menus/biomes.yml", itemSection.getConfigurationSection("no-access"))); } if (soundSection != null) { - if (soundSection.contains("access")) { + if (soundSection.isConfigurationSection("access")) { buttonBuilder.setAccessSound(MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("access"))); } - if (soundSection.contains("no-access")) { + if (soundSection.isConfigurationSection("no-access")) { buttonBuilder.setNoAccessSound(MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("no-access"))); } } if (commandSection != null) { - if (commandSection.contains("access")) { + if (commandSection.isList("access")) { buttonBuilder.setAccessCommands(commandSection.getStringList("access")); } - if (commandSection.contains("no-access")) { + if (commandSection.isList("no-access")) { buttonBuilder.setNoAccessCommands(commandSection.getStringList("no-access")); } } @@ -134,12 +134,12 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("biomes-gui.fill-items")) { + if (cfg.isConfigurationSection("biomes-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("biomes-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } - if (cfg.contains("biomes-gui.biomes")) { + if (cfg.isConfigurationSection("biomes-gui.biomes")) { for (String biomeName : cfg.getConfigurationSection("biomes-gui.biomes").getKeys(false)) { ConfigurationSection section = cfg.getConfigurationSection("biomes-gui.biomes." + biomeName); char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBorderColor.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBorderColor.java index eca98c9654..8165d7f18f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBorderColor.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBorderColor.java @@ -52,7 +52,7 @@ public static MenuBorderColor createInstance() { for (String itemsSectionName : cfg.getConfigurationSection("items").getKeys(false)) { ConfigurationSection itemsSection = cfg.getConfigurationSection("items." + itemsSectionName); - if (!itemsSection.contains("enable-border") || !itemsSection.contains("disable-border")) + if (!itemsSection.isConfigurationSection("enable-border") || !itemsSection.isConfigurationSection("disable-border")) continue; patternBuilder.setButtons(menuPatternSlots.getSlots(itemsSectionName), @@ -96,7 +96,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("border-gui.fill-items")) { + if (cfg.isConfigurationSection("border-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("border-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmDisband.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmDisband.java index d30ccfdf79..7aeaaf7876 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmDisband.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuConfirmDisband.java @@ -75,7 +75,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("disband-gui.fill-items")) { + if (cfg.isConfigurationSection("disband-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("disband-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuControlPanel.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuControlPanel.java index 9ec77849a0..e1c0b63402 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuControlPanel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuControlPanel.java @@ -78,7 +78,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("main-panel.fill-items")) { + if (cfg.isConfigurationSection("main-panel.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("main-panel.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java index 719d0ba060..78cd267982 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java @@ -64,9 +64,9 @@ public static MenuGlobalWarps createInstance() { List slots = new LinkedList<>(); - if (cfg.contains("warps")) + if (cfg.isString("warps")) slots.addAll(MenuParserImpl.getInstance().parseButtonSlots(cfg, "warps", menuPatternSlots)); - if (cfg.contains("slots")) + if (cfg.isString("slots")) slots.addAll(MenuParserImpl.getInstance().parseButtonSlots(cfg, "slots", menuPatternSlots)); if (slots.isEmpty()) slots.add(-1); @@ -124,7 +124,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("global-gui.fill-items")) { + if (cfg.isConfigurationSection("global-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("global-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java index 8c20c1858c..93de6908cf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBank.java @@ -54,7 +54,7 @@ public static MenuIslandBank createInstance() { if (cfg.isConfigurationSection("items")) { for (String itemChar : cfg.getConfigurationSection("items").getKeys(false)) { - if (cfg.contains("items." + itemChar + ".bank-action")) { + if (cfg.isConfigurationSection("items." + itemChar + ".bank-action")) { List slots = menuPatternSlots.getSlots(itemChar); if (slots.isEmpty()) { @@ -77,7 +77,7 @@ public static MenuIslandBank createInstance() { List withdrawCommands = cfg.getStringList("items." + itemChar + ".bank-action.withdraw"); patternBuilder.mapButtons(slots, new BankWithdrawButton.Builder(withdrawCommands) .setFailSound(failSound).setSuccessSound(successSound)); - } else if (cfg.contains("items." + itemChar + ".bank-action.deposit")) { + } else if (cfg.isDouble("items." + itemChar + ".bank-action.deposit")) { double depositPercentage = cfg.getDouble("items." + itemChar + ".bank-action.deposit"); if (depositPercentage <= 0) { patternBuilder.mapButtons(slots, new BankCustomDepositButton.Builder() diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java index b4ef393442..d9171b1dc3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java @@ -178,16 +178,16 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("creation-gui.fill-items")) { + if (cfg.isConfigurationSection("creation-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("creation-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } - if (cfg.contains("creation-gui.schematics")) { - for (String schemName : cfg.getConfigurationSection("creation-gui.schematics").getKeys(false)) { - ConfigurationSection section = cfg.getConfigurationSection("creation-gui.schematics." + schemName); + if (cfg.isConfigurationSection("creation-gui.schematics")) { + for (String schematicName : cfg.getConfigurationSection("creation-gui.schematics").getKeys(false)) { + ConfigurationSection section = cfg.getConfigurationSection("creation-gui.schematics." + schematicName); char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; - section.set("schematic", schemName); + section.set("schematic", schematicName); MenuConverter.convertItemAccess(section, patternChars, itemChar, itemsSection, commandsSection, soundsSection); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java index 95287c6021..4b81a9e722 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java @@ -191,7 +191,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("settings-gui.fill-items")) { + if (cfg.isConfigurationSection("settings-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("settings-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandMembers.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandMembers.java index f778587285..c6f312052e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandMembers.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandMembers.java @@ -90,7 +90,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("members-panel.fill-items")) { + if (cfg.isConfigurationSection("members-panel.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("members-panel.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java index cf53f48759..5e17cabaad 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java @@ -292,7 +292,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("permissions-gui.fill-items")) { + if (cfg.isConfigurationSection("permissions-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("permissions-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRate.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRate.java index f209347c40..91b60c261e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRate.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRate.java @@ -84,7 +84,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("rate-gui.fill-items")) { + if (cfg.isConfigurationSection("rate-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("rate-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java index 4bfd5f0229..6d8d76b5ec 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java @@ -119,7 +119,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("ratings-gui.fill-items")) { + if (cfg.isConfigurationSection("ratings-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("ratings-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandUpgrades.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandUpgrades.java index bbbe868fcc..0753e1221b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandUpgrades.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandUpgrades.java @@ -57,7 +57,7 @@ public static MenuIslandUpgrades createInstance() { YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); - if (cfg.contains("upgrades")) { + if (cfg.isConfigurationSection("upgrades")) { ConfigurationSection upgradesSection = cfg.getConfigurationSection("upgrades"); for (Upgrade upgrade : plugin.getUpgrades().getUpgrades()) { ConfigurationSection upgradeSection = upgradesSection.getConfigurationSection(upgrade.getName()); @@ -139,12 +139,12 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("upgrades-gui.fill-items")) { + if (cfg.isConfigurationSection("upgrades-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("upgrades-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } - if (cfg.contains("upgrades-gui.upgrades")) { + if (cfg.isConfigurationSection("upgrades-gui.upgrades")) { for (String upgradeName : cfg.getConfigurationSection("upgrades-gui.upgrades").getKeys(false)) { ConfigurationSection section = cfg.getConfigurationSection("upgrades-gui.upgrades." + upgradeName); char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandValues.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandValues.java index 29e4099285..eef187d780 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandValues.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandValues.java @@ -145,7 +145,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("values-gui.fill-items")) { + if (cfg.isConfigurationSection("values-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("values-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } @@ -171,16 +171,16 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur return true; } - private static void copySection(ConfigurationSection source, ConfigurationSection dest, Function stringReplacer) { + private static void copySection(ConfigurationSection source, ConfigurationSection destination, Function stringReplacer) { for (String key : source.getKeys(false)) { if (source.isConfigurationSection(key)) { - copySection(source.getConfigurationSection(key), dest.createSection(key), stringReplacer); + copySection(source.getConfigurationSection(key), destination.createSection(key), stringReplacer); } else if (source.isList(key)) { - dest.set(key, source.getStringList(key).stream().map(stringReplacer).collect(Collectors.toList())); + destination.set(key, source.getStringList(key).stream().map(stringReplacer).collect(Collectors.toList())); } else if (source.isString(key)) { - dest.set(key, stringReplacer.apply(source.getString(key))); + destination.set(key, stringReplacer.apply(source.getString(key))); } else { - dest.set(key, source.getString(key)); + destination.set(key, source.getString(key)); } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java index 7861a6a9ca..8f80c59512 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java @@ -105,7 +105,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("visitors-panel.fill-items")) { + if (cfg.isConfigurationSection("visitors-panel.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("visitors-panel.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberManage.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberManage.java index 9675c73b04..33138c6f67 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberManage.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberManage.java @@ -82,7 +82,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("players-panel.fill-items")) { + if (cfg.isConfigurationSection("players-panel.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("players-panel.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberRole.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberRole.java index fd21d019a4..879081ddae 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberRole.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMemberRole.java @@ -16,7 +16,6 @@ import com.bgsoftware.superiorskyblock.core.menu.button.impl.MemberRoleButton; import com.bgsoftware.superiorskyblock.core.menu.converter.MenuConverter; import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; -import com.bgsoftware.superiorskyblock.core.menu.view.AbstractMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.PlayerViewArgs; import com.bgsoftware.superiorskyblock.core.menu.view.impl.PlayerMenuView; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; @@ -111,12 +110,12 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("roles-panel.fill-items")) { + if (cfg.isConfigurationSection("roles-panel.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("roles-panel.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } - if (cfg.contains("roles-panel.roles")) { + if (cfg.isConfigurationSection("roles-panel.roles")) { for (String roleName : cfg.getConfigurationSection("roles-panel.roles").getKeys(false)) { ConfigurationSection section = cfg.getConfigurationSection("roles-panel.roles." + roleName); char itemChar = AbstractMenuLayout.BUTTON_SYMBOLS[charCounter++]; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMissions.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMissions.java index 79603e7e88..f762e5557b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMissions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMissions.java @@ -35,10 +35,9 @@ public static MenuMissions createInstance() { MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); - plugin.getMissions().getMissionCategories().forEach(missionCategory -> { - patternBuilder.mapButton(missionCategory.getSlot(), - new OpenMissionCategoryButton.Builder().setMissionsCategory(missionCategory)); - }); + plugin.getMissions().getMissionCategories().forEach( + missionCategory -> patternBuilder.mapButton(missionCategory.getSlot(), + new OpenMissionCategoryButton.Builder().setMissionsCategory(missionCategory))); return new MenuMissions(menuParseResult); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuPlayerLanguage.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuPlayerLanguage.java index c8a4ffe68c..f5febae7b0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuPlayerLanguage.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuPlayerLanguage.java @@ -42,7 +42,7 @@ public static MenuPlayerLanguage createInstance() { YamlConfiguration cfg = menuParseResult.getConfig(); MenuLayout.Builder patternBuilder = menuParseResult.getLayoutBuilder(); - if (cfg.contains("items")) { + if (cfg.isConfigurationSection("items")) { for (String itemsSectionName : cfg.getConfigurationSection("items").getKeys(false)) { ConfigurationSection itemSection = cfg.getConfigurationSection("items." + itemsSectionName); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuTopIslands.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuTopIslands.java index f2a640d4f5..10174bd9cc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuTopIslands.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuTopIslands.java @@ -54,15 +54,13 @@ protected View createViewInternal(SuperiorPlayer superiorPlayer, Args args, @Override public CompletableFuture refreshView(View view) { CompletableFuture res = new CompletableFuture<>(); - plugin.getGrid().sortIslands(view.sortingType, () -> { - super.refreshView(view).whenComplete((v, err) -> { - if (err != null) { - res.completeExceptionally(err); - } else { - res.complete(v); - } - }); - }); + plugin.getGrid().sortIslands(view.sortingType, () -> super.refreshView(view).whenComplete((v, err) -> { + if (err != null) { + res.completeExceptionally(err); + } else { + res.complete(v); + } + })); return res; } @@ -215,7 +213,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("top-islands.fill-items")) { + if (cfg.isConfigurationSection("top-islands.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("top-islands.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } @@ -240,24 +238,24 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur newMenu.set("sounds." + slotsChar + ".no-island", noIslandItemSection.getConfigurationSection("sound")); noIslandItemSection.set("sound", null); - if (cfg.contains("top-islands.worth-sort")) { + if (cfg.isConfigurationSection("top-islands.worth-sort")) { MenuConverter.convertItem(cfg.getConfigurationSection("top-islands.worth-sort"), patternChars, worthChar, itemsSection, commandsSection, soundsSection); } - if (cfg.contains("top-islands.level-sort")) { + if (cfg.isConfigurationSection("top-islands.level-sort")) { MenuConverter.convertItem(cfg.getConfigurationSection("top-islands.level-sort"), patternChars, levelChar, itemsSection, commandsSection, soundsSection); } - if (cfg.contains("top-islands.rating-sort")) { + if (cfg.isConfigurationSection("top-islands.rating-sort")) { MenuConverter.convertItem(cfg.getConfigurationSection("top-islands.rating-sort"), patternChars, ratingChar, itemsSection, commandsSection, soundsSection); } - if (cfg.contains("top-islands.players-sort")) { + if (cfg.isConfigurationSection("top-islands.players-sort")) { MenuConverter.convertItem(cfg.getConfigurationSection("top-islands.players-sort"), patternChars, playersChar, itemsSection, commandsSection, soundsSection); } - if (cfg.contains("player-island-slot")) + if (cfg.isInt("player-island-slot")) patternChars[cfg.getInt("player-island-slot")] = playerIslandChar; newMenu.set("worth-sort", worthChar); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java index fdc171a79e..c36cb2babc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java @@ -90,13 +90,11 @@ public Island getIsland() { @Override protected List requestObjects() { DynamicArray warpCategories = new DynamicArray<>(); - island.getWarpCategories().values().forEach(warpCategory -> { - warpCategory.getWarps() - .stream() - .filter(islandWarp -> island.isMember(getInventoryViewer()) || !islandWarp.hasPrivateFlag()) - .findAny() - .ifPresent(unused -> warpCategories.set(warpCategory.getSlot(), warpCategory)); - }); + island.getWarpCategories().values().forEach(warpCategory -> warpCategory.getWarps() + .stream() + .filter(islandWarp -> island.isMember(getInventoryViewer()) || !islandWarp.hasPrivateFlag()) + .findAny() + .ifPresent(unused -> warpCategories.set(warpCategory.getSlot(), warpCategory))); return warpCategories.toList(); } @@ -107,7 +105,7 @@ public boolean hasManagePerms() { } private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfiguration newMenu) { - if (newMenu.contains("slots") || !newMenu.contains("items")) + if (newMenu.isString("slots") || !newMenu.isConfigurationSection("items")) return false; String itemChar = newMenu.getConfigurationSection("items") diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java index 7e776d94be..d60d49fd1c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java @@ -151,7 +151,7 @@ private static boolean convertOldGUI(SuperiorSkyblockPlugin plugin, YamlConfigur int charCounter = 0; - if (cfg.contains("warps-gui.fill-items")) { + if (cfg.isConfigurationSection("warps-gui.fill-items")) { charCounter = MenuConverter.convertFillItems(cfg.getConfigurationSection("warps-gui.fill-items"), charCounter, patternChars, itemsSection, commandsSection, soundsSection); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java index 2472eafd6f..bc505350af 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java @@ -62,7 +62,7 @@ public static MenuCustom createInstance(File menuFile) { YamlConfiguration cfg = menuParseResult.getConfig(); CommandArgs args = null; - if (cfg.contains("command")) { + if (cfg.isConfigurationSection("command")) { ConfigurationSection commandsSection = cfg.getConfigurationSection("command"); if (commandsSection == null) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java index cd72e9a6b9..f6ca014c24 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java @@ -41,7 +41,7 @@ public class MissionData { this.leaveReset = section.getBoolean("leave-reset", false); this.resetAmount = section.getInt("reset-amount", 1); - if (section.contains("rewards.items")) { + if (section.isConfigurationSection("rewards.items")) { for (String key : section.getConfigurationSection("rewards.items").getKeys(false)) { TemplateItem templateItem = MenuParserImpl.getInstance().getItemStack("config.yml", section.getConfigurationSection("rewards.items." + key)); if (templateItem != null) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java index d7fae25010..793eac8cee 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java @@ -534,8 +534,7 @@ public Mission loadMission(String missionName, String missionCategoryName, Fi List requiredMissions = missionSection.getStringList("required-missions"); List requiredChecks = missionSection.getStringList("required-checks"); - boolean onlyShowIfRequiredCompleted = missionSection.contains("only-show-if-required-completed") && - missionSection.getBoolean("only-show-if-required-completed"); + boolean onlyShowIfRequiredCompleted = missionSection.getBoolean("only-show-if-required-completed", false); mission = createInstance(missionClass, missionName, islandMission, requiredMissions, requiredChecks, onlyShowIfRequiredCompleted); mission.load(plugin, missionSection); @@ -606,7 +605,7 @@ private void convertOldMissionsData() { YamlConfiguration oldData = YamlConfiguration.loadConfiguration(file); for (Mission mission : getAllMissions()) { - if (oldData.contains(mission.getName())) { + if (oldData.isConfigurationSection(mission.getName())) { ConfigurationSection dataSection = oldData.getConfigurationSection(mission.getName()); YamlConfiguration data = convertSectionToYaml(dataSection, new YamlConfiguration()); From 0e3a12d5b69784c9ea829b5560a5a18c662dfd2b Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Thu, 28 Aug 2025 21:20:35 +0200 Subject: [PATCH 270/600] Added separate command for island banned players menu (#2557) --- .../commands/player/CmdBan.java | 11 +-- .../commands/player/CmdBans.java | 73 +++++++++++++++++++ .../commands/player/PlayerCommandsMap.java | 1 + .../core/messages/Message.java | 1 + src/main/resources/lang/de-DE.yml | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/tr-TR.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + src/main/resources/plugin.yml | 2 + 17 files changed, 91 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBans.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBan.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBan.java index b4229959e8..6f686c61f1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBan.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBan.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; -import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -29,7 +28,7 @@ public String getPermission() { @Override public String getUsage(java.util.Locale locale) { - return "ban [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "]"; + return "ban <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + ">"; } @Override @@ -39,7 +38,7 @@ public String getDescription(java.util.Locale locale) { @Override public int getMinArgs() { - return 1; + return 2; } @Override @@ -64,12 +63,6 @@ public Message getPermissionLackMessage() { @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { - if (args.length == 1) { - plugin.getMenus().openIslandBannedPlayers(superiorPlayer, - MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); - return; - } - SuperiorPlayer targetPlayer = CommandArguments.getPlayer(plugin, superiorPlayer, args[1]); if (targetPlayer == null) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBans.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBans.java new file mode 100644 index 0000000000..a5762b7958 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBans.java @@ -0,0 +1,73 @@ +package com.bgsoftware.superiorskyblock.commands.player; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; +import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; +import com.bgsoftware.superiorskyblock.core.messages.Message; +import org.bukkit.command.CommandSender; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class CmdBans implements ISuperiorCommand { + + @Override + public List getAliases() { + return Arrays.asList("bans", "banlist"); + } + + @Override + public String getPermission() { + return "superior.island.bans"; + } + + @Override + public String getUsage(java.util.Locale locale) { + return "bans"; + } + + @Override + public String getDescription(java.util.Locale locale) { + return Message.COMMAND_DESCRIPTION_BANS.getMessage(locale); + } + + @Override + public int getMinArgs() { + return 1; + } + + @Override + public int getMaxArgs() { + return 1; + } + + @Override + public boolean canBeExecutedByConsole() { + return false; + } + + @Override + public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); + + Island island = arguments.getIsland(); + + if (island == null) + return; + + SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); + + plugin.getMenus().openIslandBannedPlayers(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); + } + + @Override + public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + return Collections.emptyList(); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java index e32abd21ab..d8086dc559 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java @@ -14,6 +14,7 @@ public void loadDefaultCommands() { registerCommand(new CmdAccept()); registerCommand(new CmdAdmin()); registerCommand(new CmdBan()); + registerCommand(new CmdBans()); registerCommand(new CmdBiome()); registerCommand(new CmdBorder()); registerCommand(new CmdChest()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index c48df035f6..dc982d1510 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -263,6 +263,7 @@ public enum Message { COMMAND_DESCRIPTION_BALANCE, COMMAND_DESCRIPTION_BAN, COMMAND_DESCRIPTION_BANK, + COMMAND_DESCRIPTION_BANS, COMMAND_DESCRIPTION_BIOME, COMMAND_DESCRIPTION_BORDER, COMMAND_DESCRIPTION_CHEST, diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 885b60d12a..dd4925b079 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -317,6 +317,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: Geld von der Inselbank eines anderen Spieler COMMAND_DESCRIPTION_BALANCE: Überprüfe den Geldbetrag in der Bank einer Insel. COMMAND_DESCRIPTION_BAN: Banne einen Spieler von deiner Insel. COMMAND_DESCRIPTION_BANK: Öffne die Bank der Insel. +COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: Ändere das Biom der Insel. COMMAND_DESCRIPTION_BORDER: Ändere die Randfarbe der Inseln. COMMAND_DESCRIPTION_CHEST: Öffne die Truhe der Insel. diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 2a57dff965..f45d532ff6 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -233,6 +233,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Withdraw money from another player''s islan COMMAND_DESCRIPTION_BALANCE: 'Check the amount of money inside an island''s bank.' COMMAND_DESCRIPTION_BAN: 'Ban a player from your island.' COMMAND_DESCRIPTION_BANK: 'Open the island''s bank.' +COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: 'Change the biome of the island.' COMMAND_DESCRIPTION_BORDER: 'Change the border color of the islands.' COMMAND_DESCRIPTION_CHEST: 'Open the island''s chest.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index f5a89f3825..39b80be7be 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -233,6 +233,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Retirar dinero del banco de la isla de otro COMMAND_DESCRIPTION_BALANCE: 'Verifique la cantidad de dinero dentro del banco de una isla.' COMMAND_DESCRIPTION_BAN: 'Prohibir a un jugador de tu isla.' COMMAND_DESCRIPTION_BANK: 'Abre el banco de la isla.' +COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: 'Cambia el bioma de la isla.' COMMAND_DESCRIPTION_BORDER: 'Cambia el color del borde de las islas.' COMMAND_DESCRIPTION_CHEST: 'Abre el cofre de la isla.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 5b4a298aa6..df8dc08c1b 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -233,6 +233,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: Retirer de l'argent de la banque d'île d'un COMMAND_DESCRIPTION_BALANCE: Vérifier la quantité d'argent dans le coffre de l'île spécifiée. COMMAND_DESCRIPTION_BAN: Bannir un joueur de votre île. COMMAND_DESCRIPTION_BANK: Ouvrir la banque de l'île. +COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: Changer le biome de l'île. COMMAND_DESCRIPTION_BORDER: Changer la couleur de la bordure de l'île. COMMAND_DESCRIPTION_CHEST: Ouvrir le stockage communautaire de l'île. diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 7c6a2baec6..ef045b633c 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -236,6 +236,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: Prelevare denaro dalla banca dell'isola di u COMMAND_DESCRIPTION_BALANCE: Controlla la quantità di denaro all'interno della banca di un'isola. COMMAND_DESCRIPTION_BAN: Bandisci un giocatore dalla tua isola. COMMAND_DESCRIPTION_BANK: Apri la banca dell'isola. +COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: Cambia il bioma dell'isola. COMMAND_DESCRIPTION_BORDER: Cambia il colore del bordo delle isole. COMMAND_DESCRIPTION_CHEST: Apri il baule dell'isola. diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 7d238bbe8c..4ec339c5b7 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -244,6 +244,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: רחא ןקחש לש יאמ ףסכ איצו COMMAND_DESCRIPTION_BALANCE: 'Check the amount of money inside an island''s bank.' COMMAND_DESCRIPTION_BAN: ךלש יאהמ ןקחש קיחרהל. COMMAND_DESCRIPTION_BANK: 'Open the island''s bank.' +COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: יאה לש םויבה תא ףילחהל. COMMAND_DESCRIPTION_BORDER: םייאה לש לובגה עבצ תא ףילחהל. COMMAND_DESCRIPTION_CHEST: 'Open the island''s chest.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index e8cc27ebf3..748e4545ac 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -233,6 +233,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Wyplac pieniadze z banku wyspy innego gracz COMMAND_DESCRIPTION_BALANCE: 'Sprawdz ilosc pieniedzy w banku wyspy.' COMMAND_DESCRIPTION_BAN: 'Zablokuj gracza na swojej wyspie.' COMMAND_DESCRIPTION_BANK: 'Otwórz bank wyspy.' +COMMAND_DESCRIPTION_BANS: 'Otwórz menu banów.' COMMAND_DESCRIPTION_BIOME: 'Zmień biom wyspy.' COMMAND_DESCRIPTION_BORDER: 'Zmień kolor bariery wysp.' COMMAND_DESCRIPTION_CHEST: 'Otwórz skrzynie wyspy.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 3990eac663..12d8e2ecbd 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -233,6 +233,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Retirar dinheiro do banco da ilha de outro COMMAND_DESCRIPTION_BALANCE: 'Verificar a quantidade de dinheiro no banco da ilha.' COMMAND_DESCRIPTION_BAN: 'Banir um jogador de sua ilha.' COMMAND_DESCRIPTION_BANK: 'Abrir o banco da ilha.' +COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: 'Alterar o bioma da ilha.' COMMAND_DESCRIPTION_BORDER: 'Alterar a cor da borda das ilhas.' COMMAND_DESCRIPTION_CHEST: 'Abrir o baú da ilha.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 0ef91b296b..488b6944ac 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -233,6 +233,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: 'Снять деньги с банка ос COMMAND_DESCRIPTION_BALANCE: 'Проверить количество денег в банке острова.' COMMAND_DESCRIPTION_BAN: 'Забанить игрока на своем острове.' COMMAND_DESCRIPTION_BANK: 'Открыть банк острова.' +COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: 'Изменить биом острова.' COMMAND_DESCRIPTION_BORDER: 'Изменить цвет границы островов.' COMMAND_DESCRIPTION_CHEST: 'Открыть сундук острова.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 62a608df41..5b01409b0c 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -305,6 +305,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: Başka bir oyuncunun ada bankasından para COMMAND_DESCRIPTION_BALANCE: Bir adanın bankasındaki para miktarını kontrol et. COMMAND_DESCRIPTION_BAN: Adandan bir oyuncuyu yasakla. COMMAND_DESCRIPTION_BANK: Adanın bankasını aç. +COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: Adanın biyomunu değiştir. COMMAND_DESCRIPTION_BORDER: Adaların sınır rengini değiştir. COMMAND_DESCRIPTION_CHEST: Adanın sandığını aç. diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index d344ab3c8d..d0b02ef59d 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -270,6 +270,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: Rút tiền từ ngân hàng đảo của ng COMMAND_DESCRIPTION_BALANCE: 'Kiểm tra số tiền bên trong ngân hàng của một hòn đảo.' COMMAND_DESCRIPTION_BAN: Cấm một người chơi từ đảo của bạn. COMMAND_DESCRIPTION_BANK: 'Mở ngân hàng đảo.' +COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: Thẩy đổi quần xã của hòn đảo. COMMAND_DESCRIPTION_BORDER: Thay đổi màu giới hạn đảo. COMMAND_DESCRIPTION_CHEST: 'Mở rương đảo.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 3901a14d5c..b00acb32d3 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -233,6 +233,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: '从指定岛屿的银行中取款.' COMMAND_DESCRIPTION_BALANCE: '检查指定岛屿银行中的存款.' COMMAND_DESCRIPTION_BAN: '将指定玩家从你的岛屿上封禁.' COMMAND_DESCRIPTION_BANK: '打开岛屿银行.' +COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' COMMAND_DESCRIPTION_BIOME: '更换岛屿生物群系.' COMMAND_DESCRIPTION_BORDER: '更换岛屿边界颜色.' COMMAND_DESCRIPTION_CHEST: '打开岛屿仓库.' diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index b501ec11c9..61377447a9 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -61,6 +61,8 @@ permissions: description: Ban a player from your island. superior.island.bank: description: Open the island's bank. + superior.island.bans: + description: Open the bans menu. superior.island.biome: description: Change the biome of the island. superior.island.border: From 0a8861cbc1c538bf62b6c91a1978406be6911259 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Thu, 28 Aug 2025 21:21:31 +0200 Subject: [PATCH 271/600] Added require-island option for custom menus (#2546) --- .../core/menu/impl/internal/MenuCustom.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java index bc505350af..292eea01f3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/internal/MenuCustom.java @@ -16,6 +16,7 @@ import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; +import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.messages.component.EmptyMessageComponent; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; @@ -83,8 +84,9 @@ public static MenuCustom createInstance(File menuFile) { } } boolean displayCommand = commandsSection.getBoolean("display-command", false); + boolean requireIsland = commandsSection.getBoolean("require-island", false); - args = new CommandArgs(aliases, permission, descriptions, displayCommand); + args = new CommandArgs(aliases, permission, descriptions, displayCommand, requireIsland); } return new MenuCustom(menuParseResult, fileName, args); @@ -96,12 +98,14 @@ private static class CommandArgs { private final String permission; private final Map descriptions; private final boolean displayCommand; + private final boolean requireIsland; - CommandArgs(List aliases, String permission, Map descriptions, boolean displayCommand) { + CommandArgs(List aliases, String permission, Map descriptions, boolean displayCommand, boolean requireIsland) { this.aliases = aliases; this.permission = permission; this.descriptions = descriptions; this.displayCommand = displayCommand; + this.requireIsland = requireIsland; } } @@ -157,6 +161,12 @@ public boolean displayCommand() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); + + if (this.args.requireIsland && !superiorPlayer.hasIsland()) { + Message.INVALID_ISLAND.send(superiorPlayer); + return; + } + MenuCustom.this.createView(superiorPlayer, EmptyViewArgs.INSTANCE); } From c9be50b0477dd05c083599b03c06bb80435d4b77 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Thu, 28 Aug 2025 21:26:59 +0200 Subject: [PATCH 272/600] Added placeholder support in messages with click event (#2558) --- .../component/MultipleComponents.java | 6 ++++++ .../impl/ComplexMessageComponent.java | 19 +++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java index 0152c81c48..fbab4d3fe8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java @@ -67,6 +67,12 @@ public static IMessageComponent parseSection(ConfigurationSection section) { baseComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, commandMessage)); } + String suggestMessage = section.getString(key + ".suggest"); + if (suggestMessage != null) { + for (BaseComponent baseComponent : baseComponents) + baseComponent.setClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, suggestMessage)); + } + messageComponents.add(ComplexMessageComponent.of(baseComponents)); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java index 28323fc738..1745e84315 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/ComplexMessageComponent.java @@ -120,13 +120,22 @@ private static class ContentComponent implements IWrappedComponent { @Nullable private final HoverEventContents hoverEventContents; @Nullable - private final ClickEvent clickEvent; + private final ClickEvent.Action clickEventAction; + @Nullable + private final MessageContent clickEventContent; ContentComponent(TextComponent textComponent) { this.content = MessageContent.parse(textComponent.toLegacyText()); this.hoverEventContents = textComponent.getHoverEvent() == null ? null : new HoverEventContents(textComponent.getHoverEvent()); - this.clickEvent = textComponent.getClickEvent(); + ClickEvent clickEvent = textComponent.getClickEvent(); + if (clickEvent != null) { + this.clickEventAction = clickEvent.getAction(); + this.clickEventContent = MessageContent.parse(clickEvent.getValue()); + } else { + this.clickEventAction = null; + this.clickEventContent = null; + } } @Override @@ -135,8 +144,10 @@ public BaseComponent parse(OfflinePlayer offlinePlayer, Object... args) { this.content.getContent(offlinePlayer, args).orElse(""))[0]; if (this.hoverEventContents != null) textComponent.setHoverEvent(this.hoverEventContents.parse(offlinePlayer, args)); - if (this.clickEvent != null) - textComponent.setClickEvent(this.clickEvent); + if (this.clickEventAction != null && this.clickEventContent != null) { + textComponent.setClickEvent(new ClickEvent(this.clickEventAction, + this.clickEventContent.getContent(offlinePlayer, args).orElse(""))); + } return textComponent; } From d149ecb8bd949edeee2d48538e5d76f77371bfe5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 28 Aug 2025 22:39:46 +0300 Subject: [PATCH 273/600] Adds IslandWarpTeleportEvent (#2555) --- .../api/events/IslandWarpTeleportEvent.java | 54 +++++ .../commands/player/CmdWarp.java | 4 +- .../core/events/args/PluginEventArgs.java | 4 + .../core/events/plugin/PluginEventType.java | 8 + .../events/plugin/PluginEventsFactory.java | 223 +----------------- 5 files changed, 79 insertions(+), 214 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWarpTeleportEvent.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWarpTeleportEvent.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWarpTeleportEvent.java new file mode 100644 index 0000000000..bb489203bc --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWarpTeleportEvent.java @@ -0,0 +1,54 @@ +package com.bgsoftware.superiorskyblock.api.events; + +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import org.bukkit.event.Cancellable; + +/** + * IslandWarpTeleportEvent is called when a player teleports to island warp. + */ +public class IslandWarpTeleportEvent extends IslandEvent implements Cancellable { + + private final SuperiorPlayer superiorPlayer; + private final IslandWarp islandWarp; + private boolean cancelled = false; + + /** + * The constructor of the event. + * + * @param island The island that the player talks in. + * @param superiorPlayer The player who sent the message. + * @param islandWarp The island warp the player teleports to. + */ + public IslandWarpTeleportEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { + super(island); + this.superiorPlayer = superiorPlayer; + this.islandWarp = islandWarp; + } + + /** + * Get the player who banned the other player. + */ + public SuperiorPlayer getPlayer() { + return superiorPlayer; + } + + /** + * Get the island warp that the player teleports to. + */ + public IslandWarp getIslandWarp() { + return this.islandWarp; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java index a617e96cf8..4394266dcb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -115,7 +116,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; } - targetIsland.warpPlayer(superiorPlayer, targetWarpName); + if (PluginEventsFactory.callIslandWarpTeleportEvent(targetIsland, superiorPlayer, islandWarp)) + targetIsland.warpPlayer(superiorPlayer, targetWarpName); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java index a12adb5479..0489bb4158 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java @@ -539,6 +539,10 @@ public static class IslandUpgrade extends IslandDoActionArgs { } + public static class IslandWarpTeleport extends IslandWarpDoActionArgs { + + } + public static class IslandWorldReset extends IslandDoActionArgs { public Dimension dimension; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java index 3d4fbea1fb..3d26de0e42 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java @@ -81,6 +81,7 @@ import com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent; import com.bgsoftware.superiorskyblock.api.events.IslandUnlockWorldEvent; import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandWarpTeleportEvent; import com.bgsoftware.superiorskyblock.api.events.IslandWorldResetEvent; import com.bgsoftware.superiorskyblock.api.events.IslandWorthCalculatedEvent; import com.bgsoftware.superiorskyblock.api.events.IslandWorthUpdateEvent; @@ -198,6 +199,7 @@ import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUncoopPlayer; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUnlockWorld; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUpgrade; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWarpTeleport; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorldReset; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthCalculated; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthUpdate; @@ -975,6 +977,12 @@ public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent ISLAND_WARP_TELEPORT_EVENT = new PluginEventType(IslandUpgradeEvent.class) { + @Override + public Event createBukkitEvent(IslandWarpTeleport args) { + return new IslandWarpTeleportEvent(args.island, args.superiorPlayer, args.islandWarp); + } + }; public static final PluginEventType ISLAND_WORLD_RESET_EVENT = new PluginEventType(IslandWorldResetEvent.class) { @Override public Event createBukkitEvent(IslandWorldReset args) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java index a605c15451..610d58f55f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java @@ -45,219 +45,8 @@ import java.util.List; import java.util.Locale; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.AttemptPlayerSendMessage; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.BlockStack; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.BlockUnstack; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.Empty; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBan; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBankDeposit; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBankWithdraw; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandBiomeChange; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBankLimit; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBlockLimit; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeBorderSize; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeCoopLimit; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeCropGrowth; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeDescription; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeDiscord; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeEffectLevel; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeEntityLimit; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeGeneratorRate; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeLevelBonus; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeMembersLimit; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeMobDrops; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangePaypal; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangePlayerPrivilege; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeRoleLimit; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeRolePrivilege; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeSpawnerRates; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpCategoryIcon; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpCategorySlot; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpIcon; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpLocation; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWarpsLimit; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChangeWorthBonus; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChat; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandChunkReset; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearFlags; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearGeneratorRates; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearPlayerPrivileges; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearRatings; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClearRolesPrivileges; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandClose; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCloseWarp; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCoopPlayer; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreate; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreateWarp; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandCreateWarpCategory; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDeleteWarp; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDisableFlag; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandDisband; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnableFlag; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnter; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnterPortal; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnterProtected; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandGenerateBlock; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandInvite; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandJoin; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandKick; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLeave; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLeaveProtected; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandLockWorld; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandOpen; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandOpenWarp; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandQuit; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRate; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveBlockLimit; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveEffect; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveGeneratorRate; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveRating; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveRoleLimit; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveVisitorHome; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRename; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRenameWarp; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRenameWarpCategory; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRestrictMove; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSchematicPaste; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSetHome; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandSetVisitorHome; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandTransfer; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUnban; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUncoopPlayer; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUnlockWorld; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUpgrade; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorldReset; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthCalculated; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthUpdate; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.MissionComplete; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.MissionReset; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeBorderColor; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeLanguage; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeName; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerChangeRole; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerCloseMenu; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerOpenMenu; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerReplace; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBlocksStacker; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBorder; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleBypass; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleFly; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerTogglePanel; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleSpy; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PlayerToggleTeamChat; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginInitialize; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginInitialized; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PluginLoadData; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PostIslandCreate; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PreIslandCreate; -import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.SendMessage; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ATTEMPT_PLAYER_SEND_MESSAGE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.BLOCK_STACK_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.BLOCK_UNSTACK_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.COMMANDS_UPDATE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_BANK_DEPOSIT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_BANK_WITHDRAW_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_BAN_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_BIOME_CHANGE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_BANK_LIMIT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_BLOCK_LIMIT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_BORDER_SIZE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_COOP_LIMIT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_CROP_GROWTH_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_DESCRIPTION_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_DISCORD_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_EFFECT_LEVEL_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_ENTITY_LIMIT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_GENERATOR_RATE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_LEVEL_BONUS_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_MEMBERS_LIMIT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_MOB_DROPS_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_PAYPAL_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_PLAYER_PRIVILEGE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_ROLE_LIMIT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_ROLE_PRIVILEGE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_SPAWNER_RATES_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WARPS_LIMIT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WARP_CATEGORY_ICON_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WARP_CATEGORY_SLOT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WARP_ICON_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WARP_LOCATION_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHANGE_WORTH_BONUS_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHAT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CHUNK_RESET_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_FLAGS_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_GENERATOR_RATES_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_PLAYER_PRIVILEGES_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_RATINGS_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLEAR_ROLES_PRIVILEGES_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLOSE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CLOSE_WARP_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_COOP_PLAYER_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CREATE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CREATE_WARP_CATEGORY_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_CREATE_WARP_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_DELETE_WARP_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_DISABLE_FLAG_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_DISBAND_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_ENABLE_FLAG_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_ENTER_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_ENTER_PORTAL_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_ENTER_PROTECTED_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_GENERATE_BLOCK_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_INVITE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_JOIN_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_KICK_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_LEAVE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_LEAVE_PROTECTED_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_LOCK_WORLD_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_OPEN_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_OPEN_WARP_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_QUIT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_RATE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_REMOVE_BLOCK_LIMIT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_REMOVE_EFFECT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_REMOVE_GENERATOR_RATE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_REMOVE_RATING_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_REMOVE_ROLE_LIMIT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_REMOVE_VISITOR_HOME_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_RENAME_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_RENAME_WARP_CATEGORY_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_RENAME_WARP_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_RESTRICT_MOVE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_SCHEMATIC_PASTE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_SET_HOME_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_SET_VISITOR_HOME_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_TRANSFER_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_UNBAN_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_UNCOOP_PLAYER_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_UNLOCK_WORLD_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_UPGRADE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_WORLD_RESET_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_WORTH_CALCULATED_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.ISLAND_WORTH_UPDATE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.MISSION_COMPLETE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.MISSION_RESET_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_CHANGE_BORDER_COLOR_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_CHANGE_LANGUAGE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_CHANGE_NAME_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_CHANGE_ROLE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_CLOSE_MENU_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_OPEN_MENU_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_REPLACE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_BLOCKS_STACKER_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_BORDER_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_BYPASS_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_FLY_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_PANEL_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_SPY_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLAYER_TOGGLE_TEAM_CHAT_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLUGIN_INITIALIZED_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLUGIN_INITIALIZE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PLUGIN_LOAD_DATA_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.POST_ISLAND_CREATE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.PRE_ISLAND_CREATE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.SEND_MESSAGE_EVENT; -import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.SETTINGS_UPDATE_EVENT; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.*; +import static com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType.*; public class PluginEventsFactory { @@ -1143,6 +932,14 @@ public static PluginEvent callIslandUpgradeEvent(Island island, @ return fireEvent(ISLAND_UPGRADE_EVENT, islandUpgrade); } + public static boolean callIslandWarpTeleportEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { + IslandWarpTeleport islandWarpTeleport = new IslandWarpTeleport(); + islandWarpTeleport.island = island; + islandWarpTeleport.superiorPlayer = superiorPlayer; + islandWarpTeleport.islandWarp = islandWarp; + return !fireEvent(ISLAND_WARP_TELEPORT_EVENT, islandWarpTeleport).isCancelled(); + } + public static boolean callIslandWorldResetEvent(Island island, CommandSender commandSender, Dimension dimension) { return callIslandWorldResetEvent(island, commandSenderToSuperiorPlayer(commandSender), dimension); } From a4fc117993146fad10c251ef85a4ea1b470b637d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 29 Aug 2025 15:23:31 +0300 Subject: [PATCH 274/600] Fixed last used skin of players is never saved to DB --- .../bgsoftware/superiorskyblock/player/SSuperiorPlayer.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index 0ea7b2d52f..c0edccb613 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -174,11 +174,13 @@ public void setTextureValue(String textureValue) { Log.debug(Debug.SET_TEXTURE_VALUE, getName(), textureValue); + String oldTextureValue = this.textureValue; + // We first update the texture value, even if they are equal. this.textureValue = textureValue; // We now compare them but remove the timestamp when comparing. - if (Objects.equals(removeTextureValueTimeStamp(this.textureValue), removeTextureValueTimeStamp(textureValue))) + if (Objects.equals(removeTextureValueTimeStamp(oldTextureValue), removeTextureValueTimeStamp(textureValue))) return; // We only save the value if it's actually different. From 3f8c17054af110694c42b7bfbb047bf3273bc12d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 29 Aug 2025 16:41:45 +0300 Subject: [PATCH 275/600] Faster lookups for actions when checking for ignored members --- .../superiorskyblock/island/SIsland.java | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 865cd5ba61..181c699801 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -131,6 +131,7 @@ import java.util.Date; import java.util.EnumMap; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; @@ -156,6 +157,8 @@ public class SIsland implements Island { private static final UUID CONSOLE_UUID = new UUID(0, 0); private static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2); + private static final UUID[] EMPTY_IGNORED_MEMBERS = new UUID[0]; + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference placeholdersService = new LazyReference() { @Override @@ -1757,7 +1760,7 @@ public void setDescription(String description) { public void disbandIsland() { long profilerId = Profiler.start(ProfileType.DISBAND_ISLAND, 2); - forEachIslandMember(Collections.emptyList(), false, islandMember -> { + forEachIslandMember(EMPTY_IGNORED_MEMBERS, false, islandMember -> { if (islandMember.equals(owner)) { owner.setIsland(null); } else { @@ -2125,11 +2128,9 @@ public void sendMessage(String message, UUID... ignoredMembers) { Preconditions.checkNotNull(message, "message parameter cannot be null."); Preconditions.checkNotNull(ignoredMembers, "ignoredMembers parameter cannot be null."); - List ignoredList = ignoredMembers.length == 0 ? Collections.emptyList() : Arrays.asList(ignoredMembers); - - Log.debug(Debug.SEND_MESSAGE, owner.getName(), message, ignoredList); + Log.debug(Debug.SEND_MESSAGE, owner.getName(), message, Arrays.toString(ignoredMembers)); - forEachIslandMember(ignoredList, false, islandMember -> { + forEachIslandMember(ignoredMembers, false, islandMember -> { String playerMessage = message; if (!Text.isBlank(playerMessage)) @@ -2151,7 +2152,10 @@ public void sendMessage(IMessageComponent messageComponent, List ignoredMe Log.debug(Debug.SEND_MESSAGE, owner.getName(), messageComponent.getMessage(args), ignoredMembers, Arrays.asList(args)); - forEachIslandMember(ignoredMembers, false, islandMember -> messageComponent.sendMessage(islandMember.asPlayer(), args)); + Set ignoredMembersSet = ignoredMembers.isEmpty() ? Collections.emptySet() : new HashSet<>(ignoredMembers); + + forEachIslandMember(ignoredMembersSet, false, + islandMember -> messageComponent.sendMessage(islandMember.asPlayer(), args)); } @Override @@ -2159,11 +2163,9 @@ public void sendTitle(@Nullable String title, @Nullable String subtitle, int fad int fadeOut, UUID... ignoredMembers) { Preconditions.checkNotNull(ignoredMembers, "ignoredMembers parameter cannot be null."); - List ignoredList = ignoredMembers.length == 0 ? Collections.emptyList() : Arrays.asList(ignoredMembers); - - Log.debug(Debug.SEND_TITLE, owner.getName(), title, subtitle, fadeIn, duration, fadeOut, ignoredList); + Log.debug(Debug.SEND_TITLE, owner.getName(), title, subtitle, fadeIn, duration, fadeOut, Arrays.toString(ignoredMembers)); - forEachIslandMember(ignoredList, true, islandMember -> { + forEachIslandMember(ignoredMembers, true, islandMember -> { String playerTitle = title; String playerSubtitle = subtitle; @@ -2183,11 +2185,9 @@ public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ig Preconditions.checkNotNull(command, "command parameter cannot be null."); Preconditions.checkNotNull(ignoredMembers, "ignoredMembers parameter cannot be null."); - List ignoredList = ignoredMembers.length == 0 ? Collections.emptyList() : Arrays.asList(ignoredMembers); + Log.debug(Debug.EXECUTE_ISLAND_COMMANDS, owner.getName(), command, onlyOnlineMembers, Arrays.toString(ignoredMembers)); - Log.debug(Debug.EXECUTE_ISLAND_COMMANDS, owner.getName(), command, onlyOnlineMembers, ignoredList); - - forEachIslandMember(ignoredList, onlyOnlineMembers, islandMember -> { + forEachIslandMember(ignoredMembers, onlyOnlineMembers, islandMember -> { String playerCommand = command; if (!Text.isBlank(playerCommand)) { @@ -5239,7 +5239,19 @@ private void finishCalcIsland(SuperiorPlayer asker, Runnable callback, BigDecima callback.run(); } - private void forEachIslandMember(List ignoredMembers, boolean onlyOnline, Consumer islandMemberConsumer) { + private void forEachIslandMember(UUID[] ignoredMembersArray, boolean onlyOnline, Consumer islandMemberConsumer) { + Set ignoredMembersSet; + if (ignoredMembersArray.length == 0) { + ignoredMembersSet = Collections.emptySet(); + } else { + ignoredMembersSet = new HashSet<>(); + Collections.addAll(ignoredMembersSet, ignoredMembersArray); + } + + forEachIslandMember(ignoredMembersSet, onlyOnline, islandMemberConsumer); + } + + private void forEachIslandMember(Set ignoredMembers, boolean onlyOnline, Consumer islandMemberConsumer) { for (SuperiorPlayer islandMember : getIslandMembers(true)) { if (!ignoredMembers.contains(islandMember.getUniqueId()) && (!onlyOnline || islandMember.isOnline())) { islandMemberConsumer.accept(islandMember); From d8bc9c1d5d1b3c5e9815cf95a0cf13407d6b741e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 29 Aug 2025 16:49:13 +0300 Subject: [PATCH 276/600] Add non-vararg methods to Island --- .../api/island/DelegateIsland.java | 26 +++++++++++- .../superiorskyblock/api/island/Island.java | 42 +++++++++++++++++++ .../superiorskyblock/island/SIsland.java | 28 ++++++++++++- .../superiorskyblock/island/SpawnIsland.java | 25 +++++++++++ 4 files changed, 119 insertions(+), 2 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index 541101e8d2..de9155a294 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -33,7 +33,6 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID; @@ -899,26 +898,51 @@ public void setIgnored(boolean ignored) { this.handle.setIgnored(ignored); } + @Override + public void sendMessage(String message) { + this.handle.sendMessage(message); + } + @Override public void sendMessage(String message, UUID... ignoredMembers) { this.handle.sendMessage(message, ignoredMembers); } + @Override + public void sendMessage(IMessageComponent messageComponent) { + this.handle.sendMessage(messageComponent); + } + @Override public void sendMessage(IMessageComponent messageComponent, Object... args) { this.handle.sendMessage(messageComponent, args); } + @Override + public void sendMessage(IMessageComponent messageComponent, List ignoredMembers) { + this.handle.sendMessage(messageComponent, ignoredMembers); + } + @Override public void sendMessage(IMessageComponent messageComponent, List ignoredMembers, Object... args) { this.handle.sendMessage(messageComponent, ignoredMembers, args); } + @Override + public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut) { + this.handle.sendTitle(title, subtitle, fadeIn, duration, fadeOut); + } + @Override public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut, UUID... ignoredMembers) { this.handle.sendTitle(title, subtitle, fadeIn, duration, fadeOut, ignoredMembers); } + @Override + public void executeCommand(String command, boolean onlyOnlineMembers) { + this.handle.executeCommand(command, onlyOnlineMembers); + } + @Override public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ignoredMembers) { this.handle.executeCommand(command, onlyOnlineMembers, ignoredMembers); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java index ca78798cd4..7827830907 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java @@ -1234,6 +1234,13 @@ List> getAllChunksAsync(World.Environment environment, */ void setIgnored(boolean ignored); + /** + * Send a plain message to all the members of the island. + * + * @param message The message to send + */ + void sendMessage(String message); + /** * Send a plain message to all the members of the island. * @@ -1242,6 +1249,13 @@ List> getAllChunksAsync(World.Environment environment, */ void sendMessage(String message, UUID... ignoredMembers); + /** + * Send a message to all the members of the island. + * + * @param messageComponent The message to send + */ + void sendMessage(IMessageComponent messageComponent); + /** * Send a message to all the members of the island. * @@ -1250,6 +1264,14 @@ List> getAllChunksAsync(World.Environment environment, */ void sendMessage(IMessageComponent messageComponent, Object... args); + /** + * Send a message to all the members of the island. + * + * @param messageComponent The message to send + * @param ignoredMembers An array of ignored members. + */ + void sendMessage(IMessageComponent messageComponent, List ignoredMembers); + /** * Send a message to all the members of the island. * @@ -1259,6 +1281,17 @@ List> getAllChunksAsync(World.Environment environment, */ void sendMessage(IMessageComponent messageComponent, List ignoredMembers, Object... args); + /** + * Send a plain message to all the members of the island. + * + * @param title The main title to send. + * @param subtitle The sub title to send. + * @param fadeIn The fade-in duration in ticks. + * @param duration The title duration in ticks. + * @param fadeOut The fade-out duration in ticks. + */ + void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut); + /** * Send a plain message to all the members of the island. * @@ -1271,6 +1304,15 @@ List> getAllChunksAsync(World.Environment environment, */ void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut, UUID... ignoredMembers); + /** + * Execute a command on all the members of the island. + * You can use {player-name} as a placeholder for the member's name. + * + * @param command The command to execute. + * @param onlyOnlineMembers Whether the command should be executed only for online members. + */ + void executeCommand(String command, boolean onlyOnlineMembers); + /** * Execute a command on all the members of the island. * You can use {player-name} as a placeholder for the member's name. diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 181c699801..eb87b9775f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -158,6 +158,7 @@ public class SIsland implements Island { private static final UUID CONSOLE_UUID = new UUID(0, 0); private static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2); private static final UUID[] EMPTY_IGNORED_MEMBERS = new UUID[0]; + private static final Object[] EMPTY_MESSAGE_ARGS = new Object[0]; private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference placeholdersService = new LazyReference() { @@ -2123,6 +2124,11 @@ public void setIgnored(boolean ignored) { IslandsDatabaseBridge.saveIgnoredStatus(this); } + @Override + public void sendMessage(String message) { + sendMessage(message, EMPTY_IGNORED_MEMBERS); + } + @Override public void sendMessage(String message, UUID... ignoredMembers) { Preconditions.checkNotNull(message, "message parameter cannot be null."); @@ -2140,11 +2146,21 @@ public void sendMessage(String message, UUID... ignoredMembers) { }); } + @Override + public void sendMessage(IMessageComponent messageComponent) { + sendMessage(messageComponent, EMPTY_MESSAGE_ARGS); + } + @Override public void sendMessage(IMessageComponent messageComponent, Object... args) { this.sendMessage(messageComponent, Collections.emptyList(), args); } + @Override + public void sendMessage(IMessageComponent messageComponent, List ignoredMembers) { + sendMessage(messageComponent, ignoredMembers, EMPTY_MESSAGE_ARGS); + } + @Override public void sendMessage(IMessageComponent messageComponent, List ignoredMembers, Object... args) { Preconditions.checkNotNull(messageComponent, "messageComponent parameter cannot be null."); @@ -2153,11 +2169,16 @@ public void sendMessage(IMessageComponent messageComponent, List ignoredMe Log.debug(Debug.SEND_MESSAGE, owner.getName(), messageComponent.getMessage(args), ignoredMembers, Arrays.asList(args)); Set ignoredMembersSet = ignoredMembers.isEmpty() ? Collections.emptySet() : new HashSet<>(ignoredMembers); - + forEachIslandMember(ignoredMembersSet, false, islandMember -> messageComponent.sendMessage(islandMember.asPlayer(), args)); } + @Override + public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut) { + sendTitle(title, subtitle, fadeIn, duration, fadeOut, EMPTY_IGNORED_MEMBERS); + } + @Override public void sendTitle(@Nullable String title, @Nullable String subtitle, int fadeIn, int duration, int fadeOut, UUID... ignoredMembers) { @@ -2180,6 +2201,11 @@ public void sendTitle(@Nullable String title, @Nullable String subtitle, int fad }); } + @Override + public void executeCommand(String command, boolean onlyOnlineMembers) { + executeCommand(command, onlyOnlineMembers, EMPTY_IGNORED_MEMBERS); + } + @Override public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ignoredMembers) { Preconditions.checkNotNull(command, "command parameter cannot be null."); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index b0bfabef22..9e8239baea 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -1099,26 +1099,51 @@ public void setIgnored(boolean ignored) { // Do nothing. } + @Override + public void sendMessage(String message) { + // Do nothing. + } + @Override public void sendMessage(String message, UUID... ignoredMembers) { // Do nothing. } + @Override + public void sendMessage(IMessageComponent messageComponent) { + // Do nothing. + } + @Override public void sendMessage(IMessageComponent messageComponent, Object... args) { // Do nothing. } + @Override + public void sendMessage(IMessageComponent messageComponent, List ignoredMembers) { + // Do nothing. + } + @Override public void sendMessage(IMessageComponent messageComponent, List ignoredMembers, Object... args) { // Do nothing. } + @Override + public void sendTitle(String title, String subtitle, int fadeIn, int duration, int fadeOut) { + // Do nothing. + } + @Override public void sendTitle(String title, String subtitle, int fadeIn, int duration, int fadeOut, UUID... ignoredMembers) { // Do nothing. } + @Override + public void executeCommand(String command, boolean onlyOnlineMembers) { + // Do nothing. + } + @Override public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ignoredMembers) { // Do nothing. From 72411eedbf73471cc848aaa90885d9384c7b9e00 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 29 Aug 2025 17:20:47 +0200 Subject: [PATCH 277/600] Added more "clear-on-" options (#2539) --- .../api/config/SettingsManager.java | 43 ++++++- .../api/enums/MemberRemoveReason.java | 23 ++++ .../api/island/DelegateIsland.java | 7 ++ .../superiorskyblock/api/island/Island.java | 11 ++ .../api/player/inventory/ClearAction.java | 89 +++++++++++++ .../nms/v1_12_R1/NMSPlayersImpl.java | 44 +------ .../player/OfflinePlayerDataImpl.java | 70 +++++++++++ .../nms/v1_16_R3/NMSPlayersImpl.java | 47 +------ .../player/OfflinePlayerDataImpl.java | 72 +++++++++++ .../nms/v1_17/NMSPlayersImpl.java | 53 +------- .../v1_17/player/OfflinePlayerDataImpl.java | 74 +++++++++++ .../nms/v1_18/NMSPlayersImpl.java | 53 +------- .../v1_18/player/OfflinePlayerDataImpl.java | 74 +++++++++++ .../nms/v1_19/NMSPlayersImpl.java | 53 +------- .../v1_19/player/OfflinePlayerDataImpl.java | 74 +++++++++++ .../nms/v1_20_3/NMSPlayersImpl.java | 54 +------- .../v1_20_3/player/OfflinePlayerDataImpl.java | 76 +++++++++++ .../nms/v1_20_4/NMSPlayersImpl.java | 54 +------- .../v1_20_4/player/OfflinePlayerDataImpl.java | 75 +++++++++++ .../nms/v1_21/NMSPlayersImpl.java | 54 +------- .../v1_21/player/OfflinePlayerDataImpl.java | 75 +++++++++++ .../nms/v1_21_3/NMSPlayersImpl.java | 54 +------- .../v1_21_3/player/OfflinePlayerDataImpl.java | 75 +++++++++++ .../nms/v1_21_4/NMSPlayersImpl.java | 57 +-------- .../v1_21_4/player/OfflinePlayerDataImpl.java | 79 ++++++++++++ .../nms/v1_21_5/NMSPlayersImpl.java | 57 +-------- .../v1_21_5/player/OfflinePlayerDataImpl.java | 79 ++++++++++++ .../nms/v1_21_7/NMSPlayersImpl.java | 57 +-------- .../v1_21_7/player/OfflinePlayerDataImpl.java | 79 ++++++++++++ .../nms/v1_8_R3/NMSPlayersImpl.java | 45 +------ .../v1_8_R3/player/OfflinePlayerDataImpl.java | 70 +++++++++++ .../SuperiorSkyblockPlugin.java | 2 + .../commands/admin/CmdAdminAdd.java | 5 +- .../commands/admin/CmdAdminJoin.java | 3 + .../commands/player/CmdAccept.java | 5 +- .../commands/player/CmdLeave.java | 13 +- .../config/SettingsContainer.java | 27 +++- .../config/SettingsManagerImpl.java | 49 +++++++- .../config/section/GlobalSection.java | 25 +++- .../core/menu/button/impl/LeaveButton.java | 11 +- .../superiorskyblock/island/IslandUtils.java | 14 ++- .../superiorskyblock/island/SIsland.java | 45 +++++-- .../superiorskyblock/island/SpawnIsland.java | 7 ++ .../superiorskyblock/nms/NMSPlayers.java | 3 +- .../nms/player/OfflinePlayerData.java | 18 +++ .../player/inventory/ClearActions.java | 119 ++++++++++++++++++ src/main/resources/config.yml | 33 +++-- 47 files changed, 1517 insertions(+), 689 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/MemberRemoveReason.java create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/player/inventory/ClearAction.java create mode 100644 NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/player/OfflinePlayerDataImpl.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/nms/player/OfflinePlayerData.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 5ab45fce44..0e2968fb86 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; @@ -141,7 +142,7 @@ public interface SettingsManager { VisitorsSign getVisitorsSign(); /** - * All settings related to the worlds of the plugin.. + * All settings related to the worlds of the plugin. * Config path: worlds */ Worlds getWorlds(); @@ -251,8 +252,11 @@ public interface SettingsManager { /** * Whether inventory of island members should be cleared when their island is disbanded or not. - * Config-path: disband-inventory-clear + * Return true if clear-on-disband contains both ENDER_CHEST and INVENTORY. + * This method will be deleted in the future! + * @deprecated See {@link #getClearActionsOnDisband()} */ + @Deprecated boolean isDisbandInventoryClear(); /** @@ -279,12 +283,45 @@ public interface SettingsManager { */ boolean isTeleportOnKick(); + /** + * Whether to teleport players to the spawn when they leave an island or not. + * Config-path: teleport-on-leave + */ + boolean isTeleportOnLeave(); + /** * Whether to clear players' inventories when they join a new island or not. - * Config-path: clear-on-join + * Return true if clear-on-join contains both ENDER_CHEST and INVENTORY. + * This method will be deleted in the future! + * @deprecated See {@link #getClearActionsOnJoin()} */ + @Deprecated boolean isClearOnJoin(); + /** + * Get the list of clear actions to perform on island members when their island is disbanded. + * Config-path: clear-on-disband + */ + List getClearActionsOnDisband(); + + /** + * Get the list of clear actions to perform on players when they accept an invite. + * Config-path: clear-on-join + */ + List getClearActionsOnJoin(); + + /** + * Get the list of clear actions to perform on players when they are kicked from their island. + * Config-path: clear-on-kick + */ + List getClearActionsOnKick(); + + /** + * Get the list of clear actions to perform on players when they leave an island. + * Config-path: clear-on-leave + */ + List getClearActionsOnLeave(); + /** * Whether players can rate their own island or not. * Config-path: rate-own-island diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/MemberRemoveReason.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/MemberRemoveReason.java new file mode 100644 index 0000000000..8f2f1cd91c --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/enums/MemberRemoveReason.java @@ -0,0 +1,23 @@ +package com.bgsoftware.superiorskyblock.api.enums; + +/** + * Used to determine the reason why a member was removed from an island. + */ +public enum MemberRemoveReason { + + /** + * The member was removed because the island was disbanded. + */ + DISBAND, + + /** + * The member was removed because another player kicked them from the island. + */ + KICK, + + /** + * The member was removed because they left the island. + */ + LEAVE + +} diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index de9155a294..a2e7b3e7a7 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -3,6 +3,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.annotations.Size; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; +import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; @@ -138,10 +139,16 @@ public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) { } @Override + @Deprecated public void kickMember(SuperiorPlayer superiorPlayer) { this.handle.kickMember(superiorPlayer); } + @Override + public void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason memberRemoveReason) { + this.handle.removeMember(superiorPlayer, memberRemoveReason); + } + @Override public boolean isMember(SuperiorPlayer superiorPlayer) { return this.handle.isMember(superiorPlayer); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java index 7827830907..168694a18f 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java @@ -4,6 +4,7 @@ import com.bgsoftware.common.annotations.Size; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.data.IDatabaseBridgeHolder; +import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.enums.SyncStatus; import com.bgsoftware.superiorskyblock.api.events.IslandChangeGeneratorRateEvent; @@ -164,9 +165,19 @@ public interface Island extends Comparable, IMissionsHolder, IPersistent * Kick a member from the island. * * @param superiorPlayer The player to kick. + * @deprecated See {@link #removeMember(SuperiorPlayer, MemberRemoveReason)} */ + @Deprecated void kickMember(SuperiorPlayer superiorPlayer); + /** + * Remove a member from the island. + * + * @param superiorPlayer The player to remove. + * @param memberRemoveReason The reason for removal. + */ + void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason memberRemoveReason); + /** * Check whether a player is a member of the island. * diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/inventory/ClearAction.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/inventory/ClearAction.java new file mode 100644 index 0000000000..b1df51cc41 --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/inventory/ClearAction.java @@ -0,0 +1,89 @@ +package com.bgsoftware.superiorskyblock.api.player.inventory; + +import com.bgsoftware.superiorskyblock.api.objects.Enumerable; +import com.google.common.base.Preconditions; +import org.bukkit.entity.Player; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +public abstract class ClearAction implements Enumerable { + + private static final Map clearActions = new HashMap<>(); + private static int ordinalCounter = 0; + + private final String name; + private final int ordinal; + + protected ClearAction(String name) { + Preconditions.checkArgument(!clearActions.containsKey(name), "name already exists."); + this.name = name.toUpperCase(Locale.ENGLISH); + this.ordinal = ordinalCounter++; + } + + @Override + public final int ordinal() { + return this.ordinal; + } + + /** + * Get the name of the clear action. + */ + public final String getName() { + return name; + } + + /** + * Execute this {@link ClearAction} on the player {@param player}; + * + * @param player The player to run the clear action on. + * The player instance might be fake for offline players. + * Do not save it elsewhere, only run actions that change its data. + */ + public abstract void doClear(Player player); + + @Override + public String toString() { + return "ClearAction{name=" + name + "}"; + } + + /** + * Get all the clear actions. + */ + public static Collection values() { + return clearActions.values(); + } + + /** + * Get a clear action by its name. + * + * @param name The name to check. + */ + public static ClearAction getByName(String name) { + Preconditions.checkNotNull(name, "name parameter cannot be null."); + + ClearAction clearAction = clearActions.get(name.toUpperCase(Locale.ENGLISH)); + + Preconditions.checkNotNull(clearAction, "Couldn't find an ClearAction with the name " + name + "."); + + return clearAction; + } + + /** + * Register a new clear action. + * + * @param clearAction The clear action to register. + */ + public static void register(ClearAction clearAction) { + Preconditions.checkNotNull(clearAction, "clearAction parameter cannot be null."); + + String name = clearAction.getName().toUpperCase(Locale.ENGLISH); + + Preconditions.checkState(!clearActions.containsKey(name), "ClearAction with the name " + name + " already exists."); + + clearActions.put(name, clearAction); + } + +} diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSPlayersImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSPlayersImpl.java index 1528b9bad1..280e8f3045 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSPlayersImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSPlayersImpl.java @@ -1,30 +1,23 @@ package com.bgsoftware.superiorskyblock.nms.v1_12_R1; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_12_R1.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; import net.minecraft.server.v1_12_R1.Entity; import net.minecraft.server.v1_12_R1.EntityItem; import net.minecraft.server.v1_12_R1.EntityPlayer; -import net.minecraft.server.v1_12_R1.MinecraftServer; -import net.minecraft.server.v1_12_R1.PlayerInteractManager; -import net.minecraft.server.v1_12_R1.WorldServer; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.v1_12_R1.CraftServer; -import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftItem; import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; import org.bukkit.entity.Player; @@ -34,38 +27,9 @@ public class NMSPlayersImpl implements NMSPlayers { - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - WorldServer worldServer = server.getWorldServer(0); - EntityPlayer entity = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer)); - Player targetPlayer = entity.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - entity.world = ((CraftWorld) spawnLocation.getWorld()).getHandle(); - entity.setPositionRotation(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), spawnLocation.getYaw(), spawnLocation.getPitch()); - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/player/OfflinePlayerDataImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..775013dc5e --- /dev/null +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/player/OfflinePlayerDataImpl.java @@ -0,0 +1,70 @@ +package com.bgsoftware.superiorskyblock.nms.v1_12_R1.player; + +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_12_R1.EntityPlayer; +import net.minecraft.server.v1_12_R1.MinecraftServer; +import net.minecraft.server.v1_12_R1.PlayerInteractManager; +import net.minecraft.server.v1_12_R1.WorldServer; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.v1_12_R1.CraftServer; +import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + WorldServer worldServer = server.getWorldServer(0); + EntityPlayer entityPlayer = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer)); + this.fakePlayer = entityPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + EntityPlayer entityPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + entityPlayer.world = ((CraftWorld) location.getWorld()).getHandle(); + entityPlayer.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSPlayersImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSPlayersImpl.java index 81a4fe67fd..0f4ee88c88 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSPlayersImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSPlayersImpl.java @@ -2,29 +2,21 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_16_R3.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; import net.minecraft.server.v1_16_R3.EntityPlayer; -import net.minecraft.server.v1_16_R3.MinecraftServer; -import net.minecraft.server.v1_16_R3.PlayerInteractManager; -import net.minecraft.server.v1_16_R3.World; -import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.v1_16_R3.CraftServer; -import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; @@ -36,40 +28,9 @@ public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(Player.class, "locale"); - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - assert player != null; - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - WorldServer worldServer = server.getWorldServer(World.OVERWORLD); - assert worldServer != null; - EntityPlayer entity = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer)); - Player targetPlayer = entity.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - entity.world = ((CraftWorld) spawnLocation.getWorld()).getHandle(); - entity.setPositionRotation(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), spawnLocation.getYaw(), spawnLocation.getPitch()); - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/player/OfflinePlayerDataImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..35bc264e09 --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/player/OfflinePlayerDataImpl.java @@ -0,0 +1,72 @@ +package com.bgsoftware.superiorskyblock.nms.v1_16_R3.player; + +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_16_R3.EntityPlayer; +import net.minecraft.server.v1_16_R3.MinecraftServer; +import net.minecraft.server.v1_16_R3.PlayerInteractManager; +import net.minecraft.server.v1_16_R3.World; +import net.minecraft.server.v1_16_R3.WorldServer; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.v1_16_R3.CraftServer; +import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + WorldServer worldServer = server.getWorldServer(World.OVERWORLD); + assert worldServer != null; + EntityPlayer entityPlayer = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer)); + this.fakePlayer = entityPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + EntityPlayer entityPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + entityPlayer.world = ((CraftWorld) location.getWorld()).getHandle(); + entityPlayer.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSPlayersImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSPlayersImpl.java index 59451351fc..3d04197100 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSPlayersImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSPlayersImpl.java @@ -2,79 +2,34 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_17.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.v1_17_R1.CraftServer; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; -import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(Player.class, "locale"); - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - assert player != null; - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile); - Player targetPlayer = serverPlayer.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - - if (spawnLocation != null) { - serverPlayer.setLevel(serverLevel); - serverPlayer.absMoveTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), - spawnLocation.getYaw(), spawnLocation.getPitch()); - } - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/player/OfflinePlayerDataImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..acc3062319 --- /dev/null +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/player/OfflinePlayerDataImpl.java @@ -0,0 +1,74 @@ +package com.bgsoftware.superiorskyblock.nms.v1_17.player; + +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.v1_17_R1.CraftServer; +import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return null; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile); + this.fakePlayer = serverPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); + serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSPlayersImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSPlayersImpl.java index 622abcfdc3..e1564f1b9a 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSPlayersImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSPlayersImpl.java @@ -2,79 +2,34 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_18.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.v1_18_R2.CraftServer; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; -import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(Player.class, "locale"); - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - assert player != null; - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile); - Player targetPlayer = serverPlayer.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - - if (spawnLocation != null) { - serverPlayer.setLevel(serverLevel); - serverPlayer.absMoveTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), - spawnLocation.getYaw(), spawnLocation.getPitch()); - } - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/player/OfflinePlayerDataImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..1489eb7f8a --- /dev/null +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/player/OfflinePlayerDataImpl.java @@ -0,0 +1,74 @@ +package com.bgsoftware.superiorskyblock.nms.v1_18.player; + +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.v1_18_R2.CraftServer; +import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return null; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile); + this.fakePlayer = serverPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); + serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSPlayersImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSPlayersImpl.java index 7057ef5e24..1292eb192c 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSPlayersImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSPlayersImpl.java @@ -2,79 +2,34 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_19.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.v1_19_R3.CraftServer; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; -import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - assert player != null; - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile); - Player targetPlayer = serverPlayer.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - - if (spawnLocation != null) { - serverPlayer.setLevel(serverLevel); - serverPlayer.absMoveTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), - spawnLocation.getYaw(), spawnLocation.getPitch()); - } - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/player/OfflinePlayerDataImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..70e0be16af --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/player/OfflinePlayerDataImpl.java @@ -0,0 +1,74 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.player; + +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.v1_19_R3.CraftServer; +import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return null; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile); + this.fakePlayer = serverPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); + serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSPlayersImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSPlayersImpl.java index fa16d704ce..0efc372f8b 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSPlayersImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSPlayersImpl.java @@ -2,80 +2,34 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.v1_20_R3.CraftServer; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; -import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - assert player != null; - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - Player targetPlayer = serverPlayer.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - - if (spawnLocation != null) { - serverPlayer.setLevel(serverLevel); - serverPlayer.absMoveTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), - spawnLocation.getYaw(), spawnLocation.getPitch()); - } - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/player/OfflinePlayerDataImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..0e49213191 --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/player/OfflinePlayerDataImpl.java @@ -0,0 +1,76 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.player; + +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.v1_20_R3.CraftServer; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return null; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); + this.fakePlayer = serverPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); + serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} + diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSPlayersImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSPlayersImpl.java index 857637b9e3..581e3c458e 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSPlayersImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSPlayersImpl.java @@ -2,80 +2,34 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; -import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - assert player != null; - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - Player targetPlayer = serverPlayer.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - - if (spawnLocation != null) { - serverPlayer.setLevel(serverLevel); - serverPlayer.absMoveTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), - spawnLocation.getYaw(), spawnLocation.getPitch()); - } - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/player/OfflinePlayerDataImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..1cf351f162 --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/player/OfflinePlayerDataImpl.java @@ -0,0 +1,75 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.player; + +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return null; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); + this.fakePlayer = serverPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); + serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSPlayersImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSPlayersImpl.java index 6aa23044d7..625b905c3c 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSPlayersImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSPlayersImpl.java @@ -2,80 +2,34 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_21.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; -import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - assert player != null; - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - Player targetPlayer = serverPlayer.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - - if (spawnLocation != null) { - serverPlayer.setLevel(serverLevel); - serverPlayer.absMoveTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), - spawnLocation.getYaw(), spawnLocation.getPitch()); - } - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/player/OfflinePlayerDataImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..7087c6d8f1 --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/player/OfflinePlayerDataImpl.java @@ -0,0 +1,75 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.player; + +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return null; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); + this.fakePlayer = serverPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); + serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSPlayersImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSPlayersImpl.java index a43576fa02..038c7759ce 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSPlayersImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSPlayersImpl.java @@ -2,80 +2,34 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; -import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - assert player != null; - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - Player targetPlayer = serverPlayer.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - - if (spawnLocation != null) { - serverPlayer.setLevel(serverLevel); - serverPlayer.absMoveTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), - spawnLocation.getYaw(), spawnLocation.getPitch()); - } - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/player/OfflinePlayerDataImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..bcfed6d315 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/player/OfflinePlayerDataImpl.java @@ -0,0 +1,75 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.player; + +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return null; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); + this.fakePlayer = serverPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); + serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java index a478242f40..3859b38630 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java @@ -2,83 +2,34 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; -import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - private static final ReflectMethod ENTITY_SET_LEVEL = new ReflectMethod<>( - Entity.class, 1, Level.class); - - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - assert player != null; - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - Player targetPlayer = serverPlayer.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - - if (spawnLocation != null) { - ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); - serverPlayer.absMoveTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), - spawnLocation.getYaw(), spawnLocation.getPitch()); - } - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/player/OfflinePlayerDataImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..3370878921 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/player/OfflinePlayerDataImpl.java @@ -0,0 +1,79 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.player; + +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + private static final ReflectMethod ENTITY_SET_LEVEL = new ReflectMethod<>(Entity.class, 1, Level.class); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return null; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); + this.fakePlayer = serverPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); + serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSPlayersImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSPlayersImpl.java index d5c466c570..e9e6c5bf04 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSPlayersImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSPlayersImpl.java @@ -2,83 +2,34 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; -import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - private static final ReflectMethod ENTITY_SET_LEVEL = new ReflectMethod<>( - Entity.class, 1, Level.class); - - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - assert player != null; - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - Player targetPlayer = serverPlayer.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - - if (spawnLocation != null) { - ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); - serverPlayer.absSnapTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), - spawnLocation.getYaw(), spawnLocation.getPitch()); - } - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/player/OfflinePlayerDataImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..12102f601d --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/player/OfflinePlayerDataImpl.java @@ -0,0 +1,79 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.player; + +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + private static final ReflectMethod ENTITY_SET_LEVEL = new ReflectMethod<>(Entity.class, 1, Level.class); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return null; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); + this.fakePlayer = serverPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); + serverPlayer.absSnapTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} \ No newline at end of file diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSPlayersImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSPlayersImpl.java index b552d07c5d..102bd279c5 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSPlayersImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSPlayersImpl.java @@ -2,83 +2,34 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import java.util.Locale; -import java.util.Optional; public class NMSPlayersImpl implements NMSPlayers { private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - private static final ReflectMethod ENTITY_SET_LEVEL = new ReflectMethod<>( - Entity.class, 1, Level.class); - - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - assert player != null; - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - Player targetPlayer = serverPlayer.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - - if (spawnLocation != null) { - ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); - serverPlayer.absSnapTo(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), - spawnLocation.getYaw(), spawnLocation.getPitch()); - } - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/player/OfflinePlayerDataImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..b86d5b0d9a --- /dev/null +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/player/OfflinePlayerDataImpl.java @@ -0,0 +1,79 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_7.player; + +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + private static final ReflectMethod ENTITY_SET_LEVEL = new ReflectMethod<>(Entity.class, 1, Level.class); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); + + if (serverLevel == null) + return null; + + ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); + this.fakePlayer = serverPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); + serverPlayer.absSnapTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSPlayersImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSPlayersImpl.java index 0200d18490..dfd0e70861 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSPlayersImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSPlayersImpl.java @@ -1,29 +1,21 @@ package com.bgsoftware.superiorskyblock.nms.v1_8_R3; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.v1_8_R3.player.OfflinePlayerDataImpl; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.EmptyBossBar; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import net.minecraft.server.v1_8_R3.Entity; import net.minecraft.server.v1_8_R3.EntityItem; import net.minecraft.server.v1_8_R3.EntityPlayer; -import net.minecraft.server.v1_8_R3.MinecraftServer; import net.minecraft.server.v1_8_R3.PacketPlayOutChat; import net.minecraft.server.v1_8_R3.PacketPlayOutTitle; import net.minecraft.server.v1_8_R3.PlayerConnection; -import net.minecraft.server.v1_8_R3.PlayerInteractManager; -import net.minecraft.server.v1_8_R3.WorldServer; -import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; -import org.bukkit.craftbukkit.v1_8_R3.CraftServer; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftItem; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_8_R3.util.CraftChatMessage; @@ -34,38 +26,9 @@ public class NMSPlayersImpl implements NMSPlayers { - private final SuperiorSkyblockPlugin plugin; - - public NMSPlayersImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - @Override - public void clearInventory(OfflinePlayer offlinePlayer) { - if (offlinePlayer.isOnline() || offlinePlayer instanceof Player) { - Player player = offlinePlayer instanceof Player ? (Player) offlinePlayer : offlinePlayer.getPlayer(); - player.getInventory().clear(); - player.getEnderChest().clear(); - return; - } - - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - WorldServer worldServer = server.getWorldServer(0); - EntityPlayer entity = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer)); - Player targetPlayer = entity.getBukkitEntity(); - - targetPlayer.loadData(); - - clearInventory(targetPlayer); - - //Setting the entity to the spawn location - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); - entity.world = ((CraftWorld) spawnLocation.getWorld()).getHandle(); - entity.setPositionRotation(spawnLocation.getX(), spawnLocation.getY(), spawnLocation.getZ(), spawnLocation.getYaw(), spawnLocation.getPitch()); - - targetPlayer.saveData(); + public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { + return OfflinePlayerDataImpl.create(offlinePlayer); } @Override diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/player/OfflinePlayerDataImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/player/OfflinePlayerDataImpl.java new file mode 100644 index 0000000000..7c38c1e8d9 --- /dev/null +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/player/OfflinePlayerDataImpl.java @@ -0,0 +1,70 @@ +package com.bgsoftware.superiorskyblock.nms.v1_8_R3.player; + +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.mojang.authlib.GameProfile; +import net.minecraft.server.v1_8_R3.EntityPlayer; +import net.minecraft.server.v1_8_R3.MinecraftServer; +import net.minecraft.server.v1_8_R3.PlayerInteractManager; +import net.minecraft.server.v1_8_R3.WorldServer; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.craftbukkit.v1_8_R3.CraftServer; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.util.Optional; + +public class OfflinePlayerDataImpl implements OfflinePlayerData { + + private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); + + private Player fakePlayer; + + public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { + return POOL.obtain().initialize(offlinePlayer); + } + + private OfflinePlayerDataImpl() { + + } + + private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { + GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), + Optional.ofNullable(offlinePlayer.getName()).orElse("")); + + MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); + WorldServer worldServer = server.getWorldServer(0); + EntityPlayer entityPlayer = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer)); + this.fakePlayer = entityPlayer.getBukkitEntity(); + this.fakePlayer.loadData(); + + return this; + } + + @Override + public Player getFakeOnlinePlayer() { + return this.fakePlayer; + } + + @Override + public void setLocation(Location location) { + EntityPlayer entityPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); + entityPlayer.world = ((CraftWorld) location.getWorld()).getHandle(); + entityPlayer.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + @Override + public void applyChanges() { + this.fakePlayer.saveData(); + } + + @Override + public void release() { + this.fakePlayer = null; + POOL.release(this); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index 52855bd9ad..86c0f648fe 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -75,6 +75,7 @@ import com.bgsoftware.superiorskyblock.platform.event.GameEventsDispatcher; import com.bgsoftware.superiorskyblock.player.PlayersManagerImpl; import com.bgsoftware.superiorskyblock.player.container.DefaultPlayersContainer; +import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import com.bgsoftware.superiorskyblock.player.respawn.RespawnActions; import com.bgsoftware.superiorskyblock.service.ServicesHandler; import com.bgsoftware.superiorskyblock.world.Dimensions; @@ -178,6 +179,7 @@ public void onLoad() { IslandPrivileges.registerPrivileges(); SortingTypes.registerSortingTypes(); IslandFlags.registerFlags(); + ClearActions.registerActions(); RespawnActions.registerActions(); Dimensions.registerDimensions(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java index 84ca2b6c97..89673fa42e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; +import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import org.bukkit.command.CommandSender; import java.util.Collections; @@ -91,8 +92,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (plugin.getSettings().isTeleportOnJoin() && targetPlayer.isOnline()) targetPlayer.teleport(island); - if (plugin.getSettings().isClearOnJoin()) - plugin.getNMSPlayers().clearInventory(targetPlayer.asOfflinePlayer()); + + ClearActions.runClearActions(targetPlayer.asOfflinePlayer(), false, plugin.getSettings().getClearActionsOnJoin()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java index 600af66a93..d8275d4f91 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; +import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import org.bukkit.command.CommandSender; import java.util.Collections; @@ -82,6 +83,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (plugin.getSettings().isTeleportOnJoin()) superiorPlayer.teleport(island); + + ClearActions.runClearActions(superiorPlayer.asOfflinePlayer(), false, plugin.getSettings().getClearActionsOnJoin()); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java index 91adf0485c..6f3f1655cd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; +import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import org.bukkit.command.CommandSender; import java.util.Arrays; @@ -101,8 +102,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ if (plugin.getSettings().isTeleportOnJoin()) superiorPlayer.teleport(island); - if (plugin.getSettings().isClearOnJoin()) - plugin.getNMSPlayers().clearInventory(superiorPlayer.asPlayer()); + + ClearActions.runClearActions(superiorPlayer.asOfflinePlayer(), false, plugin.getSettings().getClearActionsOnJoin()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdLeave.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdLeave.java index 9b0b15e30b..d688b5d4a7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdLeave.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdLeave.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import org.bukkit.command.CommandSender; import java.util.Collections; @@ -70,17 +71,9 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ if (plugin.getSettings().isLeaveConfirm()) { plugin.getMenus().openConfirmLeave(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView())); - return; + } else { + IslandUtils.handleLeaveIsland(superiorPlayer, island); } - - if (!PluginEventsFactory.callIslandQuitEvent(island, superiorPlayer)) - return; - - island.kickMember(superiorPlayer); - - IslandUtils.sendMessage(island, Message.LEAVE_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); - - Message.LEFT_ISLAND.send(superiorPlayer); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index db89222bc0..f9a76917a0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.config.section.WorldsSection; @@ -143,7 +144,6 @@ public class SettingsContainer { public final boolean transferConfirm; public final String spawnersProvider; public final String stackedBlocksProvider; - public final boolean disbandInventoryClear; public final boolean islandNamesRequiredForCreation; public final int islandNamesMaxLength; public final int islandNamesMinLength; @@ -154,7 +154,11 @@ public class SettingsContainer { public final boolean teleportOnCreate; public final boolean teleportOnJoin; public final boolean teleportOnKick; - public final boolean clearOnJoin; + public final boolean teleportOnLeave; + public final List clearActionsOnDisband; + public final List clearActionsOnJoin; + public final List clearActionsOnKick; + public final List clearActionsOnLeave; public final boolean rateOwnIsland; public final boolean changeIslandRating; public final List defaultSettings; @@ -387,7 +391,6 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config transferConfirm = config.getBoolean("transfer-confirm"); spawnersProvider = config.getString("spawners-provider", "AUTO"); stackedBlocksProvider = config.getString("stacked-blocks-provider", "AUTO"); - disbandInventoryClear = config.getBoolean("disband-inventory-clear", true); islandNamesRequiredForCreation = config.getBoolean("island-names.required-for-creation", true); islandNamesMaxLength = config.getInt("island-names.max-length", 16); islandNamesMinLength = config.getInt("island-names.min-length", 3); @@ -400,7 +403,11 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config teleportOnCreate = config.getBoolean("teleport-on-create", true); teleportOnJoin = config.getBoolean("teleport-on-join", false); teleportOnKick = config.getBoolean("teleport-on-kick", true); - clearOnJoin = config.getBoolean("clear-on-join", false); + teleportOnLeave = config.getBoolean("teleport-on-leave", false); + clearActionsOnDisband = loadClearActions(config.getStringList("clear-on-disband")); + clearActionsOnJoin = loadClearActions(config.getStringList("clear-on-join")); + clearActionsOnKick = loadClearActions(config.getStringList("clear-on-kick")); + clearActionsOnLeave = loadClearActions(config.getStringList("clear-on-leave")); rateOwnIsland = config.getBoolean("rate-own-island", false); changeIslandRating = config.getBoolean("change-island-rating", true); defaultSettings = Collections.unmodifiableList(config.getStringList("default-settings") @@ -566,6 +573,18 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config commandsPerPage = config.getInt("commands-per-page", 7); } + private List loadClearActions(List clearActionsNames) { + List clearActions = new LinkedList<>(); + clearActionsNames.forEach(clearAction -> { + try { + clearActions.add(ClearAction.getByName(clearAction)); + } catch (NullPointerException error) { + Log.warnFromFile("config.yml", "Invalid clear action ", clearAction + ", skipping..."); + } + }); + return Collections.unmodifiableList(clearActions); + } + private List loadInteractables(SuperiorSkyblockPlugin plugin) { File file = new File(plugin.getDataFolder(), "interactables.yml"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index e810855918..19c44407ba 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.config.section.AFKIntegrationsSection; import com.bgsoftware.superiorskyblock.config.section.DatabaseSection; @@ -25,6 +26,7 @@ import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import org.bukkit.Location; import org.bukkit.configuration.file.YamlConfiguration; @@ -32,6 +34,7 @@ import java.io.IOException; import java.math.BigInteger; import java.math.RoundingMode; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -274,7 +277,8 @@ public String getStackedBlocksProvider() { @Override public boolean isDisbandInventoryClear() { - return this.global.isDisbandInventoryClear(); + List clearActions = this.global.getClearActionsOnDisband(); + return clearActions.contains(ClearActions.ENDER_CHEST) && clearActions.contains(ClearActions.INVENTORY); } @Override @@ -297,9 +301,35 @@ public boolean isTeleportOnKick() { return this.global.isTeleportOnKick(); } + @Override + public boolean isTeleportOnLeave() { + return this.global.isTeleportOnLeave(); + } + @Override public boolean isClearOnJoin() { - return this.global.isClearOnJoin(); + List clearActions = this.global.getClearActionsOnJoin(); + return clearActions.contains(ClearActions.ENDER_CHEST) && clearActions.contains(ClearActions.INVENTORY); + } + + @Override + public List getClearActionsOnDisband() { + return this.global.getClearActionsOnDisband(); + } + + @Override + public List getClearActionsOnJoin() { + return this.global.getClearActionsOnJoin(); + } + + @Override + public List getClearActionsOnKick() { + return this.global.getClearActionsOnKick(); + } + + @Override + public List getClearActionsOnLeave() { + return this.global.getClearActionsOnLeave(); } @Override @@ -661,6 +691,21 @@ private void loadContainerFromConfig(YamlConfiguration cfg) throws ManagerLoadEx } private void convertData(YamlConfiguration cfg) { + if (cfg.isBoolean("disband-inventory-clear")) { + if (cfg.getBoolean("disband-inventory-clear")) { + cfg.set("clear-on-disband", Arrays.asList("ENDER_CHEST", "INVENTORY")); + } else { + cfg.set("clear-on-disband", Collections.emptyList()); + } + cfg.set("disband-inventory-clear", null); + } + if (cfg.isBoolean("clear-on-join")) { + if (cfg.getBoolean("disband-inventory-clear")) { + cfg.set("clear-on-join", Arrays.asList("ENDER_CHEST", "INVENTORY")); + } else { + cfg.set("clear-on-join", Collections.emptyList()); + } + } if (cfg.isInt("disband-count")) { cfg.set("default-disband-count", cfg.getInt("disband-count") == 0 ? -1 : cfg.getInt("disband-count")); cfg.set("disband-count", null); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index a26959df68..b42e6b55ae 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; import org.bukkit.Location; @@ -133,10 +134,6 @@ public String getStackedBlocksProvider() { return getContainer().stackedBlocksProvider; } - public boolean isDisbandInventoryClear() { - return getContainer().disbandInventoryClear; - } - public boolean isTeleportOnCreate() { return getContainer().teleportOnCreate; } @@ -149,8 +146,24 @@ public boolean isTeleportOnKick() { return getContainer().teleportOnKick; } - public boolean isClearOnJoin() { - return getContainer().clearOnJoin; + public boolean isTeleportOnLeave() { + return getContainer().teleportOnLeave; + } + + public List getClearActionsOnDisband() { + return getContainer().clearActionsOnDisband; + } + + public List getClearActionsOnJoin() { + return getContainer().clearActionsOnJoin; + } + + public List getClearActionsOnKick() { + return getContainer().clearActionsOnKick; + } + + public List getClearActionsOnLeave() { + return getContainer().clearActionsOnLeave; } public boolean isRateOwnIsland() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LeaveButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LeaveButton.java index 44159bf81b..f2ee66f6fb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LeaveButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/LeaveButton.java @@ -5,18 +5,15 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuTemplateButton; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractMenuViewButton; import com.bgsoftware.superiorskyblock.core.menu.button.MenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.view.BaseMenuView; -import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.event.inventory.InventoryClickEvent; -import java.util.Collections; import java.util.List; public class LeaveButton extends AbstractMenuViewButton { @@ -35,12 +32,8 @@ public void onButtonClick(InventoryClickEvent clickEvent) { SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); Island island = inventoryViewer.getIsland(); - if (getTemplate().leaveIsland && island != null && PluginEventsFactory.callIslandQuitEvent(island, inventoryViewer)) { - island.kickMember(inventoryViewer); - - IslandUtils.sendMessage(island, Message.LEAVE_ANNOUNCEMENT, Collections.emptyList(), inventoryViewer.getName()); - - Message.LEFT_ISLAND.send(inventoryViewer); + if (getTemplate().leaveIsland && island != null) { + IslandUtils.handleLeaveIsland(inventoryViewer, island); } BukkitExecutor.sync(menuView::closeView, 1L); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java index 15e0fefcd9..76f50f001b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.enums.BorderColor; +import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; @@ -228,6 +229,17 @@ public static boolean checkKickRestrictions(SuperiorPlayer superiorPlayer, Islan return true; } + public static void handleLeaveIsland(SuperiorPlayer superiorPlayer, Island island) { + if (!PluginEventsFactory.callIslandQuitEvent(island, superiorPlayer)) + return; + + island.removeMember(superiorPlayer, MemberRemoveReason.LEAVE); + + IslandUtils.sendMessage(island, Message.LEAVE_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); + + Message.LEFT_ISLAND.send(superiorPlayer); + } + public static void handleKickPlayer(SuperiorPlayer caller, Island island, SuperiorPlayer target) { handleKickPlayer(caller, caller.getName(), island, target); } @@ -236,7 +248,7 @@ public static void handleKickPlayer(SuperiorPlayer caller, String callerName, Is if (!PluginEventsFactory.callIslandKickEvent(island, caller, target)) return; - island.kickMember(target); + island.removeMember(target, MemberRemoveReason.KICK); IslandUtils.sendMessage(island, Message.KICK_ANNOUNCEMENT, Collections.emptyList(), target.getName(), callerName); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index eb87b9775f..aad10246a4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; +import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider; import com.bgsoftware.superiorskyblock.api.island.BlockChangeResult; @@ -97,6 +98,7 @@ import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeIslandEffects; +import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import com.bgsoftware.superiorskyblock.world.GeneratorType; @@ -185,7 +187,7 @@ protected PlaceholdersService create() { private final BlockPosition center; private final long creationTime; @Nullable - private final String schemName; + private final String schematicName; /* * Island Upgrade Values */ @@ -276,7 +278,7 @@ public SIsland(IslandBuilderImpl builder) { this.creationTime = builder.creationTime; this.islandName = builder.islandName; this.islandRawName = Formatters.STRIP_COLOR_FORMATTER.format(this.islandName); - this.schemName = builder.islandType; + this.schematicName = builder.islandType; this.discord = builder.discord; this.paypal = builder.paypal; this.bonusWorth.set(builder.bonusWorth); @@ -549,7 +551,7 @@ public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) { if (!addedNewMember) return; - // Remove player from being coop, invited and its ratings + // Remove player from being cooped, invited and its ratings removeCoop(superiorPlayer); revokeInvite(superiorPlayer); removeRating(superiorPlayer); @@ -575,10 +577,15 @@ public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) { } @Override - public void kickMember(SuperiorPlayer superiorPlayer) { + public void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason memberRemoveReason) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); + Preconditions.checkNotNull(memberRemoveReason, "memberRemoveReason parameter cannot be null."); - Log.debug(Debug.KICK_MEMBER, owner.getName(), superiorPlayer.getName()); + if (memberRemoveReason == MemberRemoveReason.KICK) { + Log.debug(Debug.KICK_MEMBER, owner.getName(), superiorPlayer.getName()); + } else if (memberRemoveReason == MemberRemoveReason.LEAVE) { + Log.debug(Debug.LEAVE_ISLAND, owner.getName(), superiorPlayer.getName()); + } boolean removedMember = members.writeAndGet(members -> members.remove(superiorPlayer)); @@ -595,13 +602,22 @@ public void kickMember(SuperiorPlayer superiorPlayer) { superiorPlayer.setIsland(null); + if (memberRemoveReason == MemberRemoveReason.KICK) { + ClearActions.runClearActions(superiorPlayer.asOfflinePlayer(), false, plugin.getSettings().getClearActionsOnKick()); + } else if (memberRemoveReason == MemberRemoveReason.LEAVE) { + ClearActions.runClearActions(superiorPlayer.asOfflinePlayer(), false, plugin.getSettings().getClearActionsOnLeave()); + } + superiorPlayer.runIfOnline(player -> { MenuView openedView = superiorPlayer.getOpenedView(); if (openedView != null) openedView.closeView(); - if (plugin.getSettings().isTeleportOnKick() && getAllPlayersInside().contains(superiorPlayer)) { + boolean shouldTeleport = (memberRemoveReason == MemberRemoveReason.KICK && plugin.getSettings().isTeleportOnKick()) || + (memberRemoveReason == MemberRemoveReason.LEAVE && plugin.getSettings().isTeleportOnLeave()); + + if (shouldTeleport && getAllPlayersInside().contains(superiorPlayer)) { superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); } else { updateIslandFly(superiorPlayer); @@ -621,6 +637,12 @@ public void kickMember(SuperiorPlayer superiorPlayer) { IslandsDatabaseBridge.removeMember(this, superiorPlayer); } + @Override + @Deprecated + public void kickMember(SuperiorPlayer superiorPlayer) { + removeMember(superiorPlayer, MemberRemoveReason.KICK); + } + @Override public boolean isMember(SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); @@ -645,7 +667,7 @@ public void banMember(SuperiorPlayer superiorPlayer, @Nullable SuperiorPlayer wh return; if (isMember(superiorPlayer)) - kickMember(superiorPlayer); + removeMember(superiorPlayer, MemberRemoveReason.KICK); plugin.getMenus().refreshIslandBannedPlayers(this); @@ -1765,11 +1787,10 @@ public void disbandIsland() { if (islandMember.equals(owner)) { owner.setIsland(null); } else { - kickMember(islandMember); + removeMember(islandMember, MemberRemoveReason.DISBAND); } - if (plugin.getSettings().isDisbandInventoryClear()) - plugin.getNMSPlayers().clearInventory(islandMember.asOfflinePlayer()); + ClearActions.runClearActions(islandMember.asOfflinePlayer(), true, plugin.getSettings().getClearActionsOnDisband()); for (Mission mission : plugin.getMissions().getPlayerMissions()) { MissionData missionData = plugin.getMissions().getMissionData(mission).orElse(null); @@ -4496,7 +4517,7 @@ public int getGeneratedSchematicsFlag() { @Override public String getSchematicName() { - return this.schemName == null ? "" : this.schemName; + return this.schematicName == null ? "" : this.schematicName; } @Override @@ -4583,7 +4604,7 @@ private void runCalcIslandWorthInternal(@Nullable SuperiorPlayer asker, @Nullabl Message.ISLAND_WORTH_TIME_OUT.send(asker); } else { Log.entering(owner.getName(), asker); - Log.error(error, "An unexepcted error occurred while calculating island worth:"); + Log.error(error, "An unexpected error occurred while calculating island worth:"); if (asker != null) Message.ISLAND_WORTH_ERROR.send(asker); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 9e8239baea..37344f2a57 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -4,6 +4,7 @@ import com.bgsoftware.common.annotations.Size; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; +import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.island.BlockChangeResult; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -257,10 +258,16 @@ public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) { } @Override + @Deprecated public void kickMember(SuperiorPlayer superiorPlayer) { // Do nothing. } + @Override + public void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason memberRemoveReason) { + // Do nothing. + } + @Override public boolean isMember(SuperiorPlayer superiorPlayer) { return false; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSPlayers.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSPlayers.java index f0a2602808..5f052a4f88 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSPlayers.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSPlayers.java @@ -3,6 +3,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import com.mojang.authlib.properties.Property; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Item; @@ -12,7 +13,7 @@ public interface NMSPlayers { - void clearInventory(OfflinePlayer offlinePlayer); + OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer); void setSkinTexture(SuperiorPlayer superiorPlayer); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/player/OfflinePlayerData.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/player/OfflinePlayerData.java new file mode 100644 index 0000000000..b0a4c5758d --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/player/OfflinePlayerData.java @@ -0,0 +1,18 @@ +package com.bgsoftware.superiorskyblock.nms.player; + +import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public interface OfflinePlayerData extends ObjectsPool.Releasable { + + Player getFakeOnlinePlayer(); + + void setLocation(Location location); + + void applyChanges(); + + @Override + void release(); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java b/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java new file mode 100644 index 0000000000..2183da9eb5 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java @@ -0,0 +1,119 @@ +package com.bgsoftware.superiorskyblock.player.inventory; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.world.Dimensions; +import com.bgsoftware.superiorskyblock.world.EntityTeleports; +import org.bukkit.Location; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffect; + +import java.util.Collection; + +public class ClearActions { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + public static final ClearAction EFFECTS = register(new ClearAction("EFFECTS") { + + @Override + public void doClear(Player player) { + for (PotionEffect potionEffect : player.getActivePotionEffects()) + player.removePotionEffect(potionEffect.getType()); + } + + }); + + public static final ClearAction ENDER_CHEST = register(new ClearAction("ENDER_CHEST") { + + @Override + public void doClear(Player player) { + player.getEnderChest().clear(); + } + + }); + + public static final ClearAction EXPERIENCE = register(new ClearAction("EXPERIENCE") { + + @Override + public void doClear(Player player) { + player.setExp(0); + player.setLevel(0); + player.setTotalExperience(0); + } + + }); + + public static final ClearAction HEALTH = register(new ClearAction("HEALTH") { + + @Override + public void doClear(Player player) { + player.setHealth(player.getMaxHealth()); + } + + }); + + public static final ClearAction HUNGER = register(new ClearAction("HUNGER") { + + @Override + public void doClear(Player player) { + player.setFoodLevel(20); + } + + }); + + public static final ClearAction INVENTORY = register(new ClearAction("INVENTORY") { + + @Override + public void doClear(Player player) { + player.getInventory().clear(); + } + + }); + + private ClearActions() { + + } + + public static void registerActions() { + // Do nothing, only trigger all the register calls + } + + public static void runClearActions(OfflinePlayer offlinePlayer, boolean teleportToSpawn, Collection clearActions) { + OfflinePlayerData offlinePlayerData; + Player onlinePlayer; + + if (offlinePlayer.isOnline()) { + offlinePlayerData = null; + onlinePlayer = offlinePlayer.getPlayer(); + } else { + offlinePlayerData = plugin.getNMSPlayers().createOfflinePlayerData(offlinePlayer); + onlinePlayer = offlinePlayerData.getFakeOnlinePlayer(); + } + + try { + clearActions.forEach(clearAction -> clearAction.doClear(onlinePlayer)); + + Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); + if (offlinePlayerData != null) { + if (teleportToSpawn) + offlinePlayerData.setLocation(spawnLocation); + offlinePlayerData.applyChanges(); + } else if (teleportToSpawn) { + EntityTeleports.teleport(onlinePlayer, spawnLocation); + } + } finally { + if (offlinePlayerData != null) + offlinePlayerData.release(); + } + } + + private static ClearAction register(ClearAction clearAction) { + ClearAction.register(clearAction); + return clearAction; + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 2665aabcbb..92a758cecd 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -463,9 +463,6 @@ spawners-provider: 'AUTO' # Providers: Auto, WildStacker, RoseStacker stacked-blocks-provider: 'AUTO' -# Should inventories of island members get cleared after disbanding their island? -disband-inventory-clear: true - # All settings related to island names. island-names: # Should creation of islands will ask for name (/is create )? @@ -492,17 +489,39 @@ island-names: # Should the plugin prevent players from using player names as island names? prevent-player-names: false -# Should players get teleported to the island after they create it? +# Should players get teleported to the island when they create it? teleport-on-create: true -# Should players get teleported to the island after they accept an invite? +# Should players get teleported to the island when they accept an invite? teleport-on-join: false # Should players get teleported to spawn when they are kicked from their island? teleport-on-kick: true -# Should the inventory of the players get cleared after they accept an invite? -clear-on-join: false +# Should players get teleported to spawn when they leave an island? +teleport-on-leave: false + +# List of clear actions to perform on island members when their island is disbanded. +# Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY +# You can disable this feature by setting the section to 'clear-on-disband: []' +clear-on-disband: + - ENDER_CHEST + - INVENTORY + +# List of clear actions to perform on players when they accept an invite. +# Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY +# You can disable this feature by setting the section to 'clear-on-join: []' +clear-on-join: [] + +# List of clear actions to perform on players when they are kicked from their island. +# Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY +# You can disable this feature by setting the section to 'clear-on-kick: []' +clear-on-kick: [] + +# List of clear actions to perform on players when they leave an island. +# Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY +# You can disable this feature by setting the section to 'clear-on-leave: []' +clear-on-leave: [] # Should players be able to rate their own islands? rate-own-island: false From c3dcf56143ab64b143eee71a2dca055fe5b49cef Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 29 Aug 2025 18:22:21 +0300 Subject: [PATCH 278/600] Ensure Island#executeCommand is running sync --- .../superiorskyblock/island/SIsland.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index aad10246a4..eea9c5e313 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -2234,15 +2234,17 @@ public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ig Log.debug(Debug.EXECUTE_ISLAND_COMMANDS, owner.getName(), command, onlyOnlineMembers, Arrays.toString(ignoredMembers)); - forEachIslandMember(ignoredMembers, onlyOnlineMembers, islandMember -> { - String playerCommand = command; + BukkitExecutor.ensureMain(() -> { + forEachIslandMember(ignoredMembers, onlyOnlineMembers, islandMember -> { + String playerCommand = command; - if (!Text.isBlank(playerCommand)) { - playerCommand = placeholdersService.get().parsePlaceholders(islandMember.asOfflinePlayer(), playerCommand) - .replace("{player-name}", islandMember.getName()); - } + if (!Text.isBlank(playerCommand)) { + playerCommand = placeholdersService.get().parsePlaceholders(islandMember.asOfflinePlayer(), playerCommand) + .replace("{player-name}", islandMember.getName()); + } - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), playerCommand); + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), playerCommand); + }); }); } From 149874844e2c847c0a575dd71e3bd3a331722b31 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 29 Aug 2025 18:22:43 +0300 Subject: [PATCH 279/600] Fix a potential NPE when creating title component without title / subtitle --- .../core/messages/component/impl/TitleComponent.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java index 31148e0ca1..2b26ac138c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/impl/TitleComponent.java @@ -26,9 +26,9 @@ public static IMessageComponent of(@Nullable String titleMessage, @Nullable Stri EmptyMessageComponent.getInstance() : new TitleComponent(titleMessage, subtitleMessage, fadeIn, duration, fadeOut); } - private TitleComponent(String titleMessage, String subtitleMessage, int fadeIn, int duration, int fadeOut) { - this.titleMessage = MessageContent.parse(titleMessage); - this.subtitleMessage = MessageContent.parse(subtitleMessage); + private TitleComponent(@Nullable String titleMessage, @Nullable String subtitleMessage, int fadeIn, int duration, int fadeOut) { + this.titleMessage = Text.isBlank(titleMessage) ? MessageContent.EMPTY : MessageContent.parse(titleMessage); + this.subtitleMessage = Text.isBlank(subtitleMessage) ? MessageContent.EMPTY : MessageContent.parse(subtitleMessage); this.fadeIn = fadeIn; this.duration = duration; this.fadeOut = fadeOut; From c7d21b04a9bd0f76ca8e1e9f7b1a912ab4147706 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 30 Aug 2025 23:09:43 +0200 Subject: [PATCH 280/600] Fixed bank error message when vault is not installed (#2618) --- .../bgsoftware/superiorskyblock/core/menu/MenuActions.java | 6 ++++++ .../bgsoftware/superiorskyblock/core/messages/Message.java | 1 + .../external/economy/EconomyProvider_Default.java | 4 ++-- src/main/resources/lang/de-DE.yml | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/tr-TR.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + 15 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java index 15dd536a85..c6a4170db3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java @@ -51,6 +51,9 @@ public static void handleDeposit(SuperiorPlayer superiorPlayer, Island island, B case "Exceed bank limit": Message.BANK_LIMIT_EXCEED.send(superiorPlayer); break; + case "Vault is not installed": + Message.VAULT_NOT_INSTALLED.send(superiorPlayer); + break; default: Message.DEPOSIT_ERROR.send(superiorPlayer, failureReason); break; @@ -79,6 +82,9 @@ public static void handleWithdraw(SuperiorPlayer superiorPlayer, Island island, case "Bank is empty": Message.ISLAND_BANK_EMPTY.send(superiorPlayer); break; + case "Vault is not installed": + Message.VAULT_NOT_INSTALLED.send(superiorPlayer); + break; default: Message.WITHDRAW_ERROR.send(superiorPlayer, failureReason); break; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index dc982d1510..79c170beda 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -755,6 +755,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { UPDATED_PERMISSION, UPDATED_SETTINGS, UPGRADE_COOLDOWN_FORMAT, + VAULT_NOT_INSTALLED, VISITOR_BLOCK_COMMAND, WARP_ALREADY_EXIST, WARP_CATEGORY_ICON_NEW_LORE, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/economy/EconomyProvider_Default.java b/src/main/java/com/bgsoftware/superiorskyblock/external/economy/EconomyProvider_Default.java index dd735a494b..4f4e8586e1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/economy/EconomyProvider_Default.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/economy/EconomyProvider_Default.java @@ -16,12 +16,12 @@ public BigDecimal getBalance(SuperiorPlayer superiorPlayer) { @Override public EconomyResult depositMoney(SuperiorPlayer superiorPlayer, double amount) { - return new EconomyResult("&cServer doesn't have vault installed so transactions are disabled."); + return new EconomyResult("Vault is not installed"); } @Override public EconomyResult withdrawMoney(SuperiorPlayer superiorPlayer, double amount) { - return new EconomyResult("&cServer doesn't have vault installed so transactions are disabled."); + return new EconomyResult("Vault is not installed"); } } diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index dd4925b079..6885edd3f3 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -941,6 +941,7 @@ UNSAFE_WARP: '&e&lInsel | &7&oAnscheinend ist dieser Warp unsicher. Bitte versuc UPDATED_PERMISSION: '&e&lInsel | &7Aktualisierte Berechtigungen für {0}.' UPDATED_SETTINGS: '&e&lInsel | &7Die Inseleinstellungen {0} aktualisiert.' UPGRADE_COOLDOWN_FORMAT: '&c&lError | &7Du kannst erst in {0} erneut ein Upgrade durchführen.' +VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lError | &7Du kannst diesen Befehl nicht auf anderen Inseln verwenden.' WARP_ALREADY_EXIST: '&c&lError | &7Es existiert bereits ein Warp mit diesem Namen.' diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index f45d532ff6..e9424b7548 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -742,6 +742,7 @@ UNSAFE_WARP: '&e&lIsland | &7&oLooks like this warp is unsafe. Please try anothe UPDATED_PERMISSION: '&e&lIsland | &7Updated permissions for {0}.' UPDATED_SETTINGS: '&e&lIsland | &7Updated the island settings {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lError | &7You may only upgrade again in {0}.' +VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lError | &7You cannot use that command on other islands.' WARP_ALREADY_EXIST: '&c&lError | &7There is already a warp with this name.' WARP_CATEGORY_ICON_NEW_LORE: | diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 39b80be7be..692abb412e 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -739,6 +739,7 @@ UNSAFE_WARP: '&e&lIsla | &7&oParece que este warp no es seguro. Intente con otro UPDATED_PERMISSION: '&e&lIsla | &7Permisos actualizados para {0}.' UPDATED_SETTINGS: '&e&lIsla | &7Se actualizó la configuración de la isla {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lError | &7You may only upgrade again in {0}.' +VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lError | &7No puedes usar ese comando en otras islas.' WARP_ALREADY_EXIST: '&c&lError | &7Ya existe un warp con este nombre.' WARP_CATEGORY_ICON_NEW_LORE: | diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index df8dc08c1b..d89b3916dc 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -741,6 +741,7 @@ UNSAFE_WARP: '&e&lIle | &7&oIl semblerait que ce warp ne soit pas sécurisé. Ve UPDATED_PERMISSION: '&e&lIle | &7Permission mise à jour pour {0}.' UPDATED_SETTINGS: '&e&lIle | &7Paramètre de l''île mit à jour {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lErreur | &7Vous devez patienter {0} afin d''effectuer une nouvelle amélioration.' +VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lErreur | &7Vous ne pouvez pas utiliser cette commande sur d''autres îles.' WARP_ALREADY_EXIST: '&c&lErreur | &7Un warp portant ce nom éxiste déjà.' WARP_CATEGORY_ICON_NEW_LORE: | diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index ef045b633c..5d944c781c 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -747,6 +747,7 @@ UNSAFE_WARP: '&e&lIsola | &7&oSembra che questa warp non sia sicura. Per favore, UPDATED_PERMISSION: '&e&lIsola | &7Autorizzazioni aggiornate per {0}.' UPDATED_SETTINGS: '&e&lIsola | &7Aggiornate le impostazioni dell''isola {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lError | &7Puoi eseguire nuovamente l''aggiornamento solo tra {0}.' +VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lErrore | &7Non puoi usare questo comando quando ti trovi sopra ad altre isole.' WARP_ALREADY_EXIST: '&c&lErrore | &7C''è già una warp con questo nome.' WARP_CATEGORY_ICON_NEW_LORE: | diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 4ec339c5b7..4b5300b04a 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -761,6 +761,7 @@ UNSAFE_WARP: '&e&lיא | &7&oרחא םוקימ הסנ אנא .חוטב וניא UPDATED_PERMISSION: '&e&lיא | &7{0} ל תואשרהה ונכדוע.' UPDATED_SETTINGS: '&e&lיא | &7{0} תורדגהה ונכדוע.' UPGRADE_COOLDOWN_FORMAT: '&c&lError | &7You may only upgrade again in {0}.' +VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lהאיגש | &7םירחא םייאב וזה הדוקפב שמתשהל לוכי אל התא.' WARP_ALREADY_EXIST: '&c&lהאיגש | &7הזה םשה םע םוקימ םייק רבכ.' WARP_CATEGORY_ICON_NEW_LORE: | diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 748e4545ac..3e2e9974b0 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -739,6 +739,7 @@ UNSAFE_WARP: '&e&lWyspa | &7&oWyglada na to, ze to wypaczenie jest niebezpieczne UPDATED_PERMISSION: '&e&lWyspa | &7Zaktualizowano uprawnienia dla {0}.' UPDATED_SETTINGS: '&e&lWyspa | &7Zaktualizowano ustawienia wyspy {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lBlad | &7Mozesz uaktualnic ponownie dopiero za {0}.' +VAULT_NOT_INSTALLED: '&c&lBlad | &7Na serwerze nie ma zainstalowanego pluginu Vault, wiec transakcje sa wylaczone.' VISITOR_BLOCK_COMMAND: '&c&lBlad | &7Nie mozesz uzyc tego polecenia na innych wyspach.' WARP_ALREADY_EXIST: '&c&lBlad | &7Istnieje juz warp o tej nazwie.' WARP_CATEGORY_ICON_NEW_LORE: | diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 12d8e2ecbd..5c466cd060 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -739,6 +739,7 @@ UNSAFE_WARP: '&e&lIlha | &7&oParece que este warp não é seguro. Tente outro wa UPDATED_PERMISSION: '&e&lIlha | &7Permissões atualizadas para {0}.' UPDATED_SETTINGS: '&e&lIlha | &7Configurações da ilha [{0}] atualizado.' UPGRADE_COOLDOWN_FORMAT: '&c&lErro | &7Você só pode atualizar novamente em {0}.' +VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lErro | &7Você não pode usar esse comando em outras ilhas.' WARP_ALREADY_EXIST: '&c&lErro | &7Já existe um warp com este nome.' WARP_CATEGORY_ICON_NEW_LORE: | diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 488b6944ac..f2756afda6 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -739,6 +739,7 @@ UNSAFE_WARP: '&e&lОстров | &7&oПохоже, этот варп небез UPDATED_PERMISSION: '&e&lОстров | &7Обновлены права для {0}.' UPDATED_SETTINGS: '&e&lОстров | &7Обновлены настройки острова {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lОшибка | &7Вы можете улучшить только через {0}.' +VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lОшибка | &7Вы не можете использовать эту команду на других островах.' WARP_ALREADY_EXIST: '&c&lОшибка | &7Варп с таким именем уже существует.' WARP_CATEGORY_ICON_NEW_LORE: | diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 5b01409b0c..d901f555a5 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -877,6 +877,7 @@ UNSAFE_WARP: '&e&lAda | &7&oBu ışınlanma güvensiz görünüyor. Lütfen baş UPDATED_PERMISSION: '&e&lAda | &7{0} için izinler güncellendi.' UPDATED_SETTINGS: '&e&lAda | &7Ada ayarları {0} güncellendi.' UPGRADE_COOLDOWN_FORMAT: '&c&lHata | &7Sadece {0} içinde tekrar yükseltme yapabilirsin.' +VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lHata | &7Bu komutu başka adalarda kullanamazsın.' WARP_ALREADY_EXIST: '&c&lHata | &7Bu adla bir ışınlanma noktası zaten var.' WARP_CATEGORY_ICON_NEW_LORE: | diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index d0b02ef59d..c3d25a6d8d 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -837,6 +837,7 @@ UNSAFE_WARP: '&e&lĐảo | &7&oCó vẻ như khu vực này không an toàn. Vui UPDATED_PERMISSION: '&e&lĐảo | &7Đã cập nhật quyền cho {0}.' UPDATED_SETTINGS: '&e&lĐảo | &7Thay đổi thành công điều chỉnh của đảo {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&lLỗi | &77Bạn có thể nâng cấp lại trong {0}.' +VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&lLỗi | &7Bạn không thể sử dụng lệnh này trên đảo khác.' WARP_ALREADY_EXIST: '&c&lLỗi | &7Đã có một khu vực đã được đặt với tên này.' WARP_CATEGORY_ICON_NEW_LORE: | diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index b00acb32d3..df95e7ee64 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -739,6 +739,7 @@ UNSAFE_WARP: '&e&l岛屿 | &7&o看起来该传送点不安全. 请尝试使用 UPDATED_PERMISSION: '&e&l岛屿 | &7更新了 {0} 的权限.' UPDATED_SETTINGS: '&e&l岛屿 | &7更新了岛屿设置 {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&l错误 | &7你只能在 {0} 之后才可继续进行升级操作.' +VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' VISITOR_BLOCK_COMMAND: '&c&l错误 | &7你不能对其他岛屿使用该命令.' WARP_ALREADY_EXIST: '&c&l错误 | &7已存在同名传送点.' WARP_CATEGORY_ICON_NEW_LORE: | From 2c8b88808b05059d58539d7753f1ecb7bd1b392a Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Mon, 1 Sep 2025 20:57:38 +0200 Subject: [PATCH 281/600] Added set island preview command for admins (#2623) --- .../commands/CommandTabCompletes.java | 4 +- .../commands/admin/AdminCommandsMap.java | 1 + .../admin/CmdAdminSetIslandPreview.java | 87 +++++++++++++++++++ .../commands/arguments/CommandArguments.java | 12 +++ .../commands/player/CmdCreate.java | 10 +-- .../core/messages/Message.java | 2 + src/main/resources/lang/de-DE.yml | 8 +- src/main/resources/lang/en-US.yml | 2 + src/main/resources/lang/es-ES.yml | 4 +- src/main/resources/lang/fr-FR.yml | 2 + src/main/resources/lang/it-IT.yml | 4 +- src/main/resources/lang/iw-IL.yml | 2 + src/main/resources/lang/pl-PL.yml | 8 +- src/main/resources/lang/pt-BR.yml | 4 +- src/main/resources/lang/ru-RU.yml | 2 + src/main/resources/lang/tr-TR.yml | 6 +- src/main/resources/lang/vi-VN.yml | 2 + src/main/resources/lang/zh-CN.yml | 2 + src/main/resources/plugin.yml | 2 + 19 files changed, 146 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index c532914645..083ea53b9a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -143,8 +143,8 @@ public static List getCustomComplete(String argument, IntStream tabVaria public static List getSchematics(SuperiorSkyblockPlugin plugin, String argument) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() - .filter(schematic -> !schematic.endsWith("_nether") && !schematic.endsWith("_the_end") && - schematic.toLowerCase(Locale.ENGLISH).contains(lowerArgument)) + .filter(schematic -> !schematic.endsWith("_nether") && !schematic.endsWith("_normal") && + !schematic.endsWith("_the_end") && schematic.toLowerCase(Locale.ENGLISH).contains(lowerArgument)) .build(plugin.getSchematics().getSchematics()); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java index a3543cbcfc..71d0752bc5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java @@ -59,6 +59,7 @@ public void loadDefaultCommands() { registerCommand(new CmdAdminSetCoopLimit()); registerCommand(new CmdAdminSetDisbands()); registerCommand(new CmdAdminSetEntityLimit()); + registerCommand(new CmdAdminSetIslandPreview()); registerCommand(new CmdAdminSetLeader()); registerCommand(new CmdAdminSetPermission()); registerCommand(new CmdAdminSetRate()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java new file mode 100644 index 0000000000..4799600a23 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java @@ -0,0 +1,87 @@ +package com.bgsoftware.superiorskyblock.commands.admin; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.schematic.Schematic; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; +import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.core.serialization.Serializers; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class CmdAdminSetIslandPreview implements ISuperiorCommand { + + @Override + public List getAliases() { + return Arrays.asList("setislandpreview", "setschematicpreview"); + } + + @Override + public String getPermission() { + return "superior.admin.setislandpreview"; + } + + @Override + public String getUsage(java.util.Locale locale) { + return "admin setislandpreview <" + Message.COMMAND_ARGUMENT_SCHEMATIC_NAME.getMessage(locale) + ">"; + } + + @Override + public String getDescription(java.util.Locale locale) { + return Message.COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW.getMessage(locale); + } + + @Override + public int getMinArgs() { + return 3; + } + + @Override + public int getMaxArgs() { + return 3; + } + + @Override + public boolean canBeExecutedByConsole() { + return false; + } + + @Override + public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + Schematic schematic = CommandArguments.getSchematic(plugin, sender, args[2]); + + if (schematic == null) + return; + + Player player = (Player) sender; + + String schematicPreviewLocation; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = player.getLocation(wrapper.getHandle()); + schematicPreviewLocation = Serializers.LOCATION_SPACED_SERIALIZER.serialize(location); + } + + try { + plugin.getSettings().updateValue("preview-islands." + schematic.getName(), schematicPreviewLocation); + } catch (Exception error) { + Log.entering("ENTER", schematicPreviewLocation); + Log.error(error, "An unexpected error occurred while setting schematic preview:"); + } + + Message.ISLAND_PREVIEW_SET.send(sender, schematic.getName(), schematicPreviewLocation); + } + + @Override + public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + return args.length == 3 ? CommandTabCompletes.getSchematics(plugin, args[2]) : Collections.emptyList(); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java index 7c78d49136..4b586801af 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.missions.Mission; +import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; @@ -387,6 +388,17 @@ public static Dimension getDimension(CommandSender sender, String argument) { return dimension; } + public static Schematic getSchematic(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { + Schematic schematic = plugin.getSchematics().getSchematic(argument); + + if (schematic == null || argument.endsWith("_nether") || argument.endsWith("_normal") || argument.endsWith("_the_end")) { + Message.INVALID_SCHEMATIC.send(sender, argument); + return null; + } + + return schematic; + } + public static NumberArgument getInterval(CommandSender sender, String argument) { NumberArgument interval = getInt(sender, argument, Message.INVALID_INTERVAL); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCreate.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCreate.java index 7d780399d4..7a283193ba 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCreate.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCreate.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.menu.MenuActions; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -97,12 +98,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ if (plugin.getSettings().isSchematicNameArgument() && args.length == (plugin.getSettings().getIslandNames().isRequiredForCreation() ? 3 : 2)) { - String schematicName = args[plugin.getSettings().getIslandNames().isRequiredForCreation() ? 2 : 1]; - schematic = plugin.getSchematics().getSchematic(schematicName); - if (schematic == null || schematicName.endsWith("_nether") || schematicName.endsWith("_the_end")) { - Message.INVALID_SCHEMATIC.send(sender, schematicName); + schematic = CommandArguments.getSchematic(plugin, sender, + args[plugin.getSettings().getIslandNames().isRequiredForCreation() ? 2 : 1]); + + if (schematic == null) return; - } } if (schematic == null) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 79c170beda..203502322a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -236,6 +236,7 @@ public enum Message { COMMAND_DESCRIPTION_ADMIN_SET_EFFECT, COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT, COMMAND_DESCRIPTION_ADMIN_SET_GENERATOR, + COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW, COMMAND_DESCRIPTION_ADMIN_SET_LEADER, COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS, COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION, @@ -530,6 +531,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { ISLAND_PREVIEW_CANCEL_DISTANCE, ISLAND_PREVIEW_CANCEL_TEXT, ISLAND_PREVIEW_CONFIRM_TEXT, + ISLAND_PREVIEW_SET, ISLAND_PREVIEW_START, ISLAND_PROTECTED, ISLAND_PROTECTED_OPPED, diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 6885edd3f3..37fbb4d7a8 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -280,6 +280,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Lege die Inseleffektstufe der Insel eines Spielers fest. COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Entity-Limit für die Insel eines anderen Spielers festlegen. +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: Übertrage eine Insel an jemand anderen. COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Lege den Mob-Drop-Multiplikator für die Insel eines anderen Spielers fest. @@ -614,11 +615,12 @@ ISLAND_OPENED: '&e&lIsland | &7Die Insel wurde erfolgreich der Öffentlichkeit z ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVorschau | &7Du hast sich zu weit entfernt und befindest dich nicht mehr im Vorschaumodus.' ISLAND_PREVIEW_CANCEL: '&e&lVorschau | &7Du hast den Vorschaumodus abgebrochen.' -ISLAND_PREVIEW_CONFIRM_TEXT: BESTÄTIGEN -ISLAND_PREVIEW_CANCEL_TEXT: ABBRECHEN +ISLAND_PREVIEW_CONFIRM_TEXT: 'BESTÄTIGEN' +ISLAND_PREVIEW_CANCEL_TEXT: 'ABBRECHEN' +ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lVorschau | &7Du hast den Vorschaumodus für den Schaltplan {0} gestartet. - &e&lVorschau | &7Gebe &a&lCONFIRM &7 ein, um eine neue Insel zu erstellen, oder &c&lCANCEL &7, um den Vorschaumodus abzubrechen. + &e&lVorschau | &7Gebe &a&lBESTÄTIGEN &7 ein, um eine neue Insel zu erstellen, oder &c&lABBRECHEN &7, um den Vorschaumodus abzubrechen. &e&lVorschau | &7Du kannst das Inselgebiet nicht verlassen, sonst wird der Vorschaumodus automatisch abgebrochen. ISLAND_PROTECTED: '&c&lError | &7Diese Insel ist geschützt.' ISLAND_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index e9424b7548..7eba459d34 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -204,6 +204,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Set the crop growth multiplier for a COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Set a player''s amount of island disbands.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Set the island effect level of another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Set entity limit for another player''s island.' +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Transfer an island to someone else.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Set the mob drops multiplier for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Set a required role for a permission for all the islands.' @@ -496,6 +497,7 @@ ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPreview | &7You went too far away, and you ISLAND_PREVIEW_CANCEL: '&e&lPreview | &7You cancelled the preview mode.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' ISLAND_PREVIEW_CANCEL_TEXT: 'CANCEL' +ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lPreview | &7You started the preview mode for the schematic {0}. &e&lPreview | &7Type &a&lCONFIRM &7to create a new island, or &c&lCANCEL &7to cancel the preview mode. diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 692abb412e..7b2607482d 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -204,6 +204,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Establezca el multiplicador de creci COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Establece la cantidad de islas disueltas de un jugador.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Establece el nivel de efecto de isla de la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Establece límite de entidades para la isla de otro jugador.' +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Transfiere una isla a otra persona.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Establece el multiplicador de drop de los mobs para la isla de otro jugador' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Establezca un rol obligatorio para obtener un permiso para todas las islas.' @@ -495,7 +496,8 @@ ISLAND_OPENED: '&e&lIsla | &7Abrió con éxito la isla al público.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVista Previa | &7Fuiste demasiado lejos y ya no estás en modo de vista previa.' ISLAND_PREVIEW_CANCEL: '&e&lVista Previa | &7Cancelaste el modo de vista previa.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' -ISLAND_PREVIEW_CANCEL_TEXT: 'CANCEL' +ISLAND_PREVIEW_CANCEL_TEXT: 'CANCELAR' +ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lVista Previa | &7Ha iniciado el modo de vista previa de la esquematica/schematic {0}... &e&lVista Previa | &7Type &a&lCONFIRM &7para crear una nueva isla, o &c&lCANCELAR &7para cancelar el modo de vista previa. diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index d89b3916dc..c01fd9b8da 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -207,6 +207,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Définir le multiplicateur de croissa COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Définir le nombre de suppression d'îles d'un joueur. COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Définir le niveau d'un effet d'île sur l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Définir la limite d'entités pour l'île du joueur spécifié. +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: Transférer une île à quelqu'un d'autre. COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Définir le multiplicateur de drops de mobs de l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Définir un rôle nécéssaire à une permission pour toutes les îles. @@ -498,6 +499,7 @@ ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPrévisualisation | &7Vous vous êtes trop ISLAND_PREVIEW_CANCEL: '&e&lPrévisualisation | &7Vous avez annulé(e) la prévisualisation.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRMER' ISLAND_PREVIEW_CANCEL_TEXT: 'ANNULER' +ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lPrévisualisation | &7Vous avez débuté la prévisualisation de l'île {0}. &e&lPrévisualisation | &7Tapez &a&lCONFIRMER &7pour séléctionner cette île, ou &c&lANNULER &7pour annuler la prévisualisation. diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 5d944c781c..f6e1baec5b 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -207,6 +207,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Imposta il moltiplicatore della cresc COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Imposta la quantità di reset dell'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Imposta il livello dell'effetto dell'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Imposta il limite di entità per l'isola di un altro giocatore. +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: Trasferisci un'isola a qualcun altro. COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Imposta il moltiplicatore di drops dei mob per l'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: Imposta un ruolo richiesto per avere un'autorizzazione, in tutte le isole. @@ -504,9 +505,10 @@ ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lAnteprima | &7Sei andato troppo lontano, no ISLAND_PREVIEW_CANCEL: '&e&lAnteprima | &7Hai annullato la modalità di anteprima.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFERMA' ISLAND_PREVIEW_CANCEL_TEXT: 'ANNULLA' +ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lAnteprima | &7Hai avviato la modalità di anteprima per la schematica {0}. - &e&lAnteprima | &7Scrivi &a&lCONFIRM &7per creare una nuova isola, oppure &c&lCANCEL &7per annullare la modalità di anteprima. + &e&lAnteprima | &7Scrivi &a&lCONFERMA &7per creare una nuova isola, oppure &c&lANNULLA &7per annullare la modalità di anteprima. &e&lAnteprima | &7Non è possibile lasciare l'area dell'isola, altrimenti la modalità anteprima verrà annullata automaticamente. ISLAND_PROTECTED: '&c&lErrore | &7Quest''isola è protetta.' ISLAND_PROTECTED_OPPED: '&7&oPuoi aggirare questa restrizione utilizzando "/is admin bypass".' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 4b5300b04a..8c84553137 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -212,6 +212,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: רחא ןקחש לש יא של הלי COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: ןקחש לש תורתומה תוקיחמה תומכ תא תונשל. COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Set the island effect level of another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Set entity limit for another player''s island. +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: רחא ןקחשל יא לע תוגיהנמה תא ריבעהל. COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: רחא ןקחש לש יא לש םיבומ לש םיטירפה סונוב תא תונשל. @@ -514,6 +515,7 @@ ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPreview | &7You went too far away, and you ISLAND_PREVIEW_CANCEL: '&e&lPreview | &7You cancelled the preview mode.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' ISLAND_PREVIEW_CANCEL_TEXT: 'CANCEL' +ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lPreview | &7You started the preview mode for the schematic {0}. &e&lPreview | &7Type &a&lCONFIRM &7to create a new island, or &c&lCANCEL &7to cancel the preview mode. diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 3e2e9974b0..209b47b2c2 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -204,6 +204,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Ustaw mnoznik wzrostu plonów dla wy COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Ustaw ilosc rozwiazanych wysp dla gracza.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Ustaw level wyspy innego gracza' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Ustaw limit jednostek dla wyspy innego gracza.' +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Ustaw lokalizacje podgladu dla wyspy.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Przenies wyspe komus innemu.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Ustaw mnoznik dropów mobów dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Ustaw wymagana role uprawnień dla wszystkich wysp.' @@ -494,11 +495,12 @@ ISLAND_INFO_WORTH: '&e&lWyspa | &7Wartosc: {0}' ISLAND_OPENED: '&e&lWyspa | &7Pomyslnie zmieniles status wyspy na publiczny.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPodglad | &7Odszedles za daleko, nie jestes juz w trybie podgladu.' ISLAND_PREVIEW_CANCEL: '&e&lPodglad | &7Anulowales tryb podgladu.' -ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' -ISLAND_PREVIEW_CANCEL_TEXT: 'CANCEL' +ISLAND_PREVIEW_CONFIRM_TEXT: 'POTWIERDZ' +ISLAND_PREVIEW_CANCEL_TEXT: 'ANULUJ' +ISLAND_PREVIEW_SET: '&e&lPodglad | &7Pomyslnie zaktualizowano lokalizacje podgladu dla schematu {0} na {1}.' ISLAND_PREVIEW_START: | &e&lPodglad | &7Wlaczyles tryb podgladu dla schematu {0}. - &e&lPodglad | &7Wpisz &a&lCONFIRM &7by stworzyc nowa wyspe, lub &c&lCANCEL &7by wylaczyc tryb podladu. + &e&lPodglad | &7Wpisz &a&lPOTWIERDZ &7by stworzyc nowa wyspe, lub &c&lANULUJ &7by wylaczyc tryb podladu. &e&lPodglad | &7Nie mozesz opuscic terenu wyspy, w przeciwnym razie tryb podgladowy zostanie anulowany. ISLAND_PROTECTED: '&c&lBlad | &7Ta wyspa jest chroniona.' ISLAND_PROTECTED_OPPED: '&7&oMozesz ominac to ograniczenie, uzywajac "/is admin bypass".' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 5c466cd060..ce444ccc75 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -204,6 +204,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Definir o multiplicador de crescimen COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Definir a quantidade de dissoluções de ilhas de um jogador.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Definir o nível do efeito da ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Definir o limite de entidades para a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Transferir uma ilha para outra pessoa.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Definir o multiplicador de drops de mobs para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Definir uma permissão de função obrigatória para todas as ilhas.' @@ -496,9 +497,10 @@ ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVisualizar | &7Você foi muito longe e não ISLAND_PREVIEW_CANCEL: '&e&lVisualizar | &7Você cancelou o modo de visualização.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRMAR' ISLAND_PREVIEW_CANCEL_TEXT: 'CANCELAR' +ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lVisualizar | &7Você iniciou o modo de visualização para o esquema {0}. - &e&lVisualizar | &7Digite &a&lCONFIRM &7para criar uma nova ilha, ou &c&lCANCEL &7para cancelar o modo de pré-visualização. + &e&lVisualizar | &7Digite &a&lCONFIRMAR &7para criar uma nova ilha, ou &c&lCANCELAR &7para cancelar o modo de pré-visualização. &e&lPreview | &7Você não pode sair da área da ilha, caso contrário, o modo de pré-visualização será cancelado automaticamente. ISLAND_PROTECTED: '&c&lErro | &7Esta ilha está protegida.' ISLAND_PROTECTED_OPPED: '&7&oVocê pode ignorar esta restrição usando "/is admin bypass".' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index f2756afda6..6e2fd3e416 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -204,6 +204,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: 'Установить множите COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: 'Установить количество расформирований для игрока.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Установить уровень эффекта острова для другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: 'Установить лимит сущностей для острова другого игрока.' +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: 'Передать остров другому игроку.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: 'Установить множитель дропа мобов для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: 'Установить необходимую роль для разрешения для всех островов.' @@ -496,6 +497,7 @@ ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lПредпросмотр | &7Вы отош ISLAND_PREVIEW_CANCEL: '&e&lПредпросмотр | &7Вы отменили режим предпросмотра.' ISLAND_PREVIEW_CONFIRM_TEXT: 'ПОДТВЕРДИТЬ' ISLAND_PREVIEW_CANCEL_TEXT: 'ОТМЕНА' +ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lПредпросмотр | &7Вы начали режим предпросмотра для схемы {0}. &e&lПредпросмотр | &7Введите &a&lПОДТВЕРДИТЬ &7для создания нового острова или &c&lОТМЕНА &7для отмены режима предпросмотра. diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index d901f555a5..ed7d5fc8b4 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -268,6 +268,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: Başka bir oyuncunun adasının ada efekt ayarla. COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Başka bir oyuncunun adası için varlık limitini ayarla. +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: Bir adayı başkasına devret. COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Başka bir oyuncunun adası için mob düşürme çarpanını ayarla. @@ -584,8 +585,9 @@ ISLAND_OPENED: '&e&lAda | &7Ada başarıyla halka açıldı.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lÖnizleme | &7Çok uzaklaştın ve artık önizleme modunda değilsin.' ISLAND_PREVIEW_CANCEL: '&e&lÖnizleme | &7Önizleme modunu iptal ettin.' -ISLAND_PREVIEW_CONFIRM_TEXT: ONAYLA -ISLAND_PREVIEW_CANCEL_TEXT: İPTAL ET +ISLAND_PREVIEW_CONFIRM_TEXT: 'ONAYLA' +ISLAND_PREVIEW_CANCEL_TEXT: 'İPTAL ET' +ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lÖnizleme | &7{0} şematiği için önizleme modunu başlattın. &e&lÖnizleme | &7Yeni bir ada oluşturmak için &a&lONAYLA &7yaz, veya önizleme modunu iptal etmek için &c&lİPTAL ET &7yaz. diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index c3d25a6d8d..283659b82a 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -235,6 +235,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: Đặt hệ số tăng trưởng cây COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: Đặt số lượng người cho đảo của người chơi. COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: 'Đặt hiệu ứng đảo của người chơi khác.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: Đặt giới hạn vật thể của người chơi khác. +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: Chuyển một hòn đảo cho người khác. COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: Đặt số lượng vật phẩm quái rớt cho đảo của người chơi khác. @@ -552,6 +553,7 @@ ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lXem Trước | &7Bạn đã đi ra quá xa ISLAND_PREVIEW_CANCEL: '&e&lXem Trước | &7Bạn đã hủy chế độ xem trước.' ISLAND_PREVIEW_CONFIRM_TEXT: 'DONG-Y' ISLAND_PREVIEW_CANCEL_TEXT: 'HUY-BO' +ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&lXem Trước | &7Bạn đã bắt đầu chế độ xem trước schematic {0}. &e&lXem Trước | &7Nhập &a&lDONG-Y &7để tạo đảo mới, hoặc &c&lHUY-BO &7để dừng chế độ xem trước. diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index df95e7ee64..74cc816438 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -204,6 +204,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: '设置指定岛屿的作物生长倍 COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: '设置岛屿解散所需玩家数量.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: '设置指定岛屿的效果等级.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: '设置指定岛屿的实体数量限制.' +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: '将岛屿所有权转移给其他玩家.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: '设置指定岛屿的生物掉落物倍率.' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: '设置所有岛屿上的指定权限所需的职位.' @@ -496,6 +497,7 @@ ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&l结构 | &7你离得太远离了, 已自动 ISLAND_PREVIEW_CANCEL: '&e&l结构 | &7你退出了预览模式.' ISLAND_PREVIEW_CONFIRM_TEXT: '确认' ISLAND_PREVIEW_CANCEL_TEXT: '取消' +ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' ISLAND_PREVIEW_START: | &e&l结构 | &7你正在预览结构 {0}. &e&l结构 | &7输入 &a&lCONFIRM &7来创建一个新岛屿, 或 &c&lCANCEL &7取消预览模式. diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 61377447a9..dd66c26bd3 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -297,6 +297,8 @@ permissions: description: Set entity limit for another player's island. superior.admin.setgenerator: description: Change percentage of a material for the cobblestone generator. + superior.admin.setislandpreview: + description: Set the preview location for an island. superior.admin.setleader: description: Transfer an island to someone else. superior.admin.setmobdrops: From 51cd7f4231cbbd214fe2e8f28f167fad0b8dd825 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 1 Sep 2025 22:21:57 +0300 Subject: [PATCH 282/600] Fix issues related to anti xray in Spigot (#2621) --- .../nms/v1_16_R3/NMSWorldImpl.java | 4 +++- .../nms/v1_17/NMSWorldImpl.java | 4 +++- .../nms/v1_18/NMSWorldImpl.java | 10 +++++++--- .../nms/v1_19/NMSWorldImpl.java | 5 +++-- .../nms/v1_20_3/NMSWorldImpl.java | 14 ++++++++++++-- .../nms/v1_20_4/NMSWorldImpl.java | 17 +++++++++++++---- .../nms/v1_21/NMSWorldImpl.java | 17 +++++++++++++---- .../nms/v1_21_3/NMSWorldImpl.java | 17 +++++++++++++---- .../nms/v1_21_4/NMSWorldImpl.java | 17 +++++++++++++---- .../nms/v1_21_5/NMSWorldImpl.java | 16 +++++++++++++--- .../nms/v1_21_7/NMSWorldImpl.java | 16 +++++++++++++--- 11 files changed, 106 insertions(+), 31 deletions(-) diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java index c0879e1c78..b8b74a8d58 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java @@ -174,7 +174,9 @@ public void setBlock(Location location, int combinedId) { if (blockData != null) { world.getChunkProvider().flagDirty(blockPosition); - world.chunkPacketBlockController.onBlockChange(world, blockPosition, blockData, Blocks.AIR.getBlockData(), 530); + if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { + world.chunkPacketBlockController.onBlockChange(world, blockPosition, blockData, Blocks.AIR.getBlockData(), 530); + } } } } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index e99ad2a932..b08d500c3d 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -202,7 +202,9 @@ public void setBlock(Location location, int combinedId) { if (blockState != null) { serverLevel.getChunkSource().blockChanged(blockPos); - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index 8379d9e5d4..4c7c343887 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -203,7 +203,9 @@ public void setBlock(Location location, int combinedId) { if (blockState != null) { serverLevel.getChunkSource().blockChanged(blockPos); - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } } @@ -335,9 +337,11 @@ public int getMinHeight(org.bukkit.World world) { @Override public void removeAntiXray(org.bukkit.World bukkitWorld) { + if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) + return; + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) - CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); + CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); } @Override diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index 9d0fb80fba..c275992f62 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -28,7 +28,6 @@ import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; @@ -206,7 +205,9 @@ public void setBlock(Location location, int combinedId) { if (blockState != null) { serverLevel.getChunkSource().blockChanged(blockPos); - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index 9f0e47dbd5..3e0e5a2f5e 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -25,6 +25,7 @@ import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; @@ -72,6 +73,9 @@ public class NMSWorldImpl implements NMSWorld { private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, + Object.class, "chunkPacketBlockController") + .removeFinal(); private final SuperiorSkyblockPlugin plugin; @@ -202,7 +206,9 @@ public void setBlock(Location location, int combinedId) { if (blockState != null) { serverLevel.getChunkSource().blockChanged(blockPos); - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } } @@ -339,7 +345,11 @@ public int getMinHeight(org.bukkit.World world) { @Override public void removeAntiXray(org.bukkit.World bukkitWorld) { - // Doesn't exist in this version. + if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); } @Override diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index 49c62747e6..561e6889d8 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -25,9 +25,9 @@ import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; @@ -73,6 +73,9 @@ public class NMSWorldImpl implements NMSWorld { private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, + Object.class, "chunkPacketBlockController") + .removeFinal(); private final SuperiorSkyblockPlugin plugin; @@ -203,7 +206,9 @@ public void setBlock(Location location, int combinedId) { if (blockState != null) { serverLevel.getChunkSource().blockChanged(blockPos); - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } } @@ -339,8 +344,12 @@ public int getMinHeight(World world) { } @Override - public void removeAntiXray(World bukkitWorld) { - // Doesn't exist in this version. + public void removeAntiXray(org.bukkit.World bukkitWorld) { + if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); } @Override diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index 7afe76772b..7c9ce327ec 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -26,9 +26,9 @@ import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; @@ -80,6 +80,9 @@ public class NMSWorldImpl implements NMSWorld { private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, + Object.class, "chunkPacketBlockController") + .removeFinal(); private final SuperiorSkyblockPlugin plugin; @@ -254,7 +257,9 @@ public void setBlock(Location location, int combinedId) { if (blockState != null) { serverLevel.getChunkSource().blockChanged(blockPos); - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } } @@ -390,8 +395,12 @@ public int getMinHeight(World world) { } @Override - public void removeAntiXray(World bukkitWorld) { - // Doesn't exist in this version. + public void removeAntiXray(org.bukkit.World bukkitWorld) { + if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); } @Override diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index b9ba397682..a5ba998cc6 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -26,9 +26,9 @@ import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; @@ -80,6 +80,9 @@ public class NMSWorldImpl implements NMSWorld { private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, + Object.class, "chunkPacketBlockController") + .removeFinal(); private final SuperiorSkyblockPlugin plugin; @@ -254,7 +257,9 @@ public void setBlock(Location location, int combinedId) { if (blockState != null) { serverLevel.getChunkSource().blockChanged(blockPos); - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } } @@ -390,8 +395,12 @@ public int getMinHeight(World world) { } @Override - public void removeAntiXray(World bukkitWorld) { - // Doesn't exist in this version. + public void removeAntiXray(org.bukkit.World bukkitWorld) { + if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); } @Override diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index 7af243029f..7944975c93 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -26,9 +26,9 @@ import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import io.papermc.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; @@ -80,6 +80,9 @@ public class NMSWorldImpl implements NMSWorld { private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, + Object.class, "chunkPacketBlockController") + .removeFinal(); private final SuperiorSkyblockPlugin plugin; @@ -254,7 +257,9 @@ public void setBlock(Location location, int combinedId) { if (blockState != null) { serverLevel.getChunkSource().blockChanged(blockPos); - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } } @@ -390,8 +395,12 @@ public int getMinHeight(World world) { } @Override - public void removeAntiXray(World bukkitWorld) { - // Doesn't exist in this version. + public void removeAntiXray(org.bukkit.World bukkitWorld) { + if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); } @Override diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java index 728fde018a..1e8f368bbd 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java @@ -26,6 +26,7 @@ import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import io.papermc.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; @@ -79,6 +80,9 @@ public class NMSWorldImpl implements NMSWorld { private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, + Object.class, "chunkPacketBlockController") + .removeFinal(); private final SuperiorSkyblockPlugin plugin; @@ -253,7 +257,9 @@ public void setBlock(Location location, int combinedId) { if (blockState != null) { serverLevel.getChunkSource().blockChanged(blockPos); - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } } @@ -389,8 +395,12 @@ public int getMinHeight(World world) { } @Override - public void removeAntiXray(World bukkitWorld) { - // Doesn't exist in this version. + public void removeAntiXray(org.bukkit.World bukkitWorld) { + if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); } @Override diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java index 796e57f24e..e2d312956b 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java @@ -27,6 +27,7 @@ import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import io.papermc.paper.antixray.ChunkPacketBlockController; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; @@ -80,6 +81,9 @@ public class NMSWorldImpl implements NMSWorld { private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, + Object.class, "chunkPacketBlockController") + .removeFinal(); private final SuperiorSkyblockPlugin plugin; @@ -245,7 +249,9 @@ public void setBlock(Location location, int combinedId) { if (blockState != null) { serverLevel.getChunkSource().blockChanged(blockPos); - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } } } } @@ -381,8 +387,12 @@ public int getMinHeight(World world) { } @Override - public void removeAntiXray(World bukkitWorld) { - // Doesn't exist in this version. + public void removeAntiXray(org.bukkit.World bukkitWorld) { + if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); } @Override From b2604681a3575c18bfde916b4f5ed22a148e4c04 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 1 Sep 2025 22:34:05 +0300 Subject: [PATCH 283/600] Fix not stopping database executor before closing the connection to the DB (#2620) --- .../superiorskyblock/core/database/sql/DBSession.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/DBSession.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/DBSession.java index 40fe03633d..d84a46c276 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/DBSession.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/sql/DBSession.java @@ -9,6 +9,7 @@ import com.bgsoftware.common.databasebridge.sql.session.MySQLDatabaseSession; import com.bgsoftware.common.databasebridge.sql.session.SQLDatabaseSession; import com.bgsoftware.common.databasebridge.sql.session.SQLiteDatabaseSession; +import com.bgsoftware.common.databasebridge.transaction.DatabaseTransactionsExecutor; import com.bgsoftware.common.databasebridge.transaction.IDatabaseTransaction; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; @@ -126,8 +127,10 @@ public static void customQuery(String query, QueryResult quer } public static void close() { - if (isReady()) + if (isReady()) { + DatabaseTransactionsExecutor.stopActiveExecutors(); globalSession.close(); + } } public static String getColumnFilter(DatabaseFilter filter) { From 325f6241cfa5db51d94002d0cde19b57edb9b411 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Mon, 1 Sep 2025 22:04:03 +0200 Subject: [PATCH 284/600] Added new options to edit items in the menus (#2556) --- .../nms/v1_12_R1/NMSAlgorithmsImpl.java | 15 +++++ .../nms/v1_16_R3/NMSAlgorithmsImpl.java | 15 +++++ .../nms/v1_17/NMSAlgorithmsImpl.java | 15 +++++ .../nms/v1_18/NMSAlgorithmsImpl.java | 15 +++++ .../nms/v1_19/NMSAlgorithmsImpl.java | 15 +++++ .../nms/v1_20_3/NMSAlgorithmsImpl.java | 34 +++++++++++ .../nms/v1_20_4/NMSAlgorithmsImpl.java | 36 +++++++++++ .../nms/v1_21/NMSAlgorithmsImpl.java | 36 +++++++++++ .../nms/v1_21_3/NMSAlgorithmsImpl.java | 36 +++++++++++ .../nms/v1_21_4/NMSAlgorithmsImpl.java | 36 +++++++++++ .../nms/v1_21_5/NMSAlgorithmsImpl.java | 36 +++++++++++ .../nms/v1_21_7/NMSAlgorithmsImpl.java | 36 +++++++++++ .../nms/v1_8_R3/NMSAlgorithmsImpl.java | 15 +++++ .../core/io/MenuParserImpl.java | 61 ++++++++++++++++++- .../core/itemstack/ItemBuilder.java | 28 +++++++++ .../superiorskyblock/nms/NMSAlgorithms.java | 6 ++ 16 files changed, 434 insertions(+), 1 deletion(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java index 06acd1a35b..4070e975ee 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java @@ -133,6 +133,21 @@ public void setCustomModel(ItemMeta itemMeta, int customModel) { // Doesn't exist } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + // Doesn't exist + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + // Doesn't exist + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + // Doesn't exist + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java index 430dd24571..e59674ff44 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java @@ -189,6 +189,21 @@ public void setCustomModel(ItemMeta itemMeta, int customModel) { itemMeta.setCustomModelData(customModel); } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + // Doesn't exist + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + // Doesn't exist + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + // Doesn't exist + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java index bb271c6437..1d55301417 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java @@ -192,6 +192,21 @@ public void setCustomModel(ItemMeta itemMeta, int customModel) { itemMeta.setCustomModelData(customModel); } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + // Doesn't exist + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + // Doesn't exist + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + // Doesn't exist + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java index 587a338be3..cfe27fc745 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java @@ -193,6 +193,21 @@ public void setCustomModel(ItemMeta itemMeta, int customModel) { itemMeta.setCustomModelData(customModel); } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + // Doesn't exist + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + // Doesn't exist + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + // Doesn't exist + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java index 33af50d8f8..f79f31f176 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java @@ -193,6 +193,21 @@ public void setCustomModel(ItemMeta itemMeta, int customModel) { itemMeta.setCustomModelData(customModel); } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + // Doesn't exist + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + // Doesn't exist + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + // Doesn't exist (Experimental) + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java index 5c0cc4f5e0..dd0a27987d 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java @@ -55,13 +55,19 @@ import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; import java.util.EnumMap; +import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; @@ -200,6 +206,34 @@ public void setCustomModel(ItemMeta itemMeta, int customModel) { itemMeta.setCustomModelData(customModel); } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + // Doesn't exist + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + // Doesn't exist + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java index b656e17d00..cdf914b008 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java @@ -35,6 +35,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.block.data.Ageable; @@ -51,13 +52,20 @@ import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; import java.util.EnumMap; +import java.util.Locale; +import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; @@ -194,6 +202,34 @@ public void setCustomModel(ItemMeta itemMeta, int customModel) { itemMeta.setCustomModelData(customModel); } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + // Doesn't exist + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + itemMeta.setRarity(ItemRarity.valueOf(rarity)); + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java index 652f8904ba..4ff97dc30e 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java @@ -36,6 +36,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.block.data.Ageable; @@ -52,13 +53,20 @@ import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; import java.util.EnumMap; +import java.util.Locale; +import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; @@ -258,6 +266,34 @@ public void hideAttributes(ItemMeta itemMeta) { itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + // Doesn't exist + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + itemMeta.setRarity(ItemRarity.valueOf(rarity)); + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + private interface MenuCreator extends BiFunction { } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java index 6a47875ac8..370d5021fb 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java @@ -36,6 +36,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.block.data.Ageable; @@ -52,13 +53,20 @@ import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; import java.util.EnumMap; +import java.util.Locale; +import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; @@ -195,6 +203,34 @@ public void setCustomModel(ItemMeta itemMeta, int customModel) { itemMeta.setCustomModelData(customModel); } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + itemMeta.setRarity(ItemRarity.valueOf(rarity)); + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index 9bb69d1835..dd873f3275 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -36,6 +36,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.block.Biome; @@ -53,13 +54,20 @@ import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; import java.util.EnumMap; +import java.util.Locale; +import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; @@ -208,6 +216,34 @@ public void setCustomModel(ItemMeta itemMeta, int customModel) { itemMeta.setCustomModelData(customModel); } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + itemMeta.setRarity(ItemRarity.valueOf(rarity)); + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java index 57f2ba6172..a6cdfbe5ec 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java @@ -36,6 +36,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.block.Biome; @@ -53,13 +54,20 @@ import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; import java.util.EnumMap; +import java.util.Locale; +import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; @@ -208,6 +216,34 @@ public void setCustomModel(ItemMeta itemMeta, int customModel) { itemMeta.setCustomModelData(customModel); } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + itemMeta.setRarity(ItemRarity.valueOf(rarity)); + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java index 7a4750483c..ebdcafd0ed 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java @@ -42,6 +42,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.block.Biome; @@ -59,13 +60,20 @@ import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; import org.bukkit.potion.PotionEffect; import org.jetbrains.annotations.NotNull; import java.util.EnumMap; +import java.util.Locale; +import java.util.Objects; import java.util.Optional; import java.util.function.BiFunction; @@ -219,6 +227,34 @@ public void setCustomModel(ItemMeta itemMeta, int customModel) { itemMeta.setCustomModelData(customModel); } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + itemMeta.setRarity(ItemRarity.valueOf(rarity)); + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java index d737c323fa..cca2224f7a 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java @@ -133,6 +133,21 @@ public void setCustomModel(ItemMeta itemMeta, int customModel) { // Doesn't exist } + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + // Doesn't exist + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + // Doesn't exist + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + // Doesn't exist + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { potionMeta.addCustomEffect(potionEffect, true); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java index c67237c312..4f2bf8dc38 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java @@ -24,8 +24,10 @@ import com.bgsoftware.superiorskyblock.core.menu.button.impl.DummyButton; import com.bgsoftware.superiorskyblock.core.menu.layout.PagedMenuLayoutImpl; import com.bgsoftware.superiorskyblock.core.menu.layout.RegularMenuLayoutImpl; +import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.Sound; +import org.bukkit.block.banner.PatternType; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; @@ -373,7 +375,7 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec potionEffectType = getMinecraftEnum(PotionEffectType.class, effectName, PotionEffectType::getByName); } catch (IllegalArgumentException error) { Log.warnFromFile(fileName, "Couldn't convert ", effectsSection.getCurrentPath(), - ".", effectName.toUpperCase(Locale.ENGLISH), " into a potion effect type, skipping..."); + ".", effectName.toUpperCase(Locale.ENGLISH), " into a potion effect, skipping..."); continue; } @@ -399,10 +401,67 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec } } + if (section.isConfigurationSection("bannerMeta")) { + for (String dyeColorName : section.getConfigurationSection("bannerMeta").getKeys(false)) { + DyeColor dyeColor; + PatternType patternType; + + try { + dyeColor = DyeColor.valueOf(dyeColorName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException error) { + Log.warnFromFile(fileName, "Couldn't convert ", section.getCurrentPath(), + ".bannerMeta.", dyeColorName.toUpperCase(Locale.ENGLISH), " into an dye color, skipping..."); + continue; + } + + try { + patternType = PatternType.valueOf(section.getString("bannerMeta." + dyeColorName)); + } catch (IllegalArgumentException error) { + Log.warnFromFile(fileName, "Couldn't convert ", section.getCurrentPath(), + ".bannerMeta.", dyeColorName.toUpperCase(Locale.ENGLISH), ".", + section.getString("bannerMeta." + dyeColorName), " into an pattern type, skipping..."); + continue; + } + + itemBuilder.withBannerMeta(dyeColor, patternType); + } + } + if (section.isInt("customModel")) { itemBuilder.withCustomModel(section.getInt("customModel")); } + if (section.isString("itemModel")) { + itemBuilder.withItemModel(section.getString("itemModel")); + } + + if (section.isString("rarity")) { + String rarity = section.getString("rarity"); + + try { + itemBuilder.withRarity(rarity); + } catch (IllegalArgumentException error) { + Log.warnFromFile(fileName, "Couldn't convert ", rarity, " into a rarity, skipping..."); + } + } + + if (section.isConfigurationSection("trim")) { + String trimMaterial = section.getString("trim.material"); + String trimPattern = section.getString("trim.pattern"); + + if (trimMaterial == null) { + Log.warnFromFile(fileName, "Couldn't find trim material for item with trim pattern, skipping..."); + } else if (trimPattern == null) { + Log.warnFromFile(fileName, "Couldn't find trim pattern for item with trim material, skipping..."); + } else { + try { + itemBuilder.withTrim(trimMaterial, trimPattern); + } catch (IllegalArgumentException error) { + Log.warnFromFile(fileName, error.getMessage()); + } + } + } + if (section.isString("leatherColor")) { String leatherColor = section.getString("leatherColor"); if (leatherColor.startsWith("#")) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java b/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java index bc4128b619..b9bc8cd726 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java @@ -12,12 +12,16 @@ import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.ChatColor; import org.bukkit.Color; +import org.bukkit.DyeColor; import org.bukkit.Material; import org.bukkit.OfflinePlayer; +import org.bukkit.block.banner.Pattern; +import org.bukkit.block.banner.PatternType; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.BannerMeta; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.LeatherArmorMeta; import org.bukkit.inventory.meta.PotionMeta; @@ -28,6 +32,7 @@ import java.util.Arrays; import java.util.LinkedList; import java.util.List; +import java.util.Locale; public class ItemBuilder { @@ -242,11 +247,34 @@ public ItemBuilder withEntityType(EntityType entityType) { return this; } + public ItemBuilder withBannerMeta(DyeColor dyeColor, PatternType patternType) { + if (itemMeta instanceof BannerMeta) { + BannerMeta bannerMeta = (BannerMeta) itemMeta; + bannerMeta.addPattern(new Pattern(dyeColor, patternType)); + } + return this; + } + public ItemBuilder withCustomModel(int customModel) { plugin.getNMSAlgorithms().setCustomModel(itemMeta, customModel); return this; } + public ItemBuilder withItemModel(String itemModel) { + plugin.getNMSAlgorithms().setItemModel(itemMeta, itemModel); + return this; + } + + public ItemBuilder withRarity(String rarity) { + plugin.getNMSAlgorithms().setRarity(itemMeta, rarity.toUpperCase(Locale.ENGLISH)); + return this; + } + + public ItemBuilder withTrim(String trimMaterial, String trimPattern) { + plugin.getNMSAlgorithms().setTrim(itemMeta, trimMaterial.toLowerCase(Locale.ENGLISH), trimPattern.toLowerCase(Locale.ENGLISH)); + return this; + } + public ItemBuilder withLeatherColor(int leatherColor) { if (itemMeta instanceof LeatherArmorMeta) { LeatherArmorMeta leatherArmorMeta = (LeatherArmorMeta) itemMeta; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java index 84d736f7fc..d67656858e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java @@ -60,6 +60,12 @@ public String getName(Biome enumValue) { void setCustomModel(ItemMeta itemMeta, int customModel); + void setItemModel(ItemMeta itemMeta, String itemModel); + + void setRarity(ItemMeta itemMeta, String rarity) throws IllegalArgumentException; + + void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) throws IllegalArgumentException; + void addPotion(PotionMeta potionMeta, PotionEffect potionEffect); String getMinecraftKey(ItemStack itemStack); From a4f52355cd39a809e3ddb43049f1088cceb3a1a1 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 6 Sep 2025 09:42:31 +0200 Subject: [PATCH 285/600] Added missing head and removed spawner item description display (#2628) --- src/main/resources/heads.yml | 3 +- src/main/resources/menus/counts.yml | 2 + src/main/resources/menus/counts1_12.yml | 2 + src/main/resources/menus/counts1_13.yml | 2 + src/main/resources/menus/counts1_20.yml | 53 ++++++ src/main/resources/menus/values.yml | 2 + src/main/resources/menus/values1_13.yml | 2 + src/main/resources/menus/values1_20.yml | 234 ++++++++++++++++++++++++ 8 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/menus/counts1_20.yml create mode 100644 src/main/resources/menus/values1_20.yml diff --git a/src/main/resources/heads.yml b/src/main/resources/heads.yml index 3e54479e31..821b89fc04 100644 --- a/src/main/resources/heads.yml +++ b/src/main/resources/heads.yml @@ -8,8 +8,8 @@ # A list of skull textures for spawners. # You can find the texture values on https://minecraft-heads.com/ -ARMADILLO: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTE2NGVkMGUwZWY2OWIwY2U3ODE1ZTQzMDBiNDQxM2E0ODI4ZmNiMDA5MjkxODU0MzU0NWE0MThhNDhlMGMzYyJ9fX0=' ALLAY: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmVlYTg0NWNjMGI1OGZmNzYzZGVjZmZlMTFjZDFjODQ1YzVkMDljM2IwNGZlODBiMDY2M2RhNWM3YzY5OWViMyJ9fX0=' +ARMADILLO: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOTE2NGVkMGUwZWY2OWIwY2U3ODE1ZTQzMDBiNDQxM2E0ODI4ZmNiMDA5MjkxODU0MzU0NWE0MThhNDhlMGMzYyJ9fX0=' AXOLOTL: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzg3Mjg2MGRhNGQ0NWNlNDNkMWI5ZDAyMzQ0NDJjMDNhOTE3NjVkOThhM2JiMTVmNzMzZTNjZWE1MmFmNWYxOCJ9fX0=' BAT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmZmZDgwOGY4MTI3YjRhZDQ1OGQ5ZDJlMTgxYzY5MGFkZjQ4OWE2YWQzMmVlMmFhNGFjZmE2MzQxZmU4NDIifX19' BEE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTg3NDc4N2UzNjE1OWU0ZDc0ZGI1ZTI1YmFiYTk4N2I2NjVkY2M4OTBiZTlmMjYyYmIwY2JjZjVkMDFiODJiNiJ9fX0=' @@ -22,6 +22,7 @@ CAVE_SPIDER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3 CHICKEN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzODQ2OWE1OTljZWVmNzIwNzUzNzYwMzI0OGE5YWIxMWZmNTkxZmQzNzhiZWE0NzM1YjM0NmE3ZmFlODkzIn19fQ==' COD: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzg5MmQ3ZGQ2YWFkZjM1Zjg2ZGEyN2ZiNjNkYTRlZGRhMjExZGY5NmQyODI5ZjY5MTQ2MmE0ZmIxY2FiMCJ9fX0=' COW: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ2YzZlZGE5NDJmN2Y1ZjcxYzMxNjFjNzMwNmY0YWVkMzA3ZDgyODk1ZjlkMmIwN2FiNDUyNTcxOGVkYzUifX19' +CREAKING: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzdiNWJlNzI3NjljY2ZmMWE2Y2I3N2M1ODQ4ZTAxZDdlNTcwNGEzZDM0OWMwNzM3ZmY5M2NiNTRkMDIzODBhYyJ9fX0=' CREEPER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjQyNTQ4MzhjMzNlYTIyN2ZmY2EyMjNkZGRhYWJmZTBiMDIxNWY3MGRhNjQ5ZTk0NDQ3N2Y0NDM3MGNhNjk1MiJ9fX0=' DOLPHIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGU5Njg4Yjk1MGQ4ODBiNTViN2FhMmNmY2Q3NmU1YTBmYTk0YWFjNmQxNmY3OGU4MzNmNzQ0M2VhMjlmZWQzIn19fQ==' DONKEY: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGZiNmMzYzA1MmNmNzg3ZDIzNmEyOTE1ZjgwNzJiNzdjNTQ3NDk3NzE1ZDFkMmY4Y2JjOWQyNDFkODhhIn19fQ==' diff --git a/src/main/resources/menus/counts.yml b/src/main/resources/menus/counts.yml index a7685903d8..c14a9e92e8 100644 --- a/src/main/resources/menus/counts.yml +++ b/src/main/resources/menus/counts.yml @@ -29,6 +29,8 @@ items: - '&6&l* &e&lQuantity &fx{1}' - '&6&l* &e&lWorth: &f${2}' - '&6&l* &e&lLevel: &f${3}' + flags: + - HIDE_ATTRIBUTES '%': type: PAPER name: '{0}Previous Page' diff --git a/src/main/resources/menus/counts1_12.yml b/src/main/resources/menus/counts1_12.yml index 5c16235e55..d85a43f416 100644 --- a/src/main/resources/menus/counts1_12.yml +++ b/src/main/resources/menus/counts1_12.yml @@ -29,6 +29,8 @@ items: - '&6&l* &e&lQuantity &fx{1}' - '&6&l* &e&lWorth: &f${2}' - '&6&l* &e&lLevel: &f${3}' + flags: + - HIDE_ATTRIBUTES '%': type: PAPER name: '{0}Previous Page' diff --git a/src/main/resources/menus/counts1_13.yml b/src/main/resources/menus/counts1_13.yml index fb9e5b8768..608bb9a028 100644 --- a/src/main/resources/menus/counts1_13.yml +++ b/src/main/resources/menus/counts1_13.yml @@ -29,6 +29,8 @@ items: - '&6&l* &e&lQuantity &fx{1}' - '&6&l* &e&lWorth: &f${2}' - '&6&l* &e&lLevel: &f${3}' + flags: + - HIDE_ATTRIBUTES '%': type: PAPER name: '{0}Previous Page' diff --git a/src/main/resources/menus/counts1_20.yml b/src/main/resources/menus/counts1_20.yml new file mode 100644 index 0000000000..27996d5684 --- /dev/null +++ b/src/main/resources/menus/counts1_20.yml @@ -0,0 +1,53 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Block Counts' +previous-menu: true + +pattern: + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '@ @ @ @ @ @ @ @ @' + - '$ $ $ $ $ $ $ $ $' + - '# # % # * # ^ # #' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +items: + '@': + type: STONE + name: '&e{0}' + lore: + - '&6&l* &e&lQuantity &fx{1}' + - '&6&l* &e&lWorth: &f${2}' + - '&6&l* &e&lLevel: &f${3}' + flags: + - HIDE_ADDITIONAL_TOOLTIP + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: SUNFLOWER + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + '$': + type: BLACK_STAINED_GLASS_PANE + name: '&f' + +sounds: + '@': + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/values.yml b/src/main/resources/menus/values.yml index c6cc437032..5aad3f5088 100644 --- a/src/main/resources/menus/values.yml +++ b/src/main/resources/menus/values.yml @@ -24,6 +24,8 @@ items: '$': type: MOB_SPAWNER name: '&e&lSPAWNERS ->' + flags: + - HIDE_ATTRIBUTES '*': type: BOOK_AND_QUILL name: '&e&lITEMS ->' diff --git a/src/main/resources/menus/values1_13.yml b/src/main/resources/menus/values1_13.yml index 16b8cdd2e8..887cde68d1 100644 --- a/src/main/resources/menus/values1_13.yml +++ b/src/main/resources/menus/values1_13.yml @@ -23,6 +23,8 @@ items: '$': type: SPAWNER name: '&e&lSPAWNERS ->' + flags: + - HIDE_ATTRIBUTES '*': type: WRITABLE_BOOK name: '&e&lITEMS ->' diff --git a/src/main/resources/menus/values1_20.yml b/src/main/resources/menus/values1_20.yml new file mode 100644 index 0000000000..df48dff87e --- /dev/null +++ b/src/main/resources/menus/values1_20.yml @@ -0,0 +1,234 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '{0} &n${1}' +previous-menu: true + +pattern: + - '& & & & & & & & &' + - '% $ A B C D E F %' + - '% % G H I J K L %' + - '% * M N O P Q R %' + - '% % S T U V W X %' + - '& & & & & & & & &' + +items: + '&': + type: BLACK_STAINED_GLASS_PANE + name: '&f' + '$': + type: SPAWNER + name: '&e&lSPAWNERS ->' + flags: + - HIDE_ADDITIONAL_TOOLTIP + '*': + type: WRITABLE_BOOK + name: '&e&lITEMS ->' + 'A': + block: SPAWNER:IRON_GOLEM + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODkwOTFkNzllYTBmNTllZjdlZjk0ZDdiYmE2ZTVmMTdmMmY3ZDQ1NzJjNDRmOTBmNzZjNDgxOWE3MTQifX19' + name: '&e&l[!] &7Iron Golem Spawner' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'B': + block: SPAWNER:BLAZE + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjc4ZWYyZTRjZjJjNDFhMmQxNGJmZGU5Y2FmZjEwMjE5ZjViMWJmNWIzNWE0OWViNTFjNjQ2Nzg4MmNiNWYwIn19fQ==' + name: '&e&l[!] &7Blaze Spawner' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'C': + block: SPAWNER:SPIDER + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19' + name: '&e&l[!] &7Spider Spawner' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'D': + block: SPAWNER:COW + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNWQ2YzZlZGE5NDJmN2Y1ZjcxYzMxNjFjNzMwNmY0YWVkMzA3ZDgyODk1ZjlkMmIwN2FiNDUyNTcxOGVkYzUifX19' + name: '&e&l[!] &7Cow Spawner' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'E': + block: SPAWNER:ZOMBIE + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZmYzg1NGJiODRjZjRiNzY5NzI5Nzk3M2UwMmI3OWJjMTA2OTg0NjBiNTFhNjM5YzYwZTVlNDE3NzM0ZTExIn19fQ==' + name: '&e&l[!] &7Zombie Spawner' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'F': + block: SPAWNER:SKELETON + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMzAxMjY4ZTljNDkyZGExZjBkODgyNzFjYjQ5MmE0YjMwMjM5NWY1MTVhN2JiZjc3ZjRhMjBiOTVmYzAyZWIyIn19fQ==' + name: '&e&l[!] &7Skeleton Spawner' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'G': + block: SPAWNER:CREEPER + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZjQyNTQ4MzhjMzNlYTIyN2ZmY2EyMjNkZGRhYWJmZTBiMDIxNWY3MGRhNjQ5ZTk0NDQ3N2Y0NDM3MGNhNjk1MiJ9fX0=' + name: '&e&l[!] &7Creeper Spawner' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'H': + block: SPAWNER:ZOMBIFIED_PIGLIN + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2VhYmFlY2M1ZmFlNWE4YTQ5Yzg4NjNmZjQ4MzFhYWEyODQxOThmMWEyMzk4ODkwYzc2NWUwYThkZTE4ZGE4YyJ9fX0=' + name: '&e&l[!] &7Zombified Piglin Spawner' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'I': + block: SPAWNER:GHAST + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvOGI2YTcyMTM4ZDY5ZmJiZDJmZWEzZmEyNTFjYWJkODcxNTJlNGYxYzk3ZTVmOTg2YmY2ODU1NzFkYjNjYzAifX19' + name: '&e&l[!] &7Ghast Spawner' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'J': + block: SPAWNER:SLIME + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTZhZDIwZmMyZDU3OWJlMjUwZDNkYjY1OWM4MzJkYTJiNDc4YTczYTY5OGI3ZWExMGQxOGM5MTYyZTRkOWI1In19fQ==' + name: '&e&l[!] &7Slime Spawner' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'K': + block: SPAWNER:GUARDIAN + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGZiNjc1Y2I1YTdlM2ZkMjVlMjlkYTgyNThmMjRmYzAyMGIzZmE5NTAzNjJiOGJjOGViMjUyZTU2ZTc0In19fQ==' + name: '&e&l[!] &7Guardian Spawner' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'L': + block: SPAWNER:SQUID + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMDE0MzNiZTI0MjM2NmFmMTI2ZGE0MzRiODczNWRmMWViNWIzY2IyY2VkZTM5MTQ1OTc0ZTljNDgzNjA3YmFjIn19fQ==' + name: '&e&l[!] &7Squid Spawner' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'M': + block: HOPPER + type: HOPPER + name: '&e&l[!] &7Hopper' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'N': + block: BEACON + type: BEACON + name: '&e&l[!] &7Beacon' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'O': + block: IRON_BLOCK + type: IRON_BLOCK + name: '&e&l[!] &7Iron Block' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'P': + block: GOLD_BLOCK + type: GOLD_BLOCK + name: '&e&l[!] &7Gold Block' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'Q': + block: DIAMOND_BLOCK + type: DIAMOND_BLOCK + name: '&e&l[!] &7Diamond Block' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'R': + block: EMERALD_BLOCK + type: EMERALD_BLOCK + name: '&e&l[!] &7Emerald Block' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'S': + block: BEDROCK + type: BEDROCK + name: '&e&l[!] &7Bedrock' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'T': + block: ENDER_CHEST + type: ENDER_CHEST + name: '&e&l[!] &7Ender Chest' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'U': + block: DRAGON_EGG + type: DRAGON_EGG + name: '&e&l[!] &7Dragon Egg' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'V': + block: CHEST + type: CHEST + name: '&e&l[!] &7Chest' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'W': + block: TRAPPED_CHEST + type: TRAPPED_CHEST + name: '&e&l[!] &7Trapped Chest' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' + 'X': + block: ENCHANTING_TABLE + type: ENCHANTING_TABLE + name: '&e&l[!] &7Enchantment Table' + lore: + - '&6&l* &e&lQuantity &fx{0}' + - '&6&l* &e&lWorth: &f${1}' + - '&6&l* &e&lLevel: &f${2}' \ No newline at end of file From bdd9e596f85db535df8eb3b545fedc0304c01daf Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 12 Sep 2025 13:08:12 +0300 Subject: [PATCH 286/600] Do not load worlds when accessing homes and visitor locations --- .../superiorskyblock/core/IslandWorlds.java | 22 +++++++++++++++++++ .../superiorskyblock/island/SIsland.java | 13 +++-------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java index 3f0335c8e6..ef588a3a38 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.World; import java.util.function.Consumer; @@ -50,6 +51,27 @@ public static void accessIslandWorldAsync(Island island, Dimension dimension, bo } } + public static Location setWorldToLocation(Island island, Dimension dimension, Location location) { + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); + World world = Bukkit.getWorld(worldInfo.getName()); + if (world != null) { + location = location.clone(); + location.setWorld(world); + } else { + WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); + if (worldsProvider instanceof LazyWorldsProvider) { + location = new LazyWorldLocation(worldInfo.getName(), location.getX(), location.getY(), + location.getZ(), location.getYaw(), location.getPitch()); + } else { + location = location.clone(); + world = plugin.getGrid().getIslandsWorld(island, dimension); + location.setWorld(world); + } + } + + return location; + } + private static void loadedWorldCallback(WorldInfo worldInfo, Consumer> consumer) { World world = Bukkit.getWorld(worldInfo.getName()); if (world != null) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index eea9c5e313..0229e08a3d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider; +import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; import com.bgsoftware.superiorskyblock.api.island.BlockChangeResult; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandBlockFlags; @@ -898,12 +899,7 @@ public Location getIslandHome(Dimension dimension) { if (islandHome == null) return null; - World world = plugin.getGrid().getIslandsWorld(this, dimension); - - islandHome = islandHome.clone(); - islandHome.setWorld(world); - - return islandHome; + return IslandWorlds.setWorldToLocation(this, dimension, islandHome); } @Override @@ -985,10 +981,7 @@ public Location getVisitorsLocation(Dimension unused) { if (adjustLocationToCenterOfBlock(visitorsLocation)) IslandsDatabaseBridge.saveVisitorLocation(this, defaultWorldDimension, visitorsLocation); - World world = plugin.getGrid().getIslandsWorld(this, defaultWorldDimension); - visitorsLocation.setWorld(world); - - return visitorsLocation.clone(); + return IslandWorlds.setWorldToLocation(this, defaultWorldDimension, visitorsLocation); } @Override From 6d33cc241338793fd7c6337d3b2de1f24f08bbf7 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 12 Sep 2025 17:36:35 +0200 Subject: [PATCH 287/600] Added the ability to translate "None" in the visitors panel (#2638) --- .../menu/button/impl/UniqueVisitorPagedObjectButton.java | 7 +++++-- .../core/menu/button/impl/VisitorPagedObjectButton.java | 8 ++++++-- .../superiorskyblock/core/messages/Message.java | 2 ++ src/main/resources/lang/de-DE.yml | 2 ++ src/main/resources/lang/en-US.yml | 2 ++ src/main/resources/lang/es-ES.yml | 2 ++ src/main/resources/lang/fr-FR.yml | 2 ++ src/main/resources/lang/it-IT.yml | 2 ++ src/main/resources/lang/iw-IL.yml | 2 ++ src/main/resources/lang/pl-PL.yml | 2 ++ src/main/resources/lang/pt-BR.yml | 2 ++ src/main/resources/lang/ru-RU.yml | 2 ++ src/main/resources/lang/tr-TR.yml | 2 ++ src/main/resources/lang/vi-VN.yml | 2 ++ src/main/resources/lang/zh-CN.yml | 2 ++ 15 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/UniqueVisitorPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/UniqueVisitorPagedObjectButton.java index e3c90f54ec..e35154aad7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/UniqueVisitorPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/UniqueVisitorPagedObjectButton.java @@ -9,10 +9,12 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandUniqueVisitors; +import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.Date; +import java.util.Locale; public class UniqueVisitorPagedObjectButton extends AbstractPagedMenuButton { @@ -38,9 +40,10 @@ else if (clickEvent.getClick().isLeftClick()) public ItemStack modifyViewItem(ItemStack buttonItem) { SuperiorPlayer visitor = pagedObject.getVisitor(); Island island = visitor.getIsland(); + Locale locale = menuView.getInventoryViewer().getUserLocale(); - String islandOwner = island != null ? island.getOwner().getName() : "None"; - String islandName = island != null ? island.getName().isEmpty() ? islandOwner : island.getName() : "None"; + String islandOwner = island != null ? island.getOwner().getName() : Message.ISLAND_OWNER_NONE.getMessage(locale); + String islandName = island != null ? island.getName().isEmpty() ? islandOwner : island.getName() : Message.ISLAND_NAME_NONE.getMessage(locale); return new ItemBuilder(buttonItem) .replaceAll("{0}", visitor.getName()) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/VisitorPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/VisitorPagedObjectButton.java index 0e2428e0bb..3eb8dfe860 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/VisitorPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/VisitorPagedObjectButton.java @@ -8,9 +8,12 @@ import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandVisitors; +import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; +import java.util.Locale; + public class VisitorPagedObjectButton extends AbstractPagedMenuButton { private VisitorPagedObjectButton(MenuTemplateButton templateButton, MenuIslandVisitors.View menuView) { @@ -33,9 +36,10 @@ else if (clickEvent.getClick().isLeftClick()) @Override public ItemStack modifyViewItem(ItemStack buttonItem) { Island island = pagedObject.getIsland(); + Locale locale = menuView.getInventoryViewer().getUserLocale(); - String islandOwner = island != null ? island.getOwner().getName() : "None"; - String islandName = island != null ? island.getName().isEmpty() ? islandOwner : island.getName() : "None"; + String islandOwner = island != null ? island.getOwner().getName() : Message.ISLAND_OWNER_NONE.getMessage(locale); + String islandName = island != null ? island.getName().isEmpty() ? islandOwner : island.getName() : Message.ISLAND_NAME_NONE.getMessage(locale); return new ItemBuilder(buttonItem) .replaceAll("{0}", pagedObject.getName()) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 203502322a..e30a420f34 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -526,7 +526,9 @@ public void send(CommandSender sender, Locale locale, Object... args) { ISLAND_INFO_ROLES, ISLAND_INFO_VISITORS_COUNT, ISLAND_INFO_WORTH, + ISLAND_NAME_NONE, ISLAND_OPENED, + ISLAND_OWNER_NONE, ISLAND_PREVIEW_CANCEL, ISLAND_PREVIEW_CANCEL_DISTANCE, ISLAND_PREVIEW_CANCEL_TEXT, diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 37fbb4d7a8..65c6749c65 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -610,8 +610,10 @@ ISLAND_INFO_ROLES: |- {1} ISLAND_INFO_VISITORS_COUNT: '&e&lInsel | &7Besucheranzahl: {0}' ISLAND_INFO_WORTH: '&e&lInsel | &7Wert: {0}' +ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsland | &7Die Insel wurde erfolgreich der Öffentlichkeit zugänglich gemacht.' +ISLAND_OWNER_NONE: None ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVorschau | &7Du hast sich zu weit entfernt und befindest dich nicht mehr im Vorschaumodus.' ISLAND_PREVIEW_CANCEL: '&e&lVorschau | &7Du hast den Vorschaumodus abgebrochen.' diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 7eba459d34..abb513c288 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -492,7 +492,9 @@ ISLAND_INFO_ROLES: | {1} ISLAND_INFO_VISITORS_COUNT: '&e&lIsland | &7Visitors Count: {0}' ISLAND_INFO_WORTH: '&e&lIsland | &7Worth: {0}' +ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsland | &7Successfully opened the island to the public.' +ISLAND_OWNER_NONE: None ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPreview | &7You went too far away, and you are no longer in preview mode.' ISLAND_PREVIEW_CANCEL: '&e&lPreview | &7You cancelled the preview mode.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 7b2607482d..7cb46fe4b9 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -492,7 +492,9 @@ ISLAND_INFO_ROLES: | {1} ISLAND_INFO_VISITORS_COUNT: '&e&lIsla | &7Número de visitantes: {0}' ISLAND_INFO_WORTH: '&e&lIsla | &7Valor: {0}' +ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsla | &7Abrió con éxito la isla al público.' +ISLAND_OWNER_NONE: None ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVista Previa | &7Fuiste demasiado lejos y ya no estás en modo de vista previa.' ISLAND_PREVIEW_CANCEL: '&e&lVista Previa | &7Cancelaste el modo de vista previa.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index c01fd9b8da..1d4e7804be 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -494,7 +494,9 @@ ISLAND_INFO_ROLES: | {1} ISLAND_INFO_VISITORS_COUNT: '&e&lIle | &7Nombre de visiteurs: {0}' ISLAND_INFO_WORTH: '&e&lIle | &7Valeur: {0}' +ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIle | &7L''île est désormais ouverte au public.' +ISLAND_OWNER_NONE: None ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPrévisualisation | &7Vous vous êtes trop éloigné(e). La prévisualisation à donc été désactivée.' ISLAND_PREVIEW_CANCEL: '&e&lPrévisualisation | &7Vous avez annulé(e) la prévisualisation.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRMER' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index f6e1baec5b..f031bc0c17 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -500,7 +500,9 @@ ISLAND_INFO_ROLES: | {1} ISLAND_INFO_VISITORS_COUNT: '&e&lIsola | &7Numero di visitatori: {0}' ISLAND_INFO_WORTH: '&e&lIsola | &7Valore: {0}' +ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsola | &7Aperta con successo l''isola al pubblico.' +ISLAND_OWNER_NONE: None ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lAnteprima | &7Sei andato troppo lontano, non sei più in modalità anteprima.' ISLAND_PREVIEW_CANCEL: '&e&lAnteprima | &7Hai annullato la modalità di anteprima.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFERMA' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 8c84553137..e98bfb7ee1 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -510,7 +510,9 @@ ISLAND_INFO_ROLES: | {1} ISLAND_INFO_VISITORS_COUNT: '&e&lיא | &7םירקבמ רפסמ: {0}' ISLAND_INFO_WORTH: '&e&lיא | &7יווש: {0}' +ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lיא | &7החלצהב רוביצל חתפנ יאה.' +ISLAND_OWNER_NONE: None ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPreview | &7You went too far away, and you are no longer in preview mode.' ISLAND_PREVIEW_CANCEL: '&e&lPreview | &7You cancelled the preview mode.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 209b47b2c2..6ab7b94134 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -492,7 +492,9 @@ ISLAND_INFO_ROLES: | {1} ISLAND_INFO_VISITORS_COUNT: '&e&lWyspa | &7Odwiedzajacy: {0}' ISLAND_INFO_WORTH: '&e&lWyspa | &7Wartosc: {0}' +ISLAND_NAME_NONE: Brak ISLAND_OPENED: '&e&lWyspa | &7Pomyslnie zmieniles status wyspy na publiczny.' +ISLAND_OWNER_NONE: Brak ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPodglad | &7Odszedles za daleko, nie jestes juz w trybie podgladu.' ISLAND_PREVIEW_CANCEL: '&e&lPodglad | &7Anulowales tryb podgladu.' ISLAND_PREVIEW_CONFIRM_TEXT: 'POTWIERDZ' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index ce444ccc75..47835c42f6 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -492,7 +492,9 @@ ISLAND_INFO_ROLES: | {1} ISLAND_INFO_VISITORS_COUNT: '&e&lIlha | &7Contagem de visitantes: {0}' ISLAND_INFO_WORTH: '&e&lIlha | &7Valor: {0}' +ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIlha | &7A ilha foi aberta com sucesso ao público.' +ISLAND_OWNER_NONE: None ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVisualizar | &7Você foi muito longe e não está mais no modo de visualização.' ISLAND_PREVIEW_CANCEL: '&e&lVisualizar | &7Você cancelou o modo de visualização.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRMAR' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 6e2fd3e416..49d34a7ddf 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -492,7 +492,9 @@ ISLAND_INFO_ROLES: | {1} ISLAND_INFO_VISITORS_COUNT: '&e&lОстров | &7Количество посетителей: {0}' ISLAND_INFO_WORTH: '&e&lОстров | &7Стоимость: {0}' +ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lОстров | &7Остров успешно открыт для публики.' +ISLAND_OWNER_NONE: None ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lПредпросмотр | &7Вы отошли слишком далеко, и режим предпросмотра больше не активен.' ISLAND_PREVIEW_CANCEL: '&e&lПредпросмотр | &7Вы отменили режим предпросмотра.' ISLAND_PREVIEW_CONFIRM_TEXT: 'ПОДТВЕРДИТЬ' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index ed7d5fc8b4..b2fea3b0f8 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -581,7 +581,9 @@ ISLAND_INFO_ROLES: | {1} ISLAND_INFO_VISITORS_COUNT: '&e&lAda | &7Ziyaretçi Sayısı: {0}' ISLAND_INFO_WORTH: '&e&lAda | &7Değer: {0}' +ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lAda | &7Ada başarıyla halka açıldı.' +ISLAND_OWNER_NONE: None ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lÖnizleme | &7Çok uzaklaştın ve artık önizleme modunda değilsin.' ISLAND_PREVIEW_CANCEL: '&e&lÖnizleme | &7Önizleme modunu iptal ettin.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 283659b82a..2a65a0064d 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -548,7 +548,9 @@ ISLAND_INFO_ROLES: | {1} ISLAND_INFO_VISITORS_COUNT: '&e&lĐảo | &7Số lượt khách: {0}' ISLAND_INFO_WORTH: '&e&lĐảo | &7Đáng giá: {0}' +ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lĐảo | &7Mở đảo thành công cho công cộng.' +ISLAND_OWNER_NONE: None ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lXem Trước | &7Bạn đã đi ra quá xa và thoát chế độ xem trước.' ISLAND_PREVIEW_CANCEL: '&e&lXem Trước | &7Bạn đã hủy chế độ xem trước.' ISLAND_PREVIEW_CONFIRM_TEXT: 'DONG-Y' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 74cc816438..9264d21763 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -492,7 +492,9 @@ ISLAND_INFO_ROLES: | {1} ISLAND_INFO_VISITORS_COUNT: '&e&l岛屿 | &7访客数量: {0}' ISLAND_INFO_WORTH: '&e&l岛屿 | &7价值: {0}' +ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&l岛屿 | &7成功将岛屿设置为对公众开放.' +ISLAND_OWNER_NONE: None ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&l结构 | &7你离得太远离了, 已自动退出预览模式.' ISLAND_PREVIEW_CANCEL: '&e&l结构 | &7你退出了预览模式.' ISLAND_PREVIEW_CONFIRM_TEXT: '确认' From 7ec52256c6bcc81c434c61bfbc20c2947dd85582 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 13 Sep 2025 10:29:39 +0200 Subject: [PATCH 288/600] Disabled display of empty data in island info (#2639) --- .../commands/admin/CmdAdminShow.java | 20 ++++++++++++------- .../commands/player/CmdShow.java | 15 +++++++++----- src/main/resources/lang/de-DE.yml | 2 +- src/main/resources/lang/en-US.yml | 2 +- src/main/resources/lang/es-ES.yml | 2 +- src/main/resources/lang/fr-FR.yml | 2 +- src/main/resources/lang/it-IT.yml | 2 +- src/main/resources/lang/iw-IL.yml | 2 +- src/main/resources/lang/pl-PL.yml | 2 +- src/main/resources/lang/pt-BR.yml | 2 +- src/main/resources/lang/ru-RU.yml | 2 +- src/main/resources/lang/tr-TR.yml | 2 +- src/main/resources/lang/vi-VN.yml | 2 +- src/main/resources/lang/zh-CN.yml | 2 +- 14 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java index 2f823351f2..fa3ad3774d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java @@ -150,12 +150,14 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab infoMessage.append(Message.ISLAND_INFO_LEVEL.getMessage(locale, island.getIslandLevel())).append("\n"); // Island discord - if (!Message.ISLAND_INFO_DISCORD.isEmpty(locale)) + if (!Message.ISLAND_INFO_DISCORD.isEmpty(locale) && !"None".equals(island.getDiscord())) { infoMessage.append(Message.ISLAND_INFO_DISCORD.getMessage(locale, island.getDiscord())).append("\n"); + } // Island paypal - if (!Message.ISLAND_INFO_PAYPAL.isEmpty(locale)) + if (!Message.ISLAND_INFO_PAYPAL.isEmpty(locale) && !"None".equals(island.getPaypal())) { infoMessage.append(Message.ISLAND_INFO_PAYPAL.getMessage(locale, island.getPaypal())).append("\n"); + } boolean upgradesModule = BuiltinModules.UPGRADES.isEnabled(); @@ -239,8 +241,9 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab generatorString.append(" ").append(Message.ISLAND_INFO_ADMIN_VALUE_SYNCED.getMessage(locale)); generatorString.append("\n"); } - infoMessage.append(Message.ISLAND_INFO_ADMIN_GENERATOR_RATES.getMessage(locale, generatorString, - Formatters.CAPITALIZED_FORMATTER.format(dimension.getName()))); + if (generatorString.length() > 0) + infoMessage.append(Message.ISLAND_INFO_ADMIN_GENERATOR_RATES.getMessage(locale, generatorString, + Formatters.CAPITALIZED_FORMATTER.format(dimension.getName()))); } } } @@ -270,8 +273,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab rolesStrings.keySet().stream() .sorted(Collections.reverseOrder(Comparator.comparingInt(PlayerRole::getWeight))) - .forEach(playerRole -> - infoMessage.append(Message.ISLAND_INFO_ROLES.getMessage(locale, playerRole, rolesStrings.get(playerRole)))); + .forEach(playerRole -> { + StringBuilder players = rolesStrings.get(playerRole); + if (players != null && players.length() > 0) + infoMessage.append(Message.ISLAND_INFO_ROLES.getMessage(locale, playerRole, players)); + }); } if (!Message.ISLAND_INFO_FOOTER.isEmpty(locale)) @@ -308,7 +314,7 @@ private static Optional collectIslandData(Locale locale, dataValue.append("\n"); }); - return Optional.of(dataValue); + return dataValue.length() > 0 ? Optional.of(dataValue) : Optional.empty(); } private static void collectIslandData(Locale locale, StringBuilder message, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdShow.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdShow.java index 8e12a44990..ee364c3d9b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdShow.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdShow.java @@ -100,12 +100,14 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ infoMessage.append(Message.ISLAND_INFO_WORTH.getMessage(locale, island.getWorth())).append("\n"); if (!Message.ISLAND_INFO_LEVEL.isEmpty(locale)) infoMessage.append(Message.ISLAND_INFO_LEVEL.getMessage(locale, island.getIslandLevel())).append("\n"); - if (!Message.ISLAND_INFO_DISCORD.isEmpty(locale) && island.hasPermission(sender, IslandPrivileges.DISCORD_SHOW)) + if (!Message.ISLAND_INFO_DISCORD.isEmpty(locale) && !"None".equals(island.getDiscord()) && island.hasPermission(sender, IslandPrivileges.DISCORD_SHOW)) { infoMessage.append(Message.ISLAND_INFO_DISCORD.getMessage(locale, island.getDiscord())).append("\n"); - if (!Message.ISLAND_INFO_PAYPAL.isEmpty(locale) && island.hasPermission(sender, IslandPrivileges.PAYPAL_SHOW)) + } + if (!Message.ISLAND_INFO_PAYPAL.isEmpty(locale) && !"None".equals(island.getPaypal()) && island.hasPermission(sender, IslandPrivileges.PAYPAL_SHOW)) { infoMessage.append(Message.ISLAND_INFO_PAYPAL.getMessage(locale, island.getPaypal())).append("\n"); + } if (!Message.ISLAND_INFO_VISITORS_COUNT.isEmpty(locale)) - infoMessage.append(Message.ISLAND_INFO_VISITORS_COUNT.getMessage(locale, island.getUniqueVisitorsWithTimes().size())).append("\n"); + infoMessage.append(Message.ISLAND_INFO_VISITORS_COUNT.getMessage(locale, island.getIslandVisitors(false).size(), island.getUniqueVisitorsWithTimes().size())).append("\n"); if (!Message.ISLAND_INFO_ROLES.isEmpty(locale)) { Map rolesStrings = new ArrayMap<>(); @@ -128,8 +130,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ rolesStrings.keySet().stream() .sorted(Collections.reverseOrder(Comparator.comparingInt(PlayerRole::getWeight))) - .forEach(playerRole -> - infoMessage.append(Message.ISLAND_INFO_ROLES.getMessage(locale, playerRole, rolesStrings.get(playerRole)))); + .forEach(playerRole -> { + StringBuilder players = rolesStrings.get(playerRole); + if (players != null && players.length() > 0) + infoMessage.append(Message.ISLAND_INFO_ROLES.getMessage(locale, playerRole, players)); + }); } if (!Message.ISLAND_INFO_FOOTER.isEmpty(locale)) diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 65c6749c65..122de0c2b1 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -608,7 +608,7 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: |- &e&lInsel | &7{0}s: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&lInsel | &7Besucheranzahl: {0}' +ISLAND_INFO_VISITORS_COUNT: '&e&lInsel | &7Besucheranzahl: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lInsel | &7Wert: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsland | &7Die Insel wurde erfolgreich der Öffentlichkeit zugänglich diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index abb513c288..28b6329520 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -490,7 +490,7 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lIsland | &7{0}s: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&lIsland | &7Visitors Count: {0}' +ISLAND_INFO_VISITORS_COUNT: '&e&lIsland | &7Visitors Count: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lIsland | &7Worth: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsland | &7Successfully opened the island to the public.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 7cb46fe4b9..c74426fab8 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -490,7 +490,7 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lIsla | &7{0}s: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&lIsla | &7Número de visitantes: {0}' +ISLAND_INFO_VISITORS_COUNT: '&e&lIsla | &7Número de visitantes: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lIsla | &7Valor: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsla | &7Abrió con éxito la isla al público.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 1d4e7804be..4cb4718362 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -492,7 +492,7 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lIle | &7{0}s: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&lIle | &7Nombre de visiteurs: {0}' +ISLAND_INFO_VISITORS_COUNT: '&e&lIle | &7Nombre de visiteurs: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lIle | &7Valeur: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIle | &7L''île est désormais ouverte au public.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index f031bc0c17..cc795f2292 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -498,7 +498,7 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lIsola | &7{0}: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&lIsola | &7Numero di visitatori: {0}' +ISLAND_INFO_VISITORS_COUNT: '&e&lIsola | &7Numero di visitatori: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lIsola | &7Valore: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsola | &7Aperta con successo l''isola al pubblico.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index e98bfb7ee1..1cf53081d7 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -508,7 +508,7 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lיא | &7{0}s: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&lיא | &7םירקבמ רפסמ: {0}' +ISLAND_INFO_VISITORS_COUNT: '&e&lIsland | &7Visitors Count: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lיא | &7יווש: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lיא | &7החלצהב רוביצל חתפנ יאה.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 6ab7b94134..721b6ef3d6 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -490,7 +490,7 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lWyspa | &7{0}s: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&lWyspa | &7Odwiedzajacy: {0}' +ISLAND_INFO_VISITORS_COUNT: '&e&lWyspa | &7Odwiedzajacy: {0} ({1} unikalnych odwiedzajacych)' ISLAND_INFO_WORTH: '&e&lWyspa | &7Wartosc: {0}' ISLAND_NAME_NONE: Brak ISLAND_OPENED: '&e&lWyspa | &7Pomyslnie zmieniles status wyspy na publiczny.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 47835c42f6..c4532f4069 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -490,7 +490,7 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lIlha | &7{0}s: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&lIlha | &7Contagem de visitantes: {0}' +ISLAND_INFO_VISITORS_COUNT: '&e&lIlha | &7Contagem de visitantes: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lIlha | &7Valor: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIlha | &7A ilha foi aberta com sucesso ao público.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 49d34a7ddf..0ac276e3af 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -490,7 +490,7 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lОстров | &7{0}ы: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&lОстров | &7Количество посетителей: {0}' +ISLAND_INFO_VISITORS_COUNT: '&e&lОстров | &7Количество посетителей: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lОстров | &7Стоимость: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lОстров | &7Остров успешно открыт для публики.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index b2fea3b0f8..99eaec67de 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -579,7 +579,7 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lAda | &7{0}lar: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&lAda | &7Ziyaretçi Sayısı: {0}' +ISLAND_INFO_VISITORS_COUNT: '&e&lAda | &7Ziyaretçi Sayısı: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lAda | &7Değer: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lAda | &7Ada başarıyla halka açıldı.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 2a65a0064d..23cb2cc925 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -546,7 +546,7 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&lĐảo | &7{0}s: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&lĐảo | &7Số lượt khách: {0}' +ISLAND_INFO_VISITORS_COUNT: '&e&lĐảo | &7Số lượt khách: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&lĐảo | &7Đáng giá: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lĐảo | &7Mở đảo thành công cho công cộng.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 9264d21763..1a23e06d99 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -490,7 +490,7 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&l岛屿 | &7{0}s: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&l岛屿 | &7访客数量: {0}' +ISLAND_INFO_VISITORS_COUNT: '&e&l岛屿 | &7访客数量: {0} ({1} unique visitors)' ISLAND_INFO_WORTH: '&e&l岛屿 | &7价值: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&l岛屿 | &7成功将岛屿设置为对公众开放.' From b4b83679c252401a1f0ede0e040db5c610ad6b47 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 13 Sep 2025 17:25:22 +0300 Subject: [PATCH 289/600] Fixed issues when having block limits and using the stacked-blocks deposit menu (#2640) --- .../StackedBlocksInteractionServiceImpl.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java index 0b0caf03f3..49c6742902 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java @@ -248,19 +248,21 @@ private InteractionResult handleBlockStackInternal(SuperiorPlayer superiorPlayer } } - int newStackedBlockAmount = blockAmount + amountToDeposit; + if (amountToDeposit > 0) { + int newStackedBlockAmount = blockAmount + amountToDeposit; - if (onlinePlayer != null && !PluginEventsFactory.callBlockStackEvent(stackedBlock, onlinePlayer, blockAmount, newStackedBlockAmount)) - return InteractionResult.EVENT_CANCELLED; + if (onlinePlayer != null && !PluginEventsFactory.callBlockStackEvent(stackedBlock, onlinePlayer, blockAmount, newStackedBlockAmount)) + return InteractionResult.EVENT_CANCELLED; - if (!plugin.getStackedBlocks().setStackedBlock(stackedBlockLocation, blockKey, newStackedBlockAmount)) - return InteractionResult.GLITCHED_STACKED_BLOCK; + if (!plugin.getStackedBlocks().setStackedBlock(stackedBlockLocation, blockKey, newStackedBlockAmount)) + return InteractionResult.GLITCHED_STACKED_BLOCK; - if (island != null) - island.handleBlockPlace(blockKey, amountToDeposit); + if (island != null) + island.handleBlockPlace(blockKey, amountToDeposit); - plugin.getProviders().notifyStackedBlocksListeners(onlinePlayer == null ? superiorPlayer.asOfflinePlayer() : onlinePlayer, - stackedBlock, IStackedBlocksListener.Action.BLOCK_PLACE); + plugin.getProviders().notifyStackedBlocksListeners(onlinePlayer == null ? superiorPlayer.asOfflinePlayer() : onlinePlayer, + stackedBlock, IStackedBlocksListener.Action.BLOCK_PLACE); + } final int finalAmountToDeposit = amountToDeposit; From a33cc68bc807276f6a5717c340c49431178d2a5a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 13 Sep 2025 19:18:44 +0300 Subject: [PATCH 290/600] Fix comment of the spawn-protection section (#2636) --- src/main/resources/config.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 92a758cecd..1b9561fa84 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -386,8 +386,8 @@ spawn: location: SuperiorWorld, 0, 100, 0, 0, 0 # Should the spawn be protected? - # When disabled, it's your responsibility to protect the spawn! - # Therefore, settings will be still applied to the area if false. + # When set to false, settings and permissions will not be applied to the spawn region. + # In that case, it is your own responsibility to protect the spawn region. protection: true # A list of settings that will be enabled for the spawn. @@ -511,17 +511,17 @@ clear-on-disband: # List of clear actions to perform on players when they accept an invite. # Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY # You can disable this feature by setting the section to 'clear-on-join: []' -clear-on-join: [] +clear-on-join: [ ] # List of clear actions to perform on players when they are kicked from their island. # Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY # You can disable this feature by setting the section to 'clear-on-kick: []' -clear-on-kick: [] +clear-on-kick: [ ] # List of clear actions to perform on players when they leave an island. # Available actions: EFFECTS, ENDER_CHEST, EXPERIENCE, HEALTH, HUNGER, INVENTORY # You can disable this feature by setting the section to 'clear-on-leave: []' -clear-on-leave: [] +clear-on-leave: [ ] # Should players be able to rate their own islands? rate-own-island: false From f79a2f4b3afc63641f854f8ee419868f6ff19ef6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 15 Sep 2025 23:10:51 +0300 Subject: [PATCH 291/600] Fix the ability to exceed block limits by changing spawner types (#2647) --- .../upgrades/type/UpgradeTypeBlockLimits.java | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java index 870fdac826..633596008f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java @@ -73,8 +73,8 @@ public void onBlockPlace(BlockPlaceEvent e) { } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) - public void onCartPlace(PlayerInteractEvent e) { - if (e.getAction() != Action.RIGHT_CLICK_BLOCK || !Materials.isRail(e.getClickedBlock().getType())) + public void onPlayerRightClickBlock(PlayerInteractEvent e) { + if (e.getAction() != Action.RIGHT_CLICK_BLOCK) return; PlayerHand playerHand = BukkitItems.getHand(e); @@ -85,20 +85,60 @@ public void onCartPlace(PlayerInteractEvent e) { if (handItem == null) return; + Material clickedBlockType = e.getClickedBlock().getType(); + + if (onCartPlaceInternal(e, clickedBlockType, handItem) || + onSpawnerChangeInternal(e, clickedBlockType, handItem)) + e.setCancelled(true); + } + + private boolean onCartPlaceInternal(PlayerInteractEvent e, Material clickedBlockType, ItemStack handItem) { + if (!Materials.isRail(clickedBlockType)) + return false; + Material handItemType = handItem.getType(); if (!Materials.isMinecart(handItemType)) - return; + return false; MutableObject minecraftKey = new MutableObject<>(null); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventMinecartPlace(handItemType, e.getClickedBlock().getLocation(wrapper.getHandle()), minecraftKey)) { - e.setCancelled(true); Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format( minecraftKey.getValue().getGlobalKey())); + return true; } } + + return false; + } + + private boolean onSpawnerChangeInternal(PlayerInteractEvent e, Material clickedBlockType, ItemStack handItem) { + if (clickedBlockType != Materials.SPAWNER.toBukkitType()) + return false; + + Material handItemType = handItem.getType(); + if (!Materials.isSpawnEgg(handItemType)) + return false; + + Key oldSpawnerKey = Keys.of(e.getClickedBlock()); + Key newSpawnerKey = Keys.ofSpawner(BukkitItems.getEntityType(e.getItem())); + + if (oldSpawnerKey.equals(newSpawnerKey)) + return false; + + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation(wrapper.getHandle())); + } + + if (island != null && island.hasReachedBlockLimit(newSpawnerKey)) { + Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(newSpawnerKey.toString())); + return true; + } + + return false; } @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) @@ -217,6 +257,7 @@ public void onStructureGrow(StructureGrowEvent e) { e.getBlocks().removeIf(blockState -> island.hasReachedBlockLimit(Keys.of(blockState))); } + } } From 62978a82783d120726eaf503184e4954424cd6ee Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 19 Sep 2025 20:41:15 +0300 Subject: [PATCH 292/600] Optimized checks for islands when not needed (#2654) --- .../api/player/DelegateSuperiorPlayer.java | 15 ++ .../api/wrappers/SuperiorPlayer.java | 22 +++ .../StackedBlocksManagerImpl.java | 4 + .../DefaultStackedBlocksContainer.java | 4 + .../container/StackedBlocksContainer.java | 2 + .../island/GridManagerImpl.java | 8 +- .../superiorskyblock/island/SIsland.java | 11 +- .../listener/BlockChangesListener.java | 159 ++++++++++++++--- .../listener/ChunksListener.java | 12 +- .../listener/EntityTrackingListener.java | 17 +- .../listener/FeaturesListener.java | 14 +- .../listener/IslandFlagsListener.java | 120 +++++++++++-- .../listener/IslandPreviewListener.java | 8 +- .../listener/IslandWorldEventsListener.java | 13 +- .../listener/PlayersListener.java | 60 +++++-- .../listener/PortalsListener.java | 4 +- .../listener/SignsListener.java | 27 ++- .../listener/StackedBlocksListener.java | 56 +++++- .../listener/WorldDestructionListener.java | 48 +++++- .../player/PlayersManagerImpl.java | 2 +- .../player/SSuperiorPlayer.java | 24 +++ .../player/SuperiorNPCPlayer.java | 40 ++++- .../region/RegionManagerServiceImpl.java | 163 +++++++++++++----- .../StackedBlocksInteractionServiceImpl.java | 16 ++ 24 files changed, 713 insertions(+), 136 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java index e3ffa1bb27..3b569047dc 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java @@ -253,6 +253,21 @@ public List getInvites() { return this.handle.getInvites(); } + @Override + public void addCoop(Island island) { + this.handle.addCoop(island); + } + + @Override + public void removeCoop(Island island) { + this.handle.removeCoop(island); + } + + @Override + public List getCoopIslands() { + return this.handle.getCoopIslands(); + } + @Override public PlayerRole getPlayerRole() { return this.handle.getPlayerRole(); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java index 75e446c458..225023c08e 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java @@ -337,6 +337,28 @@ public interface SuperiorPlayer extends IMissionsHolder, IPersistentDataHolder, */ List getInvites(); + /** + * Mark player as a coop of an island. + * !Can cause issues if not used properly! + * + * @param island The island to mark the player as coop. + * @throws IllegalArgumentException if island doesn't contain player as a coop. + */ + void addCoop(Island island); + + /** + * Remove mark of the player as a coop of an island. + * !Can cause issues if not used properly! + * + * @param island The island to remove the mark of the player as coop. + */ + void removeCoop(Island island); + + /** + * Get all islands that the player is coop of. + */ + List getCoopIslands(); + /** * Get the role of the player. */ diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java index 4f6cfe81e3..7406e1c62a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java @@ -209,6 +209,10 @@ public Map getStackedBlocks() { return Collections.unmodifiableMap(allStackedBlocks); } + public boolean hasStackedBlocks() { + return this.stackedBlocksContainer.size() > 0; + } + @Override public void updateStackedBlockHologram(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null."); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/container/DefaultStackedBlocksContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/container/DefaultStackedBlocksContainer.java index e0855903a8..a38d006695 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/container/DefaultStackedBlocksContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/container/DefaultStackedBlocksContainer.java @@ -53,4 +53,8 @@ public void removeStackedBlocks(ChunkPosition chunkPosition, Consumer consumer); + int size(); + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index 2c527d9b99..7d65b71ec9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -553,14 +553,18 @@ public Island getIsland(String islandName) { } @Override - public Island getIslandAt(Location location) { + public Island getIslandAt(@Nullable Location location) { if (location == null) return null; + World world = location.getWorld(); + if (world == null) + return null; + if (spawnIsland != null && spawnIsland.isInside(location)) return spawnIsland; - return this.islandsContainer.getIslandAt(location); + return isIslandsWorld(world) ? this.islandsContainer.getIslandAt(location) : null; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 0229e08a3d..9272f3d387 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -8,7 +8,6 @@ import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.enums.Rating; import com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider; -import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; import com.bgsoftware.superiorskyblock.api.island.BlockChangeResult; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandBlockFlags; @@ -713,8 +712,11 @@ public void addCoop(SuperiorPlayer superiorPlayer) { boolean coopPlayer = coopPlayers.add(superiorPlayer); - if (coopPlayer) - plugin.getMenus().refreshCoops(this); + if (!coopPlayer) + return; + + superiorPlayer.addCoop(this); + plugin.getMenus().refreshCoops(this); } @Override @@ -729,6 +731,8 @@ public void removeCoop(SuperiorPlayer superiorPlayer) { if (!uncoopPlayer) return; + superiorPlayer.removeCoop(this); + superiorPlayer.runIfOnline(player -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (isLocked() && isInside(player.getLocation(wrapper.getHandle()))) { @@ -1794,6 +1798,7 @@ public void disbandIsland() { }); invitedPlayers.forEach(invitedPlayer -> invitedPlayer.removeInvite(this)); + coopPlayers.forEach(coopPlayer -> coopPlayer.removeCoop(this)); if (BuiltinModules.BANK.getConfiguration().hasDisbandRefund()) { BigDecimal disbandRefund = BuiltinModules.BANK.getConfiguration().getDisbandRefund(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index 05e05dc934..05620ba373 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; @@ -37,10 +38,13 @@ import org.bukkit.inventory.ItemStack; import java.util.Collection; +import java.util.Map; import java.util.concurrent.TimeUnit; public class BlockChangesListener extends AbstractGameEventListener { + private static final Map BUCKET_TO_KEY_CACHE = new ArrayMap<>(); + @Nullable private static final Material CHORUS_FLOWER = EnumHelper.getEnum(Material.class, "CHORUS_FLOWER"); @Nullable @@ -51,6 +55,14 @@ public class BlockChangesListener extends AbstractGameEventListener { @WorldRecordFlags private static final int ALL_RECORD_FLAGS = REGULAR_RECORD_FLAGS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS; + static { + for (Material material : Material.values()) { + if (material.name().contains("_BUCKET")) { + BUCKET_TO_KEY_CACHE.put(material, getBlockKeyFromBucketMaterial(material)); + } + } + } + private final Collection alreadySpongeAbosrbCalled = AutoRemovalCollection.newArrayList(5L * 50, TimeUnit.MILLISECONDS); private final LazyReference worldRecordService = new LazyReference() { @@ -69,6 +81,11 @@ public BlockChangesListener(SuperiorSkyblockPlugin plugin) { private void onBlockPlace(GameEvent e) { Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + BlockState replacedState = e.getArgs().replacedState; boolean shouldAvoidReplacedState = replacedState.equals(block.getState()); @@ -84,7 +101,11 @@ private void onBlockPlace(GameEvent e) { private void onBucketEmpty(GameEvent e) { Material bucket = e.getArgs().bucket; - Key blockKey = Keys.ofMaterialAndData(bucket.name().replace("_BUCKET", "")); + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(e.getArgs().clickedBlock.getWorld())) + return; + + Key blockKey = BUCKET_TO_KEY_CACHE.computeIfAbsent(bucket, BlockChangesListener::getBlockKeyFromBucketMaterial); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Block clickedBlock = e.getArgs().clickedBlock; this.worldRecordService.get().recordBlockPlace(blockKey, @@ -94,6 +115,10 @@ private void onBucketEmpty(GameEvent e) { } private void onStructureGrow(GameEvent e) { + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(e.getArgs().location.getWorld())) + return; + KeyMap placedBlockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); KeyMap brokenBlockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); e.getArgs().blocks.forEach(blockState -> { @@ -113,6 +138,11 @@ private void onStructureGrow(GameEvent e) { private void onBlockGrow(GameEvent e) { Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + BlockState newState = e.getArgs().newState; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { @@ -124,6 +154,11 @@ private void onBlockGrow(GameEvent e) { private void onBlockForm(GameEvent e) { Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + BlockState newState = e.getArgs().newState; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { @@ -135,6 +170,11 @@ private void onBlockForm(GameEvent e) { private void onBlockSpread(GameEvent e) { Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + BlockState newState = e.getArgs().newState; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { @@ -150,6 +190,10 @@ private void onMinecartPlace(GameEvent e) { if (!(vehicle instanceof Minecart)) return; + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(vehicle.getWorld())) + return; + Key minecartBlockKey = getMinecartBlockKey(vehicle.getType()); if (minecartBlockKey != null) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { @@ -172,6 +216,10 @@ private void onSpawnerChange(GameEvent e) { if (handItem == null) return; + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(clickedBlock.getWorld())) + return; + Material handItemType = handItem.getType(); if (!Materials.isSpawnEgg(handItemType)) return; @@ -195,8 +243,13 @@ private void onSpawnerChange(GameEvent e) { } private void onEntityChangeBlock(GameEvent e) { - Key newBlockKey = e.getArgs().newType; Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + + Key newBlockKey = e.getArgs().newType; Key oldBlockKey = Keys.of(block); if (newBlockKey.equals(oldBlockKey)) @@ -221,16 +274,32 @@ private void onEntityChangeBlock(GameEvent /* BLOCK BREAKS */ private void onBlockBreak(GameEvent e) { - this.worldRecordService.get().recordBlockBreak(e.getArgs().block, ALL_RECORD_FLAGS); + Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + + this.worldRecordService.get().recordBlockBreak(block, ALL_RECORD_FLAGS); } private void onBlockDestroy(GameEvent e) { - this.worldRecordService.get().recordBlockBreak(e.getArgs().block, WorldRecordFlags.DIRTY_CHUNKS); + Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + + this.worldRecordService.get().recordBlockBreak(block, WorldRecordFlags.DIRTY_CHUNKS); } private void onBucketFill(GameEvent e) { Block clickedBlock = e.getArgs().clickedBlock; + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(clickedBlock.getWorld())) + return; + boolean isWaterLogged = plugin.getNMSWorld().isWaterLogged(clickedBlock); if (isWaterLogged || clickedBlock.isLiquid()) { Key blockKey = isWaterLogged ? ConstantKeys.WATER : Keys.of(clickedBlock); @@ -243,26 +312,37 @@ private void onBucketFill(GameEvent e) { } private void onDragonEggDrop(GameEvent e) { - if (!(e.getArgs().entity instanceof Item)) + Entity entity = e.getArgs().entity; + + if (!(entity instanceof Item)) return; - Item item = (Item) e.getArgs().entity; + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) + return; - if (item.getItemStack().getType() == Material.DRAGON_EGG) { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - for (Entity nearby : item.getNearbyEntities(2, 2, 2)) { - if (nearby instanceof FallingBlock) { - Key blockKey = plugin.getNMSAlgorithms().getFallingBlockType((FallingBlock) nearby); - this.worldRecordService.get().recordBlockBreak(blockKey, nearby.getLocation(wrapper.getHandle()), - 1, WorldRecordFlags.SAVE_BLOCK_COUNT); - return; - } + Item item = (Item) entity; + + if (item.getItemStack().getType() != Material.DRAGON_EGG) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + for (Entity nearby : item.getNearbyEntities(2, 2, 2)) { + if (nearby instanceof FallingBlock) { + Key blockKey = plugin.getNMSAlgorithms().getFallingBlockType((FallingBlock) nearby); + this.worldRecordService.get().recordBlockBreak(blockKey, nearby.getLocation(wrapper.getHandle()), + 1, WorldRecordFlags.SAVE_BLOCK_COUNT); + return; } } } } private void onPistonExtend(GameEvent e) { + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) + return; + for (Block block : e.getArgs().blocks) { if (plugin.getNMSWorld().getPistonReaction(block) == PistonPushReaction.DESTROY) { this.worldRecordService.get().recordBlockBreak(block, 1, REGULAR_RECORD_FLAGS); @@ -271,13 +351,25 @@ private void onPistonExtend(GameEvent e) { } private void onLeavesDecay(GameEvent e) { - this.worldRecordService.get().recordBlockBreak(e.getArgs().block, 1, REGULAR_RECORD_FLAGS); + Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + + this.worldRecordService.get().recordBlockBreak(block, 1, REGULAR_RECORD_FLAGS); } private void onBlockFromTo(GameEvent e) { + Block block = e.getArgs().block; + // Ignore dragon eggs, otherwise it will add +1 to the count of dragon eggs // when right-clicking them - if (e.getArgs().block.getType() == Material.DRAGON_EGG) + if (block.getType() == Material.DRAGON_EGG) + return; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; Block toBlock = e.getArgs().toBlock; @@ -294,15 +386,21 @@ private void onBlockFromTo(GameEvent e) { } private void onBlockFade(GameEvent e) { + Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + BlockState newState = e.getArgs().newState; if (newState.getType() == Material.AIR) { - this.worldRecordService.get().recordBlockBreak(e.getArgs().block, REGULAR_RECORD_FLAGS); + this.worldRecordService.get().recordBlockBreak(block, REGULAR_RECORD_FLAGS); } else { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { this.worldRecordService.get().recordBlockPlace(Keys.of(newState), newState.getLocation(wrapper.getHandle()), 1, - e.getArgs().block.getState(), + block.getState(), REGULAR_RECORD_FLAGS); } } @@ -311,6 +409,10 @@ private void onBlockFade(GameEvent e) { private void onEntityExplode(GameEvent e) { Entity entity = e.getArgs().entity; + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) + return; + KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); e.getArgs().blocks.forEach(block -> { Material blockType = block.getType(); @@ -332,7 +434,13 @@ private void onEntityExplode(GameEvent e) { } private void onChorusHit(GameEvent e) { - BukkitEntities.getPlayerSource(e.getArgs().entity).ifPresent(shooter -> { + Entity entity = e.getArgs().entity; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) + return; + + BukkitEntities.getPlayerSource(entity).ifPresent(shooter -> { Block hitBlock = e.getArgs().hitBlock; if (hitBlock != null && hitBlock.getType() == CHORUS_FLOWER) { this.worldRecordService.get().recordBlockBreak(hitBlock, 1, REGULAR_RECORD_FLAGS); @@ -341,8 +449,13 @@ private void onChorusHit(GameEvent e) { } private void onSpongeAbsorb(GameEvent e) { + Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Block block = e.getArgs().block; Location location = block.getLocation(wrapper.getHandle()); if (alreadySpongeAbosrbCalled.contains(location)) @@ -400,4 +513,8 @@ private static Key getMinecartBlockKey(EntityType minecartType) { return null; } + private static Key getBlockKeyFromBucketMaterial(Material material) { + return Keys.ofMaterialAndData(material.name().replace("_BUCKET", "")); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java index c6d9609d8b..c52ad0f6cf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java @@ -59,10 +59,18 @@ public ChunksListener(SuperiorSkyblockPlugin plugin) { } private void onChunkUnload(GameEvent e) { + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(e.getArgs().chunk.getWorld())) + return; + handleChunkUnload(e.getArgs().chunk); } private void onWorldUnload(GameEvent e) { + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(e.getArgs().world)) + return; + for (Chunk loadedChunk : e.getArgs().world.getLoadedChunks()) handleChunkUnload(loadedChunk); } @@ -74,9 +82,6 @@ private void onChunkLoad(GameEvent e) { /* INTERNAL */ private void handleChunkUnload(Chunk chunk) { - if (!plugin.getGrid().isIslandsWorld(chunk.getWorld())) - return; - plugin.getStackedBlocks().removeStackedBlockHolograms(chunk); List chunkIslands = plugin.getGrid().getIslandsAt(chunk); @@ -97,6 +102,7 @@ private void handleIslandChunkUnload(Island island, Chunk chunk) { } private void handleChunkLoad(Chunk chunk, boolean isNewChunk) { + // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(chunk.getWorld())) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java index 9eb1c58c0c..0842c688b6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/EntityTrackingListener.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import org.bukkit.entity.Entity; public class EntityTrackingListener extends AbstractGameEventListener { @@ -23,11 +24,23 @@ public EntityTrackingListener(SuperiorSkyblockPlugin plugin) { } private void onEntitySpawn(GameEvent e) { - this.worldRecordService.get().recordEntitySpawn(e.getArgs().entity); + Entity entity = e.getArgs().entity; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) + return; + + this.worldRecordService.get().recordEntitySpawn(entity); } private void onEntityDeath(GameEvent e) { - worldRecordService.get().recordEntityDespawn(e.getArgs().entity); + Entity entity = e.getArgs().entity; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) + return; + + worldRecordService.get().recordEntityDespawn(entity); } /* INTERNAL */ diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java index b337df86a4..c8a46ddff9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java @@ -105,6 +105,7 @@ private void onObsidianClick(GameEvent e) { clickedBlock.getType() != Material.OBSIDIAN) return; + // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(clickedBlock.getWorld())) return; @@ -146,6 +147,11 @@ private void onObsidianClick(GameEvent e) { private void onPlayerCommand(GameEvent e) { Player player = e.getArgs().player; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(player.getWorld())) + return; + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); if (superiorPlayer.hasBypassModeEnabled()) @@ -172,8 +178,9 @@ private void onPlayerCommand(GameEvent e) { /* BLOCKS TRACKING */ private void onChunkLoad(GameEvent e) { - List chunkIslands = plugin.getGrid().getIslandsAt(e.getArgs().chunk); - chunkIslands.forEach(island -> handleIslandChunkLoad(island, e.getArgs().chunk)); + Chunk chunk = e.getArgs().chunk; + List chunkIslands = plugin.getGrid().getIslandsAt(chunk); + chunkIslands.forEach(island -> handleIslandChunkLoad(island, chunk)); } private void handleIslandChunkLoad(Island island, Chunk chunk) { @@ -234,8 +241,7 @@ private void onSculkShriekerInteract(GameEvent originalFireballsDamager = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS); + private final World spawnIslandWorld; + public IslandFlagsListener(SuperiorSkyblockPlugin plugin) { super(plugin); + + // We want to optimize island checks only for island worlds + // However, if the spawn world is not an islands world, we want to check it as well. + Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter( + plugin.getSettings().getWorlds().getDefaultWorldDimension()); + this.spawnIslandWorld = spawnLocation.getWorld(); + this.registerListeners(); } @@ -86,6 +96,11 @@ private void onAttemptEntitySpawn(GameEvent e) { Entity entity = e.getArgs().entity; + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(entity.getWorld())) { + return; + } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); @@ -127,6 +147,11 @@ private void onHangingBreakByEntity(GameEvent e private void onEntityExplode(GameEvent e) { Entity entity = e.getArgs().entity; + + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(entity.getWorld())) + return; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventEntityExplosion(entity, entity.getLocation(wrapper.getHandle()))) e.getArgs().blocks.clear(); @@ -134,14 +159,26 @@ private void onEntityExplode(GameEvent e) { } private void onEntityChangeBlock(GameEvent e) { + Block block = e.getArgs().block; + + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(block.getWorld())) + return; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventEntityExplosion(e.getArgs().entity, e.getArgs().block.getLocation(wrapper.getHandle()))) + if (preventEntityExplosion(e.getArgs().entity, block.getLocation(wrapper.getHandle()))) e.setCancelled(); } } private void onFireballDamage(GameEvent e) { Entity entity = e.getArgs().entity; + + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(entity.getWorld())) { + return; + } + if (entity instanceof Fireball) { originalFireballsDamager.put(entity.getUniqueId(), ((Fireball) entity).getShooter()); } @@ -184,6 +221,11 @@ private void onBlockFlow(GameEvent e) { Block block = e.getArgs().block; Block toBlock = e.getArgs().toBlock; + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(toBlock.getWorld())) { + return; + } + IslandFlag islandFlag = plugin.getNMSWorld().isWaterLogged(block) ? IslandFlags.WATER_FLOW : IslandFlags.LAVA_FLOW; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { @@ -193,20 +235,41 @@ private void onBlockFlow(GameEvent e) { } private void onCropsGrowth(GameEvent e) { + Block block = e.getArgs().block; + + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(block.getWorld())) { + return; + } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventAction(e.getArgs().block.getLocation(wrapper.getHandle()), IslandFlags.CROPS_GROWTH)) + if (preventAction(block.getLocation(wrapper.getHandle()), IslandFlags.CROPS_GROWTH)) e.setCancelled(); } } private void onTreeGrowth(GameEvent e) { - if (preventAction(e.getArgs().location, IslandFlags.TREE_GROWTH)) + Location location = e.getArgs().location; + + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(location.getWorld())) { + return; + } + + if (preventAction(location, IslandFlags.TREE_GROWTH)) e.setCancelled(); } private void onFireSpread(GameEvent e) { + Block block = e.getArgs().block; + + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(block.getWorld())) { + return; + } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventAction(e.getArgs().block.getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD)) + if (preventAction(block.getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD)) e.setCancelled(); } } @@ -215,8 +278,15 @@ private void onBlockIgnite(GameEvent e) { if (e.getArgs().igniteCause != BlockIgniteEvent.IgniteCause.SPREAD) return; + Block block = e.getArgs().block; + + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(block.getWorld())) { + return; + } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventAction(e.getArgs().block.getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD)) + if (preventAction(block.getLocation(wrapper.getHandle()), IslandFlags.FIRE_SPREAD)) e.setCancelled(); } } @@ -225,8 +295,15 @@ private void onEndermanGrief(GameEvent e) if (!(e.getArgs().entity instanceof Enderman)) return; + Block block = e.getArgs().block; + + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(block.getWorld())) { + return; + } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventAction(e.getArgs().block.getLocation(wrapper.getHandle()), IslandFlags.ENDERMAN_GRIEF)) + if (preventAction(block.getLocation(wrapper.getHandle()), IslandFlags.ENDERMAN_GRIEF)) e.setCancelled(); } } @@ -240,6 +317,11 @@ private void onEggLay(GameEvent e) { if (item.getItemStack().getType() != Material.EGG) return; + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(item.getWorld())) { + return; + } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventAction(item.getLocation(wrapper.getHandle()), IslandFlags.EGG_LAY)) { for (Entity entity : item.getNearbyEntities(1, 1, 1)) { @@ -259,6 +341,11 @@ private void onPoisonAttack(GameEvent e) { if (entityType != EntityType.SPLASH_POTION) return; + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(entity.getWorld())) { + return; + } + BukkitEntities.getPlayerSource(entity).ifPresent(shooterPlayer -> { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (!preventAction(entity.getLocation(wrapper.getHandle()), IslandFlags.PVP)) @@ -276,13 +363,10 @@ private void onPoisonAttack(GameEvent e) { /* INTERNAL */ - private boolean preventAction(Location location, IslandFlag islandFlag, Flag... flags) { + private boolean preventAction(Location location, IslandFlag islandFlag) { Island island = plugin.getGrid().getIslandAt(location); - - if (island == null) { - EnumSet flagsSet = flags.length == 0 ? EnumSet.noneOf(Flag.class) : EnumSet.copyOf(Arrays.asList(flags)); - return !flagsSet.contains(Flag.ALLOW_OUTSIDE) && plugin.getGrid().isIslandsWorld(location.getWorld()); - } + if (island == null) + return false; if (!plugin.getSettings().getSpawn().isProtected() && island.isSpawn()) return false; @@ -306,6 +390,10 @@ private void registerListeners() { registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.LOWEST, this::onPoisonAttack); } + private boolean shouldIgnoreWorldEvents(@Nullable World world) { + return world == null || (world != this.spawnIslandWorld && !plugin.getGrid().isIslandsWorld(world)); + } + private static EnumSet initializeNaturalSpawnReasons() { EnumSet naturalSpawnReasons = EnumSet.noneOf(CreatureSpawnEvent.SpawnReason.class); @@ -327,10 +415,4 @@ private static EnumSet initializeNaturalSpawnRea return naturalSpawnReasons; } - private enum Flag { - - ALLOW_OUTSIDE - - } - } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java index 017d31bccb..c0d5abb8cc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java @@ -24,8 +24,10 @@ private void onPlayerQuit(GameEvent e) { Player player = e.getArgs().player; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); - if (superiorPlayer instanceof SuperiorNPCPlayer) + if (superiorPlayer instanceof SuperiorNPCPlayer) { + ((SuperiorNPCPlayer) superiorPlayer).release(); return; + } // Cancelling island preview mode if (plugin.getGrid().getIslandPreview(superiorPlayer) != null) { @@ -45,8 +47,10 @@ private void onPlayerTeleport(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) entity); - if (superiorPlayer instanceof SuperiorNPCPlayer) + if (superiorPlayer instanceof SuperiorNPCPlayer) { + ((SuperiorNPCPlayer) superiorPlayer).release(); return; + } if (((Player) entity).getGameMode() == GameMode.SPECTATOR && plugin.getGrid().getIslandPreview(superiorPlayer) != null) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java index 92475758c6..9acd8da18b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import org.bukkit.Location; +import org.bukkit.block.Block; import org.bukkit.entity.Entity; public class IslandWorldEventsListener extends AbstractGameEventListener { @@ -33,9 +34,15 @@ public IslandWorldEventsListener(SuperiorSkyblockPlugin plugin) { } private void onBlockRedstone(GameEvent e) { + Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(e.getArgs().block.getLocation(wrapper.getHandle())); + island = plugin.getGrid().getIslandAt(block.getLocation(wrapper.getHandle())); } if (island == null || island.isSpawn()) @@ -54,6 +61,10 @@ private void onEntitySpawn(GameEvent e) { if (hologramsService.get().isHologram(entity)) return; + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) + return; + Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle())); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java index 96dacb701c..74f5439581 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java @@ -13,7 +13,6 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; @@ -113,8 +112,10 @@ private void onPlayerJoin(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); - if (superiorPlayer instanceof SuperiorNPCPlayer) + if (superiorPlayer instanceof SuperiorNPCPlayer) { + ((SuperiorNPCPlayer) superiorPlayer).release(); return; + } // Updating the name of the player. if (!superiorPlayer.getName().equals(player.getName())) { @@ -175,16 +176,16 @@ private void onPlayerQuit(GameEvent e) { Player player = e.getArgs().player; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); - if (superiorPlayer instanceof SuperiorNPCPlayer) + if (superiorPlayer instanceof SuperiorNPCPlayer) { + ((SuperiorNPCPlayer) superiorPlayer).release(); return; + } // Removing coop status from other islands. - for (Island _island : plugin.getGrid().getIslands()) { - if (_island.isCoop(superiorPlayer)) { - if (PluginEventsFactory.callIslandUncoopPlayerEvent(_island, null, superiorPlayer, IslandUncoopPlayerEvent.UncoopReason.SERVER_LEAVE)) { - _island.removeCoop(superiorPlayer); - IslandUtils.sendMessage(_island, Message.UNCOOP_LEFT_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); - } + for (Island coopIsland : superiorPlayer.getCoopIslands()) { + if (PluginEventsFactory.callIslandUncoopPlayerEvent(coopIsland, null, superiorPlayer, IslandUncoopPlayerEvent.UncoopReason.SERVER_LEAVE)) { + coopIsland.removeCoop(superiorPlayer); + IslandUtils.sendMessage(coopIsland, Message.UNCOOP_LEFT_ANNOUNCEMENT, Collections.emptyList(), superiorPlayer.getName()); } } @@ -233,7 +234,12 @@ private void onPlayerMove(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); - if (superiorPlayer instanceof SuperiorNPCPlayer || superiorPlayer.hasPlayerStatus(PlayerStatus.VOID_TELEPORT)) + if (superiorPlayer instanceof SuperiorNPCPlayer) { + ((SuperiorNPCPlayer) superiorPlayer).release(); + return; + } + + if (superiorPlayer.hasPlayerStatus(PlayerStatus.VOID_TELEPORT)) return; MoveResult moveResult = this.regionManagerService.get().handlePlayerMove( @@ -254,9 +260,14 @@ private void onPlayerTeleport(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getArgs().entity); - if (superiorPlayer == null || superiorPlayer instanceof SuperiorNPCPlayer) + if (superiorPlayer == null) return; + if (superiorPlayer instanceof SuperiorNPCPlayer) { + ((SuperiorNPCPlayer) superiorPlayer).release(); + return; + } + MoveResult moveResult = this.regionManagerService.get().handlePlayerTeleport( superiorPlayer, e.getArgs().from, e.getArgs().to); if (moveResult != MoveResult.SUCCESS) @@ -266,6 +277,11 @@ private void onPlayerTeleport(GameEvent e) { private void onPlayerChangeWorld(GameEvent e) { Player player = e.getArgs().player; + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(player.getWorld())) + return; + Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); @@ -290,12 +306,9 @@ private void onPlayerDamage(GameEvent e) { Player player = (Player) e.getArgs().entity; SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(player); - if (targetPlayer instanceof SuperiorNPCPlayer) + if (targetPlayer instanceof SuperiorNPCPlayer) { + ((SuperiorNPCPlayer) targetPlayer).release(); return; - - Island island; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); } SuperiorPlayer damagerPlayer = e.getArgs().damager == null ? null : @@ -303,10 +316,23 @@ private void onPlayerDamage(GameEvent e) { .map(plugin.getPlayers()::getSuperiorPlayer).orElse(null); // Some plugins, such as Sentinel, may actually cause a NPC to attack. - if (damagerPlayer instanceof SuperiorNPCPlayer) + if (damagerPlayer instanceof SuperiorNPCPlayer) { + ((SuperiorNPCPlayer) damagerPlayer).release(); return; + } if (damagerPlayer == null) { + // We do not care about spawn island when spawn protection is disabled or player damage is enabled in spawn, + // and therefore only island worlds are relevant. + if ((!plugin.getSettings().getSpawn().isProtected() || plugin.getSettings().getSpawn().isPlayersDamage()) && + !plugin.getGrid().isIslandsWorld(player.getWorld())) + return; + + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); + } + if (island != null) { if (island.isSpawn() ? (plugin.getSettings().getSpawn().isProtected() && !plugin.getSettings().getSpawn().isPlayersDamage()) : ((!plugin.getSettings().isVisitorsDamage() && island.isVisitor(targetPlayer, false)) || diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java index 362e444f51..d94ef68d6b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java @@ -133,8 +133,10 @@ private void onEntityEnterPortal(GameEvent private void handlePlayerPortal(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer((Player) e.getArgs().entity); - if (superiorPlayer instanceof SuperiorNPCPlayer) + if (superiorPlayer instanceof SuperiorNPCPlayer) { + ((SuperiorNPCPlayer) superiorPlayer).release(); return; + } PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? PortalType.NETHER : PortalType.ENDER; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java index 9d1b677e1c..3994d99593 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java @@ -3,6 +3,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; @@ -20,6 +21,7 @@ import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.block.data.Directional; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import java.util.Arrays; @@ -37,8 +39,13 @@ public SignsListener(SuperiorSkyblockPlugin plugin) { } private void onSignPlace(GameEvent e) { - Player player = e.getArgs().player; Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + + Player player = e.getArgs().player; String[] lines = e.getArgs().lines; String[] signLines; @@ -85,9 +92,15 @@ private void onSignPlace(GameEvent e) { } private void onSignBreak(GameEvent e) { + Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(e.getArgs().block.getLocation(wrapper.getHandle())); + island = plugin.getGrid().getIslandAt(block.getLocation(wrapper.getHandle())); } if (!isValidIsland(island)) @@ -95,7 +108,7 @@ private void onSignBreak(GameEvent e) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); - IslandSigns.Result result = handleBlockBreak(island, e.getArgs().block, superiorPlayer); + IslandSigns.Result result = handleBlockBreak(island, block, superiorPlayer); if (result.isCancelEvent()) e.setCancelled(); } @@ -104,9 +117,15 @@ private void onSignExplode(GameEvent e) { if (e.getArgs().isSoftExplosion) return; + Entity entity = e.getArgs().entity; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) + return; + Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(e.getArgs().entity.getLocation(wrapper.getHandle())); + island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle())); } if (!isValidIsland(island)) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java index 4950e55d23..ba383a0697 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java @@ -24,6 +24,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.block.Action; import org.bukkit.event.entity.CreatureSpawnEvent; @@ -67,6 +68,11 @@ private void onStackedBlockInteract(GameEvent private void onStackedBlockPlace(GameEvent e) { Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + Block againstBlock = e.getArgs().againstBlock; if (againstBlock.equals(block)) @@ -97,6 +103,9 @@ private void onStackedBlockPlace(GameEvent e) { } private boolean handleStackedBlockPlace(GameEvent e) { + if (!plugin.getSettings().getStackedBlocks().isEnabled()) + return false; + boolean cancelled = false; Player player = e.getArgs().player; @@ -149,6 +158,10 @@ private boolean handleStackedBlockUnstack(GameEvent e if (e.getArgs().isSoftExplosion) return; + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(e.getArgs().entity.getWorld())) + return; + Iterator blockIterator = e.getArgs().blocks.iterator(); while (blockIterator.hasNext()) { Block block = blockIterator.next(); @@ -223,6 +240,10 @@ private void onStackedBlockExplode(GameEvent e /* STACKED-BLOCKS PROTECTION */ private void onPistonExtend(GameEvent e) { + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) + return; + for (Block block : e.getArgs().blocks) { if (plugin.getStackedBlocks().getStackedBlockAmount(block) > 1) { e.setCancelled(); @@ -232,6 +253,10 @@ private void onPistonExtend(GameEvent e) { } public void onPistonRetract(GameEvent e) { + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) + return; + for (Block block : e.getArgs().blocks) { if (plugin.getStackedBlocks().getStackedBlockAmount(block) > 1) { e.setCancelled(); @@ -241,18 +266,27 @@ public void onPistonRetract(GameEvent e) { } private void onBlockChangeState(GameEvent e) { + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) + return; + if (plugin.getStackedBlocks().getStackedBlockAmount(e.getArgs().block) > 1) e.setCancelled(); } private void onGolemCreate(GameEvent e) { List entityTemplateOffsets = ENTITY_TEMPLATE_OFFSETS.get(e.getArgs().spawnReason); - if (entityTemplateOffsets == null) return; + Entity entity = e.getArgs().entity; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) + return; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location entityLocation = e.getArgs().entity.getLocation(wrapper.getHandle()); + Location entityLocation = entity.getLocation(wrapper.getHandle()); if (plugin.getStackedBlocks().getStackedBlockAmount(entityLocation) > 1) { e.setCancelled(); @@ -269,11 +303,19 @@ private void onGolemCreate(GameEvent e) { } private void onSpongeAbsorb(GameEvent e) { + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) + return; + if (plugin.getStackedBlocks().getStackedBlockAmount(e.getArgs().block) > 1) e.setCancelled(); } private void onStackedBlockPhysics(GameEvent e) { + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) + return; + if (plugin.getStackedBlocks().getStackedBlockAmount(e.getArgs().block) > 1) e.setCancelled(); } @@ -281,7 +323,15 @@ private void onStackedBlockPhysics(GameEvent e) /* INTERNAL */ private void registerListeners() { - registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockPlace); + if (!plugin.getSettings().getStackedBlocks().isEnabled()) { + // Even if stacked blocks are disabled, we might want to keep the break or change related listeners. + // We only want to keep them if there are any stacked blocks registered. + if (!plugin.getStackedBlocks().hasStackedBlocks()) + return; + } else { + registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockPlace); + } + registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockBreak); registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockInteract); registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.HIGHEST, this::onStackedBlockBreakByEntity); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java index 7b1c7bcd52..cff7000802 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java @@ -24,8 +24,14 @@ public WorldDestructionListener(SuperiorSkyblockPlugin plugin) { //Checking for structures growing outside island. private void onStructureGrow(GameEvent e) { Location location = e.getArgs().location; + + // We care about destruction of island worlds only + if (!plugin.getGrid().isIslandsWorld(location.getWorld())) { + return; + } + Island island = plugin.getGrid().getIslandAt(location); - if (island != null && plugin.getGrid().isIslandsWorld(location.getWorld())) { + if (island != null) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { e.getArgs().blocks.removeIf(blockState -> !island.isInsideRange(blockState.getLocation(wrapper.getHandle()))); @@ -35,31 +41,59 @@ private void onStructureGrow(GameEvent e) { //Checking for chorus flower spread outside island. private void onBlockSpread(GameEvent e) { + Block block = e.getArgs().block; + + // We care about destruction of island worlds only + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) { + return; + } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { if (preventDestruction(e.getArgs().source.getLocation(wrapper.getHandle())) || - preventDestruction(e.getArgs().block.getLocation(wrapper.getHandle()))) + preventDestruction(block.getLocation(wrapper.getHandle()))) e.setCancelled(); } } public void onPistonExtend(GameEvent e) { + Block block = e.getArgs().block; + + // We care about destruction of island worlds only + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) { + return; + } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventMultiDestruction(e.getArgs().block.getLocation(wrapper.getHandle()), e.getArgs().blocks, null)) + if (preventMultiDestruction(block.getLocation(wrapper.getHandle()), e.getArgs().blocks, null)) e.setCancelled(); } } public void onPistonRetract(GameEvent e) { + Block pistonBlock = e.getArgs().block; + + // We care about destruction of island worlds only + if (!plugin.getGrid().isIslandsWorld(pistonBlock.getWorld())) { + return; + } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventMultiDestruction(e.getArgs().block.getLocation(wrapper.getHandle()), e.getArgs().blocks, + if (preventMultiDestruction(pistonBlock.getLocation(wrapper.getHandle()), e.getArgs().blocks, block -> block.getRelative(e.getArgs().direction))) e.setCancelled(); } } private void onBlockFlow(GameEvent e) { + Block block = e.getArgs().toBlock; + + // We care about destruction of island worlds only + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) { + return; + } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location blockLocation = e.getArgs().toBlock.getLocation(wrapper.getHandle()); + Location blockLocation = block.getLocation(wrapper.getHandle()); if (preventDestruction(blockLocation)) e.setCancelled(); } @@ -69,7 +103,7 @@ private void onBlockFlow(GameEvent e) { private boolean preventDestruction(Location location) { Island island = plugin.getGrid().getIslandAt(location); - return island == null ? plugin.getGrid().isIslandsWorld(location.getWorld()) : !island.isInsideRange(location); + return island == null || !island.isInsideRange(location); } private boolean preventMultiDestruction(Location islandLocation, List blockList, @@ -77,7 +111,7 @@ private boolean preventMultiDestruction(Location islandLocation, List blo Island island = plugin.getGrid().getIslandAt(islandLocation); if (island == null) - return plugin.getGrid().isIslandsWorld(islandLocation.getWorld()); + return true; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { for (Block block : blockList) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/PlayersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/player/PlayersManagerImpl.java index 341bf43a24..6673645b52 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/PlayersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/PlayersManagerImpl.java @@ -47,7 +47,7 @@ public SuperiorPlayer getSuperiorPlayer(String name) { @Override public SuperiorPlayer getSuperiorPlayer(Player player) { Preconditions.checkNotNull(player, "player parameter cannot be null."); - return player.hasMetadata("NPC") ? new SuperiorNPCPlayer(player) : getSuperiorPlayer(player.getUniqueId()); + return player.hasMetadata("NPC") ? SuperiorNPCPlayer.obtain(player) : getSuperiorPlayer(player.getUniqueId()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index c0edccb613..3fa2152ec6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -68,6 +68,7 @@ public class SSuperiorPlayer implements SuperiorPlayer { private final Map completedMissions = new ConcurrentHashMap<>(); private final List pendingInvites = new LinkedList<>(); + private final List coopIslands = new LinkedList<>(); private final UUID uuid; @@ -131,6 +132,11 @@ private static HitActionResult checkPvPAllow(SuperiorPlayer player, boolean targ if (player.hasPlayerStatus(PlayerStatus.PVP_IMMUNED)) return target ? HitActionResult.TARGET_PVP_WARMUP : HitActionResult.PVP_WARMUP; + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(player.getWorld())) + return HitActionResult.SUCCESS; + Island standingIsland; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { standingIsland = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); @@ -532,6 +538,24 @@ public List getInvites() { .map(this.pendingInvites, uuid -> plugin.getGrid().getIslandByUUID(uuid)); } + @Override + public void addCoop(Island island) { + Preconditions.checkNotNull(island, "island parameter cannot be null"); + Preconditions.checkArgument(island.isCoop(this), "player is not coop of given island"); + this.coopIslands.add(island); + } + + @Override + public void removeCoop(Island island) { + Preconditions.checkNotNull(island, "island parameter cannot be null"); + this.coopIslands.remove(island); + } + + @Override + public List getCoopIslands() { + return new SequentialListBuilder().build(this.coopIslands); + } + @Override public PlayerRole getPlayerRole() { PlayerRole playerRole = this.playerRole.get(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java index 9aa0d09c87..70b267938d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java @@ -14,6 +14,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.database.bridge.EmptyDatabaseBridge; import com.bgsoftware.superiorskyblock.core.persistence.EmptyPersistentDataContainer; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; @@ -21,7 +22,6 @@ import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; @@ -32,12 +32,29 @@ import java.util.UUID; import java.util.function.Consumer; -public class SuperiorNPCPlayer implements SuperiorPlayer { +public class SuperiorNPCPlayer implements SuperiorPlayer, ObjectsPool.Releasable { - private final Entity npc; + private static final ObjectsPool POOL = new ObjectsPool<>(SuperiorNPCPlayer::new); - public SuperiorNPCPlayer(Entity npc) { + public static SuperiorNPCPlayer obtain(Player npc) { + return POOL.obtain().initialize(npc); + } + + private Player npc; + + private SuperiorNPCPlayer() { + + } + + private SuperiorNPCPlayer initialize(Player npc) { this.npc = npc; + return this; + } + + @Override + public void release() { + this.npc = null; + } @Override @@ -257,6 +274,21 @@ public List getInvites() { return Collections.emptyList(); } + @Override + public void addCoop(Island island) { + throw new UnsupportedOperationException("Cannot mark NPCs as coop players"); + } + + @Override + public void removeCoop(Island island) { + throw new UnsupportedOperationException("Cannot mark NPCs as coop players"); + } + + @Override + public List getCoopIslands() { + throw new UnsupportedOperationException("Cannot mark NPCs as coop players"); + } + @Override public PlayerRole getPlayerRole() { return SPlayerRole.guestRole(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index da130966ed..1766b4ba71 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -128,10 +128,14 @@ public InteractionResult handleBlockPlace(SuperiorPlayer superiorPlayer, Block b Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(block.getWorld())) + return InteractionResult.SUCCESS; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(blockLocation); - return handleInteractionInternal(superiorPlayer, blockLocation, island, IslandPrivileges.BUILD, + return handleInteractionInternal(superiorPlayer, blockLocation, IslandPrivileges.BUILD, 0, true, true); } } @@ -141,6 +145,11 @@ public InteractionResult handleBlockBreak(SuperiorPlayer superiorPlayer, Block b Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(block.getWorld())) + return InteractionResult.SUCCESS; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); Island island = plugin.getGrid().getIslandAt(blockLocation); @@ -148,7 +157,8 @@ public InteractionResult handleBlockBreak(SuperiorPlayer superiorPlayer, Block b Material blockType = block.getType(); IslandPrivilege islandPrivilege = blockType == Materials.SPAWNER.toBukkitType() ? IslandPrivileges.SPAWNER_BREAK : IslandPrivileges.BREAK; - InteractionResult interactionResult = handleInteractionInternal(superiorPlayer, blockLocation, island, islandPrivilege, 0, true, true); + InteractionResult interactionResult = handleInteractionInternal(superiorPlayer, blockLocation, islandPrivilege, + 0, true, true, island, false); if (interactionResult != InteractionResult.SUCCESS) return interactionResult; @@ -157,7 +167,8 @@ public InteractionResult handleBlockBreak(SuperiorPlayer superiorPlayer, Block b return InteractionResult.SUCCESS; if (plugin.getSettings().getValuableBlocks().contains(Keys.of(block))) - return handleInteractionInternal(superiorPlayer, blockLocation, island, IslandPrivileges.VALUABLE_BREAK, 0, false, false); + return handleInteractionInternal(superiorPlayer, blockLocation, IslandPrivileges.VALUABLE_BREAK, + 0, false, false, island, false); } return InteractionResult.SUCCESS; @@ -168,6 +179,11 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(block.getWorld())) + return InteractionResult.SUCCESS; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); Key blockKey = Keys.of(block); @@ -179,8 +195,6 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc if (!isInteractableItem && stackedBlockAmount <= 1 && !INTERACTABLES_CACHE.contains(blockKey)) return InteractionResult.SUCCESS; - Island island = plugin.getGrid().getIslandAt(blockLocation); - BlockState blockState = block.getState(); EntityType spawnType = usedItem == null ? EntityType.UNKNOWN : BukkitItems.getEntityType(usedItem); Material blockType = block.getType(); @@ -217,7 +231,7 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc islandPrivilege = IslandPrivileges.INTERACT; } - return handleInteractionInternal(superiorPlayer, blockLocation, island, islandPrivilege, + return handleInteractionInternal(superiorPlayer, blockLocation, islandPrivilege, 0, true, true); } } @@ -227,11 +241,14 @@ public InteractionResult handleBlockFertilize(SuperiorPlayer superiorPlayer, Blo Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(block, "block cannot be null"); + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(block.getWorld())) + return InteractionResult.SUCCESS; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(blockLocation); - - return handleInteractionInternal(superiorPlayer, blockLocation, island, IslandPrivileges.FERTILIZE, + return handleInteractionInternal(superiorPlayer, blockLocation, IslandPrivileges.FERTILIZE, 0, true, true); } } @@ -241,12 +258,16 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(entity, "entity cannot be null"); + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(entity.getWorld())) + return InteractionResult.SUCCESS; + InteractionResult interactionResult; boolean closeInventory = false; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(entityLocation); EntityType entityType = entity.getType(); Material usedItemType = usedItem == null ? Material.AIR : usedItem.getType(); @@ -288,7 +309,8 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent return InteractionResult.SUCCESS; } - interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, island, islandPrivilege, 0, true, true); + interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, islandPrivilege, + 0, true, true); } if (closeInventory && interactionResult != InteractionResult.SUCCESS) { @@ -310,6 +332,11 @@ public InteractionResult handleEntityDamage(Entity damager, Entity entity) { Preconditions.checkNotNull(damager, "damager cannot be null"); Preconditions.checkNotNull(entity, "entity cannot be null"); + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(entity.getWorld())) + return InteractionResult.SUCCESS; + Optional damagerSource = BukkitEntities.getPlayerSource(damager).map(plugin.getPlayers()::getSuperiorPlayer); if (!damagerSource.isPresent()) @@ -319,10 +346,9 @@ public InteractionResult handleEntityDamage(Entity damager, Entity entity) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(entityLocation); IslandPrivilege islandPrivilege = BukkitEntities.getCategory(entity.getType()).getDamagePrivilege(); - interactionResult = handleInteractionInternal(damagerSource.get(), entityLocation, island, islandPrivilege, + interactionResult = handleInteractionInternal(damagerSource.get(), entityLocation, islandPrivilege, 0, true, false); } @@ -337,13 +363,17 @@ public InteractionResult handleEntityRide(SuperiorPlayer superiorPlayer, Entity Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(vehicle, "vehicle cannot be null"); + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(vehicle.getWorld())) + return InteractionResult.SUCCESS; + IslandPrivilege islandPrivilege = BukkitEntities.isHorse(vehicle) ? IslandPrivileges.HORSE_INTERACT : vehicle instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_ENTER; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = vehicle.getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(entityLocation); - return handleInteractionInternal(superiorPlayer, entityLocation, island, islandPrivilege, + return handleInteractionInternal(superiorPlayer, entityLocation, islandPrivilege, 0, true, false); } } @@ -353,11 +383,14 @@ public InteractionResult handleEntityShear(SuperiorPlayer superiorPlayer, Entity Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(entity, "entity cannot be null"); + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(entity.getWorld())) + return InteractionResult.SUCCESS; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(entityLocation); - - return handleInteractionInternal(superiorPlayer, entityLocation, island, IslandPrivileges.ANIMAL_SHEAR, + return handleInteractionInternal(superiorPlayer, entityLocation, IslandPrivileges.ANIMAL_SHEAR, 0, true, false); } } @@ -367,11 +400,14 @@ public InteractionResult handleEntityLeash(SuperiorPlayer superiorPlayer, Entity Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(entity, "entity cannot be null"); + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(entity.getWorld())) + return InteractionResult.SUCCESS; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(entityLocation); - - return handleInteractionInternal(superiorPlayer, entityLocation, island, IslandPrivileges.LEASH, + return handleInteractionInternal(superiorPlayer, entityLocation, IslandPrivileges.LEASH, 0, true, false); } } @@ -384,11 +420,14 @@ public InteractionResult handlePlayerPickupItem(SuperiorPlayer superiorPlayer, I if (plugin.getNMSPlayers().wasThrownByPlayer(item, superiorPlayer)) return InteractionResult.SUCCESS; + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(item.getWorld())) + return InteractionResult.SUCCESS; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location itemLocation = item.getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(itemLocation); - - return handleInteractionInternal(superiorPlayer, itemLocation, island, IslandPrivileges.PICKUP_DROPS, + return handleInteractionInternal(superiorPlayer, itemLocation, IslandPrivileges.PICKUP_DROPS, MAX_PICKUP_DISTANCE, true, false); } } @@ -398,11 +437,14 @@ public InteractionResult handlePlayerDropItem(SuperiorPlayer superiorPlayer, Ite Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null"); Preconditions.checkNotNull(item, "item cannot be null"); + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(item.getWorld())) + return InteractionResult.SUCCESS; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location itemLocation = item.getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(itemLocation); - - return handleInteractionInternal(superiorPlayer, itemLocation, island, IslandPrivileges.DROP_ITEMS, + return handleInteractionInternal(superiorPlayer, itemLocation, IslandPrivileges.DROP_ITEMS, 0, true, false); } } @@ -413,9 +455,13 @@ public InteractionResult handlePlayerEnderPearl(SuperiorPlayer superiorPlayer, L Preconditions.checkNotNull(destination, "destination cannot be null"); Preconditions.checkArgument(destination.getWorld() != null, "destination's world cannot be null"); - Island island = plugin.getGrid().getIslandAt(destination); + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(destination.getWorld())) + return InteractionResult.SUCCESS; - return handleInteractionInternal(superiorPlayer, destination, island, IslandPrivileges.ENDER_PEARL, 0, true, false); + return handleInteractionInternal(superiorPlayer, destination, IslandPrivileges.ENDER_PEARL, + 0, true, false); } @Override @@ -429,8 +475,12 @@ public InteractionResult handlePlayerConsumeChorusFruit(SuperiorPlayer superiorP return InteractionResult.SUCCESS; } - Island island = plugin.getGrid().getIslandAt(location); - return handleInteractionInternal(superiorPlayer, location, island, IslandPrivileges.CHORUS_FRUIT, + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(location.getWorld())) + return InteractionResult.SUCCESS; + + return handleInteractionInternal(superiorPlayer, location, IslandPrivileges.CHORUS_FRUIT, 0, true, true); } @@ -445,8 +495,12 @@ public InteractionResult handlePlayerUseWindCharge(SuperiorPlayer superiorPlayer return InteractionResult.SUCCESS; } - Island island = plugin.getGrid().getIslandAt(location); - return handleInteractionInternal(superiorPlayer, location, island, IslandPrivileges.WIND_CHARGE, + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(location.getWorld())) + return InteractionResult.SUCCESS; + + return handleInteractionInternal(superiorPlayer, location, IslandPrivileges.WIND_CHARGE, 0, true, true); } @@ -456,16 +510,33 @@ public InteractionResult handleCustomInteraction(SuperiorPlayer superiorPlayer, Preconditions.checkNotNull(location, "location cannot be null"); Preconditions.checkNotNull(islandPrivilege, "islandPrivilege cannot be null"); - Island island = plugin.getGrid().getIslandAt(location); - return handleInteractionInternal(superiorPlayer, location, island, islandPrivilege, 0, true, false); + // We do not care about spawn island when spawn protection is disabled, + // and therefore only island worlds are relevant. + if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(location.getWorld())) + return InteractionResult.SUCCESS; + + return handleInteractionInternal(superiorPlayer, location, islandPrivilege, + 0, true, false); + } + + private InteractionResult handleInteractionInternal(SuperiorPlayer superiorPlayer, Location location, + IslandPrivilege islandPrivilege, int extraRadius, + boolean checkIslandBoundaries, boolean checkRecalculation) { + return handleInteractionInternal(superiorPlayer, location, islandPrivilege, extraRadius, checkIslandBoundaries, + checkRecalculation, null, true); } private InteractionResult handleInteractionInternal(SuperiorPlayer superiorPlayer, Location location, - @Nullable Island island, IslandPrivilege islandPrivilege, - int extraRadius, boolean checkIslandBoundaries, boolean checkRecalculation) { + IslandPrivilege islandPrivilege, int extraRadius, + boolean checkIslandBoundaries, boolean checkRecalculation, + @Nullable Island island, boolean callIslandLookup) { if (superiorPlayer.hasBypassModeEnabled()) return InteractionResult.SUCCESS; + if (callIslandLookup) { + island = plugin.getGrid().getIslandAt(location); + } + if (checkIslandBoundaries && !WORLD_PERMISSIONS_CACHE.contains(islandPrivilege)) { if (island == null && plugin.getGrid().isIslandsWorld(superiorPlayer.getWorld())) return InteractionResult.OUTSIDE_ISLAND; @@ -491,6 +562,9 @@ public MoveResult handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, Preconditions.checkNotNull(from, "from cannot be null"); Preconditions.checkNotNull(to, "to cannot be null"); + Island fromIsland = null; + boolean lookupFromIsland = true; + if (from.getBlockX() != to.getBlockX() || from.getBlockZ() != to.getBlockZ()) { // Handle moving while in teleport warmup. BukkitTask teleportTask = superiorPlayer.getTeleportTask(); @@ -522,7 +596,9 @@ public MoveResult handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, return moveResult; } - Island fromIsland = plugin.getGrid().getIslandAt(from); + lookupFromIsland = false; + + fromIsland = plugin.getGrid().getIslandAt(from); if (fromIsland != null) { moveResult = handlePlayerLeaveIslandInternal(superiorPlayer, fromIsland, from, to, IslandLeaveEvent.LeaveCause.PLAYER_MOVE); if (moveResult != MoveResult.SUCCESS) @@ -531,16 +607,19 @@ public MoveResult handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, } if (from.getBlockY() != to.getBlockY() && to.getBlockY() <= plugin.getNMSWorld().getMinHeight(to.getWorld()) - 5) { - Island island = plugin.getGrid().getIslandAt(from); + if (lookupFromIsland) { + fromIsland = plugin.getGrid().getIslandAt(from); + } - if (island == null || (island.isVisitor(superiorPlayer, false) ? !plugin.getSettings().getVoidTeleport().isVisitors() : !plugin.getSettings().getVoidTeleport().isMembers())) + if (fromIsland == null || (fromIsland.isVisitor(superiorPlayer, false) ? + !plugin.getSettings().getVoidTeleport().isVisitors() : !plugin.getSettings().getVoidTeleport().isMembers())) return MoveResult.SUCCESS; Log.debug(Debug.VOID_TELEPORT, superiorPlayer.getName()); superiorPlayer.setPlayerStatus(PlayerStatus.VOID_TELEPORT); - superiorPlayer.teleport(island, result -> { + superiorPlayer.teleport(fromIsland, result -> { if (!result) { Message.TELEPORTED_FAILED.send(superiorPlayer); superiorPlayer.teleport(plugin.getGrid().getSpawnIsland(), result2 -> { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java index 49c6742902..b351fce3bd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java @@ -67,6 +67,10 @@ public InteractionResult handleStackedBlockPlace(SuperiorPlayer superiorPlayer, if (!plugin.getSettings().getStackedBlocks().isEnabled()) return InteractionResult.STACKED_BLOCKS_DISABLED; + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return InteractionResult.DISABLED_WORLD; + Player onlinePlayer = superiorPlayer.asPlayer(); ItemStack handItem = onlinePlayer == null ? null : BukkitItems.getHandItem(onlinePlayer, PlayerHand.of(usedHand)); @@ -89,6 +93,10 @@ public InteractionResult handleStackedBlockPlace(SuperiorPlayer superiorPlayer, if (!plugin.getSettings().getStackedBlocks().isEnabled()) return InteractionResult.STACKED_BLOCKS_DISABLED; + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return InteractionResult.DISABLED_WORLD; + InteractionResult interactionResult = checkBlockStackInternal(superiorPlayer, block, null); if (interactionResult != InteractionResult.SUCCESS) return interactionResult; @@ -102,6 +110,10 @@ public InteractionResult checkStackedBlockInteraction(SuperiorPlayer superiorPla Preconditions.checkNotNull(block, "block parameter cannot be null"); Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null"); + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return InteractionResult.DISABLED_WORLD; + return checkBlockStackInternal(superiorPlayer, block, itemStack); } @@ -109,6 +121,10 @@ public InteractionResult checkStackedBlockInteraction(SuperiorPlayer superiorPla public InteractionResult handleStackedBlockBreak(Block block, @Nullable SuperiorPlayer superiorPlayer) { Preconditions.checkNotNull(block, "block cannot be null"); + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return InteractionResult.DISABLED_WORLD; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location blockLocation = block.getLocation(wrapper.getHandle()); From 4a7283f0e37a2eba3df80472e3d7a1d462410d8b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 19 Sep 2025 20:42:40 +0300 Subject: [PATCH 293/600] Deprecate GridManager#transferIsland --- .../bgsoftware/superiorskyblock/api/handlers/GridManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java index a1817ffb86..4fb5ef0a79 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java @@ -245,7 +245,9 @@ void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bo * * @param oldOwner The old owner of the island. * @param newOwner The new owner of the island. + * @deprecated Does nothing. See {@link Island#transferIsland(SuperiorPlayer)} */ + @Deprecated void transferIsland(UUID oldOwner, UUID newOwner); /** From ccfc47f055922cbb56ee9aaf5358a583657d4ae4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 19 Sep 2025 22:00:13 +0300 Subject: [PATCH 294/600] Add temporary cache for players and islands --- .../api/island/DelegateIsland.java | 6 ++ .../superiorskyblock/api/island/Island.java | 8 +- .../api/island/cache/IslandCache.java | 67 ++++++++++++++ .../api/island/cache/IslandCacheKey.java | 87 +++++++++++++++++++ .../api/player/DelegateSuperiorPlayer.java | 6 ++ .../api/player/cache/PlayerCache.java | 67 ++++++++++++++ .../api/player/cache/PlayerCacheKey.java | 87 +++++++++++++++++++ .../api/wrappers/SuperiorPlayer.java | 6 ++ .../nms/v1_12_R1/NMSDragonFightImpl.java | 6 +- .../EndWorldEnderDragonBattleHandler.java | 21 ++--- .../dragon/IslandEntityEnderDragon.java | 2 +- .../nms/v1_16_R3/NMSDragonFightImpl.java | 6 +- .../EndWorldEnderDragonBattleHandler.java | 21 ++--- .../dragon/IslandEntityEnderDragon.java | 2 +- .../nms/v1_17/NMSDragonFightImpl.java | 6 +- .../dragon/EndWorldEndDragonFightHandler.java | 21 ++--- .../v1_17/dragon/IslandEntityEnderDragon.java | 2 +- .../nms/v1_18/NMSDragonFightImpl.java | 6 +- .../dragon/EndWorldEndDragonFightHandler.java | 21 ++--- .../v1_18/dragon/IslandEntityEnderDragon.java | 2 +- .../nms/v1_19/NMSDragonFightImpl.java | 6 +- .../dragon/EndWorldEndDragonFightHandler.java | 21 ++--- .../v1_19/dragon/IslandEntityEnderDragon.java | 2 +- .../nms/v1_20_3/NMSDragonFightImpl.java | 6 +- .../dragon/EndWorldEndDragonFightHandler.java | 21 ++--- .../dragon/IslandEntityEnderDragon.java | 2 +- .../nms/v1_20_4/NMSDragonFightImpl.java | 6 +- .../dragon/EndWorldEndDragonFightHandler.java | 21 ++--- .../dragon/IslandEntityEnderDragon.java | 2 +- .../nms/v1_21/NMSDragonFightImpl.java | 6 +- .../dragon/EndWorldEndDragonFightHandler.java | 21 ++--- .../v1_21/dragon/IslandEntityEnderDragon.java | 2 +- .../nms/v1_21_3/NMSDragonFightImpl.java | 6 +- .../dragon/EndWorldEndDragonFightHandler.java | 21 ++--- .../dragon/IslandEntityEnderDragon.java | 2 +- .../nms/v1_21_4/NMSDragonFightImpl.java | 6 +- .../dragon/EndWorldEndDragonFightHandler.java | 21 ++--- .../dragon/IslandEntityEnderDragon.java | 2 +- .../nms/v1_21_5/NMSDragonFightImpl.java | 6 +- .../dragon/EndWorldEndDragonFightHandler.java | 22 ++--- .../dragon/IslandEntityEnderDragon.java | 2 +- .../nms/v1_21_7/NMSDragonFightImpl.java | 6 +- .../dragon/EndWorldEndDragonFightHandler.java | 21 ++--- .../dragon/IslandEntityEnderDragon.java | 2 +- .../SuperiorSkyblockPlugin.java | 2 + .../superiorskyblock/core/BaseCacheImpl.java | 59 +++++++++++++ .../superiorskyblock/island/SIsland.java | 13 +++ .../superiorskyblock/island/SpawnIsland.java | 13 +++ .../island/cache/IslandCacheImpl.java | 50 +++++++++++ .../island/cache/IslandCacheKeys.java | 27 ++++++ .../listener/ChunksListener.java | 14 +-- .../listener/IslandFlagsListener.java | 13 ++- .../listener/MenusListener.java | 15 ++-- .../player/SSuperiorPlayer.java | 14 +++ .../player/SuperiorNPCPlayer.java | 6 ++ .../player/cache/PlayerCacheImpl.java | 50 +++++++++++ .../world/BukkitEntities.java | 17 ++-- 57 files changed, 776 insertions(+), 200 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/island/cache/IslandCache.java create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/island/cache/IslandCacheKey.java create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/player/cache/PlayerCache.java create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/player/cache/PlayerCacheKey.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/BaseCacheImpl.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/island/cache/IslandCacheImpl.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/island/cache/IslandCacheKeys.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/player/cache/PlayerCacheImpl.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index a2e7b3e7a7..f970f61576 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -73,6 +74,11 @@ public void updateDatesFormatter() { this.handle.updateDatesFormatter(); } + @Override + public IslandCache getCache() { + return this.handle.getCache(); + } + @Override public List getIslandMembers(boolean includeOwner) { return this.handle.getIslandMembers(includeOwner); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java index 168694a18f..961b4f95b6 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.bank.BankTransaction; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -79,6 +80,11 @@ public interface Island extends Comparable, IMissionsHolder, IPersistent */ void updateDatesFormatter(); + /** + * Get the island cache. + */ + IslandCache getCache(); + /* * Player related methods */ @@ -172,7 +178,7 @@ public interface Island extends Comparable, IMissionsHolder, IPersistent /** * Remove a member from the island. - * + * * @param superiorPlayer The player to remove. * @param memberRemoveReason The reason for removal. */ diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/cache/IslandCache.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/cache/IslandCache.java new file mode 100644 index 0000000000..28f79add98 --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/cache/IslandCache.java @@ -0,0 +1,67 @@ +package com.bgsoftware.superiorskyblock.api.island.cache; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.Island; + +import java.util.function.Function; + +/** + * Island caches can be used by other plugins to store temporary data for an island, retrieve it, etc. + * The cache is not persistent between server sessions. For persistent data solution, see {@link Island#getPersistentDataContainer()} + * Data can be stored and retrieved by registering custom {@link IslandCacheKey} for your plugin. + * The cache is thread-safe and can be accessed from multiple threads. + */ +public interface IslandCache { + + /** + * Get the island this cache is for. + */ + Island getIsland(); + + /** + * Store data in this cache. + * + * @param key The key to store. + * @param value The value to store. + * @return The old value that was stored in the cache, or null if not data was cached. + */ + @Nullable + T store(IslandCacheKey key, T value); + + /** + * Remove data from this cache. + * + * @param key The cache key. + * @return The old value that was stored in the cache, or null if not data was cached. + */ + @Nullable + T remove(IslandCacheKey key); + + /** + * Get data that was stored. + * + * @param key The cache key + * @return The value stored for the provided key, or null if no data was cached. + */ + @Nullable + T get(IslandCacheKey key); + + /** + * Get data that was stored. + * + * @param key The cache key + * @param def The value to return in case the cache did not contain the provided key + * @return The value stored for the provided key. + */ + T getOrDefault(IslandCacheKey key, T def); + + /** + * Get data that was stored. + * + * @param key The cache key + * @param mappingFunction The value to store in case the cache did not contain the provided key + * @return The value stored for the provided key. + */ + T computeIfAbsent(IslandCacheKey key, Function, T> mappingFunction); + +} diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/cache/IslandCacheKey.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/cache/IslandCacheKey.java new file mode 100644 index 0000000000..e19c439123 --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/cache/IslandCacheKey.java @@ -0,0 +1,87 @@ +package com.bgsoftware.superiorskyblock.api.island.cache; + +import com.bgsoftware.superiorskyblock.api.objects.Enumerable; +import com.google.common.base.Preconditions; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +public class IslandCacheKey implements Enumerable { + + private static final Map> islandCacheKeys = new HashMap<>(); + private static int ordinalCounter = 0; + + private final String name; + private final Class valueType; + private final int ordinal; + + private IslandCacheKey(String name, Class valueType) { + this.name = name.toUpperCase(Locale.ENGLISH); + this.valueType = valueType; + this.ordinal = ordinalCounter++; + } + + /** + * Get the name of the island cache key. + */ + public String getName() { + return name; + } + + /** + * Get the type of the value for this cache-key. + */ + public Class getValueType() { + return valueType; + } + + @Override + public int ordinal() { + return this.ordinal; + } + + @Override + public String toString() { + return "IslandCacheKey{name=" + name + "}"; + } + + /** + * Get all the island cache keys. + */ + public static Collection> values() { + return islandCacheKeys.values(); + } + + /** + * Get an island cache key by its name. + * + * @param name The name to check. + */ + public static IslandCacheKey getByName(String name) { + Preconditions.checkNotNull(name, "name parameter cannot be null."); + + IslandCacheKey islandCacheKey = islandCacheKeys.get(name.toUpperCase(Locale.ENGLISH)); + + Preconditions.checkNotNull(islandCacheKey, "Couldn't find an IslandCacheKey with the name " + name + "."); + + return islandCacheKey; + } + + /** + * Register a new island cache key. + * + * @param name The name for the island cache key. + */ + public static void register(String name, Class valueType) { + Preconditions.checkNotNull(name, "name parameter cannot be null."); + + name = name.toUpperCase(Locale.ENGLISH); + + Preconditions.checkState(!islandCacheKeys.containsKey(name), "IslandCacheKey with the name " + name + " already exists."); + + islandCacheKeys.put(name, new IslandCacheKey<>(name, valueType)); + } + +} diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java index 3b569047dc..f50cbc54f4 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; +import com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; @@ -44,6 +45,11 @@ public String getName() { return this.handle.getName(); } + @Override + public PlayerCache getCache() { + return this.handle.getCache(); + } + @Override public String getTextureValue() { return this.handle.getTextureValue(); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/cache/PlayerCache.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/cache/PlayerCache.java new file mode 100644 index 0000000000..5d8e11af7c --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/cache/PlayerCache.java @@ -0,0 +1,67 @@ +package com.bgsoftware.superiorskyblock.api.player.cache; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; + +import java.util.function.Function; + +/** + * Player caches can be used by other plugins to store temporary data for a player, retrieve it, etc. + * The cache is not persistent between server sessions. For persistent data solution, see {@link SuperiorPlayer#getPersistentDataContainer()} + * Data can be stored and retrieved by registering custom {@link PlayerCacheKey} for your plugin. + * The cache is thread-safe and can be accessed from multiple threads. + */ +public interface PlayerCache { + + /** + * Get the player this cache is for. + */ + SuperiorPlayer getPlayer(); + + /** + * Store data in this cache. + * + * @param key The key to store. + * @param value The value to store. + * @return The old value that was stored in the cache, or null if not data was cached. + */ + @Nullable + T store(PlayerCacheKey key, T value); + + /** + * Remove data from this cache. + * + * @param key The cache key. + * @return The old value that was stored in the cache, or null if not data was cached. + */ + @Nullable + T remove(PlayerCacheKey key); + + /** + * Get data that was stored. + * + * @param key The cache key + * @return The value stored for the provided key, or null if no data was cached. + */ + @Nullable + T get(PlayerCacheKey key); + + /** + * Get data that was stored. + * + * @param key The cache key + * @param def The value to return in case the cache did not contain the provided key + * @return The value stored for the provided key. + */ + T getOrDefault(PlayerCacheKey key, T def); + + /** + * Get data that was stored. + * + * @param key The cache key + * @param mappingFunction The value to store in case the cache did not contain the provided key + * @return The value stored for the provided key. + */ + T computeIfAbsent(PlayerCacheKey key, Function, T> mappingFunction); + +} diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/cache/PlayerCacheKey.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/cache/PlayerCacheKey.java new file mode 100644 index 0000000000..7407c335f2 --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/cache/PlayerCacheKey.java @@ -0,0 +1,87 @@ +package com.bgsoftware.superiorskyblock.api.player.cache; + +import com.bgsoftware.superiorskyblock.api.objects.Enumerable; +import com.google.common.base.Preconditions; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +public class PlayerCacheKey implements Enumerable { + + private static final Map> playerCacheKeys = new HashMap<>(); + private static int ordinalCounter = 0; + + private final String name; + private final Class valueType; + private final int ordinal; + + private PlayerCacheKey(String name, Class valueType) { + this.name = name.toUpperCase(Locale.ENGLISH); + this.valueType = valueType; + this.ordinal = ordinalCounter++; + } + + /** + * Get the name of the player cache key. + */ + public String getName() { + return name; + } + + /** + * Get the type of the value for this cache-key. + */ + public Class getValueType() { + return valueType; + } + + @Override + public int ordinal() { + return this.ordinal; + } + + @Override + public String toString() { + return "PlayerCacheKey{name=" + name + "}"; + } + + /** + * Get all the player cache keys. + */ + public static Collection> values() { + return playerCacheKeys.values(); + } + + /** + * Get an player cache key by its name. + * + * @param name The name to check. + */ + public static PlayerCacheKey getByName(String name) { + Preconditions.checkNotNull(name, "name parameter cannot be null."); + + PlayerCacheKey playerCacheKey = playerCacheKeys.get(name.toUpperCase(Locale.ENGLISH)); + + Preconditions.checkNotNull(playerCacheKey, "Couldn't find an PlayerCacheKey with the name " + name + "."); + + return playerCacheKey; + } + + /** + * Register a new player cache key. + * + * @param name The name for the player cache key. + */ + public static void register(String name, Class valueType) { + Preconditions.checkNotNull(name, "name parameter cannot be null."); + + name = name.toUpperCase(Locale.ENGLISH); + + Preconditions.checkState(!playerCacheKeys.containsKey(name), "PlayerCacheKey with the name " + name + " already exists."); + + playerCacheKeys.put(name, new PlayerCacheKey<>(name, valueType)); + } + +} diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java index 225023c08e..48343f0301 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.persistence.IPersistentDataHolder; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; +import com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache; import com.bgsoftware.superiorskyblock.api.world.Dimension; import org.bukkit.Location; import org.bukkit.OfflinePlayer; @@ -43,6 +44,11 @@ public interface SuperiorPlayer extends IMissionsHolder, IPersistentDataHolder, */ String getName(); + /** + * Get the player cache. + */ + PlayerCache getCache(); + /** * Get the last known skin-texture value of the player. */ diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSDragonFightImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSDragonFightImpl.java index 50277aa2aa..a73519fe33 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSDragonFightImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSDragonFightImpl.java @@ -50,7 +50,7 @@ public EnderDragon getEnderDragon(Island island, Dimension dimension) { return null; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldEnderDragonBattle; - IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.getDragonBattle(island.getUniqueId()); + IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.getDragonBattle(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -73,7 +73,7 @@ public void startDragonBattle(Island island, Location location) { return; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) enderDragonBattle; - dragonBattleHandler.addDragonBattle(island.getUniqueId(), new IslandEnderDragonBattle(island, worldServer, location)); + dragonBattleHandler.addDragonBattle(island.getCache(), new IslandEnderDragonBattle(island, worldServer, location)); } @Override @@ -94,7 +94,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { return; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldEnderDragonBattle; - IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.removeDragonBattle(island.getUniqueId()); + IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.removeDragonBattle(island.getCache()); if (enderDragonBattle != null) { enderDragonBattle.removeBattlePlayers(); enderDragonBattle.getEnderDragon().die(); diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/EndWorldEnderDragonBattleHandler.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/EndWorldEnderDragonBattleHandler.java index e78420159a..5680bb9d8a 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/EndWorldEnderDragonBattleHandler.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/EndWorldEnderDragonBattleHandler.java @@ -1,19 +1,20 @@ package com.bgsoftware.superiorskyblock.nms.v1_12_R1.dragon; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.server.v1_12_R1.EnderDragonBattle; import net.minecraft.server.v1_12_R1.NBTTagCompound; import net.minecraft.server.v1_12_R1.WorldServer; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.UUID; public class EndWorldEnderDragonBattleHandler extends EnderDragonBattle { - private final Map worldDragonBattlesMap = new HashMap<>(); + private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_BATTLE", IslandEnderDragonBattle.class); + private final List worldDragonBattlesList = new LinkedList<>(); public EndWorldEnderDragonBattleHandler(WorldServer worldServer) { @@ -25,21 +26,21 @@ public void b() { this.worldDragonBattlesList.forEach(EnderDragonBattle::b); } - public void addDragonBattle(UUID uuid, IslandEnderDragonBattle enderDragonBattle) { - IslandEnderDragonBattle oldBattle = this.worldDragonBattlesMap.put(uuid, enderDragonBattle); + public void addDragonBattle(IslandCache islandCache, IslandEnderDragonBattle enderDragonBattle) { + IslandEnderDragonBattle oldBattle = islandCache.store(CACHE_KEY, enderDragonBattle); if (oldBattle != null) this.worldDragonBattlesList.remove(oldBattle); this.worldDragonBattlesList.add(enderDragonBattle); } @Nullable - public IslandEnderDragonBattle getDragonBattle(UUID uuid) { - return this.worldDragonBattlesMap.get(uuid); + public IslandEnderDragonBattle getDragonBattle(IslandCache islandCache) { + return islandCache.get(CACHE_KEY); } @Nullable - public IslandEnderDragonBattle removeDragonBattle(UUID uuid) { - IslandEnderDragonBattle enderDragonBattle = this.worldDragonBattlesMap.remove(uuid); + public IslandEnderDragonBattle removeDragonBattle(IslandCache islandCache) { + IslandEnderDragonBattle enderDragonBattle = islandCache.remove(CACHE_KEY); if (enderDragonBattle != null) this.worldDragonBattlesList.remove(enderDragonBattle); return enderDragonBattle; diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java index c4124f9334..1e82bff6d8 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEntityEnderDragon.java @@ -92,7 +92,7 @@ private void finalizeIslandEnderDragon() { this.islandBlockPosition = new BlockPosition(middleBlock.getX(), middleBlock.getY(), middleBlock.getZ()); IslandEnderDragonBattle dragonBattle = new IslandEnderDragonBattle(island, (WorldServer) world, this.islandBlockPosition, this); - dragonBattleHandler.addDragonBattle(island.getUniqueId(), dragonBattle); + dragonBattleHandler.addDragonBattle(island.getCache(), dragonBattle); } } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSDragonFightImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSDragonFightImpl.java index 65a914c093..f5d42cf551 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSDragonFightImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSDragonFightImpl.java @@ -67,7 +67,7 @@ public EnderDragon getEnderDragon(Island island, Dimension dimension) { return null; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldServer.getDragonBattle(); - IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.getDragonBattle(island.getUniqueId()); + IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.getDragonBattle(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -85,7 +85,7 @@ public void startDragonBattle(Island island, Location location) { return; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldServer.getDragonBattle(); - dragonBattleHandler.addDragonBattle(island.getUniqueId(), new IslandEnderDragonBattle(island, worldServer, location)); + dragonBattleHandler.addDragonBattle(island.getCache(), new IslandEnderDragonBattle(island, worldServer, location)); } @Override @@ -101,7 +101,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { return; EndWorldEnderDragonBattleHandler dragonBattleHandler = (EndWorldEnderDragonBattleHandler) worldServer.getDragonBattle(); - IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.removeDragonBattle(island.getUniqueId()); + IslandEnderDragonBattle enderDragonBattle = dragonBattleHandler.removeDragonBattle(island.getCache()); if (enderDragonBattle != null) { enderDragonBattle.removeBattlePlayers(); enderDragonBattle.getEnderDragon().die(); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/EndWorldEnderDragonBattleHandler.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/EndWorldEnderDragonBattleHandler.java index d7d7710266..e19aa48e94 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/EndWorldEnderDragonBattleHandler.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/EndWorldEnderDragonBattleHandler.java @@ -1,19 +1,20 @@ package com.bgsoftware.superiorskyblock.nms.v1_16_R3.dragon; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.server.v1_16_R3.EnderDragonBattle; import net.minecraft.server.v1_16_R3.NBTTagCompound; import net.minecraft.server.v1_16_R3.WorldServer; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.UUID; public class EndWorldEnderDragonBattleHandler extends EnderDragonBattle { - private final Map worldDragonBattlesMap = new HashMap<>(); + private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_BATTLE", IslandEnderDragonBattle.class); + private final List worldDragonBattlesList = new LinkedList<>(); public EndWorldEnderDragonBattleHandler(WorldServer worldServer) { @@ -25,21 +26,21 @@ public void b() { this.worldDragonBattlesList.forEach(EnderDragonBattle::b); } - public void addDragonBattle(UUID uuid, IslandEnderDragonBattle enderDragonBattle) { - IslandEnderDragonBattle oldBattle = this.worldDragonBattlesMap.put(uuid, enderDragonBattle); + public void addDragonBattle(IslandCache islandCache, IslandEnderDragonBattle enderDragonBattle) { + IslandEnderDragonBattle oldBattle = islandCache.store(CACHE_KEY, enderDragonBattle); if (oldBattle != null) this.worldDragonBattlesList.remove(oldBattle); this.worldDragonBattlesList.add(enderDragonBattle); } @Nullable - public IslandEnderDragonBattle getDragonBattle(UUID uuid) { - return this.worldDragonBattlesMap.get(uuid); + public IslandEnderDragonBattle getDragonBattle(IslandCache islandCache) { + return islandCache.get(CACHE_KEY); } @Nullable - public IslandEnderDragonBattle removeDragonBattle(UUID uuid) { - IslandEnderDragonBattle enderDragonBattle = this.worldDragonBattlesMap.remove(uuid); + public IslandEnderDragonBattle removeDragonBattle(IslandCache islandCache) { + IslandEnderDragonBattle enderDragonBattle = islandCache.remove(CACHE_KEY); if (enderDragonBattle != null) this.worldDragonBattlesList.remove(enderDragonBattle); return enderDragonBattle; diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java index bc186835c7..4d2330dd3c 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEntityEnderDragon.java @@ -94,7 +94,7 @@ private void finalizeIslandEnderDragon() { this.islandBlockPosition = new BlockPosition(middleBlock.getX(), middleBlock.getY(), middleBlock.getZ()); IslandEnderDragonBattle dragonBattle = new IslandEnderDragonBattle(island, (WorldServer) world, this.islandBlockPosition, this); - dragonBattleHandler.addDragonBattle(island.getUniqueId(), dragonBattle); + dragonBattleHandler.addDragonBattle(island.getCache(), dragonBattle); } } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSDragonFightImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSDragonFightImpl.java index 826b5f34ae..19c661d0e6 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSDragonFightImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSDragonFightImpl.java @@ -70,7 +70,7 @@ public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dim if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return null; - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -86,7 +86,7 @@ public void startDragonBattle(Island island, Location location) { if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); } @Override @@ -101,7 +101,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { islandEndDragonFight.removeBattlePlayers(); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndWorldEndDragonFightHandler.java index 57297c1fc3..4a0de50bde 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndWorldEndDragonFightHandler.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndWorldEndDragonFightHandler.java @@ -1,19 +1,20 @@ package com.bgsoftware.superiorskyblock.nms.v1_17.dragon; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.UUID; public class EndWorldEndDragonFightHandler extends EndDragonFight { - private final Map worldDragonFightsMap = new HashMap<>(); + private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); + private final List worldDragonFightsList = new LinkedList<>(); public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { @@ -25,21 +26,21 @@ public void tick() { this.worldDragonFightsList.forEach(EndDragonFight::tick); } - public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); if (oldDragonFight != null) this.worldDragonFightsList.remove(oldDragonFight); this.worldDragonFightsList.add(endDragonFight); } @Nullable - public IslandEndDragonFight getDragonFight(UUID uuid) { - return this.worldDragonFightsMap.get(uuid); + public IslandEndDragonFight getDragonFight(IslandCache islandCache) { + return islandCache.get(CACHE_KEY); } @Nullable - public IslandEndDragonFight removeDragonFight(UUID uuid) { - IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { + IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); if (endDragonFight != null) this.worldDragonFightsList.remove(endDragonFight); return endDragonFight; diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java index 9bb1d3cf96..276921581f 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java @@ -97,7 +97,7 @@ private void finalizeIslandEnderDragon() { this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); } } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSDragonFightImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSDragonFightImpl.java index 8a46f76c07..27536164b3 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSDragonFightImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSDragonFightImpl.java @@ -70,7 +70,7 @@ public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dim if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return null; - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -86,7 +86,7 @@ public void startDragonBattle(Island island, Location location) { if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); } @Override @@ -101,7 +101,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { islandEndDragonFight.removeBattlePlayers(); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndWorldEndDragonFightHandler.java index d04e354190..0a0748561d 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndWorldEndDragonFightHandler.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndWorldEndDragonFightHandler.java @@ -1,19 +1,20 @@ package com.bgsoftware.superiorskyblock.nms.v1_18.dragon; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.UUID; public class EndWorldEndDragonFightHandler extends EndDragonFight { - private final Map worldDragonFightsMap = new HashMap<>(); + private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); + private final List worldDragonFightsList = new LinkedList<>(); public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { @@ -25,21 +26,21 @@ public void tick() { this.worldDragonFightsList.forEach(EndDragonFight::tick); } - public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); if (oldDragonFight != null) this.worldDragonFightsList.remove(oldDragonFight); this.worldDragonFightsList.add(endDragonFight); } @Nullable - public IslandEndDragonFight getDragonFight(UUID uuid) { - return this.worldDragonFightsMap.get(uuid); + public IslandEndDragonFight getDragonFight(IslandCache islandCache) { + return islandCache.get(CACHE_KEY); } @Nullable - public IslandEndDragonFight removeDragonFight(UUID uuid) { - IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { + IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); if (endDragonFight != null) this.worldDragonFightsList.remove(endDragonFight); return endDragonFight; diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java index bd6f9bfa5d..31570857bd 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java @@ -98,7 +98,7 @@ private void finalizeIslandEnderDragon() { this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); } } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSDragonFightImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSDragonFightImpl.java index ee76962bdc..67c889826b 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSDragonFightImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSDragonFightImpl.java @@ -70,7 +70,7 @@ public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dim if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return null; - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -86,7 +86,7 @@ public void startDragonBattle(Island island, Location location) { if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); } @Override @@ -101,7 +101,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { islandEndDragonFight.removeBattlePlayers(); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndWorldEndDragonFightHandler.java index be3c16dd07..95aa749947 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndWorldEndDragonFightHandler.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndWorldEndDragonFightHandler.java @@ -1,19 +1,20 @@ package com.bgsoftware.superiorskyblock.nms.v1_19.dragon; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.UUID; public class EndWorldEndDragonFightHandler extends EndDragonFight { - private final Map worldDragonFightsMap = new HashMap<>(); + private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); + private final List worldDragonFightsList = new LinkedList<>(); public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { @@ -25,21 +26,21 @@ public void tick() { this.worldDragonFightsList.forEach(EndDragonFight::tick); } - public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); if (oldDragonFight != null) this.worldDragonFightsList.remove(oldDragonFight); this.worldDragonFightsList.add(endDragonFight); } @Nullable - public IslandEndDragonFight getDragonFight(UUID uuid) { - return this.worldDragonFightsMap.get(uuid); + public IslandEndDragonFight getDragonFight(IslandCache islandCache) { + return islandCache.get(CACHE_KEY); } @Nullable - public IslandEndDragonFight removeDragonFight(UUID uuid) { - IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { + IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); if (endDragonFight != null) this.worldDragonFightsList.remove(endDragonFight); return endDragonFight; diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java index eba35bc0cd..0914b4d4bd 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java @@ -98,7 +98,7 @@ private void finalizeIslandEnderDragon() { this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); } } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSDragonFightImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSDragonFightImpl.java index d5cb778815..c2485597d0 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSDragonFightImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSDragonFightImpl.java @@ -69,7 +69,7 @@ public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dim if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return null; - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -85,7 +85,7 @@ public void startDragonBattle(Island island, Location location) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); } @Override @@ -100,7 +100,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { islandEndDragonFight.removeBattlePlayers(); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndWorldEndDragonFightHandler.java index 036c0a8cba..b45d366953 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndWorldEndDragonFightHandler.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndWorldEndDragonFightHandler.java @@ -1,18 +1,19 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.UUID; public class EndWorldEndDragonFightHandler extends EndDragonFight { - private final Map worldDragonFightsMap = new HashMap<>(); + private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); + private final List worldDragonFightsList = new LinkedList<>(); public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { @@ -24,21 +25,21 @@ public void tick() { this.worldDragonFightsList.forEach(EndDragonFight::tick); } - public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); if (oldDragonFight != null) this.worldDragonFightsList.remove(oldDragonFight); this.worldDragonFightsList.add(endDragonFight); } @Nullable - public IslandEndDragonFight getDragonFight(UUID uuid) { - return this.worldDragonFightsMap.get(uuid); + public IslandEndDragonFight getDragonFight(IslandCache islandCache) { + return islandCache.get(CACHE_KEY); } @Nullable - public IslandEndDragonFight removeDragonFight(UUID uuid) { - IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { + IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); if (endDragonFight != null) this.worldDragonFightsList.remove(endDragonFight); return endDragonFight; diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java index fa065d33d9..6c8441e575 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java @@ -98,7 +98,7 @@ private void finalizeIslandEnderDragon() { this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); } } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSDragonFightImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSDragonFightImpl.java index 3716437422..8c8843efa1 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSDragonFightImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSDragonFightImpl.java @@ -69,7 +69,7 @@ public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dim if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return null; - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -85,7 +85,7 @@ public void startDragonBattle(Island island, Location location) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); } @Override @@ -100,7 +100,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { islandEndDragonFight.removeBattlePlayers(); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndWorldEndDragonFightHandler.java index 2592de9b0a..5f7e254e7b 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndWorldEndDragonFightHandler.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndWorldEndDragonFightHandler.java @@ -1,18 +1,19 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.UUID; public class EndWorldEndDragonFightHandler extends EndDragonFight { - private final Map worldDragonFightsMap = new HashMap<>(); + private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); + private final List worldDragonFightsList = new LinkedList<>(); public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { @@ -24,21 +25,21 @@ public void tick() { this.worldDragonFightsList.forEach(EndDragonFight::tick); } - public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); if (oldDragonFight != null) this.worldDragonFightsList.remove(oldDragonFight); this.worldDragonFightsList.add(endDragonFight); } @Nullable - public IslandEndDragonFight getDragonFight(UUID uuid) { - return this.worldDragonFightsMap.get(uuid); + public IslandEndDragonFight getDragonFight(IslandCache islandCache) { + return islandCache.get(CACHE_KEY); } @Nullable - public IslandEndDragonFight removeDragonFight(UUID uuid) { - IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { + IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); if (endDragonFight != null) this.worldDragonFightsList.remove(endDragonFight); return endDragonFight; diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java index 21e0019736..9fba3e662c 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java @@ -97,7 +97,7 @@ private void finalizeIslandEnderDragon() { this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); } } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSDragonFightImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSDragonFightImpl.java index 3daea5141b..14ddfe1921 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSDragonFightImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSDragonFightImpl.java @@ -69,7 +69,7 @@ public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dim if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return null; - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -85,7 +85,7 @@ public void startDragonBattle(Island island, Location location) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); } @Override @@ -100,7 +100,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { islandEndDragonFight.removeBattlePlayers(); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndWorldEndDragonFightHandler.java index 0768a3e368..1655d63a81 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndWorldEndDragonFightHandler.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndWorldEndDragonFightHandler.java @@ -1,18 +1,19 @@ package com.bgsoftware.superiorskyblock.nms.v1_21.dragon; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.UUID; public class EndWorldEndDragonFightHandler extends EndDragonFight { - private final Map worldDragonFightsMap = new HashMap<>(); + private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); + private final List worldDragonFightsList = new LinkedList<>(); public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { @@ -24,21 +25,21 @@ public void tick() { this.worldDragonFightsList.forEach(EndDragonFight::tick); } - public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); if (oldDragonFight != null) this.worldDragonFightsList.remove(oldDragonFight); this.worldDragonFightsList.add(endDragonFight); } @Nullable - public IslandEndDragonFight getDragonFight(UUID uuid) { - return this.worldDragonFightsMap.get(uuid); + public IslandEndDragonFight getDragonFight(IslandCache islandCache) { + return islandCache.get(CACHE_KEY); } @Nullable - public IslandEndDragonFight removeDragonFight(UUID uuid) { - IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { + IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); if (endDragonFight != null) this.worldDragonFightsList.remove(endDragonFight); return endDragonFight; diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java index 54989c98cd..3cc2b65c3f 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java @@ -97,7 +97,7 @@ private void finalizeIslandEnderDragon() { this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); } } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSDragonFightImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSDragonFightImpl.java index ea6a8033e1..c06c73f170 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSDragonFightImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSDragonFightImpl.java @@ -69,7 +69,7 @@ public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dim if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return null; - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -85,7 +85,7 @@ public void startDragonBattle(Island island, Location location) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); } @Override @@ -100,7 +100,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { islandEndDragonFight.removeBattlePlayers(); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndWorldEndDragonFightHandler.java index 746f3e034f..dfe908e641 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndWorldEndDragonFightHandler.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndWorldEndDragonFightHandler.java @@ -1,18 +1,19 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.UUID; public class EndWorldEndDragonFightHandler extends EndDragonFight { - private final Map worldDragonFightsMap = new HashMap<>(); + private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); + private final List worldDragonFightsList = new LinkedList<>(); public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { @@ -24,21 +25,21 @@ public void tick() { this.worldDragonFightsList.forEach(EndDragonFight::tick); } - public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); if (oldDragonFight != null) this.worldDragonFightsList.remove(oldDragonFight); this.worldDragonFightsList.add(endDragonFight); } @Nullable - public IslandEndDragonFight getDragonFight(UUID uuid) { - return this.worldDragonFightsMap.get(uuid); + public IslandEndDragonFight getDragonFight(IslandCache islandCache) { + return islandCache.get(CACHE_KEY); } @Nullable - public IslandEndDragonFight removeDragonFight(UUID uuid) { - IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { + IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); if (endDragonFight != null) this.worldDragonFightsList.remove(endDragonFight); return endDragonFight; diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java index 4ce6ede51f..2a10d46c3e 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java @@ -97,7 +97,7 @@ private void finalizeIslandEnderDragon() { this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); } } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSDragonFightImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSDragonFightImpl.java index 41a01f1cc2..6efec4868e 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSDragonFightImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSDragonFightImpl.java @@ -69,7 +69,7 @@ public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dim if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return null; - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -85,7 +85,7 @@ public void startDragonBattle(Island island, Location location) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); } @Override @@ -100,7 +100,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { islandEndDragonFight.removeBattlePlayers(); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndWorldEndDragonFightHandler.java index e78f27aa4e..3c3370d29e 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndWorldEndDragonFightHandler.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndWorldEndDragonFightHandler.java @@ -1,18 +1,19 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.UUID; public class EndWorldEndDragonFightHandler extends EndDragonFight { - private final Map worldDragonFightsMap = new HashMap<>(); + private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); + private final List worldDragonFightsList = new LinkedList<>(); public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { @@ -24,21 +25,21 @@ public void tick() { this.worldDragonFightsList.forEach(EndDragonFight::tick); } - public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); if (oldDragonFight != null) this.worldDragonFightsList.remove(oldDragonFight); this.worldDragonFightsList.add(endDragonFight); } @Nullable - public IslandEndDragonFight getDragonFight(UUID uuid) { - return this.worldDragonFightsMap.get(uuid); + public IslandEndDragonFight getDragonFight(IslandCache islandCache) { + return islandCache.get(CACHE_KEY); } @Nullable - public IslandEndDragonFight removeDragonFight(UUID uuid) { - IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { + IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); if (endDragonFight != null) this.worldDragonFightsList.remove(endDragonFight); return endDragonFight; diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java index 2cb6571990..54ab5dcf9e 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java @@ -97,7 +97,7 @@ private void finalizeIslandEnderDragon() { this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); } } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSDragonFightImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSDragonFightImpl.java index 236654a588..9ecfa5c8a5 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSDragonFightImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSDragonFightImpl.java @@ -69,7 +69,7 @@ public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dim if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return null; - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -85,7 +85,7 @@ public void startDragonBattle(Island island, Location location) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); } @Override @@ -100,7 +100,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { islandEndDragonFight.removeBattlePlayers(); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndWorldEndDragonFightHandler.java index e49cb190c5..286e82fa7f 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndWorldEndDragonFightHandler.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndWorldEndDragonFightHandler.java @@ -1,19 +1,19 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.IslandEndDragonFight; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.UUID; public class EndWorldEndDragonFightHandler extends EndDragonFight { - private final Map worldDragonFightsMap = new HashMap<>(); + private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); + private final List worldDragonFightsList = new LinkedList<>(); public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { @@ -25,21 +25,21 @@ public void tick() { this.worldDragonFightsList.forEach(EndDragonFight::tick); } - public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); if (oldDragonFight != null) this.worldDragonFightsList.remove(oldDragonFight); this.worldDragonFightsList.add(endDragonFight); } @Nullable - public IslandEndDragonFight getDragonFight(UUID uuid) { - return this.worldDragonFightsMap.get(uuid); + public IslandEndDragonFight getDragonFight(IslandCache islandCache) { + return islandCache.get(CACHE_KEY); } @Nullable - public IslandEndDragonFight removeDragonFight(UUID uuid) { - IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { + IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); if (endDragonFight != null) this.worldDragonFightsList.remove(endDragonFight); return endDragonFight; diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java index 99717993a5..de857b5881 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java @@ -97,7 +97,7 @@ private void finalizeIslandEnderDragon() { this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); } } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSDragonFightImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSDragonFightImpl.java index 3a9b50cd74..1a1e7c5e41 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSDragonFightImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSDragonFightImpl.java @@ -69,7 +69,7 @@ public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dim if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return null; - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getUniqueId()); + IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -85,7 +85,7 @@ public void startDragonBattle(Island island, Location location) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - dragonFightHandler.addDragonFight(island.getUniqueId(), new IslandEndDragonFight(island, serverLevel, location)); + dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); } @Override @@ -100,7 +100,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getUniqueId()); + EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { islandEndDragonFight.removeBattlePlayers(); diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndWorldEndDragonFightHandler.java index 7dbfd2f017..342e6edd6c 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndWorldEndDragonFightHandler.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndWorldEndDragonFightHandler.java @@ -1,18 +1,19 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.dimension.end.EndDragonFight; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.UUID; public class EndWorldEndDragonFightHandler extends EndDragonFight { - private final Map worldDragonFightsMap = new HashMap<>(); + private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); + private final List worldDragonFightsList = new LinkedList<>(); public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { @@ -24,21 +25,21 @@ public void tick() { this.worldDragonFightsList.forEach(EndDragonFight::tick); } - public void addDragonFight(UUID uuid, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = this.worldDragonFightsMap.put(uuid, endDragonFight); + public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { + IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); if (oldDragonFight != null) this.worldDragonFightsList.remove(oldDragonFight); this.worldDragonFightsList.add(endDragonFight); } @Nullable - public IslandEndDragonFight getDragonFight(UUID uuid) { - return this.worldDragonFightsMap.get(uuid); + public IslandEndDragonFight getDragonFight(IslandCache islandCache) { + return islandCache.get(CACHE_KEY); } @Nullable - public IslandEndDragonFight removeDragonFight(UUID uuid) { - IslandEndDragonFight endDragonFight = this.worldDragonFightsMap.remove(uuid); + public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { + IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); if (endDragonFight != null) this.worldDragonFightsList.remove(endDragonFight); return endDragonFight; diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java index 58917abbdc..c96a14d756 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java @@ -97,7 +97,7 @@ private void finalizeIslandEnderDragon() { this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getUniqueId(), dragonBattle); + dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index 86c0f648fe..bd347c9c05 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -45,6 +45,7 @@ import com.bgsoftware.superiorskyblock.core.values.container.BlockValuesContainer; import com.bgsoftware.superiorskyblock.external.ProvidersManagerImpl; import com.bgsoftware.superiorskyblock.island.GridManagerImpl; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import com.bgsoftware.superiorskyblock.island.container.DefaultIslandsContainer; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.island.preview.DefaultIslandPreviews; @@ -182,6 +183,7 @@ public void onLoad() { ClearActions.registerActions(); RespawnActions.registerActions(); Dimensions.registerDimensions(); + IslandCacheKeys.registerCacheKeys(); try { SortingComparators.initializeTopIslandMembersSorting(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/BaseCacheImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/BaseCacheImpl.java new file mode 100644 index 0000000000..3e1dadaf24 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/BaseCacheImpl.java @@ -0,0 +1,59 @@ +package com.bgsoftware.superiorskyblock.core; + +import com.bgsoftware.superiorskyblock.api.objects.Enumerable; +import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; +import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.google.common.base.Preconditions; + +import java.util.Collection; +import java.util.function.Function; + +@SuppressWarnings("unchecked") +public class BaseCacheImpl { + + private final Synchronized> cache; + + public BaseCacheImpl(Collection keys) { + this.cache = Synchronized.of(new EnumerateMap<>(keys)); + } + + public final T store(K key, T value) { + Preconditions.checkNotNull(key, "key parameter cannot be null"); + Preconditions.checkNotNull(value, "value parameter cannot be null"); + + Object oldValue = this.cache.writeAndGet(cache -> cache.put(key, value)); + return oldValue == null ? null : (T) oldValue; + } + + public T remove(K key) { + Preconditions.checkNotNull(key, "key parameter cannot be null"); + + Object oldValue = this.cache.writeAndGet(cache -> cache.remove(key)); + return oldValue == null ? null : (T) oldValue; + } + + public T get(K key) { + return getOrDefault(key, null); + } + + public T getOrDefault(K key, T def) { + Preconditions.checkNotNull(key, "key parameter cannot be null"); + + Object oldValue = this.cache.readAndGet(cache -> cache.get(key)); + return oldValue == null ? def : (T) oldValue; + } + + public T computeIfAbsent(K key, Function mappingFunction) { + Preconditions.checkNotNull(key, "key parameter cannot be null"); + Preconditions.checkNotNull(mappingFunction, "mappingFunction parameter cannot be null"); + + return (T) this.cache.writeAndGet(cache -> { + Object value = cache.get(key); + if (value == null) { + value = mappingFunction.apply(key); + cache.put(key, value); + } + return value; + }); + } +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 9272f3d387..3054d4b143 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -22,6 +22,7 @@ import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -80,6 +81,7 @@ import com.bgsoftware.superiorskyblock.core.value.Value; import com.bgsoftware.superiorskyblock.core.values.BlockValue; import com.bgsoftware.superiorskyblock.island.builder.IslandBuilderImpl; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheImpl; import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -179,6 +181,12 @@ protected PlaceholdersService create() { private final IslandEntitiesTrackerAlgorithm entitiesTracker; private final Synchronized bankInterestTask = Synchronized.of(null); private final DirtyChunksContainer dirtyChunksContainer; + private final LazyReference islandCache = new LazyReference() { + @Override + protected IslandCache create() { + return new IslandCacheImpl(SIsland.this); + } + }; /* * Island Identifiers @@ -439,6 +447,11 @@ public void updateDatesFormatter() { this.creationTimeDate = Formatters.DATE_FORMATTER.format(new Date(creationTime * 1000)); } + @Override + public IslandCache getCache() { + return this.islandCache.get(); + } + @Override public List getIslandMembers(boolean includeOwner) { List members = this.members.readAndGet(_members -> new SequentialListBuilder() diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 37344f2a57..74725dcf96 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -20,6 +20,7 @@ import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.island.bank.IslandBank; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -51,6 +52,7 @@ import com.bgsoftware.superiorskyblock.island.algorithm.SpawnIslandBlocksTrackerAlgorithm; import com.bgsoftware.superiorskyblock.island.algorithm.SpawnIslandCalculationAlgorithm; import com.bgsoftware.superiorskyblock.island.algorithm.SpawnIslandEntitiesTrackerAlgorithm; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheImpl; import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; @@ -123,6 +125,12 @@ private static void onSettingsUpdate() { private final PriorityQueue playersInside = new PriorityQueue<>(SortingComparators.PLAYER_NAMES_COMPARATOR); private final DirtyChunksContainer dirtyChunksContainer; + private final LazyReference islandCache = new LazyReference() { + @Override + protected IslandCache create() { + return new IslandCacheImpl(SpawnIsland.this); + } + }; private final BlockPosition center; private final World spawnWorld; @@ -192,6 +200,11 @@ public void updateDatesFormatter() { // Do nothing. } + @Override + public IslandCache getCache() { + return this.islandCache.get(); + } + @Override public List getIslandMembers(boolean includeOwner) { return Collections.emptyList(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/cache/IslandCacheImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/cache/IslandCacheImpl.java new file mode 100644 index 0000000000..14a09137d7 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/cache/IslandCacheImpl.java @@ -0,0 +1,50 @@ +package com.bgsoftware.superiorskyblock.island.cache; + +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import com.bgsoftware.superiorskyblock.core.BaseCacheImpl; + +import java.util.function.Function; + +public class IslandCacheImpl implements IslandCache { + + private final BaseCacheImpl> cache = new BaseCacheImpl<>(IslandCacheKey.values()); + + private final Island island; + + public IslandCacheImpl(Island island) { + this.island = island; + } + + @Override + public Island getIsland() { + return this.island; + } + + @Override + public T store(IslandCacheKey key, T value) { + return this.cache.store(key, value); + } + + @Override + public T remove(IslandCacheKey key) { + return this.cache.remove(key); + } + + @Override + public T get(IslandCacheKey key) { + return this.cache.get(key); + } + + @Override + public T getOrDefault(IslandCacheKey key, T def) { + return this.cache.getOrDefault(key, def); + } + + @Override + public T computeIfAbsent(IslandCacheKey key, Function, T> mappingFunction) { + return this.cache.computeIfAbsent(key, unused -> mappingFunction.apply(key)); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/cache/IslandCacheKeys.java b/src/main/java/com/bgsoftware/superiorskyblock/island/cache/IslandCacheKeys.java new file mode 100644 index 0000000000..39f7fd30b1 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/cache/IslandCacheKeys.java @@ -0,0 +1,27 @@ +package com.bgsoftware.superiorskyblock.island.cache; + +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; +import org.bukkit.Chunk; + +import java.util.Set; + +@SuppressWarnings({"rawtypes", "unchecked"}) +public class IslandCacheKeys { + + public static final IslandCacheKey> PENDING_LOADED_CHUNKS = + (IslandCacheKey>) (IslandCacheKey) register("PENDING_LOADED_CHUNKS", Set.class); + + private IslandCacheKeys() { + + } + + public static void registerCacheKeys() { + // Do nothing, only trigger all the register calls + } + + public static IslandCacheKey register(String name, Class valueType) { + IslandCacheKey.register(name, valueType); + return (IslandCacheKey) IslandCacheKey.getByName(name); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java index c52ad0f6cf..ca118f3837 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; @@ -10,11 +11,11 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.algorithm.DefaultIslandCalculationAlgorithm; +import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeEntityLimits; @@ -35,14 +36,10 @@ import java.util.Collections; import java.util.LinkedHashSet; import java.util.List; -import java.util.Map; import java.util.Set; -import java.util.UUID; public class ChunksListener extends AbstractGameEventListener { - private final Map> pendingLoadedChunks = new ArrayMap<>(); - private final LazyReference worldRecordService = new LazyReference() { @Override protected WorldRecordService create() { @@ -133,7 +130,10 @@ private void handleIslandChunkLoad(Island island, Chunk chunk, ChunkPosition chu plugin.getNMSChunks().injectChunkSections(chunk); - Set pendingLoadedChunksForIsland = this.pendingLoadedChunks.computeIfAbsent(island.getUniqueId(), u -> new LinkedHashSet<>()); + IslandCache islandCache = island.getCache(); + + Set pendingLoadedChunksForIsland = islandCache.computeIfAbsent(IslandCacheKeys.PENDING_LOADED_CHUNKS, + k -> new LinkedHashSet<>()); pendingLoadedChunksForIsland.add(chunk); boolean cropGrowthEnabled = BuiltinModules.UPGRADES.isUpgradeTypeEnabled(UpgradeTypeCropGrowth.class); @@ -185,7 +185,7 @@ private void handleIslandChunkLoad(Island island, Chunk chunk, ChunkPosition chu if (recalculateEntities.get()) { island.getEntitiesTracker().recalculateEntityCounts(); pendingLoadedChunksForIsland.clear(); - this.pendingLoadedChunks.remove(island.getUniqueId()); + islandCache.remove(IslandCacheKeys.PENDING_LOADED_CHUNKS); } }, 2L); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java index 20df8e577e..6103e32dcb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java @@ -6,7 +6,8 @@ import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalMap; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; @@ -35,16 +36,13 @@ import java.util.EnumSet; import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.TimeUnit; public class IslandFlagsListener extends AbstractGameEventListener { private static final EnumSet NATURAL_SPAWN_REASONS = initializeNaturalSpawnReasons(); - private final Map originalFireballsDamager = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS); + private final Int2ObjectMapView originalFireballsDamager = CollectionsFactory.createInt2ObjectArrayMap(); private final World spawnIslandWorld; @@ -180,7 +178,8 @@ private void onFireballDamage(GameEvent e) { } if (entity instanceof Fireball) { - originalFireballsDamager.put(entity.getUniqueId(), ((Fireball) entity).getShooter()); + originalFireballsDamager.put(entity.getEntityId(), ((Fireball) entity).getShooter()); + BukkitExecutor.sync(() -> originalFireballsDamager.remove(entity.getEntityId()), 40L); } } @@ -200,7 +199,7 @@ public boolean preventEntityExplosion(Entity source, Location explodeLocation) { islandFlag = IslandFlags.WITHER_EXPLOSION; break; case FIREBALL: { - ProjectileSource projectileSource = originalFireballsDamager.get(source.getUniqueId()); + ProjectileSource projectileSource = originalFireballsDamager.remove(source.getEntityId()); if (projectileSource == null) projectileSource = ((Fireball) source).getShooter(); if (projectileSource instanceof Ghast) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/MenusListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/MenusListener.java index b408b9463a..469051e200 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/MenusListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/MenusListener.java @@ -2,7 +2,8 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; -import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalMap; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.StackedBlocksDepositMenu; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; @@ -15,13 +16,9 @@ import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.ItemStack; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - public class MenusListener extends AbstractGameEventListener { - private final Map latestClickedItem = AutoRemovalMap.newHashMap(1, TimeUnit.SECONDS); + private final Int2ObjectMapView latestClickedItem = CollectionsFactory.createInt2ObjectArrayMap(); public MenusListener(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -45,13 +42,15 @@ private void onInventoryClickDupePatch(GameEvent latestClickedItem.remove(entityId), 20L); } } private void onInventoryCloseDupePatch(GameEvent e) { Player player = (Player) e.getArgs().bukkitEvent.getPlayer(); - ItemStack clickedItem = latestClickedItem.get(player.getUniqueId()); + ItemStack clickedItem = latestClickedItem.remove(player.getEntityId()); if (clickedItem != null) { BukkitExecutor.sync(() -> { player.getInventory().removeItem(clickedItem); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index 3fa2152ec6..52b182eebd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -14,10 +14,12 @@ import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; import com.bgsoftware.superiorskyblock.api.player.algorithm.PlayerTeleportAlgorithm; +import com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Counter; +import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; @@ -30,6 +32,7 @@ import com.bgsoftware.superiorskyblock.mission.MissionData; import com.bgsoftware.superiorskyblock.mission.MissionReference; import com.bgsoftware.superiorskyblock.player.builder.SuperiorPlayerBuilderImpl; +import com.bgsoftware.superiorskyblock.player.cache.PlayerCacheImpl; import com.bgsoftware.superiorskyblock.world.Dimensions; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; @@ -65,6 +68,12 @@ public class SSuperiorPlayer implements SuperiorPlayer { private final PlayerTeleportAlgorithm playerTeleportAlgorithm; @Nullable private PersistentDataContainer persistentDataContainer; // Lazy loading + private LazyReference playerCache = new LazyReference() { + @Override + protected PlayerCache create() { + return new PlayerCacheImpl(SSuperiorPlayer.this); + } + }; private final Map completedMissions = new ConcurrentHashMap<>(); private final List pendingInvites = new LinkedList<>(); @@ -169,6 +178,11 @@ public String getName() { return name; } + @Override + public PlayerCache getCache() { + return this.playerCache.get(); + } + @Override public String getTextureValue() { return textureValue; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java index 70b267938d..9883dc6a32 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.persistence.PersistentDataContainer; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; +import com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; @@ -67,6 +68,11 @@ public String getName() { return "NPC-Citizens"; } + @Override + public PlayerCache getCache() { + throw new UnsupportedOperationException(); + } + @Override public String getTextureValue() { return ""; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/cache/PlayerCacheImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/player/cache/PlayerCacheImpl.java new file mode 100644 index 0000000000..a6dd617f1f --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/cache/PlayerCacheImpl.java @@ -0,0 +1,50 @@ +package com.bgsoftware.superiorskyblock.player.cache; + +import com.bgsoftware.superiorskyblock.api.player.cache.PlayerCache; +import com.bgsoftware.superiorskyblock.api.player.cache.PlayerCacheKey; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.BaseCacheImpl; + +import java.util.function.Function; + +public class PlayerCacheImpl implements PlayerCache { + + private final BaseCacheImpl> cache = new BaseCacheImpl<>(PlayerCacheKey.values()); + + private final SuperiorPlayer superiorPlayer; + + public PlayerCacheImpl(SuperiorPlayer superiorPlayer) { + this.superiorPlayer = superiorPlayer; + } + + @Override + public SuperiorPlayer getPlayer() { + return this.superiorPlayer; + } + + @Override + public T store(PlayerCacheKey key, T value) { + return this.cache.store(key, value); + } + + @Override + public T remove(PlayerCacheKey key) { + return this.cache.remove(key); + } + + @Override + public T get(PlayerCacheKey key) { + return this.cache.get(key); + } + + @Override + public T getOrDefault(PlayerCacheKey key, T def) { + return this.cache.getOrDefault(key, def); + } + + @Override + public T computeIfAbsent(PlayerCacheKey key, Function, T> mappingFunction) { + return this.cache.computeIfAbsent(key, unused -> mappingFunction.apply(key)); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java index b4ac1535b8..fb79e3e396 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java @@ -6,7 +6,10 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ServerVersion; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import org.bukkit.Material; import org.bukkit.entity.AbstractHorse; import org.bukkit.entity.ArmorStand; @@ -31,15 +34,12 @@ import java.util.EnumMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; public class BukkitEntities { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final Map> entityContent = new ConcurrentHashMap<>(); + private static final Synchronized>> entityContent = Synchronized.of(CollectionsFactory.createInt2ObjectArrayMap()); @Nullable private static final EntityType CAMEL_TYPE = EnumHelper.getEnum(EntityType.class, "CAMEL"); @@ -62,8 +62,8 @@ private BukkitEntities() { } public static boolean isEquipment(LivingEntity livingEntity, ItemStack itemStack) { - List entityEquipment = entityContent.computeIfAbsent(livingEntity.getUniqueId(), u -> - cacheEntityEquipmentInternal(livingEntity)); + List entityEquipment = entityContent.writeAndGet(entityContent -> + entityContent.computeIfAbsent(livingEntity.getEntityId(), u -> cacheEntityEquipmentInternal(livingEntity))); return entityEquipment.stream().anyMatch(equipmentItem -> equipmentItem != null && equipmentItem.getType() == itemStack.getType()); @@ -71,7 +71,8 @@ public static boolean isEquipment(LivingEntity livingEntity, ItemStack itemStack public static void cacheEntityEquipment(LivingEntity livingEntity) { List entityEquipment = cacheEntityEquipmentInternal(livingEntity); - entityContent.put(livingEntity.getUniqueId(), entityEquipment); + entityContent.write(entityContent -> + entityContent.put(livingEntity.getEntityId(), entityEquipment)); } private static List cacheEntityEquipmentInternal(LivingEntity livingEntity) { @@ -117,7 +118,7 @@ private static List cacheEntityEquipmentInternal(LivingEntity livingE } public static void clearEntityEquipment(LivingEntity livingEntity) { - entityContent.remove(livingEntity.getUniqueId()); + entityContent.write(entityContent -> entityContent.remove(livingEntity.getEntityId())); } public static Optional getPlayerSource(Entity damager) { From 60488c50a1c4b609457cc0432a8d3aa3f65fa2ff Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 20 Sep 2025 13:54:06 +0300 Subject: [PATCH 295/600] Fixed damage events are not recoded correctly if not occurred by entities (#2631) --- .../superiorskyblock/listener/BukkitEventsListener.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index 41dbc5ee98..85371c5b98 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -148,6 +148,7 @@ public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { createEventListener(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, EntityChangeBlockEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_COLLISION_EVENT, VehicleEntityCollisionEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, EntityDamageByEntityEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, EntityDamageEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, VehicleDamageEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_ENTER_PORTAL_EVENT, EntityPortalEnterEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_EXPLODE_EVENT, EntityExplodeEvent.class, this::createGameEvent); @@ -451,6 +452,14 @@ private GameEvent createGameEvent(GameEventType return eventType.createEvent(entityDamageEvent); } + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityDamageEvent e) { + GameEventArgs.EntityDamageEvent entityDamageEvent = new GameEventArgs.EntityDamageEvent(); + entityDamageEvent.entity = e.getEntity(); + entityDamageEvent.damageCause = e.getCause(); + entityDamageEvent.damager = null; + return eventType.createEvent(entityDamageEvent); + } + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, VehicleDamageEvent e) { GameEventArgs.EntityDamageEvent entityDamageEvent = new GameEventArgs.EntityDamageEvent(); entityDamageEvent.entity = e.getVehicle(); From 15a4c83f93cb51a9649ea8e63fc9ffe5e8ad15f0 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 20 Sep 2025 14:28:28 +0300 Subject: [PATCH 296/600] Fix issue with loading old data of FishingMissions to new versions (#2635) --- .../resources/modules/missions/BlocksMissions | Bin 40145 -> 40179 bytes .../modules/missions/FarmingMissions | Bin 37409 -> 37432 bytes .../modules/missions/FishingMissions | Bin 21737 -> 21749 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/modules/missions/BlocksMissions b/src/main/resources/modules/missions/BlocksMissions index 5ed2942865c67b9d78f96ed80dc58cb06f9e802f..d33dd4c5a91832785c3b0d4da6003d80cee3bef4 100644 GIT binary patch delta 13187 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 diff --git a/src/main/resources/modules/missions/FarmingMissions b/src/main/resources/modules/missions/FarmingMissions index 6d844c3e14dfd7cd5bc4e3f83419b991eb798f39..c975df6a13f4b0fac8a3f1c4d2c1fc8283a439e7 100644 GIT binary patch delta 10137 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 Y@st2K>j=>26d}-k3M~>@cgX3D#Mn= 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 Sco2x<=2^l4fzV)oM*jz3$3OP~ delta 6930 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 Date: Sat, 20 Sep 2025 14:33:08 +0300 Subject: [PATCH 297/600] Fixed mission jars are not generated when changed --- .../module/missions/MissionsModule.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java index b38a7eb1b5..6ca88f9722 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java @@ -53,6 +53,8 @@ protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfigu if (convertNonCategorizedMissions(plugin, config)) updatedConfig = true; + generateDefaultMissionJars(); + if (firstTime) { generateDefaultFiles(); } @@ -352,17 +354,6 @@ private void copyOldMissionsMenuFile(SuperiorSkyblockPlugin plugin) { } private void generateDefaultFiles() { - Resources.copyResource("modules/missions/BlocksMissions"); - Resources.copyResource("modules/missions/BrewingMissions"); - Resources.copyResource("modules/missions/CraftingMissions"); - Resources.copyResource("modules/missions/EnchantingMissions"); - Resources.copyResource("modules/missions/FarmingMissions"); - Resources.copyResource("modules/missions/FishingMissions"); - Resources.copyResource("modules/missions/IslandMissions"); - Resources.copyResource("modules/missions/ItemsMissions"); - Resources.copyResource("modules/missions/KillsMissions"); - Resources.copyResource("modules/missions/StatisticsMissions"); - File categoriesFolder = new File(getModuleFolder(), "categories"); if ((!categoriesFolder.exists() || !categoriesFolder.isDirectory()) && categoriesFolder.mkdirs()) { @@ -388,6 +379,19 @@ private void generateDefaultFiles() { } } + private void generateDefaultMissionJars() { + Resources.copyResource("modules/missions/BlocksMissions"); + Resources.copyResource("modules/missions/BrewingMissions"); + Resources.copyResource("modules/missions/CraftingMissions"); + Resources.copyResource("modules/missions/EnchantingMissions"); + Resources.copyResource("modules/missions/FarmingMissions"); + Resources.copyResource("modules/missions/FishingMissions"); + Resources.copyResource("modules/missions/IslandMissions"); + Resources.copyResource("modules/missions/ItemsMissions"); + Resources.copyResource("modules/missions/KillsMissions"); + Resources.copyResource("modules/missions/StatisticsMissions"); + } + private static class MissionsComparator implements Comparator> { private final Map, Integer> missionWeights; From 90cc9f12697cb1b80487fdd0868bcd7b7ab7e401 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 20 Sep 2025 14:46:12 +0300 Subject: [PATCH 298/600] Do not fail on loading data when encountering invalid island flags or island privileges (#2634) --- .../serialization/IslandsDeserializer.java | 39 +++++++------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java index e65a2b8279..971e2a8c58 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java @@ -158,17 +158,14 @@ public static void deserializePlayerPermissions(DatabaseBridge databaseBridge, D return; } - Optional islandPrivilege = playerPermissions.getString("permission").map(name -> { + IslandPrivilege islandPrivilege = playerPermissions.getString("permission").map(name -> { try { return IslandPrivilege.getByName(name); } catch (NullPointerException error) { - return null; + IslandPrivilege.register(name); + return IslandPrivilege.getByName(name); } - }); - if (!islandPrivilege.isPresent()) { - Log.warn("Cannot load player permissions with invalid permission for player ", playerUUID.get(), ", skipping..."); - return; - } + }).orElseThrow(IllegalStateException::new); Optional status = playerPermissions.getByte("status"); if (!status.isPresent()) { @@ -177,7 +174,7 @@ public static void deserializePlayerPermissions(DatabaseBridge databaseBridge, D } Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); - builder.setPlayerPermission(superiorPlayer, islandPrivilege.get(), status.get() == 1); + builder.setPlayerPermission(superiorPlayer, islandPrivilege, status.get() == 1); }); } @@ -197,20 +194,17 @@ public static void deserializeRolePermissions(DatabaseBridge databaseBridge, Dat return; } - Optional islandPrivilege = rolePermissions.getString("permission").map(name -> { + IslandPrivilege islandPrivilege = rolePermissions.getString("permission").map(name -> { try { return IslandPrivilege.getByName(name); } catch (NullPointerException error) { - return null; + IslandPrivilege.register(name); + return IslandPrivilege.getByName(name); } - }); - if (!islandPrivilege.isPresent()) { - Log.warn("Cannot load role permissions with invalid permission for ", uuid.get(), ", skipping..."); - return; - } + }).orElseThrow(IllegalStateException::new); Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); - builder.setRolePermission(islandPrivilege.get(), playerRole.get()); + builder.setRolePermission(islandPrivilege, playerRole.get()); }); } @@ -453,17 +447,14 @@ public static void deserializeIslandFlags(DatabaseBridge databaseBridge, Databas return; } - Optional islandFlag = islandFlagResult.getString("name").map(name -> { + IslandFlag islandFlag = islandFlagResult.getString("name").map(name -> { try { return IslandFlag.getByName(name); } catch (NullPointerException error) { - return null; + IslandFlag.register(name); + return IslandFlag.getByName(name); } - }); - if (!islandFlag.isPresent()) { - Log.warn("Cannot load island flags with invalid flags for ", uuid.get(), ", skipping..."); - return; - } + }).orElseThrow(IllegalStateException::new); Optional status = islandFlagResult.getByte("status"); if (!status.isPresent()) { @@ -472,7 +463,7 @@ public static void deserializeIslandFlags(DatabaseBridge databaseBridge, Databas } Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); - builder.setIslandFlag(islandFlag.get(), status.get() == 1); + builder.setIslandFlag(islandFlag, status.get() == 1); }); } From b241bcce3c55b34726b8ef240abed975c15936c4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 20 Sep 2025 16:14:14 +0300 Subject: [PATCH 299/600] Add support to regex patterns in pvp worlds (#2626) --- .../core/config/PvPWorldsCache.java | 53 +++++++++++++++++++ .../events/plugin/PluginEventsDispatcher.java | 2 + .../player/SSuperiorPlayer.java | 23 +++++++- 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/config/PvPWorldsCache.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/config/PvPWorldsCache.java b/src/main/java/com/bgsoftware/superiorskyblock/core/config/PvPWorldsCache.java new file mode 100644 index 0000000000..8fbe862083 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/config/PvPWorldsCache.java @@ -0,0 +1,53 @@ +package com.bgsoftware.superiorskyblock.core.config; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class PvPWorldsCache { + + private final Set pvpWorldNames = new HashSet<>(); + private final List pvpWorldPatterns = new LinkedList<>(); + + public PvPWorldsCache(List pvpWorlds) { + for (String worldName : pvpWorlds) { + Pattern worldNamePattern = getPatternRegex(worldName); + if (worldNamePattern == null) { + this.pvpWorldNames.add(worldName); + } else { + this.pvpWorldPatterns.add(worldNamePattern); + } + } + } + + public boolean isPvPWorld(String worldName) { + return isPvPWorldByName(worldName) || isPvPWorldByPattern(worldName); + } + + private boolean isPvPWorldByName(String worldName) { + return !this.pvpWorldNames.isEmpty() && this.pvpWorldNames.contains(worldName); + } + + private boolean isPvPWorldByPattern(String worldName) { + for (Pattern pattern : this.pvpWorldPatterns) { + if (pattern.matcher(worldName).matches()) + return true; + } + + return false; + } + + private static Pattern getPatternRegex(String value) { + try { + Pattern pattern = Pattern.compile(value); + if (value.matches(".*[.*+?^${}()|\\[\\]\\\\].*")) + return pattern; + } catch (PatternSyntaxException ignored) { + } + return null; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java index 4ebd5e101d..6bde85cefc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.SpawnIsland; +import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; @@ -39,6 +40,7 @@ public void registerDefaultListeners() { CmdHelp.registerListeners(this); CmdAdmin.registerCallbacks(this); Message.registerListeners(this); + SSuperiorPlayer.registerListeners(this); } public void registerCallback(PluginEventType type, Runnable callback) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index 52b182eebd..f253709d06 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -23,8 +23,11 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.core.config.PvPWorldsCache; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; @@ -64,6 +67,8 @@ public class SSuperiorPlayer implements SuperiorPlayer { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static PvPWorldsCache pvpWorldsCache = null; + private final DatabaseBridge databaseBridge; private final PlayerTeleportAlgorithm playerTeleportAlgorithm; @Nullable @@ -382,8 +387,7 @@ public HitActionResult canHit(SuperiorPlayer otherPlayer) { World world = getWorld(); // Checks for island teammates pvp - if (getIslandLeader().equals(otherPlayer.getIslandLeader()) && - (world == null || !plugin.getSettings().getPvPWorlds().contains(world.getName()))) + if (getIsland() == otherPlayer.getIsland() && (world == null || !isPvPWorldInternal(world.getName()))) return HitActionResult.ISLAND_TEAM_PVP; // Checks if this player can bypass all pvp restrictions @@ -1137,6 +1141,10 @@ private void setPlayerRoleInternal(@Nullable PlayerRole playerRole) { this.playerRoleId = newRole.getId(); } + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SSuperiorPlayer::onSettingsUpdate); + } + private static String removeTextureValueTimeStamp(@Nullable String textureValue) { // The texture value string is a json containing a timestamp value. // However, when we compare texture values, we want to emit the timestamp value. @@ -1144,4 +1152,15 @@ private static String removeTextureValueTimeStamp(@Nullable String textureValue) return textureValue == null || textureValue.length() <= 42 ? null : textureValue.substring(0, 35) + textureValue.substring(42); } + private static boolean isPvPWorldInternal(String worldName) { + if (pvpWorldsCache == null) + pvpWorldsCache = new PvPWorldsCache(plugin.getSettings().getPvPWorlds()); + + return pvpWorldsCache.isPvPWorld(worldName); + } + + private static void onSettingsUpdate() { + pvpWorldsCache = null; + } + } From 8ddb2061b09ed391d9df32ef016930d9aed62862 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 20 Sep 2025 16:43:07 +0300 Subject: [PATCH 300/600] Add support to reset default world (#2616) --- .../commands/admin/CmdAdminResetWorld.java | 70 +++++++++++++++---- 1 file changed, 58 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java index b2027aa088..354d431f34 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java @@ -2,20 +2,31 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.config.SettingsManager; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags; +import com.bgsoftware.superiorskyblock.api.schematic.Schematic; +import com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.IslandWorlds; +import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; +import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.block.BlockFace; import org.bukkit.command.CommandSender; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -26,6 +37,13 @@ public class CmdAdminResetWorld implements IAdminIslandCommand { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final LazyReference dragonBattleService = new LazyReference() { + @Override + protected DragonBattleService create() { + return plugin.getServices().getService(DragonBattleService.class); + } + }; + @Override public List getAliases() { return Arrays.asList("resetworld", "rworld"); @@ -76,11 +94,6 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (dimension == null) return; - if (dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { - Message.INVALID_ENVIRONMENT.send(sender, args[3]); - return; - } - int islandsChangedCount = 0; for (Island island : islands) { @@ -100,30 +113,63 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (islandsChangedCount > 1) Message.RESET_WORLD_SUCCEED_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3])); else if (targetPlayer == null) - Message.RESET_WORLD_SUCCEED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3]), islands.get(0). - - getName()); + Message.RESET_WORLD_SUCCEED_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3]), islands.get(0).getName()); else Message.RESET_WORLD_SUCCEED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(args[3]), targetPlayer.getName()); } private static void resetChunksInternal(Island island, World world, Dimension dimension) { - + boolean isDefaultDimension = dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension(); // Sending the players that are in that world to the main island. // If the world that will be reset is the normal world, they will be teleported to spawn. for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { assert superiorPlayer.getWorld() != null; - if (superiorPlayer.getWorld().equals(world)) - superiorPlayer.teleport(island); + if (superiorPlayer.getWorld().equals(world)) { + if (isDefaultDimension) { + superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); + } else { + superiorPlayer.teleport(island); + } + } } // Resetting the chunks - island.resetChunks(dimension, IslandChunkFlags.ONLY_PROTECTED, () -> island.calcIslandWorth(null)); + island.resetChunks(dimension, IslandChunkFlags.ONLY_PROTECTED, + isDefaultDimension ? null : () -> island.calcIslandWorth(null)); + + if (isDefaultDimension) { + String islandSchematic = island.getSchematicName(); + Schematic schematic = plugin.getSchematics().getSchematic(islandSchematic); + if (schematic != null) { + regenerateSchematicInternal(island, dimension, schematic); + return; + } + } island.setSchematicGenerate(dimension, false); } + private static void regenerateSchematicInternal(Island island, Dimension dimension, Schematic schematic) { + Location centerLocation = island.getCenter(dimension); + Location schematicPlacementLocation = centerLocation.getBlock().getRelative(BlockFace.DOWN).getLocation(); + + schematic.pasteSchematic(island, schematicPlacementLocation, () -> { + island.setSchematicGenerate(dimension); + + Location homeLocation = schematic.adjustRotation(centerLocation); + island.setIslandHome(dimension, homeLocation); + + if (dimension.getEnvironment() == World.Environment.THE_END) { + dragonBattleService.get().resetEnderDragonBattle(island, dimension); + } + + island.setIslandHome(dimension, homeLocation); + + island.calcIslandWorth(null); + }, Throwable::printStackTrace); + } + @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { if (args.length != 4) From a64b5b14018f04a3131cb30ecefc9ab9dfbd31a6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 20 Sep 2025 19:48:36 +0300 Subject: [PATCH 301/600] Implement caching for schematics, which should improve schematics placement performance --- .../api/config/SettingsManager.java | 8 + .../v1_12_R1/world/WorldEditSessionImpl.java | 68 ++++++ .../v1_16_R3/world/WorldEditSessionImpl.java | 82 ++++++- .../nms/v1_17/world/WorldEditSessionImpl.java | 85 ++++++- .../nms/v1_18/world/WorldEditSessionImpl.java | 85 ++++++- .../nms/v1_19/world/WorldEditSessionImpl.java | 85 ++++++- .../v1_20_3/world/WorldEditSessionImpl.java | 85 ++++++- .../v1_20_4/world/WorldEditSessionImpl.java | 84 ++++++- .../nms/v1_21/world/WorldEditSessionImpl.java | 85 ++++++- .../v1_21_3/world/WorldEditSessionImpl.java | 85 ++++++- .../v1_21_4/world/WorldEditSessionImpl.java | 84 ++++++- .../v1_21_5/world/WorldEditSessionImpl.java | 84 ++++++- .../v1_21_7/world/WorldEditSessionImpl.java | 85 ++++++- .../v1_8_R3/world/WorldEditSessionImpl.java | 67 +++++ .../SuperiorSkyblockPlugin.java | 2 + .../config/SettingsContainer.java | 2 + .../config/SettingsManagerImpl.java | 5 + .../config/section/GlobalSection.java | 4 + .../collections/view/Long2ObjectMapView.java | 8 + .../core/schematic/SchematicBlock.java | 9 +- .../nms/world/WorldEditSession.java | 4 + .../world/schematic/BaseSchematic.java | 7 + .../schematic/SchematicsManagerImpl.java | 31 ++- .../container/DefaultSchematicsContainer.java | 9 +- .../container/SchematicsContainer.java | 3 +- .../impl/CachedSuperiorSchematic.java | 228 ++++++++++++++++++ .../schematic/impl/SuperiorSchematic.java | 54 +++-- src/main/resources/config.yml | 7 +- 28 files changed, 1384 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 0e2968fb86..da47133248 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -254,6 +254,7 @@ public interface SettingsManager { * Whether inventory of island members should be cleared when their island is disbanded or not. * Return true if clear-on-disband contains both ENDER_CHEST and INVENTORY. * This method will be deleted in the future! + * * @deprecated See {@link #getClearActionsOnDisband()} */ @Deprecated @@ -293,6 +294,7 @@ public interface SettingsManager { * Whether to clear players' inventories when they join a new island or not. * Return true if clear-on-join contains both ENDER_CHEST and INVENTORY. * This method will be deleted in the future! + * * @deprecated See {@link #getClearActionsOnJoin()} */ @Deprecated @@ -721,6 +723,12 @@ public interface SettingsManager { */ int getCommandsPerPage(); + /** + * Whether the plugin should cache schematics for faster placement of schematics. + * Config-path: cache-schematics + */ + boolean isCacheSchematics(); + interface Database { /** diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java index c4d5ceb788..4ee7aae50f 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java @@ -34,12 +34,14 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_12_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import org.bukkit.craftbukkit.v1_12_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_12_R1.generator.CustomChunkGenerator; import org.bukkit.generator.ChunkGenerator; import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -58,6 +60,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private WorldServer worldServer; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(WorldServer worldServer) { return POOL.obtain().initialize(worldServer); } @@ -125,6 +129,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(org.bukkit.Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); ChunkData chunkData = this.chunks.get(chunk.chunkKey); @@ -151,6 +158,9 @@ public void applyBlocks(org.bukkit.Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> worldServer.setTypeAndData(data.getKey(), data.getValue(), 3)); @@ -192,8 +202,57 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = (location.getBlockX() >> 4) - (baseLocationForCache.getBlockX() >> 4); + int chunkPosZAxisDelta = (location.getBlockZ() >> 4) - (baseLocationForCache.getBlockZ() >> 4); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(worldServer); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkCoordIntPair.a(getChunkCoordX(entry.getKey()) + chunkPosXAxisDelta, + getChunkCoordZ(entry.getKey()) + chunkPosZAxisDelta); + worldEditSession.chunks.put(newPos, entry.getValue()); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPosition newPos = blockToUpdatePair.getKey().a(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPosition newPos = blockEntityPair.getKey().a(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lights.forEach(lightPosition -> { + BlockPosition newPos = lightPosition.a(xAxisDelta, 0, zAxisDelta); + worldEditSession.lights.add(newPos); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -209,7 +268,16 @@ private boolean isValidPosition(BlockPosition blockPosition) { blockPosition.getY() >= 0 && blockPosition.getY() < worldServer.getHeight(); } + private static int getChunkCoordX(long i) { + return (int) (i & 4294967295L); + } + + private static int getChunkCoordZ(long i) { + return (int) (i >>> 32 & 4294967295L); + } + private class ChunkData { + private final ChunkSection[] chunkSections = new ChunkSection[16]; public ChunkData(long chunkKey) { diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java index d5f95a9fca..9a105259e5 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java @@ -45,6 +45,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_16_R3.CraftChunk; +import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_16_R3.generator.CustomChunkGenerator; import org.bukkit.generator.ChunkGenerator; @@ -53,6 +54,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -83,6 +85,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private WorldServer worldServer; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(WorldServer worldServer) { return POOL.obtain().initialize(worldServer); } @@ -179,6 +183,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(org.bukkit.Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); ChunkCoordIntPair chunkCoord = chunk.getPos(); @@ -221,6 +228,9 @@ public void applyBlocks(org.bukkit.Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> worldServer.setTypeAndData(data.getKey(), data.getValue(), 3)); @@ -249,8 +259,66 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = (location.getBlockX() >> 4) - (baseLocationForCache.getBlockX() >> 4); + int chunkPosZAxisDelta = (location.getBlockZ() >> 4) - (baseLocationForCache.getBlockZ() >> 4); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(worldServer); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkCoordIntPair.pair(ChunkCoordIntPair.getX(entry.getKey()) + chunkPosXAxisDelta, + ChunkCoordIntPair.getZ(entry.getKey()) + chunkPosZAxisDelta); + + ChunkSection[] sections = entry.getValue().chunkSections; + Map heightmaps = entry.getValue().heightmaps; + List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + entry.getValue().lights.forEach(blockPos -> { + lights.add(blockPos.add(xAxisDelta, 0, zAxisDelta)); + }); + + ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); + worldEditSession.chunks.put(newPos, newChunkData); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPosition newPos = blockToUpdatePair.getKey().add(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPosition newPos = blockEntityPair.getKey().add(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lightenChunks.forEach(lightenChunk -> { + worldEditSession.lightenChunks.add(new ChunkCoordIntPair( + lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -267,12 +335,14 @@ private boolean isValidPosition(BlockPosition blockPosition) { } private class ChunkData { - private final ChunkSection[] chunkSections = new ChunkSection[16]; - private final Map heightmaps = new EnumMap<>(HeightMap.Type.class); - private final List lights = new LinkedList<>(); + private final ChunkSection[] chunkSections; + private final Map heightmaps; + private final List lights; public ChunkData(long chunkKey) { + this(new ChunkSection[16], new EnumMap<>(HeightMap.Type.class), new LinkedList<>()); + ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair(chunkKey); createChunkSections(); @@ -296,6 +366,12 @@ public ChunkData(long chunkKey) { runCustomWorldGenerator(tempChunk); } + public ChunkData(ChunkSection[] chunkSections, Map heightmaps, List lights) { + this.chunkSections = chunkSections; + this.heightmaps = heightmaps; + this.lights = lights; + } + private void createChunkSections() { for (int i = 0; i < this.chunkSections.length; ++i) { int chunkSectionPos = i << 4; diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java index b9c6eada93..dcb88662ff 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java @@ -22,6 +22,7 @@ import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; @@ -47,6 +48,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage; @@ -56,6 +58,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -86,6 +89,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private ServerLevel serverLevel; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } @@ -182,6 +187,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); ChunkPos chunkPos = levelChunk.getPos(); @@ -223,6 +231,9 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -263,8 +274,66 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); + int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(serverLevel); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, + ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); + + LevelChunkSection[] sections = entry.getValue().chunkSections; + Map heightmaps = entry.getValue().heightmaps; + List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + entry.getValue().lights.forEach(blockPos -> { + lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); + }); + + ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); + worldEditSession.chunks.put(newPos, newChunkData); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lightenChunks.forEach(lightenChunk -> { + worldEditSession.lightenChunks.add(new ChunkPos( + lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -281,11 +350,15 @@ private boolean isValidPosition(BlockPos blockPos) { } private class ChunkData { - private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); - private final List lights = new LinkedList<>(); + + private final LevelChunkSection[] chunkSections; + private final Map heightmaps; + private final List lights; public ChunkData(long chunkKey) { + this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); + ChunkPos chunkPos = new ChunkPos(chunkKey); createChunkSections(); @@ -309,6 +382,12 @@ public ChunkData(long chunkKey) { runCustomWorldGenerator(tempChunk); } + public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + this.chunkSections = chunkSections; + this.heightmaps = heightmaps; + this.lights = lights; + } + private void createChunkSections() { for (int i = 0; i < this.chunkSections.length; ++i) { int chunkSectionPos = serverLevel.getSectionYFromSectionIndex(i); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java index 9bb9b80806..00ef8dd103 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java @@ -22,6 +22,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -47,6 +48,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; +import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; @@ -55,6 +57,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -82,6 +85,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private ServerLevel serverLevel; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } @@ -178,6 +183,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); ChunkPos chunkPos = levelChunk.getPos(); @@ -211,6 +219,9 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -251,8 +262,66 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); + int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(serverLevel); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, + ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); + + LevelChunkSection[] sections = entry.getValue().chunkSections; + Map heightmaps = entry.getValue().heightmaps; + List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + entry.getValue().lights.forEach(blockPos -> { + lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); + }); + + ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); + worldEditSession.chunks.put(newPos, newChunkData); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lightenChunks.forEach(lightenChunk -> { + worldEditSession.lightenChunks.add(new ChunkPos( + lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -269,11 +338,15 @@ private boolean isValidPosition(BlockPos blockPos) { } private class ChunkData { - private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); - private final List lights = new LinkedList<>(); + + private final LevelChunkSection[] chunkSections; + private final Map heightmaps; + private final List lights; public ChunkData(long chunkKey) { + this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); + ChunkPos chunkPos = new ChunkPos(chunkKey); Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); @@ -287,6 +360,12 @@ public ChunkData(long chunkKey) { runCustomWorldGenerator(tempChunk); } + public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + this.chunkSections = chunkSections; + this.heightmaps = heightmaps; + this.lights = lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java index 0999116f2b..e6df77c7af 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java @@ -23,6 +23,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; @@ -49,6 +50,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; +import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage; @@ -57,6 +59,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -85,6 +88,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private ServerLevel serverLevel; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } @@ -181,6 +186,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -215,6 +223,9 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -255,8 +266,66 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); + int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(serverLevel); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, + ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); + + LevelChunkSection[] sections = entry.getValue().chunkSections; + Map heightmaps = entry.getValue().heightmaps; + List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + entry.getValue().lights.forEach(blockPos -> { + lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); + }); + + ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); + worldEditSession.chunks.put(newPos, newChunkData); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lightenChunks.forEach(lightenChunk -> { + worldEditSession.lightenChunks.add(new ChunkPos( + lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -273,11 +342,15 @@ private boolean isValidPosition(BlockPos blockPos) { } private class ChunkData { - private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); - private final List lights = isStarLightInterface ? Collections.emptyList() : new LinkedList<>(); + + private final LevelChunkSection[] chunkSections; + private final Map heightmaps; + private final List lights; public ChunkData(long chunkKey) { + this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); + ChunkPos chunkPos = new ChunkPos(chunkKey); Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); @@ -291,6 +364,12 @@ public ChunkData(long chunkKey) { runCustomWorldGenerator(tempChunk); } + public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + this.chunkSections = chunkSections; + this.heightmaps = heightmaps; + this.lights = lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java index 32e0c801a3..7a06e3e09a 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java @@ -24,6 +24,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; @@ -54,6 +55,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome; import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; @@ -64,6 +66,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -94,6 +97,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private ServerLevel serverLevel; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } @@ -190,6 +195,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -224,6 +232,9 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -257,8 +268,66 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); + int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(serverLevel); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, + ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); + + LevelChunkSection[] sections = entry.getValue().chunkSections; + Map heightmaps = entry.getValue().heightmaps; + List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + entry.getValue().lights.forEach(blockPos -> { + lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); + }); + + ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); + worldEditSession.chunks.put(newPos, newChunkData); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lightenChunks.forEach(lightenChunk -> { + worldEditSession.lightenChunks.add(new ChunkPos( + lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -327,11 +396,15 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } private class ChunkData { - private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); - private final List lights = isStarLightInterface ? Collections.emptyList() : new LinkedList<>(); + + private final LevelChunkSection[] chunkSections; + private final Map heightmaps; + private final List lights; public ChunkData(long chunkKey) { + this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); + ChunkPos chunkPos = new ChunkPos(chunkKey); Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); @@ -345,6 +418,12 @@ public ChunkData(long chunkKey) { runCustomWorldGenerator(tempChunk); } + public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + this.chunkSections = chunkSections; + this.heightmaps = heightmaps; + this.lights = lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java index 00ad9b1899..586fa6d244 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java @@ -24,6 +24,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; @@ -54,6 +55,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; @@ -64,6 +66,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -94,6 +97,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private ServerLevel serverLevel; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } @@ -190,6 +195,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -224,6 +232,9 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -257,8 +268,66 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); + int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(serverLevel); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, + ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); + + LevelChunkSection[] sections = entry.getValue().chunkSections; + Map heightmaps = entry.getValue().heightmaps; + List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + entry.getValue().lights.forEach(blockPos -> { + lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); + }); + + ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); + worldEditSession.chunks.put(newPos, newChunkData); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lightenChunks.forEach(lightenChunk -> { + worldEditSession.lightenChunks.add(new ChunkPos( + lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -327,11 +396,14 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } private class ChunkData { - private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); - private final List lights = isStarLightInterface ? Collections.emptyList() : new LinkedList<>(); + + private final LevelChunkSection[] chunkSections; + private final Map heightmaps; + private final List lights; public ChunkData(long chunkKey) { + this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); @@ -345,6 +417,12 @@ public ChunkData(long chunkKey) { runCustomWorldGenerator(tempChunk); } + public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + this.chunkSections = chunkSections; + this.heightmaps = heightmaps; + this.lights = lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java index bd5837d5fb..7fa630d260 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java @@ -24,6 +24,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; @@ -53,6 +54,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; @@ -62,6 +64,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -92,6 +95,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private ServerLevel serverLevel; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } @@ -188,6 +193,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -222,6 +230,9 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -255,8 +266,66 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); + int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(serverLevel); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, + ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); + + LevelChunkSection[] sections = entry.getValue().chunkSections; + Map heightmaps = entry.getValue().heightmaps; + List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + entry.getValue().lights.forEach(blockPos -> { + lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); + }); + + ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); + worldEditSession.chunks.put(newPos, newChunkData); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lightenChunks.forEach(lightenChunk -> { + worldEditSession.lightenChunks.add(new ChunkPos( + lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -325,11 +394,15 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } private class ChunkData { - private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); - private final List lights = isStarLightInterface ? Collections.emptyList() : new LinkedList<>(); + + private final LevelChunkSection[] chunkSections; + private final Map heightmaps; + private final List lights; public ChunkData(long chunkKey) { + this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); + ChunkPos chunkPos = new ChunkPos(chunkKey); Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); @@ -343,6 +416,12 @@ public ChunkData(long chunkKey) { runCustomWorldGenerator(tempChunk); } + public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + this.chunkSections = chunkSections; + this.heightmaps = heightmaps; + this.lights = lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java index 1eb4e880b0..65b374bd47 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java @@ -24,6 +24,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; @@ -53,6 +54,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; @@ -62,6 +64,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -92,6 +95,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private ServerLevel serverLevel; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } @@ -188,6 +193,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -222,6 +230,9 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -255,8 +266,66 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); + int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(serverLevel); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, + ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); + + LevelChunkSection[] sections = entry.getValue().chunkSections; + Map heightmaps = entry.getValue().heightmaps; + List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + entry.getValue().lights.forEach(blockPos -> { + lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); + }); + + ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); + worldEditSession.chunks.put(newPos, newChunkData); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lightenChunks.forEach(lightenChunk -> { + worldEditSession.lightenChunks.add(new ChunkPos( + lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -325,11 +394,15 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } private class ChunkData { - private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); - private final List lights = isStarLightInterface ? Collections.emptyList() : new LinkedList<>(); + + private final LevelChunkSection[] chunkSections; + private final Map heightmaps; + private final List lights; public ChunkData(long chunkKey) { + this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); + ChunkPos chunkPos = new ChunkPos(chunkKey); Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); @@ -343,6 +416,12 @@ public ChunkData(long chunkKey) { runCustomWorldGenerator(tempChunk); } + public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + this.chunkSections = chunkSections; + this.heightmaps = heightmaps; + this.lights = lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java index c288df3590..589b935ce8 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java @@ -24,6 +24,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; @@ -53,6 +54,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; @@ -62,6 +64,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -92,6 +95,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private ServerLevel serverLevel; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } @@ -188,6 +193,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -222,6 +230,9 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -255,8 +266,66 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); + int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(serverLevel); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, + ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); + + LevelChunkSection[] sections = entry.getValue().chunkSections; + Map heightmaps = entry.getValue().heightmaps; + List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + entry.getValue().lights.forEach(blockPos -> { + lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); + }); + + ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); + worldEditSession.chunks.put(newPos, newChunkData); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lightenChunks.forEach(lightenChunk -> { + worldEditSession.lightenChunks.add(new ChunkPos( + lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -325,11 +394,14 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } private class ChunkData { - private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); - private final List lights = isStarLightInterface ? Collections.emptyList() : new LinkedList<>(); + + private final LevelChunkSection[] chunkSections; + private final Map heightmaps; + private final List lights; public ChunkData(long chunkKey) { + this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); @@ -343,6 +415,12 @@ public ChunkData(long chunkKey) { runCustomWorldGenerator(tempChunk); } + public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + this.chunkSections = chunkSections; + this.heightmaps = heightmaps; + this.lights = lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java index 8fb2a05102..f498d1d81a 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java @@ -24,6 +24,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; @@ -53,6 +54,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; @@ -62,6 +64,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -92,6 +95,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private ServerLevel serverLevel; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } @@ -188,6 +193,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -222,6 +230,9 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -255,8 +266,66 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); + int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(serverLevel); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, + ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); + + LevelChunkSection[] sections = entry.getValue().chunkSections; + Map heightmaps = entry.getValue().heightmaps; + List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + entry.getValue().lights.forEach(blockPos -> { + lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); + }); + + ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); + worldEditSession.chunks.put(newPos, newChunkData); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lightenChunks.forEach(lightenChunk -> { + worldEditSession.lightenChunks.add(new ChunkPos( + lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -324,11 +393,14 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } private class ChunkData { - private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); - private final List lights = isStarLightInterface ? Collections.emptyList() : new LinkedList<>(); + + private final LevelChunkSection[] chunkSections; + private final Map heightmaps; + private final List lights; public ChunkData(long chunkKey) { + this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); @@ -342,6 +414,12 @@ public ChunkData(long chunkKey) { runCustomWorldGenerator(tempChunk); } + public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + this.chunkSections = chunkSections; + this.heightmaps = heightmaps; + this.lights = lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java index 00634b1ba4..a98c34a085 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java @@ -25,6 +25,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; @@ -57,6 +58,7 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; @@ -67,6 +69,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -99,6 +102,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private ServerLevel serverLevel; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } @@ -195,6 +200,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -229,6 +237,9 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -267,8 +278,66 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); + int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(serverLevel); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, + ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); + + LevelChunkSection[] sections = entry.getValue().chunkSections; + Map heightmaps = entry.getValue().heightmaps; + List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + entry.getValue().lights.forEach(blockPos -> { + lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); + }); + + ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); + worldEditSession.chunks.put(newPos, newChunkData); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lightenChunks.forEach(lightenChunk -> { + worldEditSession.lightenChunks.add(new ChunkPos( + lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -338,11 +407,15 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } private class ChunkData { - private final LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - private final Map heightmaps = new EnumMap<>(Heightmap.Types.class); - private final List lights = isStarLightInterface ? Collections.emptyList() : new LinkedList<>(); + + private final LevelChunkSection[] chunkSections; + private final Map heightmaps; + private final List lights; public ChunkData(long chunkKey) { + this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); + ChunkPos chunkPos = new ChunkPos(chunkKey); Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); @@ -356,6 +429,12 @@ public ChunkData(long chunkKey) { runCustomWorldGenerator(tempChunk); } + public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + this.chunkSections = chunkSections; + this.heightmaps = heightmaps; + this.lights = lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java index 0d1183985f..734779e13e 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java @@ -33,12 +33,14 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_8_R3.CraftChunk; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import org.bukkit.craftbukkit.v1_8_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_8_R3.generator.CustomChunkGenerator; import org.bukkit.generator.ChunkGenerator; import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -55,6 +57,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private WorldServer worldServer; private Dimension dimension; + private Location baseLocationForCache = null; + public static WorldEditSessionImpl obtain(WorldServer worldServer) { return POOL.obtain().initialize(worldServer); } @@ -123,6 +127,9 @@ public List getAffectedChunks() { @Override public void applyBlocks(org.bukkit.Chunk bukkitChunk) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); ChunkData chunkData = this.chunks.get(ChunkCoordIntPair.a(chunk.locX, chunk.locZ)); @@ -152,6 +159,9 @@ public void applyBlocks(org.bukkit.Chunk bukkitChunk) { @Override public void finish(Island island) { + if (baseLocationForCache != null) + throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + // Update blocks blocksToUpdate.forEach(data -> worldServer.setTypeAndData(data.getKey(), data.getValue(), 3)); @@ -192,8 +202,57 @@ public void finish(Island island) { release(); } + @Override + public void markForCache(Location location) { + this.baseLocationForCache = location.clone(); + } + + @Override + public WorldEditSession buildFromCache(Location location) { + if (this.baseLocationForCache == null) + throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + + int chunkPosXAxisDelta = (location.getBlockX() >> 4) - (baseLocationForCache.getBlockX() >> 4); + int chunkPosZAxisDelta = (location.getBlockZ() >> 4) - (baseLocationForCache.getBlockZ() >> 4); + int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); + int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + + WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); + + WorldEditSessionImpl worldEditSession = obtain(worldServer); + + // We need to transform all data to the new base location values + Iterator> chunksIterator = this.chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + long newPos = ChunkCoordIntPair.a(getChunkCoordX(entry.getKey()) + chunkPosXAxisDelta, + getChunkCoordZ(entry.getKey()) + chunkPosZAxisDelta); + worldEditSession.chunks.put(newPos, entry.getValue()); + } + + this.blocksToUpdate.forEach(blockToUpdatePair -> { + BlockPosition newPos = blockToUpdatePair.getKey().a(xAxisDelta, 0, zAxisDelta); + worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); + }); + + this.blockEntities.forEach(blockEntityPair -> { + BlockPosition newPos = blockEntityPair.getKey().a(xAxisDelta, 0, zAxisDelta); + worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); + }); + + this.lights.forEach(lightPosition -> { + BlockPosition newPos = lightPosition.a(xAxisDelta, 0, zAxisDelta); + worldEditSession.lights.add(newPos); + }); + + return worldEditSession; + } + @Override public void release() { + if (this.baseLocationForCache != null) + return; + this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -209,6 +268,14 @@ private boolean isValidPosition(BlockPosition blockPosition) { blockPosition.getY() >= 0 && blockPosition.getY() < worldServer.getHeight(); } + private static int getChunkCoordX(long i) { + return (int) (i & 4294967295L); + } + + private static int getChunkCoordZ(long i) { + return (int) (i >>> 32 & 4294967295L); + } + private class ChunkData { private final ChunkSection[] chunkSections = new ChunkSection[16]; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index bd347c9c05..c518a1edc6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -485,6 +485,8 @@ public void reloadPlugin(PluginReloadReason reloadReason) throws ManagerLoadExce stackedBlocksHandler.loadData(); } + BukkitExecutor.sync(schematicsHandler::cacheSchematics); + modulesHandler.runModuleLifecycle(ModuleLoadTime.AFTER_MODULE_DATA_LOAD, reloadReason == PluginReloadReason.COMMAND); BukkitExecutor.sync(() -> { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index f9a76917a0..0a860a807f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -228,6 +228,7 @@ public class SettingsContainer { public final BigInteger blockCountsSaveThreshold; public final boolean chatSigningSupport; public final int commandsPerPage; + public final boolean cacheSchematics; public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config) throws ManagerLoadException { databaseType = config.getString("database.type").toUpperCase(Locale.ENGLISH); @@ -571,6 +572,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config blockCountsSaveThreshold = BigInteger.valueOf(config.getInt("block-counts-save-threshold", 100)); chatSigningSupport = config.getBoolean("chat-signing-support", true); commandsPerPage = config.getInt("commands-per-page", 7); + cacheSchematics = config.getBoolean("cache-schematics", true); } private List loadClearActions(List clearActionsNames) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index 19c44407ba..f74ab7fd4e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -652,6 +652,11 @@ public int getCommandsPerPage() { return this.global.getCommandsPerPage(); } + @Override + public boolean isCacheSchematics() { + return this.global.isCacheSchematics(); + } + public void updateValue(String path, Object value) throws IOException { File file = new File(plugin.getDataFolder(), "config.yml"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index b42e6b55ae..613b36bd14 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -410,4 +410,8 @@ public int getCommandsPerPage() { return getContainer().commandsPerPage; } + public boolean isCacheSchematics() { + return getContainer().cacheSchematics; + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Long2ObjectMapView.java b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Long2ObjectMapView.java index c33dbea7c7..9abd596968 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Long2ObjectMapView.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/view/Long2ObjectMapView.java @@ -17,6 +17,14 @@ default V getOrDefault(long key, V def) { return value == null ? def : value; } + default void putAll(Long2ObjectMapView other) { + Iterator> iterator = other.entryIterator(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + put(entry.getKey(), entry.getValue()); + } + } + @Nullable V remove(long key); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java index 0e18815365..70897ac71f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java @@ -52,6 +52,10 @@ public World getWorld() { return location.getWorld(); } + public Location getLocation() { + return location; + } + public int getCombinedId() { return this.blockId; } @@ -78,7 +82,6 @@ public void doPrePlace(Island island) { if (originalTileEntity == null) return; - this.tileEntityData = CompoundTag.fromNBT(originalTileEntity.toNBT()); String id = this.tileEntityData.getString("id").orElse(null); @@ -191,6 +194,10 @@ private static void legacySignLinesReplace(CompoundTag tileEntityData, Island is tileEntityData.setByte("SSB.HasSignLines", (byte) 1); } + public SchematicBlock setLocation(Location newBlockLoc) { + return new SchematicBlock(newBlockLoc, this.blockId, this.extra); + } + public static class Extra { @Nullable diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java index ee35617cca..a3bfdb23d5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java @@ -20,4 +20,8 @@ public interface WorldEditSession extends ObjectsPool.Releasable { void finish(Island island); + void markForCache(Location baseLocation); + + WorldEditSession buildFromCache(Location baseLocation); + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java index 9c93c9c72a..abba78ef16 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/BaseSchematic.java @@ -2,12 +2,14 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import org.bukkit.Location; import java.util.Collections; import java.util.List; @@ -40,6 +42,11 @@ public Map getBlockCounts() { return Collections.unmodifiableMap(cachedCounts); } + @Override + public void pasteSchematic(Island island, Location location, Runnable callback) { + pasteSchematic(island, location, callback, null); + } + public abstract List getAffectedChunks(); @Nullable diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index 9e67cd2d5b..d3b40cb794 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -14,6 +14,7 @@ import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockOffset; +import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.io.Files; @@ -32,6 +33,7 @@ import com.bgsoftware.superiorskyblock.world.WorldReader; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.schematic.container.SchematicsContainer; +import com.bgsoftware.superiorskyblock.world.schematic.impl.CachedSuperiorSchematic; import com.bgsoftware.superiorskyblock.world.schematic.impl.SuperiorSchematic; import com.bgsoftware.superiorskyblock.world.schematic.parser.DefaultSchematicParser; import com.google.common.base.Preconditions; @@ -101,7 +103,7 @@ public void loadSchematics() throws ManagerLoadException { } } - if (this.schematicsContainer.getSchematicNames().isEmpty()) { + if (this.schematicsContainer.getSchematics().isEmpty()) { throw new ManagerLoadException("&cThere were no valid schematics.", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } @@ -109,6 +111,28 @@ public void loadSchematics() throws ManagerLoadException { System.gc(); } + public void cacheSchematics() { + if (!plugin.getSettings().isCacheSchematics() || plugin.getSettings().getMaxIslandSize() % 4 != 0) + return; + + List newSchematics = new LinkedList<>(); + boolean cachedSchematic = false; + + for (Schematic schematic : this.schematicsContainer.getSchematics().values()) { + if (schematic instanceof SuperiorSchematic) { + schematic = new CachedSuperiorSchematic((SuperiorSchematic) schematic); + cachedSchematic = true; + } + newSchematics.add(schematic); + } + + if (!cachedSchematic) + return; + + this.schematicsContainer.clearSchematics(); + newSchematics.forEach(this.schematicsContainer::addSchematic); + } + private void loadDefaultSchematicParsers() { if (Bukkit.getPluginManager().isPluginEnabled("FastAsyncWorldEdit")) { try { @@ -128,7 +152,8 @@ public Schematic getSchematic(String name) { @Override public List getSchematics() { - return this.schematicsContainer.getSchematicNames(); + return new SequentialListBuilder() + .build(this.schematicsContainer.getSchematics().keySet()); } @Override @@ -341,7 +366,7 @@ public void saveSchematic(Location pos1, Location pos2, SchematicOptions schemat public String getDefaultSchematic(Dimension dimension) { String suffix = "_" + dimension.getName().toLowerCase(Locale.ENGLISH); - for (String schematicName : this.schematicsContainer.getSchematicNames()) { + for (String schematicName : this.schematicsContainer.getSchematics().keySet()) { if (getSchematic(schematicName + suffix) != null) return schematicName; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/DefaultSchematicsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/DefaultSchematicsContainer.java index 27ae003676..e680096ad6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/DefaultSchematicsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/DefaultSchematicsContainer.java @@ -3,10 +3,9 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser; -import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import java.util.Collections; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -14,7 +13,7 @@ public class DefaultSchematicsContainer implements SchematicsContainer { - private final Map schematicMap = new HashMap<>(); + private final Map schematicMap = new LinkedHashMap<>(); private final List schematicParsers = new LinkedList<>(); @Nullable @@ -29,8 +28,8 @@ public void addSchematic(Schematic schematic) { } @Override - public List getSchematicNames() { - return new SequentialListBuilder().build(this.schematicMap.keySet()); + public Map getSchematics() { + return Collections.unmodifiableMap(this.schematicMap); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/SchematicsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/SchematicsContainer.java index 1c76e4b9f8..fdac912b42 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/SchematicsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/container/SchematicsContainer.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.schematic.parser.SchematicParser; import java.util.List; +import java.util.Map; public interface SchematicsContainer { @@ -13,7 +14,7 @@ public interface SchematicsContainer { void addSchematic(Schematic schematic); - List getSchematicNames(); + Map getSchematics(); void addSchematicParser(SchematicParser schematicParser); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java new file mode 100644 index 0000000000..603e1a607e --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java @@ -0,0 +1,228 @@ +package com.bgsoftware.superiorskyblock.world.schematic.impl; + +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.schematic.Schematic; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.bgsoftware.superiorskyblock.core.logging.Debug; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.profiler.ProfileType; +import com.bgsoftware.superiorskyblock.core.profiler.Profiler; +import com.bgsoftware.superiorskyblock.core.schematic.SchematicBlock; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.world.schematic.BaseSchematic; +import com.google.common.base.Preconditions; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +public class CachedSuperiorSchematic extends BaseSchematic implements Schematic { + + private final Int2ObjectMapView cachedSessions = CollectionsFactory.createInt2ObjectArrayMap(); + private final SuperiorSchematic baseSchematic; + + public CachedSuperiorSchematic(SuperiorSchematic baseSchematic) { + super(baseSchematic.getName(), KeyMaps.createEmptyMap()); + this.baseSchematic = baseSchematic; + populateCache(); + } + + @Override + public Map getBlockCounts() { + return this.baseSchematic.getBlockCounts(); + } + + @Override + public List getAffectedChunks() { + return this.baseSchematic.getAffectedChunks(); + } + + @Override + public Runnable onTeleportCallback() { + return this.baseSchematic.onTeleportCallback(); + } + + @Override + public void pasteSchematic(Island island, Location location, Runnable callback, Consumer onFailure) { + if (Bukkit.isPrimaryThread()) { + BukkitExecutor.async(() -> pasteSchematic(island, location, callback, onFailure)); + return; + } + + long profiler = Profiler.start(ProfileType.SCHEMATIC_PLACE, getName()); + + Log.debug(Debug.PASTE_SCHEMATIC, this.name, island.getOwner().getName(), location); + + try { + pasteSchematicAsyncInternal(island, location, profiler, callback, onFailure); + } catch (Throwable error) { + Log.debugResult(Debug.PASTE_SCHEMATIC, "Failed Schematic Placement", error); + Profiler.end(profiler); + if (onFailure != null) + onFailure.accept(error); + } + } + + private void pasteSchematicAsyncInternal(Island island, Location location, long profiler, Runnable callback, Consumer onFailure) { + int chunkX = location.getBlockX() & 0xF; + int chunkZ = location.getBlockZ() & 0xF; + + long placeProfiler = Profiler.start(ProfileType.SCHEMATIC_BLOCKS_PLACE, getName()); + + WorldEditSessionCache worldEditSessionCache = this.cachedSessions.get(posKey(chunkX, chunkZ)); + + if (worldEditSessionCache == null) + throw new IllegalStateException("Cannot find cache for (" + chunkX + "," + chunkZ + ")"); + + WorldEditSession worldEditSession = worldEditSessionCache.session.buildFromCache(location); + + worldEditSessionCache.prePlaceTasks.forEach(schematicBlock -> { + schematicBlock.doPrePlace(island); + + Location newBlockLoc = new Location( + location.getWorld(), + location.getBlockX() - worldEditSessionCache.baseLocation.getX() + schematicBlock.getLocation().getBlockX(), + schematicBlock.getLocation().getBlockY(), + location.getBlockZ() - worldEditSessionCache.baseLocation.getZ() + schematicBlock.getLocation().getBlockZ() + ); + + worldEditSession.setBlock(newBlockLoc, schematicBlock.getCombinedId(), + schematicBlock.getStatesTag(), schematicBlock.getTileEntityData()); + }); + + Profiler.end(placeProfiler); + + List postPlaceTasks = worldEditSessionCache.postPlaceTasks.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + worldEditSessionCache.postPlaceTasks.forEach(schematicBlock -> { + Location newBlockLoc = new Location( + location.getWorld(), + location.getBlockX() - worldEditSessionCache.baseLocation.getX() + schematicBlock.getLocation().getBlockX(), + schematicBlock.getLocation().getBlockY(), + location.getBlockZ() - worldEditSessionCache.baseLocation.getZ() + schematicBlock.getLocation().getBlockZ() + ); + + postPlaceTasks.add(schematicBlock.setLocation(newBlockLoc)); + }); + + this.baseSchematic.finishPlaceSchematic(worldEditSession, postPlaceTasks, + island, location, profiler, callback, onFailure); + } + + @Override + public Location adjustRotation(Location location) { + return this.baseSchematic.adjustRotation(location); + } + + private void populateCache() { + Log.info("Caching schematics for ", this.name, "..."); + int cacheSize = calculateCacheSize(); + switch (cacheSize) { + case 1: + populateCache1Size(); + break; + case 4: + populateCache4Size(); + break; + case 16: + populateCache16Size(); + break; + } + } + + private void populateCache1Size() { + // Possible chunk offsets: {(0, 0)} + this.cachedSessions.put(posKey(0, 0), createSessionCache(48, 0)); + } + + private void populateCache4Size() { + // Possible chunk offsets: {(8, 8), (0, 8), (8, 0), (0, 0)} + this.cachedSessions.put(posKey(8, 8), createSessionCache(24, 24)); + this.cachedSessions.put(posKey(0, 8), createSessionCache(0, 24)); + this.cachedSessions.put(posKey(8, 0), createSessionCache(24, 0)); + this.cachedSessions.put(posKey(0, 0), createSessionCache(48, 0)); + } + + private void populateCache16Size() { + // Possible chunk offsets: {(4, 4), (12, 4), (8, 8), (4, 0), (0, 4), (8, 4), (0, 0), (12, 0), (4, 12), (8, 0), (0, 12), (12, 12), (4, 8), (8, 12), (0, 8), (12, 8)} + this.cachedSessions.put(posKey(4, 4), createSessionCache(-12, -12)); + this.cachedSessions.put(posKey(12, 4), createSessionCache(12, -12)); + this.cachedSessions.put(posKey(8, 8), createSessionCache(24, 24)); + this.cachedSessions.put(posKey(4, 0), createSessionCache(-12, 0)); + this.cachedSessions.put(posKey(0, 4), createSessionCache(0, -12)); + this.cachedSessions.put(posKey(8, 4), createSessionCache(24, -12)); + this.cachedSessions.put(posKey(0, 0), createSessionCache(48, 0)); + this.cachedSessions.put(posKey(12, 0), createSessionCache(12, 0)); + this.cachedSessions.put(posKey(4, 12), createSessionCache(-12, 12)); + this.cachedSessions.put(posKey(8, 0), createSessionCache(24, 0)); + this.cachedSessions.put(posKey(0, 12), createSessionCache(0, 12)); + this.cachedSessions.put(posKey(12, 12), createSessionCache(12, 12)); + this.cachedSessions.put(posKey(4, 8), createSessionCache(-12, 24)); + this.cachedSessions.put(posKey(8, 12), createSessionCache(-24, 12)); + this.cachedSessions.put(posKey(0, 8), createSessionCache(0, 24)); + this.cachedSessions.put(posKey(12, 8), createSessionCache(12, 24)); + } + + private WorldEditSessionCache createSessionCache(int x, int z) { + World islandsWorld = null; + for (World world : Bukkit.getWorlds()) { + if (plugin.getProviders().getWorldsProvider().isIslandsWorld(world)) { + islandsWorld = world; + break; + } + } + Preconditions.checkState(islandsWorld != null, "Cannot find valid islands world"); + Location location = new Location(islandsWorld, x, plugin.getSettings().getIslandHeight(), z); + List prePlaceTasks = new LinkedList<>(); + List postPlaceTasks = new LinkedList<>(); + WorldEditSession session = this.baseSchematic.createSessionWithSchematicBlocks(location, prePlaceTasks, postPlaceTasks); + session.markForCache(location); + return new WorldEditSessionCache(session, prePlaceTasks, postPlaceTasks, location); + } + + private static int posKey(int x, int z) { + byte xByte = (byte) (x & 0xF); + byte zByte = (byte) (z & 0xF); + return xByte << 8 | zByte; + } + + private static int calculateCacheSize() { + switch ((plugin.getSettings().getMaxIslandSize() / 4) % 4) { + case 0: + return 1; + case 2: + return 4; + // case 1: + // case 3: + default: + return 16; + } + } + + private static class WorldEditSessionCache { + + private final WorldEditSession session; + private final List prePlaceTasks; + private final List postPlaceTasks; + private final Location baseLocation; + + WorldEditSessionCache(WorldEditSession session, List prePlaceTasks, List postPlaceTasks, Location baseLocation) { + this.session = session; + this.prePlaceTasks = prePlaceTasks; + this.postPlaceTasks = postPlaceTasks; + this.baseLocation = baseLocation; + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java index 5d2ef37795..127b58c928 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java @@ -183,11 +183,6 @@ private SuperiorSchematic(String name, Data data, KeyMap cachedCounts) this.data = data; } - @Override - public void pasteSchematic(Island island, Location location, Runnable callback) { - pasteSchematic(island, location, callback, null); - } - @Override public void pasteSchematic(Island island, Location location, Runnable callback, Consumer onFailure) { if (Bukkit.isPrimaryThread()) { @@ -209,13 +204,11 @@ public void pasteSchematic(Island island, Location location, Runnable callback, } } - private void pasteSchematicAsyncInternal(Island island, Location location, long profiler, Runnable callback, Consumer onFailure) { + public WorldEditSession createSessionWithSchematicBlocks(Location location, List prePlaceTasks, + List postPlaceTasks) { WorldEditSession worldEditSession = plugin.getNMSWorld().createEditSession(location.getWorld()); - Location min = this.data.offset.applyToLocation(location); - - List finishTasks = new LinkedList<>(); - long placeProfiler = Profiler.start(ProfileType.SCHEMATIC_BLOCKS_PLACE, getName()); + Location min = this.data.offset.applyToLocation(location); VarintArray.Itr blockIdsIterator = new VarintArray(this.data.blockIds).iterator(); @@ -226,24 +219,28 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long BlockOffset blockOffset = SBlockOffset.fromOffsets(x, y, z); - Location blockLocation = blockOffset.applyToLocation(min.clone()); + Location blockLocation = blockOffset.applyToLocation(min); SchematicBlock schematicBlock = new SchematicBlock(blockLocation, (int) blockIdsIterator.next(), data.extra.get(blockOffset)); - schematicBlock.doPrePlace(island); + prePlaceTasks.add(schematicBlock); worldEditSession.setBlock(blockLocation, schematicBlock.getCombinedId(), schematicBlock.getStatesTag(), schematicBlock.getTileEntityData()); if (schematicBlock.shouldPostPlace()) - finishTasks.add(() -> schematicBlock.doPostPlace(island)); + postPlaceTasks.add(schematicBlock); } if (blockIdsIterator.hasNext()) throw new IllegalStateException("Not all blocks were read from varint iterator"); - Profiler.end(placeProfiler); + return worldEditSession; + } + public void finishPlaceSchematic(WorldEditSession worldEditSession, List postPlaceTasks, + Island island, Location location, long profiler, Runnable callback, + Consumer onFailure) { List affectedChunks = worldEditSession.getAffectedChunks(); List> chunkFutures = new ArrayList<>(affectedChunks.size()); @@ -295,8 +292,11 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long Log.debugResult(Debug.PASTE_SCHEMATIC, "Placing Schematic", ""); worldEditSession.finish(island); - if (island.getOwner().isOnline()) - finishTasks.forEach(Runnable::run); + if (island.getOwner().isOnline()) { + postPlaceTasks.forEach(schematicBlock -> { + schematicBlock.doPostPlace(island); + }); + } Log.debugResult(Debug.PASTE_SCHEMATIC, "Finished Schematic Placement", ""); @@ -308,6 +308,7 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long synchronized (this) { try { + Location min = this.data.offset.applyToLocation(location); prepareCallback(affectedChunks, min); callback.run(); } finally { @@ -324,6 +325,25 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long }); } + private void pasteSchematicAsyncInternal(Island island, Location location, long profiler, Runnable callback, Consumer onFailure) { + List postPlaceTasks = new LinkedList<>(); + List prePlaceTasks = new LinkedList<>(); + + long placeProfiler = Profiler.start(ProfileType.SCHEMATIC_BLOCKS_PLACE, getName()); + + WorldEditSession worldEditSession = createSessionWithSchematicBlocks(location, prePlaceTasks, postPlaceTasks); + + prePlaceTasks.forEach(schematicBlock -> { + schematicBlock.doPrePlace(island); + worldEditSession.setBlock(schematicBlock.getLocation(), schematicBlock.getCombinedId(), + schematicBlock.getStatesTag(), schematicBlock.getTileEntityData()); + }); + + Profiler.end(placeProfiler); + + finishPlaceSchematic(worldEditSession, postPlaceTasks, island, location, profiler, callback, onFailure); + } + @Override public Location adjustRotation(Location location) { location.setYaw(this.data.yaw); @@ -340,7 +360,7 @@ public List getAffectedChunks() { public Runnable onTeleportCallback() { return this.onTeleportCallback; } - + public SuperiorSchematic copy(String newName) { return new SuperiorSchematic(newName, this.data, this.cachedCounts); } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 1b9561fa84..7d982d2b01 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -904,4 +904,9 @@ chat-signing-support: true # Amount of commands to be listed in the `/is help` and `/is admin` commands. # Setting this to 0 or below will result all commands to be shown in a single page. -commands-per-page: 7 \ No newline at end of file +commands-per-page: 7 + +# Whether the plugin should cache schematics for faster placement of schematics. +# This may consume more RAM usage, but will place schematics much faster. +# This will only work if max-island-size is divisible by 4 with no remainder. +cache-schematics: true \ No newline at end of file From e96a440781a951495b896e021cb5b0012c7b81b3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 20 Sep 2025 20:56:08 +0300 Subject: [PATCH 302/600] Adds the ability to toggle fly mode for other players (#2518) --- .../commands/admin/AdminCommandsMap.java | 1 + .../commands/admin/CmdAdminFly.java | 122 ++++++++++++++++++ .../commands/player/CmdFly.java | 9 +- .../core/messages/Message.java | 3 + src/main/resources/lang/de-DE.yml | 3 + src/main/resources/lang/en-US.yml | 3 + src/main/resources/lang/es-ES.yml | 3 + src/main/resources/lang/fr-FR.yml | 3 + src/main/resources/lang/it-IT.yml | 3 + src/main/resources/lang/iw-IL.yml | 3 + src/main/resources/lang/pl-PL.yml | 3 + src/main/resources/lang/pt-BR.yml | 3 + src/main/resources/lang/ru-RU.yml | 3 + src/main/resources/lang/tr-TR.yml | 3 + src/main/resources/lang/vi-VN.yml | 3 + src/main/resources/lang/zh-CN.yml | 3 + 16 files changed, 167 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminFly.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java index 71d0752bc5..e8d68626c1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java @@ -31,6 +31,7 @@ public void loadDefaultCommands() { registerCommand(new CmdAdminDelWarp()); registerCommand(new CmdAdminDemote()); registerCommand(new CmdAdminDisband()); + registerCommand(new CmdAdminFly()); registerCommand(new CmdAdminIgnore()); registerCommand(new CmdAdminJoin()); registerCommand(new CmdAdminKick()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminFly.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminFly.java new file mode 100644 index 0000000000..fd2d735af0 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminFly.java @@ -0,0 +1,122 @@ +package com.bgsoftware.superiorskyblock.commands.admin; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; +import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; +import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; + +import java.util.Collections; +import java.util.List; + +public class CmdAdminFly implements IAdminPlayerCommand { + + private static final LazyReference placeholdersService = new LazyReference() { + @Override + protected PlaceholdersService create() { + return SuperiorSkyblockPlugin.getPlugin().getServices().getService(PlaceholdersService.class); + } + }; + + @Override + public List getAliases() { + return Collections.singletonList("fly"); + } + + @Override + public String getPermission() { + return "superior.admin.fly"; + } + + @Override + public String getUsage(java.util.Locale locale) { + return "admin fly <" + + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "> [flying[true/false]]"; + } + + @Override + public String getDescription(java.util.Locale locale) { + return Message.COMMAND_DESCRIPTION_ADMIN_FLY.getMessage(locale); + } + + @Override + public int getMinArgs() { + return 3; + } + + @Override + public int getMaxArgs() { + return 4; + } + + @Override + public boolean canBeExecutedByConsole() { + return true; + } + + @Override + public boolean supportMultiplePlayers() { + return false; + } + + @Override + public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { + if (args.length == 4) { + boolean enableFlying = Boolean.parseBoolean(args[3]); + + if (enableFlying == targetPlayer.hasIslandFlyEnabled()) { + // Nothing changes, let's just send message to sender and return + if (enableFlying) { + Message.TOGGLED_FLY_ON_OTHER.send(sender, targetPlayer.getName()); + } else { + Message.TOGGLED_FLY_OFF_OTHER.send(sender, targetPlayer.getName()); + } + return; + } + } + + if (!PluginEventsFactory.callPlayerToggleFlyEvent(targetPlayer)) + return; + + if (targetPlayer.hasIslandFlyEnabled()) { + targetPlayer.runIfOnline(player -> { + player.setAllowFlight(false); + player.setFlying(false); + }); + + Message.TOGGLED_FLY_OFF.send(targetPlayer); + Message.TOGGLED_FLY_OFF_OTHER.send(sender, targetPlayer.getName()); + } else { + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(targetPlayer.getLocation(wrapper.getHandle())); + } + + if (island != null && island.hasPermission(targetPlayer, IslandPrivileges.FLY)) { + targetPlayer.runIfOnline(player -> { + player.setAllowFlight(true); + player.setFlying(true); + }); + } + + Message.TOGGLED_FLY_ON.send(targetPlayer); + Message.TOGGLED_FLY_ON_OTHER.send(sender, targetPlayer.getName()); + } + + targetPlayer.toggleIslandFly(); + } + + @Override + public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { + return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], "true", "false") : null; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java index 33d405b932..2e6453a79f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdFly.java @@ -60,10 +60,6 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; Player player = (Player) sender; - Island island; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); - } if (superiorPlayer.hasIslandFlyEnabled()) { player.setAllowFlight(false); @@ -71,6 +67,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ Message.TOGGLED_FLY_OFF.send(superiorPlayer); } else { + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(player.getLocation(wrapper.getHandle())); + } + if (island != null && island.hasPermission(superiorPlayer, IslandPrivileges.FLY)) { player.setAllowFlight(true); player.setFlying(true); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index e30a420f34..bf580d1a24 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -203,6 +203,7 @@ public enum Message { COMMAND_DESCRIPTION_ADMIN_DEMOTE, COMMAND_DESCRIPTION_ADMIN_DEPOSIT, COMMAND_DESCRIPTION_ADMIN_DISBAND, + COMMAND_DESCRIPTION_ADMIN_FLY, COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS, COMMAND_DESCRIPTION_ADMIN_IGNORE, COMMAND_DESCRIPTION_ADMIN_JOIN, @@ -730,6 +731,8 @@ public void send(CommandSender sender, Locale locale, Object... args) { TOGGLED_BYPASS_ON, TOGGLED_FLY_OFF, TOGGLED_FLY_ON, + TOGGLED_FLY_OFF_OTHER, + TOGGLED_FLY_ON_OTHER, TOGGLED_SCHEMATIC_OFF, TOGGLED_SCHEMATIC_ON, TOGGLED_SPY_OFF, diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 122de0c2b1..5f3e64cd04 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -238,6 +238,7 @@ COMMAND_DESCRIPTION_ADMIN_DEMOTE: Ein Mitglied auf der Insel eines anderen Spiel degradieren. COMMAND_DESCRIPTION_ADMIN_DEPOSIT: Geld auf die Inselbank eines anderen Spielers einzahlen. COMMAND_DESCRIPTION_ADMIN_DISBAND: Die Insel eines anderen Spielers dauerhaft auflösen. +COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Gib einem Spieler Auflösungen. COMMAND_DESCRIPTION_ADMIN_IGNORE: Ignoriere eine Insel von den Top-Inseln. COMMAND_DESCRIPTION_ADMIN_JOIN: Treten Sie ohne Einladung einer Insel bei. @@ -908,6 +909,8 @@ TOGGLED_BYPASS_OFF: '&e&lBypass | &7Umgehungsmodus &cOFF&7 umgeschaltet.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Umgehungsmodus &aON&7 umgeschaltet.' TOGGLED_FLY_OFF: '&e&lFly | &7Inselflug umgeschaltet &cOFF&7.' TOGGLED_FLY_ON: '&e&lFly | &7Inselflug umgeschaltet &aON&7.' +TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' +TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Schematicsmodus &cOFF&7 umschalten.' TOGGLED_SCHEMATIC_ON: |- &e&lSchaltpläne | &7Schematicsmodus umschalten &aON&7. diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 28b6329520..4dea96e714 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -174,6 +174,7 @@ COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Delete a warp for an island.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Demote a member in another player''s island.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Deposit money into another player''s island bank.' COMMAND_DESCRIPTION_ADMIN_DISBAND: 'Disband another player''s island permanently.' +COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Give disbands to a player.' COMMAND_DESCRIPTION_ADMIN_IGNORE: 'Ignore an island from top islands.' COMMAND_DESCRIPTION_ADMIN_JOIN: 'Join an island without an invitation.' @@ -715,6 +716,8 @@ TOGGLED_BYPASS_OFF: '&e&lBypass | &7Toggled bypass mode &cOFF&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Toggled bypass mode &aON&7.' TOGGLED_FLY_OFF: '&e&lFly | &7Toggled island fly &cOFF&7.' TOGGLED_FLY_ON: '&e&lFly | &7Toggled island fly &aON&7.' +TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' +TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Toggling schematic mode &cOFF&7.' TOGGLED_SCHEMATIC_ON: |- &e&lSchematics | &7Toggling schematic mode &aON&7. diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index c74426fab8..af2be22e0d 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -174,6 +174,7 @@ COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Elimina un warp de una isla' COMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Degradar a un miembro en la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Deposite dinero en el banco de la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_DISBAND: 'Borra la isla de otro jugador de forma permanente.' +COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Permite que un jugador borre la isla.' COMMAND_DESCRIPTION_ADMIN_IGNORE: 'Hace que la isla ingnore el Top Islas' COMMAND_DESCRIPTION_ADMIN_JOIN: 'Únete a una isla sin invitación.' @@ -712,6 +713,8 @@ TOGGLED_BYPASS_OFF: '&e&lBypass | &7Modo de bypass &cAPAGADO&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Modo de bypass &aENCENDIDO&7.' TOGGLED_FLY_OFF: '&e&lVuelo | &7Vuelo en la isla &cAPAGADO&7.' TOGGLED_FLY_ON: '&e&lVuelo | &7Vuelo en la isla &aENCENDIDO&7.' +TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' +TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Alternar el modo schematic/esquematica &cAPAGADO&7.' TOGGLED_SCHEMATIC_ON: |- &e&lSchematics | &7Alterna el modo schematic/esquematica a &aENCENDIDO&7. diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 4cb4718362..b173e6344f 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -179,6 +179,7 @@ COMMAND_DESCRIPTION_ADMIN_DATA: 'Interact with persistent data of players or isl COMMAND_DESCRIPTION_ADMIN_DEMOTE: Dégrader un membre de l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_DEPOSIT: Déposer de l'argent sur le compte de l'île d'un joueur. COMMAND_DESCRIPTION_ADMIN_DISBAND: Supprimer l'île d'un joueur. +COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Donner des suppressions d'île à un joueur. COMMAND_DESCRIPTION_ADMIN_IGNORE: Masquer une île du top des îles. COMMAND_DESCRIPTION_ADMIN_JOIN: Rejoindre une île sans invitation. @@ -714,6 +715,8 @@ TOGGLED_BYPASS_OFF: '&e&lBypass | &7Mode bypass &cDÉSACTIVÉ&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Mode bypass &aACTIVÉ&7.' TOGGLED_FLY_OFF: '&e&lVol | &7Mode de fly d''île &cDÉSACTIVÉ&7.' TOGGLED_FLY_ON: '&e&lVol | &7Mode de fly d''île &aACTIVÉ&7.' +TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' +TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchémas | &7Mode de création de schematics &cDÉSACTIVÉ&7.' TOGGLED_SCHEMATIC_ON: |- &e&lSchémas | &7Mode de création de schematics &aACTIVÉ&7. diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index cc795f2292..bb9b01a071 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -177,6 +177,7 @@ COMMAND_DESCRIPTION_ADMIN_DEL_WARP: Elimina un warp per un'isola. COMMAND_DESCRIPTION_ADMIN_DEMOTE: Diminuisci il ruolo di un membro dell'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_DEPOSIT: Depositare denaro nella banca dell'isola di un giocatore. COMMAND_DESCRIPTION_ADMIN_DISBAND: Sciogli definitivamente l'isola di un giocatore. +COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Aumenta la quantità di reset disponibili di un giocatore. COMMAND_DESCRIPTION_ADMIN_IGNORE: Rimuovi un giocatore dal menu delle migliori isole. COMMAND_DESCRIPTION_ADMIN_JOIN: Unisciti a un'isola senza un invito. @@ -720,6 +721,8 @@ TOGGLED_BYPASS_OFF: '&e&lBypass | &7Modalità bypass &cOFF&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Modalità bypass &aON&7.' TOGGLED_FLY_OFF: '&e&lFly | &7Modalità volo &cOFF&7.' TOGGLED_FLY_ON: '&e&lFly | &7Modalità volo &aON&7.' +TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' +TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Modalità schematica &cOFF&7.' TOGGLED_SCHEMATIC_ON: | &e&lSchematics | &7Schematic mode &aON&7. diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 1cf53081d7..861e17fb33 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -182,6 +182,7 @@ COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Delete a warp for an island.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: רחא יאב ןקחש הגרדב דירוהל. COMMAND_DESCRIPTION_ADMIN_DEPOSIT: רחא יא לש קנב לא ףסכ ריבעהל. COMMAND_DESCRIPTION_ADMIN_DISBAND: רחא ןקחש לש יא קוחמל. +COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: ןקחשל םייא תוקיחמ תתל. COMMAND_DESCRIPTION_ADMIN_IGNORE: רתויב םיבוטה םייאה תמישרמ יא דירוהל. COMMAND_DESCRIPTION_ADMIN_JOIN: הנמזה אלל יאל סנכיהל. @@ -734,6 +735,8 @@ TOGGLED_BYPASS_OFF: '&e&lהפיקע | &7הפיקעה בצמ תא &cתיביכ&7. TOGGLED_BYPASS_ON: '&e&lהפיקע | &7הפיקעה בצמ תא &aתקלדה&7.' TOGGLED_FLY_OFF: '&e&lהפועת | &7תיטמוטואה הפועתה בצמ תא &cתיביכ&7.' TOGGLED_FLY_ON: '&e&lהפועת | &7תיטמוטואה הפועתה בצמ תא &aתקלדה&7.' +TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' +TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lםינבמ רצוי | &7םינבמה תריצי בצמ תא &cתיביכ&7.' TOGGLED_SCHEMATIC_ON: |- &e&lםינבמ רצוי | &7םינבמה תריצי בצמ תא &aתקלדה&7. diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 721b6ef3d6..0b5c444d7a 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -174,6 +174,7 @@ COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Usuń warp dla wyspy.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Zdegraduj czlonka na wyspie innego gracza.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Wplac pieniadze do banku wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_DISBAND: 'Rozwiaz wyspe innego gracza na stale.' +COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Daj rozwiazania graczowi.' COMMAND_DESCRIPTION_ADMIN_IGNORE: 'Ignoruj ​​wyspe z najlepszych wysp.' COMMAND_DESCRIPTION_ADMIN_JOIN: 'Dolacz do wyspy bez zaproszenia.' @@ -712,6 +713,8 @@ TOGGLED_BYPASS_OFF: '&e&lBypass | &7Wlaczony tryb obejscia &cWYl&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Wlaczony tryb obejscia &aWl&7.' TOGGLED_FLY_OFF: '&e&lFly | &7Wlacz lot wyspowy &cWYl&7.' TOGGLED_FLY_ON: '&e&lFly | &7Wlacz lot wyspowy &aON&7.' +TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' +TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchematy | &7Przelaczanie trybu schematu &cOFF&7.' TOGGLED_SCHEMATIC_ON: |- &e&lSchematy | &7Przelaczanie trybu schematu &aWl&7. diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index c4532f4069..6f3cfda3b3 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -174,6 +174,7 @@ COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Excluir um warp de uma ilha.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Rebaixar um membro na ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Depositar dinheiro no banco da ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_DISBAND: 'Desfazer permanentemente a ilha de outro jogador.' +COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Conceder dissoluções de ilhas a um jogador.' COMMAND_DESCRIPTION_ADMIN_IGNORE: 'Ignorar uma ilha das melhores ilhas.' COMMAND_DESCRIPTION_ADMIN_JOIN: 'Entrar em uma ilha sem convite.' @@ -712,6 +713,8 @@ TOGGLED_BYPASS_OFF: '&e&lIgnorar | &7Modo de desvio alternado &cOFF&7.' TOGGLED_BYPASS_ON: '&e&lIgnorar | &7Modo de desvio alternado &aON&7.' TOGGLED_FLY_OFF: '&e&lVoar | &7Voar ilha alternado &cOFF&7.' TOGGLED_FLY_ON: '&e&lVoar | &7Voar ilha alternado &aON&7.' +TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' +TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lEsquemas | &7Alternando modo esquemático &cOFF&7.' TOGGLED_SCHEMATIC_ON: |- &e&lschematic | &7Modo de esquemas ativado &aON&7. diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 0ac276e3af..8e2dc41072 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -174,6 +174,7 @@ COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Удалить варп для остров COMMAND_DESCRIPTION_ADMIN_DEMOTE: 'Понизить участника на острове другого игрока.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: 'Внести деньги в банк острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_DISBAND: 'Расформировать остров другого игрока навсегда.' +COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: 'Выдать расформирования игроку.' COMMAND_DESCRIPTION_ADMIN_IGNORE: 'Игнорировать остров в списке лучших островов.' COMMAND_DESCRIPTION_ADMIN_JOIN: 'Присоединиться к острову без приглашения.' @@ -712,6 +713,8 @@ TOGGLED_BYPASS_OFF: '&e&lОбход | &7Режим обхода отключен TOGGLED_BYPASS_ON: '&e&lОбход | &7Режим обхода включен &aON&7.' TOGGLED_FLY_OFF: '&e&lПолет | &7Режим полета на острове отключен &cOFF&7.' TOGGLED_FLY_ON: '&e&lПолет | &7Режим полета на острове включен &aON&7.' +TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' +TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lСхемы | &7Режим схем отключен &cOFF&7.' TOGGLED_SCHEMATIC_ON: |- &e&lСхемы | &7Режим схем включен &aON&7. diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 99eaec67de..a957fe5e75 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -229,6 +229,7 @@ COMMAND_DESCRIPTION_ADMIN_DEL_WARP: Bir ada için bir ışınlanma noktasını s COMMAND_DESCRIPTION_ADMIN_DEMOTE: Başka bir oyuncunun adasındaki bir üyeyi rütbe düşür. COMMAND_DESCRIPTION_ADMIN_DEPOSIT: Başka bir oyuncunun ada bankasına para yatır. COMMAND_DESCRIPTION_ADMIN_DISBAND: Başka bir oyuncunun adasını kalıcı olarak dağıt. +COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Bir oyuncuya ada dağıtma hakkı ver. COMMAND_DESCRIPTION_ADMIN_IGNORE: En iyi adalardan bir adayı yoksay. COMMAND_DESCRIPTION_ADMIN_JOIN: Davet olmadan bir adaya katıl. @@ -846,6 +847,8 @@ TOGGLED_BYPASS_OFF: '&e&lBypass | &7Bypass modu &cKAPALI&7.' TOGGLED_BYPASS_ON: '&e&lBypass | &7Bypass modu &aAÇIK&7.' TOGGLED_FLY_OFF: '&e&lUçuş | &7Ada uçuşu &cKAPALI&7.' TOGGLED_FLY_ON: '&e&lUçuş | &7Ada uçuşu &aAÇIK&7.' +TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' +TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lŞematikler | &7Şematik modu &cKAPALI&7.' TOGGLED_SCHEMATIC_ON: |- &e&lŞematikler | &7Şematik modu &aAÇIK&7. diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 23cb2cc925..7bfff899fc 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -199,6 +199,7 @@ COMMAND_DESCRIPTION_ADMIN_DEL_WARP: 'Xóa một khu vực cho một hòn đảo. COMMAND_DESCRIPTION_ADMIN_DEMOTE: Hạ cấp thành viên ở đảo của người chơi khác. COMMAND_DESCRIPTION_ADMIN_DEPOSIT: Gửi tiền vào ngân hàng đảo của người chơi khác. COMMAND_DESCRIPTION_ADMIN_DISBAND: Giải tán vĩnh viễn hòn đảo của người chơi khác. +COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: Giải tán cho người chơi. COMMAND_DESCRIPTION_ADMIN_IGNORE: Bỏ qua một hòn đảo từ những hòn đảo hàng đầu. COMMAND_DESCRIPTION_ADMIN_JOIN: Tham gia một hòn đảo mà không cần lời mời. @@ -803,6 +804,8 @@ TOGGLED_BYPASS_OFF: '&e&lBypass | &7Chuyển đổi chế độ bypass: &cTẮT& TOGGLED_BYPASS_ON: '&e&lBypass | &7Chuyển đổi chế độ bypass: &aBẬT&7.' TOGGLED_FLY_OFF: '&e&lBay | &7Chuyển đổi chế độ bay trong đảo: &cTẮT&7.' TOGGLED_FLY_ON: '&e&lBay | &7Chuyển đổi chế độ bay trong đảo: &aBẬT&7.' +TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' +TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&lSchematics | &7Chuyển đổi chế độ schematic: &cTẮT&7.' TOGGLED_SCHEMATIC_ON: |- &e&lSchematics | &7Chuyển đổi chế độ schematic: &aBẬT&7. diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 1a23e06d99..340a37aa96 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -174,6 +174,7 @@ COMMAND_DESCRIPTION_ADMIN_DEL_WARP: '删除指定岛屿的传送点.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: '将岛屿中的指定玩家升职.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: '向指定岛屿的银行中存款.' COMMAND_DESCRIPTION_ADMIN_DISBAND: '永久解散指定岛屿.' +COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: '使指定玩家从其团队中解散.' COMMAND_DESCRIPTION_ADMIN_IGNORE: '将指定岛屿设置为不参与排行榜排名.' COMMAND_DESCRIPTION_ADMIN_JOIN: '强制加入岛屿.' @@ -712,6 +713,8 @@ TOGGLED_BYPASS_OFF: '&e&l绕过 | &7绕过模式已 &c关闭&7.' TOGGLED_BYPASS_ON: '&e&l绕过 | &7绕过模式已 &a开启&7.' TOGGLED_FLY_OFF: '&e&l飞行 | &7岛屿飞行已 &c关闭&7.' TOGGLED_FLY_ON: '&e&l飞行 | &7岛屿飞行已 &a开启&7.' +TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' +TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' TOGGLED_SCHEMATIC_OFF: '&e&l结构 | &7结构模式已 &c关闭&7.' TOGGLED_SCHEMATIC_ON: |- &e&l结构 | &7结构模式已 &a开启&7. From f8e93eef11707f443cb193fd4f34dec8c93398c7 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 20 Sep 2025 22:40:31 +0300 Subject: [PATCH 303/600] Fixed cached schematics are placed one block up (#2658) --- .../world/schematic/impl/CachedSuperiorSchematic.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java index 603e1a607e..564793dfc9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java @@ -182,7 +182,7 @@ private WorldEditSessionCache createSessionCache(int x, int z) { } } Preconditions.checkState(islandsWorld != null, "Cannot find valid islands world"); - Location location = new Location(islandsWorld, x, plugin.getSettings().getIslandHeight(), z); + Location location = new Location(islandsWorld, x, plugin.getSettings().getIslandHeight() - 1, z); List prePlaceTasks = new LinkedList<>(); List postPlaceTasks = new LinkedList<>(); WorldEditSession session = this.baseSchematic.createSessionWithSchematicBlocks(location, prePlaceTasks, postPlaceTasks); From b83062fc4a68a5f393affff33c29277a86f96f6b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 20 Sep 2025 22:42:27 +0300 Subject: [PATCH 304/600] Fix admin reset world not including default dimension in tab complete (#2616) --- .../commands/admin/CmdAdminResetWorld.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java index 354d431f34..f620bc9ed1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java @@ -2,9 +2,6 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.config.SettingsManager; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeLevelBonusEvent; -import com.bgsoftware.superiorskyblock.api.events.IslandChangeWorthBonusEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandChunkFlags; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; @@ -16,8 +13,6 @@ import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyReference; -import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -26,7 +21,6 @@ import org.bukkit.block.BlockFace; import org.bukkit.command.CommandSender; -import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -178,9 +172,8 @@ public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSende List environments = new ArrayList<>(); for (Dimension dimension : Dimension.values()) { - if (dimension != plugin.getSettings().getWorlds().getDefaultWorldDimension()) { - if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) - environments.add(dimension.getName().toLowerCase(Locale.ENGLISH)); + if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { + environments.add(dimension.getName().toLowerCase(Locale.ENGLISH)); } } From 273e743b997db37d4e87111b11e3087cf30a118d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 20 Sep 2025 22:55:40 +0300 Subject: [PATCH 305/600] Fix coops do not take damage if visitors damage is disabled (#2656) --- .../bgsoftware/superiorskyblock/listener/PlayersListener.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java index 74f5439581..765c5645a4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java @@ -335,8 +335,8 @@ private void onPlayerDamage(GameEvent e) { if (island != null) { if (island.isSpawn() ? (plugin.getSettings().getSpawn().isProtected() && !plugin.getSettings().getSpawn().isPlayersDamage()) : - ((!plugin.getSettings().isVisitorsDamage() && island.isVisitor(targetPlayer, false)) || - (!plugin.getSettings().isCoopDamage() && island.isCoop(targetPlayer)))) + ((!plugin.getSettings().isCoopDamage() && island.isCoop(targetPlayer)) || + (!plugin.getSettings().isVisitorsDamage() && island.isVisitor(targetPlayer, true)))) e.setCancelled(); } From 168496c61859182c222e258961531eb30a8a8742 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 20 Sep 2025 23:03:14 +0300 Subject: [PATCH 306/600] Add `superior.admin.fly` to plugin.yml --- src/main/resources/plugin.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index dd66c26bd3..2e753bbe4c 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -233,6 +233,8 @@ permissions: description: Deposit money into another player's island bank. superior.admin.disband: description: Disband another player's island permanently. + superior.admin.fly: + description: Toggle island fly for another player. superior.admin.givedisbands: description: Give disbands to a player. superior.admin.ignore: From 26b33ad57425a35a9a68406497eb5fa8ee42ee72 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 20 Sep 2025 22:04:59 +0200 Subject: [PATCH 307/600] Added description of the admin resetsettings command (#2643) --- src/main/resources/lang/de-DE.yml | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/tr-TR.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + 12 files changed, 12 insertions(+) diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 5f3e64cd04..610298252c 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -261,6 +261,7 @@ COMMAND_DESCRIPTION_ADMIN_RELOAD: Alle Konfigurationen und Aufgaben des Plugins laden. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Entferne ein Blocklimit von einer Insel. COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Alle Bewertungen eines Spielers entfernen. +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Setze eine Welt für eine Insel zurück. COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Schaltpläne für das Plugin erstellen. COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: Banklimit für eine Insel festlegen. diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 4dea96e714..1c744fcc5b 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -193,6 +193,7 @@ COMMAND_DESCRIPTION_ADMIN_RECALC: 'Re-calculates the worth of an island.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Reload all configurations and tasks of the plugin.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remove a block limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Remove all ratings given by a player.' +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Create schematics for the plugin.' COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set a bank limit to an island.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index af2be22e0d..9f5235f969 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -193,6 +193,7 @@ COMMAND_DESCRIPTION_ADMIN_RECALC: 'Vuelve a calcular el valor de una isla.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Recarga todas las configuraciones y tareas del plugin/complemento.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Eliminar el límite de bloques de una isla.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Eliminar todas las calificaciones dadas por un jugador.' +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Cree schematics para el plugin.' COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Establezca un límite bancario para una isla.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index b173e6344f..e83f7eb3c2 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -196,6 +196,7 @@ COMMAND_DESCRIPTION_ADMIN_RECALC: Re-calculer la valeur d'une île. COMMAND_DESCRIPTION_ADMIN_RELOAD: Recharger toutes les configurations du plugin. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Retirer la limite de bloc d'une île. COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Suppimer toutes les notes attribuées par un joueur. +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Réinitialiser l'île d'un monde précis pour l'île spécifiée. COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Créer des schematics pour le plugin. COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: Définir la limite bancaire d'une île. diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index bb9b01a071..721cfe177e 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -196,6 +196,7 @@ COMMAND_DESCRIPTION_ADMIN_RECALC: Ricalcola il valore di un'isola. COMMAND_DESCRIPTION_ADMIN_RELOAD: Ricarica tutte le configurazioni e le attività del plugin. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Rimuovi il limite di un blocco da un'isola. COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Rimuovi tutte le valutazioni fornite da un giocatore. +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Ripristina il mondo su un''isole.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Crea una schematica per il plugin. COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: Imposta un limite di banca per un'isola. diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 861e17fb33..599ca84448 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -201,6 +201,7 @@ COMMAND_DESCRIPTION_ADMIN_RECALC: יא לש יווש שדחמ בשחל. COMMAND_DESCRIPTION_ADMIN_RELOAD: ןיגאלפה לש םיצבקה לכ תא שדחמ ןועטל. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remove a block limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: ןקחש ידי לע ונתנש םיגורידה לכ תא קוחמל. +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: ןיגאלפל שדח הנבמ רוציל. COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set a bank limit to an island.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 0b5c444d7a..6c5a738816 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -193,6 +193,7 @@ COMMAND_DESCRIPTION_ADMIN_RECALC: 'Ponownie oblicza wartosc wyspy.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Zaladuj ponownie wszystkie konfiguracje i zadania wtyczki.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Usuń limit bloków z wyspy.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Usuń wszystkie oceny wystawione przez gracza.' +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Zresetuj wszystkie ustawienia wyspy dla konkretnej wyspy.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Zresetuj swiat dla wyspy.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Utwórz schematy dla wtyczki.' COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Ustaw limit banku dla wyspy.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 6f3cfda3b3..be52c6884a 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -193,6 +193,7 @@ COMMAND_DESCRIPTION_ADMIN_RECALC: 'Recalcular o valor de uma ilha.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Recarregar todas as configurações e tarefas do plugin.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remover o limite de blocos de uma ilha.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Remover todas as avaliações dadas por um jogador.' +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Redefinir um mundo para uma ilha.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Criar esquemas para o plugin.' COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Definir o limite do banco para uma ilha.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 8e2dc41072..2d5eb4a35e 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -193,6 +193,7 @@ COMMAND_DESCRIPTION_ADMIN_RECALC: 'Пересчитать стоимость о COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Перезагрузить все настройки и задачи плагина.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Удалить лимит блоков с острова.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Удалить все оценки, выставленные игроком.' +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Сбросить мир для острова.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Создать схемы для плагина.' COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Установить лимит банка для острова.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index a957fe5e75..72a3f641e9 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -251,6 +251,7 @@ COMMAND_DESCRIPTION_ADMIN_RELOAD: Eklentinin tüm yapılandırmalarını ve gör COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Bir adadan blok limitini kaldır. COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Bir oyuncu tarafından verilen tüm değerlendirmeleri kaldır. +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Bir ada için bir dünyayı sıfırla. COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Eklenti için şematikler oluştur. COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: Bir adaya banka limiti belirle. diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 7bfff899fc..a07147a54c 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -222,6 +222,7 @@ COMMAND_DESCRIPTION_ADMIN_RELOAD: Tải lại tất cả các config và tác v COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Xóa giới hạn khối khỏi một hòn đảo.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Xóa tất cả các xếp hạng được cung cấp bởi một người chơi. +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Tái tạo lại thế giới cho một hòn đảo.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Tạo các schematic cho plugin. COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Đặt mức giới hạn ngân hàng cho một hòn đảo.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 340a37aa96..d5eb44a3b5 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -193,6 +193,7 @@ COMMAND_DESCRIPTION_ADMIN_RECALC: '重新计算指定岛屿的价值.' COMMAND_DESCRIPTION_ADMIN_RELOAD: '重载本插件的所有配置和进程.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: '去除指定岛屿的方块数量限制.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: '去除指定玩家的所有评分.' +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: '重置指定岛屿所在的世界.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: '从插件创建结构文件.' COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: '设置指定岛屿的银行存量上限.' From 8b20d03b04e566983173e833bf848cb8e2bc5be0 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 20 Sep 2025 22:11:01 +0200 Subject: [PATCH 308/600] Fixed default menus (#2633) --- src/main/resources/menus/bank-logs.yml | 8 +- src/main/resources/menus/bank-logs1_12.yml | 8 +- src/main/resources/menus/bank-logs1_13.yml | 4 +- src/main/resources/menus/border-color.yml | 2 +- src/main/resources/menus/border-color1_12.yml | 2 +- src/main/resources/menus/border-color1_13.yml | 2 +- src/main/resources/menus/counts.yml | 8 +- src/main/resources/menus/counts1_12.yml | 8 +- src/main/resources/menus/counts1_13.yml | 8 +- src/main/resources/menus/counts1_20.yml | 8 +- src/main/resources/menus/missions.yml | 1 + src/main/resources/menus/missions1_12.yml | 1 + src/main/resources/menus/permissions1_13.yml | 2342 ----------------- src/main/resources/menus/permissions1_16.yml | 6 +- src/main/resources/menus/permissions1_17.yml | 6 +- src/main/resources/menus/player-language.yml | 10 +- src/main/resources/menus/upgrades.yml | 490 ++-- src/main/resources/menus/upgrades1_12.yml | 490 ++-- src/main/resources/menus/upgrades1_13.yml | 478 ++-- src/main/resources/menus/upgrades1_20.yml | 1213 +++++++++ .../menus/warp-category-icon-edit1_13.yml | 60 - .../menus/warp-category-manage1_13.yml | 48 - .../resources/menus/warp-icon-edit1_13.yml | 60 - src/main/resources/menus/warp-manage1_13.yml | 58 - 24 files changed, 2014 insertions(+), 3307 deletions(-) delete mode 100644 src/main/resources/menus/permissions1_13.yml create mode 100644 src/main/resources/menus/upgrades1_20.yml delete mode 100644 src/main/resources/menus/warp-category-icon-edit1_13.yml delete mode 100644 src/main/resources/menus/warp-category-manage1_13.yml delete mode 100644 src/main/resources/menus/warp-icon-edit1_13.yml delete mode 100644 src/main/resources/menus/warp-manage1_13.yml diff --git a/src/main/resources/menus/bank-logs.yml b/src/main/resources/menus/bank-logs.yml index decbda174c..db6496d053 100644 --- a/src/main/resources/menus/bank-logs.yml +++ b/src/main/resources/menus/bank-logs.yml @@ -27,14 +27,14 @@ money-sort: '-' items: '@': type: PAPER - name: '&e#{0}' + name: '&eTransaction #{0}' lore: - '&7Player: {1}' - '&7Status: {2}' - '&7Time: {3}' - - '&7Amount: {4}' - - '&7 ' - - '&7&o(( &f&oRight-Click &7&oto filter transactions by this player. ))' + - '&7Amount: ${4}' + - '' + - '&7Click to filter transactions by this player.' '%': type: PAPER name: '{0}Previous Page' diff --git a/src/main/resources/menus/bank-logs1_12.yml b/src/main/resources/menus/bank-logs1_12.yml index aebddb2681..72457b5a1d 100644 --- a/src/main/resources/menus/bank-logs1_12.yml +++ b/src/main/resources/menus/bank-logs1_12.yml @@ -27,14 +27,14 @@ money-sort: '-' items: '@': type: PAPER - name: '&e#{0}' + name: '&eTransaction #{0}' lore: - '&7Player: {1}' - '&7Status: {2}' - '&7Time: {3}' - - '&7Amount: {4}' - - '&7 ' - - '&7&o(( &f&oRight-Click &7&oto filter transactions by this player. ))' + - '&7Amount: ${4}' + - '' + - '&7Click to filter transactions by this player.' '%': type: PAPER name: '{0}Previous Page' diff --git a/src/main/resources/menus/bank-logs1_13.yml b/src/main/resources/menus/bank-logs1_13.yml index c1ab69343f..397d601e64 100644 --- a/src/main/resources/menus/bank-logs1_13.yml +++ b/src/main/resources/menus/bank-logs1_13.yml @@ -33,8 +33,8 @@ items: - '&7Status: {2}' - '&7Time: {3}' - '&7Amount: ${4}' - - '&7 ' - - '&7&o(( &f&oRight-Click &7&oto filter transactions by this player. ))' + - '' + - '&7Click to filter transactions by this player.' '%': type: PAPER name: '{0}Previous Page' diff --git a/src/main/resources/menus/border-color.yml b/src/main/resources/menus/border-color.yml index 52dc549e7b..3a8fffd63f 100644 --- a/src/main/resources/menus/border-color.yml +++ b/src/main/resources/menus/border-color.yml @@ -31,7 +31,7 @@ items: '#': type: STAINED_GLASS_PANE data: 15 - name: '&f ' + name: '&f' '@': type: SKULL_ITEM data: 3 diff --git a/src/main/resources/menus/border-color1_12.yml b/src/main/resources/menus/border-color1_12.yml index 22ec82f8e8..07e8d5dc53 100644 --- a/src/main/resources/menus/border-color1_12.yml +++ b/src/main/resources/menus/border-color1_12.yml @@ -31,7 +31,7 @@ items: '#': type: STAINED_GLASS_PANE data: 15 - name: '&f ' + name: '&f' '@': type: SKULL_ITEM data: 3 diff --git a/src/main/resources/menus/border-color1_13.yml b/src/main/resources/menus/border-color1_13.yml index 2983152779..50edcc5da6 100644 --- a/src/main/resources/menus/border-color1_13.yml +++ b/src/main/resources/menus/border-color1_13.yml @@ -28,7 +28,7 @@ items: name: '&cDisable Border' '#': type: BLACK_STAINED_GLASS_PANE - name: '&f ' + name: '&f' '@': type: PLAYER_HEAD skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzc0NzJkNjA4ODIxZjQ1YTg4MDUzNzZlYzBjNmZmY2I3ODExNzgyOWVhNWY5NjAwNDFjMmEwOWQxMGUwNGNiNCJ9fX0=' diff --git a/src/main/resources/menus/counts.yml b/src/main/resources/menus/counts.yml index c14a9e92e8..f9bc1b6178 100644 --- a/src/main/resources/menus/counts.yml +++ b/src/main/resources/menus/counts.yml @@ -45,10 +45,4 @@ items: '$': type: STAINED_GLASS_PANE data: 15 - name: '&f' - -sounds: - '@': - type: ORB_PICKUP - volume: 0.2 - pitch: 0.2 \ No newline at end of file + name: '&f' \ No newline at end of file diff --git a/src/main/resources/menus/counts1_12.yml b/src/main/resources/menus/counts1_12.yml index d85a43f416..f9bc1b6178 100644 --- a/src/main/resources/menus/counts1_12.yml +++ b/src/main/resources/menus/counts1_12.yml @@ -45,10 +45,4 @@ items: '$': type: STAINED_GLASS_PANE data: 15 - name: '&f' - -sounds: - '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 \ No newline at end of file + name: '&f' \ No newline at end of file diff --git a/src/main/resources/menus/counts1_13.yml b/src/main/resources/menus/counts1_13.yml index 608bb9a028..ad15d8b1f4 100644 --- a/src/main/resources/menus/counts1_13.yml +++ b/src/main/resources/menus/counts1_13.yml @@ -44,10 +44,4 @@ items: name: '{0}Next Page' '$': type: BLACK_STAINED_GLASS_PANE - name: '&f' - -sounds: - '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 \ No newline at end of file + name: '&f' \ No newline at end of file diff --git a/src/main/resources/menus/counts1_20.yml b/src/main/resources/menus/counts1_20.yml index 27996d5684..503c174616 100644 --- a/src/main/resources/menus/counts1_20.yml +++ b/src/main/resources/menus/counts1_20.yml @@ -44,10 +44,4 @@ items: name: '{0}Next Page' '$': type: BLACK_STAINED_GLASS_PANE - name: '&f' - -sounds: - '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 \ No newline at end of file + name: '&f' \ No newline at end of file diff --git a/src/main/resources/menus/missions.yml b/src/main/resources/menus/missions.yml index c49b60fc39..6c9d288391 100644 --- a/src/main/resources/menus/missions.yml +++ b/src/main/resources/menus/missions.yml @@ -19,6 +19,7 @@ items: '$': type: STAINED_GLASS_PANE data: 15 + name: '&f' '#': type: DIAMOND_PICKAXE name: '&eMiner Missions' diff --git a/src/main/resources/menus/missions1_12.yml b/src/main/resources/menus/missions1_12.yml index ecad82af88..31c3f86203 100644 --- a/src/main/resources/menus/missions1_12.yml +++ b/src/main/resources/menus/missions1_12.yml @@ -19,6 +19,7 @@ items: '$': type: STAINED_GLASS_PANE data: 15 + name: '&f' '#': type: DIAMOND_PICKAXE name: '&eMiner Missions' diff --git a/src/main/resources/menus/permissions1_13.yml b/src/main/resources/menus/permissions1_13.yml deleted file mode 100644 index c41fc7a18e..0000000000 --- a/src/main/resources/menus/permissions1_13.yml +++ /dev/null @@ -1,2342 +0,0 @@ -###################################################### -## ## -## SuperiorSkyblock 2 ## -## Developed by Ome_R ## -## ## -###################################################### - -title: '&lPermissions Controller' -previous-menu: true - -pattern: - - '$ $ $ $ $ $ $ $ $' - - '$ @ @ @ @ @ @ @ $' - - '$ @ @ @ @ @ @ @ $' - - '$ @ @ @ @ @ @ @ $' - - '$ $ % $ * $ ^ $ $' - -slots: '@' -previous-page: '%' -current-page: '*' -next-page: '^' - -messages: - no-role-permission: '&8 - &c{}' - exact-role-permission: '&8 - &2{}' - higher-role-permission: '&8 - &a{}' - -items: - '$': - type: CYAN_STAINED_GLASS_PANE - name: '&f' - '%': - type: PAPER - name: '{0}Previous Page' - '*': - type: SUNFLOWER - name: '&aCurrent Page' - lore: - - '&7Page {0}' - '^': - type: PAPER - name: '{0}Next Page' - -permissions: - all: - display-menu: true - permission-enabled: - type: BEDROCK - name: '&6All' - lore: - - '&7Access to all the abilities of the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: BEDROCK - name: '&6All' - lore: - - '&7Access to all the abilities of the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: BEDROCK - name: '&6All' - lore: - - '&7Access to all the abilities of the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - animal_breed: - display-menu: true - permission-enabled: - type: WHEAT - name: '&6Animal Breed' - lore: - - '&7Access to breed animals inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - name: '&6Animal Breed' - type: WHEAT - lore: - - '&7Access to breed animals inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - name: '&6Animal Breed' - type: WHEAT - lore: - - '&7Access to breed animals inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - animal_damage: - display-menu: true - permission-enabled: - type: DIAMOND_SWORD - name: '&6Animal Damage' - lore: - - '&7Access to damage animals inside the island.' - - '&7Currently &aENABLED&7.' - flags: - - HIDE_ATTRIBUTES - permission-disabled: - type: DIAMOND_SWORD - name: '&6Animal Damage' - lore: - - '&7Access to damage animals inside the island.' - - '&7Currently &cDISABLED&7.' - flags: - - HIDE_ATTRIBUTES - role-permission: - type: DIAMOND_SWORD - name: '&6Animal Damage' - lore: - - '&7Access to damage animals inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - flags: - - HIDE_ATTRIBUTES - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - animal_shear: - display-menu: true - permission-enabled: - type: SHEARS - name: '&6Animal Shear' - lore: - - '&7Access to shear animals inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: SHEARS - name: '&6Animal Shear' - lore: - - '&7Access to shear animals inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: SHEARS - name: '&6Animal Shear' - lore: - - '&7Access to shear animals inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - animal_spawn: - display-menu: true - permission-enabled: - type: CHICKEN_SPAWN_EGG - name: '&6Animal Spawn' - lore: - - '&7Access to spawn animals inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: CHICKEN_SPAWN_EGG - name: '&6Animal Spawn' - lore: - - '&7Access to spawn animals inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: CHICKEN_SPAWN_EGG - name: '&6Animal Spawn' - lore: - - '&7Access to spawn animals inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - ban_member: - display-menu: true - permission-enabled: - type: SKELETON_SKULL - name: '&6Ban Member' - lore: - - '&7Access to ban members from the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: SKELETON_SKULL - name: '&6Ban Member' - lore: - - '&7Access to ban members from the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: SKELETON_SKULL - name: '&6Ban Member' - lore: - - '&7Access to ban members from the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - break: - display-menu: true - permission-enabled: - type: DIAMOND_PICKAXE - name: '&6Break' - lore: - - '&7Access to break blocks inside the island.' - - '&7Currently &aENABLED&7.' - flags: - - HIDE_ATTRIBUTES - permission-disabled: - type: DIAMOND_PICKAXE - name: '&6Break' - lore: - - '&7Access to break blocks inside the island.' - - '&7Currently &cDISABLED&7.' - flags: - - HIDE_ATTRIBUTES - role-permission: - type: DIAMOND_PICKAXE - name: '&6Break' - lore: - - '&7Access to break blocks inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - flags: - - HIDE_ATTRIBUTES - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - build: - display-menu: true - permission-enabled: - type: COBBLESTONE - name: '&6Build' - lore: - - '&7Access to place blocks inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: COBBLESTONE - name: '&6Build' - lore: - - '&7Access to place blocks inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: COBBLESTONE - name: '&6Build' - lore: - - '&7Access to place blocks inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - change_name: - display-menu: true - permission-enabled: - type: NAME_TAG - name: '&6Change Name' - lore: - - '&7Access to change the island''s name.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: NAME_TAG - name: '&6Change Name' - lore: - - '&7Access to change the island''s name.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: NAME_TAG - name: '&6Change Name' - lore: - - '&7Access to change the island''s name.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - chest_access: - display-menu: true - permission-enabled: - type: CHEST - name: '&6Chest Access' - lore: - - '&7Access to open chests inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: CHEST - name: '&6Chest Access' - lore: - - '&7Access to open chests inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: CHEST - name: '&6Chest Access' - lore: - - '&7Access to open chests inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - chorus_fruit: - display-menu: true - permission-enabled: - type: CHORUS_FRUIT - name: '&6Chorus Fruit' - lore: - - '&7Access to consume chorus fruits inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: CHORUS_FRUIT - name: '&6Chorus Fruit' - lore: - - '&7Access to consume chorus fruits inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: CHORUS_FRUIT - name: '&6Chorus Fruit' - lore: - - '&7Access to consume chorus fruits inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - close_bypass: - display-menu: true - permission-enabled: - type: TRIPWIRE_HOOK - name: '&6Locked Bypass' - lore: - - '&7Access to bypass the island''s lock.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: TRIPWIRE_HOOK - name: '&6Locked Bypass' - lore: - - '&7Access to bypass the island''s lock.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: TRIPWIRE_HOOK - name: '&6Locked Bypass' - lore: - - '&7Access to bypass the island''s lock.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - close_island: - display-menu: true - permission-enabled: - type: BARRIER - name: '&6Lock Island' - lore: - - '&7Access to lock the island from public.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: BARRIER - name: '&6Lock Island' - lore: - - '&7Access to lock the island from public.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: BARRIER - name: '&6Lock Island' - lore: - - '&7Access to lock the island from public.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - coop_member: - display-menu: true - permission-enabled: - type: GOLDEN_APPLE - name: '&6Coop Member' - lore: - - '&7Access to add a player as a co-op member.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: GOLDEN_APPLE - name: '&6Coop Member' - lore: - - '&7Access to add a player as a co-op member.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: GOLDEN_APPLE - name: '&6Coop Member' - lore: - - '&7Access to add a player as a co-op member.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - delete_warp: - display-menu: true - permission-enabled: - type: ENDER_PEARL - name: '&6Delete Warp' - lore: - - '&7Access to delete island warps.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: ENDER_PEARL - name: '&6Delete Warp' - lore: - - '&7Access to delete island warps.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: ENDER_PEARL - name: '&6Delete Warp' - lore: - - '&7Access to delete island warps.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - demote_members: - display-menu: true - permission-enabled: - type: IRON_INGOT - name: '&6Demote Members' - lore: - - '&7Access to demote members inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: IRON_INGOT - name: '&6Demote Members' - lore: - - '&7Access to demote members inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: IRON_INGOT - name: '&6Demote Members' - lore: - - '&7Access to demote members inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - deposit_money: - display-menu: true - permission-enabled: - type: MAP - name: '&6Deposit Money' - lore: - - '&7Access to deposit money into the island''s bank.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: MAP - name: '&6Deposit Money' - lore: - - '&7Access to deposit money into the island''s bank.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: MAP - name: '&6Deposit Money' - lore: - - '&7Access to deposit money into the island''s bank.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - disband_island: - display-menu: true - permission-enabled: - type: TNT - name: '&6Disband Island' - lore: - - '&7Access to disband the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: TNT - name: '&6Disband Island' - lore: - - '&7Access to disband the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: TNT - name: '&6Disband Island' - lore: - - '&7Access to disband the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - discord_show: - display-menu: true - permission-enabled: - type: LIGHT_BLUE_TERRACOTTA - name: '&6Discord Show' - lore: - - '&7Access to check the island''s linked discord.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: LIGHT_BLUE_TERRACOTTA - name: '&6Discord Show' - lore: - - '&7Access to check the island''s linked discord.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: LIGHT_BLUE_TERRACOTTA - name: '&6Discord Show' - lore: - - '&7Access to check the island''s linked discord.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - drop_items: - display-menu: true - permission-enabled: - type: ARROW - name: '&6Drop Items' - lore: - - '&7Access to drop items inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: ARROW - name: '&6Drop Items' - lore: - - '&7Access to drop items inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: ARROW - name: '&6Drop Items' - lore: - - '&7Access to drop items inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - dye_sheep: - display-menu: true - permission-enabled: - type: SHEEP_SPAWN_EGG - name: '&6Dye Sheep' - lore: - - '&7Access to dye sheep inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: SHEEP_SPAWN_EGG - name: '&6Dye Sheep' - lore: - - '&7Access to dye sheep inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: SHEEP_SPAWN_EGG - name: '&6Dye Sheep' - lore: - - '&7Access to dye sheep inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - ender_pearl: - display-menu: true - permission-enabled: - type: ENDER_PEARL - name: '&6Ender Pearl' - lore: - - '&7Access to use ender pearls inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: ENDER_PEARL - name: '&6Ender Pearl' - lore: - - '&7Access to use ender pearls inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: ENDER_PEARL - name: '&6Ender Pearl' - lore: - - '&7Access to use ender pearls inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - entity_ride: - display-menu: true - permission-enabled: - type: SADDLE - name: '&6Entity Ride' - lore: - - '&7Access to ride entities inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: SADDLE - name: '&6Entity Ride' - lore: - - '&7Access to ride entities inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: SADDLE - name: '&6Entity Ride' - lore: - - '&7Access to ride entities inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - expel_bypass: - display-menu: true - permission-enabled: - type: FEATHER - name: '&6Expel Bypass' - lore: - - '&7Access to bypass from being expelled.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: FEATHER - name: '&6Expel Bypass' - lore: - - '&7Access to bypass from being expelled.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: FEATHER - name: '&6Expel Bypass' - lore: - - '&7Access to bypass from being expelled.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - expel_players: - display-menu: true - permission-enabled: - type: DISPENSER - name: '&6Expel Players' - lore: - - '&7Access to expel players from the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: DISPENSER - name: '&6Expel Players' - lore: - - '&7Access to expel players from the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: DISPENSER - name: '&6Expel Players' - lore: - - '&7Access to expel players from the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - farm_tramping: - display-menu: true - permission-enabled: - type: FARMLAND - name: '&6Farm Tramping' - lore: - - '&7Access to tramp farmlands inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: FARMLAND - name: '&6Farm Tramping' - lore: - - '&7Access to tramp farmlands inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: FARMLAND - name: '&6Farm Tramping' - lore: - - '&7Access to tramp farmlands inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - fertilize: - display-menu: true - permission-enabled: - type: BONE_MEAL - name: '&6Fertilize' - lore: - - '&7Access to fertilize blocks around the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: BONE_MEAL - name: '&6Fertilize' - lore: - - '&7Access to fertilize blocks around the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: BONE_MEAL - name: '&6Fertilize' - lore: - - '&7Access to fertilize blocks around the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - fish: - display-menu: true - permission-enabled: - type: FISHING_ROD - name: '&6Fish' - lore: - - '&7Access fishing around the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: FISHING_ROD - name: '&6Fish' - lore: - - '&7Access fishing around the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: FISHING_ROD - name: '&6Fish' - lore: - - '&7Access fishing around the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - fly: - display-menu: true - permission-enabled: - type: FEATHER - name: '&6Fly' - lore: - - '&7Access fly around the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: FEATHER - name: '&6Fly' - lore: - - '&7Access fly around the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: FEATHER - name: '&6Fly' - lore: - - '&7Access fly around the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - horse_interact: - display-menu: true - permission-enabled: - type: HORSE_SPAWN_EGG - name: '&6Horse Interact' - lore: - - '&7Access to interact with horses inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: HORSE_SPAWN_EGG - name: '&6Horse Interact' - lore: - - '&7Access to interact with horses inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: HORSE_SPAWN_EGG - name: '&6Horse Interact' - lore: - - '&7Access to interact with horses inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - ignite_creeper: - display-menu: true - permission-enabled: - type: CREEPER_SPAWN_EGG - name: '&6Ignite Creepers' - lore: - - '&7Access to ignite creepers with flint and steel inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: CREEPER_SPAWN_EGG - name: '&6Ignite Creepers' - lore: - - '&7Access to ignite creepers with flint and steel inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: CREEPER_SPAWN_EGG - name: '&6Ignite Creepers' - lore: - - '&7Access to ignite creepers with flint and steel inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - interact: - display-menu: true - permission-enabled: - type: PISTON - name: '&6Interact' - lore: - - '&7Access to interact with blocks inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: PISTON - name: '&6Interact' - lore: - - '&7Access to interact with blocks inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: PISTON - name: '&6Interact' - lore: - - '&7Access to interact with blocks inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - invite_member: - display-menu: true - permission-enabled: - type: PLAYER_HEAD - data: 3 - name: '&6Invite Member' - lore: - - '&7Access to invite new members to the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: PLAYER_HEAD - name: '&6Invite Member' - lore: - - '&7Access to invite new members to the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: PLAYER_HEAD - name: '&6Invite Member' - lore: - - '&7Access to invite new members to the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - island_chest: - display-menu: true - permission-enabled: - type: ENDER_CHEST - name: '&6Community Chest' - lore: - - '&7Access to the community chest of the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: ENDER_CHEST - name: '&6Community Chest' - lore: - - '&7Access to the community chest of the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: ENDER_CHEST - name: '&6Community Chest' - lore: - - '&7Access to the community chest of the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - item_frame: - display-menu: true - permission-enabled: - type: ITEM_FRAME - name: '&6Item Frame' - lore: - - '&7Access to interact with item frames inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: ITEM_FRAME - name: '&6Item Frame' - lore: - - '&7Access to interact with item frames inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: ITEM_FRAME - name: '&6Item Frame' - lore: - - '&7Access to interact with item frames inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - kick_member: - display-menu: true - permission-enabled: - type: SKELETON_SKULL - name: '&6Kick Member' - lore: - - '&7Access to kick members from the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: SKELETON_SKULL - name: '&6Kick Member' - lore: - - '&7Access to kick members from the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: SKELETON_SKULL - name: '&6Kick Member' - lore: - - '&7Access to kick members from the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - leash: - display-menu: true - permission-enabled: - type: LEAD - name: '&6Leash Mobs' - lore: - - '&7Access to leash mobs inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: LEAD - name: '&6Leash Mobs' - lore: - - '&7Access to leash mobs inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: LEAD - name: '&6Leash Mobs' - lore: - - '&7Access to leash mobs inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - minecart_damage: - display-menu: true - permission-enabled: - type: TNT_MINECART - name: '&6Minecart Damage' - lore: - - '&7Access to damage minecarts inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: TNT_MINECART - name: '&6Minecart Damage' - lore: - - '&7Access to damage minecarts inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: TNT_MINECART - name: '&6Minecart Damage' - lore: - - '&7Access to damage minecarts inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - minecart_enter: - display-menu: true - permission-enabled: - type: HOPPER_MINECART - name: '&6Minecart Enter' - lore: - - '&7Access to enter minecarts inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: HOPPER_MINECART - name: '&6Minecart Enter' - lore: - - '&7Access to enter minecarts inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: HOPPER_MINECART - name: '&6Minecart Enter' - lore: - - '&7Access to enter minecarts inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - minecart_open: - display-menu: true - permission-enabled: - type: CHEST_MINECART - name: '&6Minecart Open' - lore: - - '&7Access to open minecarts inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: CHEST_MINECART - name: '&6Minecart Open' - lore: - - '&7Access to open minecarts inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: CHEST_MINECART - name: '&6Minecart Open' - lore: - - '&7Access to open minecarts inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - minecart_place: - display-menu: true - permission-enabled: - type: MINECART - name: '&6Minecart Place' - lore: - - '&7Access to place minecarts inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: MINECART - name: '&6Minecart Place' - lore: - - '&7Access to place minecarts inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: MINECART - name: '&6Minecart Place' - lore: - - '&7Access to place minecarts inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - monster_damage: - display-menu: true - permission-enabled: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: ZOMBIE_HEAD - name: '&6Monster Damage' - lore: - - '&7Access to damage monsters inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - monster_spawn: - display-menu: true - permission-enabled: - type: CAVE_SPIDER_SPAWN_EGG - name: '&6Monster Spawn' - lore: - - '&7Access to spawn monsters inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: CAVE_SPIDER_SPAWN_EGG - name: '&6Monster Spawn' - lore: - - '&7Access to spawn monsters inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: CAVE_SPIDER_SPAWN_EGG - name: '&6Monster Spawn' - lore: - - '&7Access to spawn monsters inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - name_entity: - display-menu: true - permission-enabled: - type: NAME_TAG - name: '&6Name Entity' - lore: - - '&7Access to name-tag entities inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: NAME_TAG - name: '&6Name Entity' - lore: - - '&7Access to name-tag entities inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: NAME_TAG - name: '&6Name Entity' - lore: - - '&7Access to name-tag entities inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - open_island: - display-menu: true - permission-enabled: - type: REDSTONE_TORCH - name: '&6Open Island' - lore: - - '&7Access to open the island to the public.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: REDSTONE_TORCH - name: '&6Open Island' - lore: - - '&7Access to open the island to the public.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: REDSTONE_TORCH - name: '&6Open Island' - lore: - - '&7Access to open the island to the public.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - painting: - display-menu: true - permission-enabled: - type: PAINTING - name: '&6Painting' - lore: - - '&7Access to interact with paintings inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: PAINTING - name: '&6Painting' - lore: - - '&7Access to interact with paintings inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: PAINTING - name: '&6Painting' - lore: - - '&7Access to interact with paintings inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - paypal_show: - display-menu: true - permission-enabled: - type: BLUE_WOOL - name: '&6Paypal Show' - lore: - - '&7Access to check the island''s linked paypal.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: BLUE_WOOL - name: '&6Paypal Show' - lore: - - '&7Access to check the island''s linked paypal.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: BLUE_WOOL - name: '&6Paypal Show' - lore: - - '&7Access to check the island''s linked paypal.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - pickup_drops: - display-menu: true - permission-enabled: - type: HOPPER - name: '&6Pickup Drops' - lore: - - '&7Access to pickup items inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: HOPPER - name: '&6Pickup Drops' - lore: - - '&7Access to pickup items inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: HOPPER - name: '&6Pickup Drops' - lore: - - '&7Access to pickup items inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - pickup_fish: - display-menu: true - permission-enabled: - type: COD - name: '&6Pickup Fish' - lore: - - '&7Access to pickup fish using buckets inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: COD - name: '&6Pickup Fish' - lore: - - '&7Access to pickup fish using buckets inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: COD - name: '&6Pickup Fish' - lore: - - '&7Access to pickup fish using buckets inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - promote_members: - display-menu: true - permission-enabled: - type: DIAMOND - name: '&6Promote Members' - lore: - - '&7Access to promote members inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: DIAMOND - name: '&6Promote Members' - lore: - - '&7Access to promote members inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: DIAMOND - name: '&6Promote Members' - lore: - - '&7Access to promote members inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - rankup: - display-menu: true - permission-enabled: - type: GOLD_INGOT - name: '&6Upgrades Rankup' - lore: - - '&7Access to rankup island''s upgrades.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: GOLD_INGOT - name: '&6Upgrades Rankup' - lore: - - '&7Access to rankup island''s upgrades.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: GOLD_INGOT - name: '&6Upgrades Rankup' - lore: - - '&7Access to rankup island''s upgrades.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - ratings_show: - display-menu: true - permission-enabled: - type: NETHER_STAR - name: '&6Ratings Show' - lore: - - '&7Access to see all island''s ratings.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: NETHER_STAR - name: '&6Ratings Show' - lore: - - '&7Access to see all island''s ratings.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: NETHER_STAR - name: '&6Ratings Show' - lore: - - '&7Access to see all island''s ratings.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - saddle_entity: - display-menu: true - permission-enabled: - type: SADDLE - name: '&6Saddle Entity' - lore: - - '&7Access to add saddle to entities inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: SADDLE - name: '&6Saddle Entity' - lore: - - '&7Access to add saddle to entities inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: SADDLE - name: '&6Saddle Entity' - lore: - - '&7Access to add saddle to entities inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - set_biome: - display-menu: true - permission-enabled: - type: GRASS - name: '&6Set Biome' - lore: - - '&7Access to change the island''s biome.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: GRASS - name: '&6Set Biome' - lore: - - '&7Access to change the island''s biome.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: GRASS - name: '&6Set Biome' - lore: - - '&7Access to change the island''s biome.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - set_discord: - display-menu: true - permission-enabled: - type: LIGHT_BLUE_TERRACOTTA - name: '&6Set Discord' - lore: - - '&7Access to change the discord linked to the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: LIGHT_BLUE_TERRACOTTA - name: '&6Set Discord' - lore: - - '&7Access to change the discord linked to the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: LIGHT_BLUE_TERRACOTTA - name: '&6Set Discord' - lore: - - '&7Access to change the discord linked to the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - set_home: - display-menu: true - permission-enabled: - type: RED_BED - name: '&6Set Home' - lore: - - '&7Access to change the home location of the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: RED_BED - name: '&6Set Home' - lore: - - '&7Access to change the home location of the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: RED_BED - name: '&6Set Home' - lore: - - '&7Access to change the home location of the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - set_paypal: - display-menu: true - permission-enabled: - type: BLUE_WOOL - name: '&6Set Paypal' - lore: - - '&7Access to change the paypal linked to the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: BLUE_WOOL - name: '&6Set Paypal' - lore: - - '&7Access to change the paypal linked to the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: BLUE_WOOL - name: '&6Set Paypal' - lore: - - '&7Access to change the paypal linked to the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - set_permission: - display-menu: true - permission-enabled: - type: REPEATER - name: '&6Set Permission' - lore: - - '&7Access to change permissions for island members.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: REPEATER - name: '&6Set Permission' - lore: - - '&7Access to change permissions for island members.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: REPEATER - name: '&6Set Permission' - lore: - - '&7Access to change permissions for island members.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - set_role: - display-menu: true - permission-enabled: - type: DIAMOND_CHESTPLATE - name: '&6Set Role' - lore: - - '&7Access to change roles for island members.' - - '&7Currently &aENABLED&7.' - flags: - - HIDE_ATTRIBUTES - permission-disabled: - type: DIAMOND_CHESTPLATE - name: '&6Set Role' - lore: - - '&7Access to change roles for island members.' - - '&7Currently &cDISABLED&7.' - flags: - - HIDE_ATTRIBUTES - role-permission: - type: DIAMOND_CHESTPLATE - name: '&6Set Role' - lore: - - '&7Access to change roles for island members.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - flags: - - HIDE_ATTRIBUTES - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - set_settings: - display-menu: true - permission-enabled: - type: LEVER - name: '&6Set Settings' - lore: - - '&7Access to change settings for islands.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: LEVER - name: '&6Set Settings' - lore: - - '&7Access to change settings for islands.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: LEVER - name: '&6Set Settings' - lore: - - '&7Access to change settings for islands.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - set_warp: - display-menu: true - permission-enabled: - type: ENDER_EYE - name: '&6Set Warp' - lore: - - '&7Access to set new warps for the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: ENDER_EYE - name: '&6Set Warp' - lore: - - '&7Access to set new warps for the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: ENDER_EYE - name: '&6Set Warp' - lore: - - '&7Access to set new warps for the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - sign_interact: - display-menu: true - permission-enabled: - type: OAK_SIGN - name: '&6Sign Interact' - lore: - - '&7Access to interact with signs inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: OAK_SIGN - name: '&6Sign Interact' - lore: - - '&7Access to interact with signs inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: OAK_SIGN - name: '&6Sign Interact' - lore: - - '&7Access to interact with signs inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - spawner_break: - display-menu: true - permission-enabled: - type: SPAWNER - name: '&6Spawner Break' - lore: - - '&7Access to break spawners inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: SPAWNER - name: '&6Spawner Break' - lore: - - '&7Access to break spawners inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: SPAWNER - name: '&6Spawner Break' - lore: - - '&7Access to break spawners inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - turtle_egg_tramping: - display-menu: true - permission-enabled: - type: TURTLE_EGG - name: '&6Turtle Eggs Tramping' - lore: - - '&7Access to tramp turtle eggs inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: TURTLE_EGG - name: '&6Turtle Eggs Tramping' - lore: - - '&7Access to tramp turtle eggs inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: TURTLE_EGG - name: '&6Turtle Eggs Tramping' - lore: - - '&7Access to tramp turtle eggs inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - uncoop_member: - display-menu: true - permission-enabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: GOLDEN_APPLE - name: '&6Uncoop Member' - lore: - - '&7Access to remove co-op members from the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - use: - display-menu: true - permission-enabled: - type: STONE_BUTTON - name: '&6Use' - lore: - - '&7Access to use different blocks inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: STONE_BUTTON - name: '&6Use' - lore: - - '&7Access to use different blocks inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: STONE_BUTTON - name: '&6Use' - lore: - - '&7Access to use different blocks inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - valuable_break: - display-menu: true - permission-enabled: - type: GOLD_INGOT - name: '&6Valuable Blocks Break' - lore: - - '&7Access to break valuable blocks inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: GOLD_INGOT - name: '&6Valuable Blocks Break' - lore: - - '&7Access to break valuable blocks inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: GOLD_INGOT - name: '&6Valuable Blocks Break' - lore: - - '&7Access to break valuable blocks inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - villager_trading: - display-menu: true - permission-enabled: - type: PLAYER_HEAD - skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' - name: '&6Villagers Trading' - lore: - - '&7Access to trade with villagers inside the island.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: PLAYER_HEAD - skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' - name: '&6Villagers Trading' - lore: - - '&7Access to trade with villagers inside the island.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: PLAYER_HEAD - skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' - name: '&6Villagers Trading' - lore: - - '&7Access to trade with villagers inside the island.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 - - withdraw_money: - display-menu: true - permission-enabled: - type: EMERALD - name: '&6Withdraw Money' - lore: - - '&7Access to withdraw money from the island''s bank.' - - '&7Currently &aENABLED&7.' - permission-disabled: - type: EMERALD - name: '&6Withdraw Money' - lore: - - '&7Access to withdraw money from the island''s bank.' - - '&7Currently &cDISABLED&7.' - role-permission: - type: EMERALD - name: '&6Withdraw Money' - lore: - - '&7Access to withdraw money from the island''s bank.' - - '&7Role: &e{}&7.' - - '' - - '{0}' - has-access: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - no-access: - sound: - type: BLOCK_ANVIL_PLACE - volume: 0.2 - pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/permissions1_16.yml b/src/main/resources/menus/permissions1_16.yml index b130a84b42..1527cbc59e 100644 --- a/src/main/resources/menus/permissions1_16.yml +++ b/src/main/resources/menus/permissions1_16.yml @@ -1840,19 +1840,19 @@ permissions: set_biome: display-menu: true permission-enabled: - type: GRASS + type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &aENABLED&7.' permission-disabled: - type: GRASS + type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &cDISABLED&7.' role-permission: - type: GRASS + type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' diff --git a/src/main/resources/menus/permissions1_17.yml b/src/main/resources/menus/permissions1_17.yml index eca18a6c1b..4d41a99341 100644 --- a/src/main/resources/menus/permissions1_17.yml +++ b/src/main/resources/menus/permissions1_17.yml @@ -1906,19 +1906,19 @@ permissions: set_biome: display-menu: true permission-enabled: - type: GRASS + type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &aENABLED&7.' permission-disabled: - type: GRASS + type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' - '&7Currently &cDISABLED&7.' role-permission: - type: GRASS + type: GRASS_BLOCK name: '&6Set Biome' lore: - '&7Access to change the island''s biome.' diff --git a/src/main/resources/menus/player-language.yml b/src/main/resources/menus/player-language.yml index 045aca59be..99b63a4c7c 100644 --- a/src/main/resources/menus/player-language.yml +++ b/src/main/resources/menus/player-language.yml @@ -11,7 +11,7 @@ previous-menu: true pattern: - '@ @ @ @ @ @ @ @ @' - '@ # % * + ^ ~ 1 @' - - '@ @ - = @ ! 2 @ @' + - '@ @ - = ! 2 3 @ @' - '@ @ @ @ @ @ @ @ @' items: @@ -103,6 +103,14 @@ items: name: '&eGerman' lore: - '&7Change language to German.' + '3': + language: 'tr-TR' + type: SKULL_ITEM + data: 3 + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNmJiZWFmNTJlMWM0YmZjZDhhMWY0YzY5MTMyMzRiODQwMjQxYWE0ODgyOWMxNWFiYzZmZjhmZGY5MmNkODllIn19fQ==' + name: '&eTurkish' + lore: + - '&7Change language to Turkish.' sounds: '#': diff --git a/src/main/resources/menus/upgrades.yml b/src/main/resources/menus/upgrades.yml index 57e511c450..ba815eb763 100644 --- a/src/main/resources/menus/upgrades.yml +++ b/src/main/resources/menus/upgrades.yml @@ -10,36 +10,22 @@ previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - - '% % @ % # % ^ % %' - - '% % % ! % + % % %' - - '% % * % ~ % & % %' + - '# # @ # % # ^ # #' + - '# # # ! # + # # #' + - '# # * # ~ # & # #' - '$ $ $ $ $ $ $ $ $' items: '$': type: STAINED_GLASS_PANE - data: 9 + data: 15 name: '&f' - '%': - type: STAINED_GLASS_PANE - data: 11 - name: '&f' - -sounds: - '@': - type: ORB_PICKUP - volume: 0.2 - pitch: 0.2 upgrades: hoppers-limit: item: '@' '1': has-next-level: - sound: - type: ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: @@ -53,12 +39,12 @@ upgrades: - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -72,13 +58,13 @@ upgrades: - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: @@ -92,12 +78,12 @@ upgrades: - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -111,13 +97,13 @@ upgrades: - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: @@ -131,12 +117,12 @@ upgrades: - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -150,36 +136,36 @@ upgrades: - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the hoppers limit!' - no-next-level: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + no-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the hoppers limit!' - crop-growth: - item: '#' - '1': - has-next-level: sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + crop-growth: + item: '%' + '1': + has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: @@ -193,12 +179,14 @@ upgrades: - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: @@ -212,13 +200,15 @@ upgrades: - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: @@ -232,12 +222,14 @@ upgrades: - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: @@ -251,13 +243,15 @@ upgrades: - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: @@ -271,12 +265,14 @@ upgrades: - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: @@ -290,36 +286,42 @@ upgrades: - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the crop growth!' - no-next-level: + flags: + - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + no-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the crop growth!' + flags: + - HIDE_ATTRIBUTES + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 spawner-rates: item: '^' '1': has-next-level: - sound: - type: ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: MOB_SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: @@ -333,12 +335,14 @@ upgrades: - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: @@ -352,13 +356,15 @@ upgrades: - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: @@ -372,12 +378,14 @@ upgrades: - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: @@ -391,13 +399,15 @@ upgrades: - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: @@ -411,12 +421,14 @@ upgrades: - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: @@ -430,36 +442,42 @@ upgrades: - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: MOB_SPAWNER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the spawner rates!' - no-next-level: + flags: + - HIDE_ATTRIBUTES sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + no-next-level: type: MOB_SPAWNER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the spawner rates!' + flags: + - HIDE_ATTRIBUTES + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 mob-drops: item: '*' '1': has-next-level: - sound: - type: ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: @@ -473,12 +491,12 @@ upgrades: - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: @@ -492,13 +510,13 @@ upgrades: - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: @@ -512,12 +530,12 @@ upgrades: - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: @@ -531,13 +549,13 @@ upgrades: - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: @@ -548,15 +566,15 @@ upgrades: - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - - '&4Amount: &fx5 Drops' + - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: @@ -567,39 +585,39 @@ upgrades: - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - - '&4Amount: &fx5 Drops' + - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the mob drops!' - no-next-level: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + no-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the mob drops!' + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 members-limit: item: '~' '1': has-next-level: - sound: - type: ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: SKULL_ITEM data: 3 name: '&2&lMembers Size &a(Available)' @@ -614,12 +632,12 @@ upgrades: - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &c(Unavailable)' @@ -634,13 +652,13 @@ upgrades: - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &a(Available)' @@ -655,12 +673,12 @@ upgrades: - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &c(Unavailable)' @@ -675,13 +693,13 @@ upgrades: - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &a(Available)' @@ -696,12 +714,12 @@ upgrades: - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &c(Unavailable)' @@ -716,38 +734,38 @@ upgrades: - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: SKULL_ITEM data: 3 name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the members limit!' - no-next-level: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + no-next-level: type: SKULL_ITEM data: 3 name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the members limit!' + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 border-size: item: '!' '1': has-next-level: - sound: - type: ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: BARRIER name: '&9&lBorder Size &a(Available)' lore: @@ -761,12 +779,12 @@ upgrades: - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: @@ -780,13 +798,13 @@ upgrades: - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: @@ -800,12 +818,12 @@ upgrades: - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: @@ -819,13 +837,13 @@ upgrades: - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: @@ -839,12 +857,12 @@ upgrades: - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: @@ -858,36 +876,36 @@ upgrades: - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the border size!' - no-next-level: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + no-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the border size!' + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 generator-rates: item: '+' '1': has-next-level: - sound: - type: ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: @@ -905,12 +923,12 @@ upgrades: - '&7' - '&3Price: &f$25,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: @@ -928,13 +946,13 @@ upgrades: - '&7' - '&3Price: &f$25,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: @@ -954,12 +972,12 @@ upgrades: - '&7' - '&3Price: &f$75,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: @@ -979,13 +997,13 @@ upgrades: - '&7' - '&3Price: &f$75,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: @@ -1008,12 +1026,12 @@ upgrades: - '&7' - '&3Price: &f$150,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: @@ -1036,36 +1054,36 @@ upgrades: - '&7' - '&3Price: &f$150,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the generator rates!' - no-next-level: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + no-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the generator rates!' + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 minecarts-limit: item: '&' '1': has-next-level: - sound: - type: ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: MINECART name: '&d&lMinecart Increase &a(Available)' lore: @@ -1079,12 +1097,12 @@ upgrades: - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -1098,13 +1116,13 @@ upgrades: - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: @@ -1118,12 +1136,12 @@ upgrades: - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -1137,13 +1155,13 @@ upgrades: - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ORB_PICKUP + type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: @@ -1157,12 +1175,12 @@ upgrades: - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: ANVIL_LAND + type: ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -1176,25 +1194,29 @@ upgrades: - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the minecarts limit!' - no-next-level: sound: type: ANVIL_LAND volume: 0.2 pitch: 0.2 + no-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' - - '&7level of the minecarts limit!' \ No newline at end of file + - '&7You have reached the maximum' + - '&7level of the minecarts limit!' + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/upgrades1_12.yml b/src/main/resources/menus/upgrades1_12.yml index 596cce7021..db1e61639a 100644 --- a/src/main/resources/menus/upgrades1_12.yml +++ b/src/main/resources/menus/upgrades1_12.yml @@ -10,36 +10,22 @@ previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - - '% % @ % # % ^ % %' - - '% % % ! % + % % %' - - '% % * % ~ % & % %' + - '# # @ # % # ^ # #' + - '# # # ! # + # # #' + - '# # * # ~ # & # #' - '$ $ $ $ $ $ $ $ $' items: '$': type: STAINED_GLASS_PANE - data: 9 + data: 15 name: '&f' - '%': - type: STAINED_GLASS_PANE - data: 11 - name: '&f' - -sounds: - '@': - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 upgrades: hoppers-limit: item: '@' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: @@ -53,12 +39,12 @@ upgrades: - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -72,13 +58,13 @@ upgrades: - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: @@ -92,12 +78,12 @@ upgrades: - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -111,13 +97,13 @@ upgrades: - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: @@ -131,12 +117,12 @@ upgrades: - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -150,36 +136,36 @@ upgrades: - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the hoppers limit!' - no-next-level: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the hoppers limit!' - crop-growth: - item: '#' - '1': - has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + crop-growth: + item: '%' + '1': + has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: @@ -193,12 +179,14 @@ upgrades: - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: @@ -212,13 +200,15 @@ upgrades: - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: @@ -232,12 +222,14 @@ upgrades: - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: @@ -251,13 +243,15 @@ upgrades: - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: @@ -271,12 +265,14 @@ upgrades: - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: @@ -290,36 +286,42 @@ upgrades: - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the crop growth!' - no-next-level: + flags: + - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the crop growth!' + flags: + - HIDE_ATTRIBUTES + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 spawner-rates: item: '^' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: MOB_SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: @@ -333,12 +335,14 @@ upgrades: - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: @@ -352,13 +356,15 @@ upgrades: - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: @@ -372,12 +378,14 @@ upgrades: - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: @@ -391,13 +399,15 @@ upgrades: - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: @@ -411,12 +421,14 @@ upgrades: - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MOB_SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: @@ -430,36 +442,42 @@ upgrades: - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: MOB_SPAWNER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the spawner rates!' - no-next-level: + flags: + - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: MOB_SPAWNER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the spawner rates!' + flags: + - HIDE_ATTRIBUTES + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 mob-drops: item: '*' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: @@ -473,12 +491,12 @@ upgrades: - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: @@ -492,13 +510,13 @@ upgrades: - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: @@ -512,12 +530,12 @@ upgrades: - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: @@ -531,13 +549,13 @@ upgrades: - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: @@ -548,15 +566,15 @@ upgrades: - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - - '&4Amount: &fx5 Drops' + - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: @@ -567,39 +585,39 @@ upgrades: - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - - '&4Amount: &fx5 Drops' + - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the mob drops!' - no-next-level: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the mob drops!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 members-limit: item: '~' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: SKULL_ITEM data: 3 name: '&2&lMembers Size &a(Available)' @@ -614,12 +632,12 @@ upgrades: - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &c(Unavailable)' @@ -634,13 +652,13 @@ upgrades: - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &a(Available)' @@ -655,12 +673,12 @@ upgrades: - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &c(Unavailable)' @@ -675,13 +693,13 @@ upgrades: - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &a(Available)' @@ -696,12 +714,12 @@ upgrades: - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: SKULL_ITEM data: 3 name: '&2&lMembers Size &c(Unavailable)' @@ -716,38 +734,38 @@ upgrades: - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: SKULL_ITEM data: 3 name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the members limit!' - no-next-level: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: SKULL_ITEM data: 3 name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the members limit!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 border-size: item: '!' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: BARRIER name: '&9&lBorder Size &a(Available)' lore: @@ -761,12 +779,12 @@ upgrades: - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: @@ -780,13 +798,13 @@ upgrades: - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: @@ -800,12 +818,12 @@ upgrades: - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: @@ -819,13 +837,13 @@ upgrades: - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: @@ -839,12 +857,12 @@ upgrades: - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: @@ -858,36 +876,36 @@ upgrades: - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the border size!' - no-next-level: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the border size!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 generator-rates: item: '+' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: @@ -905,12 +923,12 @@ upgrades: - '&7' - '&3Price: &f$25,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: @@ -928,13 +946,13 @@ upgrades: - '&7' - '&3Price: &f$25,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: @@ -954,12 +972,12 @@ upgrades: - '&7' - '&3Price: &f$75,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: @@ -979,13 +997,13 @@ upgrades: - '&7' - '&3Price: &f$75,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: @@ -1008,12 +1026,12 @@ upgrades: - '&7' - '&3Price: &f$150,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: @@ -1036,36 +1054,36 @@ upgrades: - '&7' - '&3Price: &f$150,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the generator rates!' - no-next-level: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the generator rates!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 minecarts-limit: item: '&' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: MINECART name: '&d&lMinecart Increase &a(Available)' lore: @@ -1079,12 +1097,12 @@ upgrades: - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -1098,13 +1116,13 @@ upgrades: - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: @@ -1118,12 +1136,12 @@ upgrades: - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -1137,13 +1155,13 @@ upgrades: - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: @@ -1157,12 +1175,12 @@ upgrades: - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -1176,25 +1194,29 @@ upgrades: - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the minecarts limit!' - no-next-level: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' - - '&7level of the minecarts limit!' \ No newline at end of file + - '&7You have reached the maximum' + - '&7level of the minecarts limit!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/upgrades1_13.yml b/src/main/resources/menus/upgrades1_13.yml index 6e1977522c..2ff8522145 100644 --- a/src/main/resources/menus/upgrades1_13.yml +++ b/src/main/resources/menus/upgrades1_13.yml @@ -10,9 +10,9 @@ previous-menu: true pattern: - '$ $ $ $ $ $ $ $ $' - - '% % @ % # % ^ % %' - - '% % % ! % + % % %' - - '% % * % ~ % & % %' + - '# # @ # % # ^ # #' + - '# # # ! # + # # #' + - '# # * # ~ # & # #' - '$ $ $ $ $ $ $ $ $' items: @@ -25,10 +25,6 @@ upgrades: item: '@' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: @@ -42,12 +38,12 @@ upgrades: - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -61,13 +57,13 @@ upgrades: - '&dAmount: &f16x Hoppers' - '&dPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: @@ -81,12 +77,12 @@ upgrades: - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -100,13 +96,13 @@ upgrades: - '&dAmount: &f32x Hoppers' - '&dPrice: &f$3,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: HOPPER name: '&d&lHopper Increase &a(Available)' lore: @@ -120,12 +116,12 @@ upgrades: - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: HOPPER name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -139,36 +135,36 @@ upgrades: - '&dAmount: &f64x Hoppers' - '&dPrice: &f$9,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the hoppers limit!' - no-next-level: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: HOPPER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the hoppers limit!' - crop-growth: - item: '#' - '1': - has-next-level: sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + crop-growth: + item: '%' + '1': + has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: @@ -182,12 +178,14 @@ upgrades: - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: @@ -201,13 +199,15 @@ upgrades: - '&eGrowth: &fx2 Speed' - '&ePrice: &f$100,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: @@ -221,12 +221,14 @@ upgrades: - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: @@ -240,13 +242,15 @@ upgrades: - '&eGrowth: &fx3 Speed' - '&ePrice: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &a(Available)' lore: @@ -260,12 +264,14 @@ upgrades: - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: DIAMOND_HOE name: '&e&lCrop Growth &c(Unavailable)' lore: @@ -279,36 +285,42 @@ upgrades: - '&eGrowth: &fx4 Speed' - '&ePrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the crop growth!' - no-next-level: + flags: + - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: DIAMOND_HOE name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the crop growth!' + flags: + - HIDE_ATTRIBUTES + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 spawner-rates: item: '^' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: @@ -322,12 +334,14 @@ upgrades: - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: @@ -341,13 +355,15 @@ upgrades: - '&bBoost: &fx2 Speed' - '&bPrice: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: @@ -361,12 +377,14 @@ upgrades: - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: @@ -380,13 +398,15 @@ upgrades: - '&bBoost: &fx3 Speed' - '&bPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: SPAWNER name: '&b&lSpawner Boost &a(Available)' lore: @@ -400,12 +420,14 @@ upgrades: - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: SPAWNER name: '&b&lSpawner Boost &c(Unavailable)' lore: @@ -419,36 +441,42 @@ upgrades: - '&bBoost: &fx4 Speed' - '&bPrice: &f$2,500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: SPAWNER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the spawner rates!' - no-next-level: + flags: + - HIDE_ATTRIBUTES sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: SPAWNER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the spawner rates!' + flags: + - HIDE_ATTRIBUTES + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 mob-drops: item: '*' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: @@ -462,12 +490,12 @@ upgrades: - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: @@ -481,13 +509,13 @@ upgrades: - '&4Amount: &fx2 Drops' - '&4Price: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: @@ -501,12 +529,12 @@ upgrades: - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: @@ -520,13 +548,13 @@ upgrades: - '&4Amount: &fx3 Drops' - '&4Price: &f$2,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &a(Available)' lore: @@ -537,15 +565,15 @@ upgrades: - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - - '&4Amount: &fx5 Drops' + - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: ROTTEN_FLESH name: '&4&lPremium Drops &c(Unavailable)' lore: @@ -556,39 +584,39 @@ upgrades: - '&7gives all mobs within your island' - '&7increased loot drops.' - '&7' - - '&4Amount: &fx5 Drops' + - '&4Amount: &fx4 Drops' - '&4Price: &f$5,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the mob drops!' - no-next-level: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: ROTTEN_FLESH name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the mob drops!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 members-limit: item: '~' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: PLAYER_HEAD name: '&2&lMembers Size &a(Available)' lore: @@ -602,12 +630,12 @@ upgrades: - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &c(Unavailable)' lore: @@ -621,13 +649,13 @@ upgrades: - '&2Amount: &f8 Members' - '&2Price: &f$100,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &a(Available)' lore: @@ -641,12 +669,12 @@ upgrades: - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &c(Unavailable)' lore: @@ -660,13 +688,13 @@ upgrades: - '&2Amount: &f16 Members' - '&2Price: &f$300,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &a(Available)' lore: @@ -680,12 +708,12 @@ upgrades: - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: PLAYER_HEAD name: '&2&lMembers Size &c(Unavailable)' lore: @@ -699,36 +727,36 @@ upgrades: - '&2Amount: &f32 Members' - '&2Price: &f$500,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: PLAYER_HEAD name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the members limit!' - no-next-level: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: PLAYER_HEAD name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the members limit!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 border-size: item: '!' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: BARRIER name: '&9&lBorder Size &a(Available)' lore: @@ -742,12 +770,12 @@ upgrades: - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: @@ -761,13 +789,13 @@ upgrades: - '&9Radius: &f50 Blocks' - '&9Price: &f$30,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: @@ -781,12 +809,12 @@ upgrades: - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: @@ -800,13 +828,13 @@ upgrades: - '&9Radius: &f75 Blocks' - '&9Price: &f$80,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: BARRIER name: '&9&lBorder Size &a(Available)' lore: @@ -820,12 +848,12 @@ upgrades: - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: BARRIER name: '&9&lBorder Size &c(Unavailable)' lore: @@ -839,36 +867,36 @@ upgrades: - '&9Radius: &f125 Blocks' - '&9Price: &f$150,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the border size!' - no-next-level: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: BARRIER name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the border size!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 generator-rates: item: '+' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: @@ -886,12 +914,12 @@ upgrades: - '&7' - '&3Price: &f$25,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: @@ -909,13 +937,13 @@ upgrades: - '&7' - '&3Price: &f$25,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: @@ -935,12 +963,12 @@ upgrades: - '&7' - '&3Price: &f$75,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: @@ -960,13 +988,13 @@ upgrades: - '&7' - '&3Price: &f$75,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &a(Available)' lore: @@ -989,12 +1017,12 @@ upgrades: - '&7' - '&3Price: &f$150,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: COBBLESTONE name: '&3&lGenerator Boost &c(Unavailable)' lore: @@ -1017,36 +1045,36 @@ upgrades: - '&7' - '&3Price: &f$150,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the generator rates!' - no-next-level: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: COBBLESTONE name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the generator rates!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 minecarts-limit: item: '&' '1': has-next-level: - sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 type: MINECART name: '&d&lMinecart Increase &a(Available)' lore: @@ -1060,12 +1088,12 @@ upgrades: - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -1079,13 +1107,13 @@ upgrades: - '&dAmount: &f8x Minecarts' - '&dPrice: &f$1,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '2': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '2': + has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: @@ -1099,12 +1127,12 @@ upgrades: - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -1118,13 +1146,13 @@ upgrades: - '&dAmount: &f16x Minecarts' - '&dPrice: &f$3,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '3': - has-next-level: + - '&aClick to purchase upgrade.' sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP + type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '3': + has-next-level: type: MINECART name: '&d&lHopper Increase &a(Available)' lore: @@ -1138,12 +1166,12 @@ upgrades: - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - no-next-level: + - '&aClick to purchase upgrade.' sound: - type: BLOCK_ANVIL_PLACE + type: ENTITY_EXPERIENCE_ORB_PICKUP volume: 0.2 pitch: 0.2 + no-next-level: type: MINECART name: '&d&lHopper Increase &c(Unavailable)' lore: @@ -1157,25 +1185,29 @@ upgrades: - '&dAmount: &f32x Minecarts' - '&dPrice: &f$9,000,000' - '&7' - - '&aLeft-click to purchase upgrade.' - '4': - has-next-level: + - '&aClick to purchase upgrade.' sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + '4': + has-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' + - '&7You have reached the maximum' - '&7level of the minecarts limit!' - no-next-level: sound: type: BLOCK_ANVIL_PLACE volume: 0.2 pitch: 0.2 + no-next-level: type: MINECART name: '&c&lMAX LEVEL' lore: - - '&7You have reached the maxmimum' - - '&7level of the minecarts limit!' \ No newline at end of file + - '&7You have reached the maximum' + - '&7level of the minecarts limit!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/upgrades1_20.yml b/src/main/resources/menus/upgrades1_20.yml new file mode 100644 index 0000000000..bbef01cce2 --- /dev/null +++ b/src/main/resources/menus/upgrades1_20.yml @@ -0,0 +1,1213 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lIsland Upgrades' +previous-menu: true + +pattern: + - '$ $ $ $ $ $ $ $ $' + - '# # @ # % # ^ # #' + - '# # # ! # + # # #' + - '# # * # ~ # & # #' + - '$ $ $ $ $ $ $ $ $' + +items: + '$': + type: BLACK_STAINED_GLASS_PANE + name: '&f' + +upgrades: + hoppers-limit: + item: '@' + '1': + has-next-level: + type: HOPPER + name: '&d&lHopper Increase &a(Available)' + lore: + - '&7' + - '&dNext Level: &e2' + - '&7' + - '&7Purchasing the hopper upgrade' + - '&7will increase your island''s' + - '&7max hoppers limit.' + - '&7' + - '&dAmount: &f16x Hoppers' + - '&dPrice: &f$1,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: HOPPER + name: '&d&lHopper Increase &c(Unavailable)' + lore: + - '&7' + - '&dNext Level: &e2' + - '&7' + - '&7Purchasing the hopper upgrade' + - '&7will increase your island''s' + - '&7max hoppers limit.' + - '&7' + - '&dAmount: &f16x Hoppers' + - '&dPrice: &f$1,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '2': + has-next-level: + type: HOPPER + name: '&d&lHopper Increase &a(Available)' + lore: + - '&7' + - '&dNext Level: &e3' + - '&7' + - '&7Purchasing the hopper upgrade' + - '&7will increase your island''s' + - '&7max hoppers limit.' + - '&7' + - '&dAmount: &f32x Hoppers' + - '&dPrice: &f$3,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: HOPPER + name: '&d&lHopper Increase &c(Unavailable)' + lore: + - '&7' + - '&dNext Level: &e3' + - '&7' + - '&7Purchasing the hopper upgrade' + - '&7will increase your island''s' + - '&7max hoppers limit.' + - '&7' + - '&dAmount: &f32x Hoppers' + - '&dPrice: &f$3,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '3': + has-next-level: + type: HOPPER + name: '&d&lHopper Increase &a(Available)' + lore: + - '&7' + - '&dNext Level: &e4' + - '&7' + - '&7Purchasing the hopper upgrade' + - '&7will increase your island''s' + - '&7max hoppers limit.' + - '&7' + - '&dAmount: &f64x Hoppers' + - '&dPrice: &f$9,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: HOPPER + name: '&d&lHopper Increase &c(Unavailable)' + lore: + - '&7' + - '&dNext Level: &e2' + - '&7' + - '&7Purchasing the hopper upgrade' + - '&7will increase your island''s' + - '&7max hoppers limit.' + - '&7' + - '&dAmount: &f64x Hoppers' + - '&dPrice: &f$9,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '4': + has-next-level: + type: HOPPER + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the hoppers limit!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + no-next-level: + type: HOPPER + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the hoppers limit!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + crop-growth: + item: '%' + '1': + has-next-level: + type: DIAMOND_HOE + name: '&e&lCrop Growth &a(Available)' + lore: + - '&7' + - '&eNext Level: 2' + - '&7' + - '&7Purchasing the growth upgrade' + - '&7gives all crops within your island' + - '&7increased growth speed.' + - '&7' + - '&eGrowth: &fx2 Speed' + - '&ePrice: &f$100,000' + - '&7' + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: DIAMOND_HOE + name: '&e&lCrop Growth &c(Unavailable)' + lore: + - '&7' + - '&eNext Level: 2' + - '&7' + - '&7Purchasing the growth upgrade' + - '&7gives all crops within your island' + - '&7increased growth speed.' + - '&7' + - '&eGrowth: &fx2 Speed' + - '&ePrice: &f$100,000' + - '&7' + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '2': + has-next-level: + type: DIAMOND_HOE + name: '&e&lCrop Growth &a(Available)' + lore: + - '&7' + - '&eNext Level: 3' + - '&7' + - '&7Purchasing the growth upgrade' + - '&7gives all crops within your island' + - '&7increased growth speed.' + - '&7' + - '&eGrowth: &fx3 Speed' + - '&ePrice: &f$500,000' + - '&7' + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: DIAMOND_HOE + name: '&e&lCrop Growth &c(Unavailable)' + lore: + - '&7' + - '&eNext Level: 3' + - '&7' + - '&7Purchasing the growth upgrade' + - '&7gives all crops within your island' + - '&7increased growth speed.' + - '&7' + - '&eGrowth: &fx3 Speed' + - '&ePrice: &f$500,000' + - '&7' + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '3': + has-next-level: + type: DIAMOND_HOE + name: '&e&lCrop Growth &a(Available)' + lore: + - '&7' + - '&eNext Level: 4' + - '&7' + - '&7Purchasing the growth upgrade' + - '&7gives all crops within your island' + - '&7increased growth speed.' + - '&7' + - '&eGrowth: &fx4 Speed' + - '&ePrice: &f$1,000,000' + - '&7' + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: DIAMOND_HOE + name: '&e&lCrop Growth &c(Unavailable)' + lore: + - '&7' + - '&eNext Level: 4' + - '&7' + - '&7Purchasing the growth upgrade' + - '&7gives all crops within your island' + - '&7increased growth speed.' + - '&7' + - '&eGrowth: &fx4 Speed' + - '&ePrice: &f$1,000,000' + - '&7' + - '&aClick to purchase upgrade.' + flags: + - HIDE_ATTRIBUTES + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '4': + has-next-level: + type: DIAMOND_HOE + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the crop growth!' + flags: + - HIDE_ATTRIBUTES + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + no-next-level: + type: DIAMOND_HOE + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the crop growth!' + flags: + - HIDE_ATTRIBUTES + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + spawner-rates: + item: '^' + '1': + has-next-level: + type: SPAWNER + name: '&b&lSpawner Boost &a(Available)' + lore: + - '&7' + - '&bNext Level: &e2' + - '&7' + - '&7Purchasing the spawner upgrade' + - '&7gives all spawners within your island' + - '&7increased spawn speed.' + - '&7' + - '&bBoost: &fx2 Speed' + - '&bPrice: &f$500,000' + - '&7' + - '&aClick to purchase upgrade.' + flags: + - HIDE_ADDITIONAL_TOOLTIP + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: SPAWNER + name: '&b&lSpawner Boost &c(Unavailable)' + lore: + - '&7' + - '&bNext Level: &e2' + - '&7' + - '&7Purchasing the spawner upgrade' + - '&7gives all spawners within your island' + - '&7increased spawn speed.' + - '&7' + - '&bBoost: &fx2 Speed' + - '&bPrice: &f$500,000' + - '&7' + - '&aClick to purchase upgrade.' + flags: + - HIDE_ADDITIONAL_TOOLTIP + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '2': + has-next-level: + type: SPAWNER + name: '&b&lSpawner Boost &a(Available)' + lore: + - '&7' + - '&bNext Level: &e3' + - '&7' + - '&7Purchasing the spawner upgrade' + - '&7gives all spawners within your island' + - '&7increased spawn speed.' + - '&7' + - '&bBoost: &fx3 Speed' + - '&bPrice: &f$1,000,000' + - '&7' + - '&aClick to purchase upgrade.' + flags: + - HIDE_ADDITIONAL_TOOLTIP + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: SPAWNER + name: '&b&lSpawner Boost &c(Unavailable)' + lore: + - '&7' + - '&bNext Level: &e3' + - '&7' + - '&7Purchasing the spawner upgrade' + - '&7gives all spawners within your island' + - '&7increased spawn speed.' + - '&7' + - '&bBoost: &fx3 Speed' + - '&bPrice: &f$1,000,000' + - '&7' + - '&aClick to purchase upgrade.' + flags: + - HIDE_ADDITIONAL_TOOLTIP + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '3': + has-next-level: + type: SPAWNER + name: '&b&lSpawner Boost &a(Available)' + lore: + - '&7' + - '&bNext Level: &e4' + - '&7' + - '&7Purchasing the spawner upgrade' + - '&7gives all spawners within your island' + - '&7increased spawn speed.' + - '&7' + - '&bBoost: &fx4 Speed' + - '&bPrice: &f$2,500,000' + - '&7' + - '&aClick to purchase upgrade.' + flags: + - HIDE_ADDITIONAL_TOOLTIP + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: SPAWNER + name: '&b&lSpawner Boost &c(Unavailable)' + lore: + - '&7' + - '&bNext Level: &e4' + - '&7' + - '&7Purchasing the spawner upgrade' + - '&7gives all spawners within your island' + - '&7increased spawn speed.' + - '&7' + - '&bBoost: &fx4 Speed' + - '&bPrice: &f$2,500,000' + - '&7' + - '&aClick to purchase upgrade.' + flags: + - HIDE_ADDITIONAL_TOOLTIP + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '4': + has-next-level: + type: SPAWNER + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the spawner rates!' + flags: + - HIDE_ADDITIONAL_TOOLTIP + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + no-next-level: + type: SPAWNER + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the spawner rates!' + flags: + - HIDE_ADDITIONAL_TOOLTIP + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + mob-drops: + item: '*' + '1': + has-next-level: + type: ROTTEN_FLESH + name: '&4&lPremium Drops &a(Available)' + lore: + - '&7' + - '&4Next Level: &e2' + - '&7' + - '&7Purchasing the drops upgrade' + - '&7gives all mobs within your island' + - '&7increased loot drops.' + - '&7' + - '&4Amount: &fx2 Drops' + - '&4Price: &f$1,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: ROTTEN_FLESH + name: '&4&lPremium Drops &c(Unavailable)' + lore: + - '&7' + - '&4Next Level: &e2' + - '&7' + - '&7Purchasing the drops upgrade' + - '&7gives all mobs within your island' + - '&7increased loot drops.' + - '&7' + - '&4Amount: &fx2 Drops' + - '&4Price: &f$1,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '2': + has-next-level: + type: ROTTEN_FLESH + name: '&4&lPremium Drops &a(Available)' + lore: + - '&7' + - '&4Next Level: &e3' + - '&7' + - '&7Purchasing the drops upgrade' + - '&7gives all mobs within your island' + - '&7increased loot drops.' + - '&7' + - '&4Amount: &fx3 Drops' + - '&4Price: &f$2,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: ROTTEN_FLESH + name: '&4&lPremium Drops &c(Unavailable)' + lore: + - '&7' + - '&4Next Level: &e3' + - '&7' + - '&7Purchasing the drops upgrade' + - '&7gives all mobs within your island' + - '&7increased loot drops.' + - '&7' + - '&4Amount: &fx3 Drops' + - '&4Price: &f$2,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '3': + has-next-level: + type: ROTTEN_FLESH + name: '&4&lPremium Drops &a(Available)' + lore: + - '&7' + - '&4Next Level: &e4' + - '&7' + - '&7Purchasing the drops upgrade' + - '&7gives all mobs within your island' + - '&7increased loot drops.' + - '&7' + - '&4Amount: &fx4 Drops' + - '&4Price: &f$5,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: ROTTEN_FLESH + name: '&4&lPremium Drops &c(Unavailable)' + lore: + - '&7' + - '&4Next Level: &e4' + - '&7' + - '&7Purchasing the drops upgrade' + - '&7gives all mobs within your island' + - '&7increased loot drops.' + - '&7' + - '&4Amount: &fx4 Drops' + - '&4Price: &f$5,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '4': + has-next-level: + type: ROTTEN_FLESH + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the mob drops!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + no-next-level: + type: ROTTEN_FLESH + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the mob drops!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + members-limit: + item: '~' + '1': + has-next-level: + type: PLAYER_HEAD + name: '&2&lMembers Size &a(Available)' + lore: + - '&7' + - '&2Next Level: &e2' + - '&7' + - '&7Purchasing the members upgrade' + - '&7will increase the maximum allowed' + - '&7members in your island.' + - '&7' + - '&2Amount: &f8 Members' + - '&2Price: &f$100,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: PLAYER_HEAD + name: '&2&lMembers Size &c(Unavailable)' + lore: + - '&7' + - '&2Next Level: &e2' + - '&7' + - '&7Purchasing the members upgrade' + - '&7will increase the maximum allowed' + - '&7members in your island.' + - '&7' + - '&2Amount: &f8 Members' + - '&2Price: &f$100,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '2': + has-next-level: + type: PLAYER_HEAD + name: '&2&lMembers Size &a(Available)' + lore: + - '&7' + - '&2Next Level: &e3' + - '&7' + - '&7Purchasing the members upgrade' + - '&7will increase the maximum allowed' + - '&7members in your island.' + - '&7' + - '&2Amount: &f16 Members' + - '&2Price: &f$300,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: PLAYER_HEAD + name: '&2&lMembers Size &c(Unavailable)' + lore: + - '&7' + - '&2Next Level: &e3' + - '&7' + - '&7Purchasing the members upgrade' + - '&7will increase the maximum allowed' + - '&7members in your island.' + - '&7' + - '&2Amount: &f16 Members' + - '&2Price: &f$300,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '3': + has-next-level: + type: PLAYER_HEAD + name: '&2&lMembers Size &a(Available)' + lore: + - '&7' + - '&2Next Level: &e4' + - '&7' + - '&7Purchasing the members upgrade' + - '&7will increase the maximum allowed' + - '&7members in your island.' + - '&7' + - '&2Amount: &f32 Members' + - '&2Price: &f$500,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: PLAYER_HEAD + name: '&2&lMembers Size &c(Unavailable)' + lore: + - '&7' + - '&2Next Level: &e4' + - '&7' + - '&7Purchasing the members upgrade' + - '&7will increase the maximum allowed' + - '&7members in your island.' + - '&7' + - '&2Amount: &f32 Members' + - '&2Price: &f$500,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '4': + has-next-level: + type: PLAYER_HEAD + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the members limit!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + no-next-level: + type: PLAYER_HEAD + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the members limit!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + border-size: + item: '!' + '1': + has-next-level: + type: BARRIER + name: '&9&lBorder Size &a(Available)' + lore: + - '&7' + - '&9Next Level: &e2' + - '&7' + - '&7Purchasing the border upgrade' + - '&7will increase the radius' + - '&7of your island.' + - '&7' + - '&9Radius: &f50 Blocks' + - '&9Price: &f$30,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: BARRIER + name: '&9&lBorder Size &c(Unavailable)' + lore: + - '&7' + - '&9Next Level: &e2' + - '&7' + - '&7Purchasing the border upgrade' + - '&7will increase the radius' + - '&7of your island.' + - '&7' + - '&9Radius: &f50 Blocks' + - '&9Price: &f$30,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '2': + has-next-level: + type: BARRIER + name: '&9&lBorder Size &a(Available)' + lore: + - '&7' + - '&9Next Level: &e3' + - '&7' + - '&7Purchasing the border upgrade' + - '&7will increase the radius' + - '&7of your island.' + - '&7' + - '&9Radius: &f75 Blocks' + - '&9Price: &f$80,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: BARRIER + name: '&9&lBorder Size &c(Unavailable)' + lore: + - '&7' + - '&9Next Level: &e3' + - '&7' + - '&7Purchasing the border upgrade' + - '&7will increase the radius' + - '&7of your island.' + - '&7' + - '&9Radius: &f75 Blocks' + - '&9Price: &f$80,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '3': + has-next-level: + type: BARRIER + name: '&9&lBorder Size &a(Available)' + lore: + - '&7' + - '&9Next Level: &e4' + - '&7' + - '&7Purchasing the border upgrade' + - '&7will increase the radius' + - '&7of your island.' + - '&7' + - '&9Radius: &f125 Blocks' + - '&9Price: &f$150,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: BARRIER + name: '&9&lBorder Size &c(Unavailable)' + lore: + - '&7' + - '&9Next Level: &e4' + - '&7' + - '&7Purchasing the border upgrade' + - '&7will increase the radius' + - '&7of your island.' + - '&7' + - '&9Radius: &f125 Blocks' + - '&9Price: &f$150,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '4': + has-next-level: + type: BARRIER + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the border size!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + no-next-level: + type: BARRIER + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the border size!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + generator-rates: + item: '+' + '1': + has-next-level: + type: COBBLESTONE + name: '&3&lGenerator Boost &a(Available)' + lore: + - '&7' + - '&3Next Level: &e2' + - '&7' + - '&7Purchasing the generator upgrade' + - '&7will increase rates of ores from' + - '&7cobblestone generators in your island.' + - '&7' + - '&3Rates:' + - ' &7 - &f92% Stone' + - ' &7 - &f5% Coal Ore' + - ' &7 - &f3% Redstone Ore' + - '&7' + - '&3Price: &f$25,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: COBBLESTONE + name: '&3&lGenerator Boost &c(Unavailable)' + lore: + - '&7' + - '&3Next Level: &e2' + - '&7' + - '&7Purchasing the generator upgrade' + - '&7will increase rates of ores from' + - '&7cobblestone generators in your island.' + - '&7' + - '&3Rates:' + - ' &7 - &f92% Stone' + - ' &7 - &f5% Coal Ore' + - ' &7 - &f3% Redstone Ore' + - '&7' + - '&3Price: &f$25,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '2': + has-next-level: + type: COBBLESTONE + name: '&3&lGenerator Boost &a(Available)' + lore: + - '&7' + - '&3Next Level: &e3' + - '&7' + - '&7Purchasing the generator upgrade' + - '&7will increase rates of ores from' + - '&7cobblestone generators in your island.' + - '&7' + - '&3Rates:' + - ' &7 - &f80% Stone' + - ' &7 - &f8% Coal Ore' + - ' &7 - &f6% Redstone Ore' + - ' &7 - &f4% Lapis Ore' + - ' &7 - &f2% Iron Ore' + - '&7' + - '&3Price: &f$75,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: COBBLESTONE + name: '&3&lGenerator Boost &c(Unavailable)' + lore: + - '&7' + - '&3Next Level: &e3' + - '&7' + - '&7Purchasing the generator upgrade' + - '&7will increase rates of ores from' + - '&7cobblestone generators in your island.' + - '&7' + - '&3Rates:' + - ' &7 - &f80% Stone' + - ' &7 - &f8% Coal Ore' + - ' &7 - &f6% Redstone Ore' + - ' &7 - &f4% Lapis Ore' + - ' &7 - &f2% Iron Ore' + - '&7' + - '&3Price: &f$75,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '3': + has-next-level: + type: COBBLESTONE + name: '&3&lGenerator Boost &a(Available)' + lore: + - '&7' + - '&3Next Level: &e4' + - '&7' + - '&7Purchasing the generator upgrade' + - '&7will increase rates of ores from' + - '&7cobblestone generators in your island.' + - '&7' + - '&3Rates:' + - ' &7 - &f65% Stone' + - ' &7 - &f10% Coal Ore' + - ' &7 - &f9% Redstone Ore' + - ' &7 - &f6% Lapis Ore' + - ' &7 - &f4% Iron Ore' + - ' &7 - &f3% Gold Ore' + - ' &7 - &f2% Diamond Ore' + - ' &7 - &f1% Emerald Ore' + - '&7' + - '&3Price: &f$150,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: COBBLESTONE + name: '&3&lGenerator Boost &c(Unavailable)' + lore: + - '&7' + - '&3Next Level: &e4' + - '&7' + - '&7Purchasing the generator upgrade' + - '&7will increase rates of ores from' + - '&7cobblestone generators in your island.' + - '&7' + - '&3Rates:' + - ' &7 - &f65% Stone' + - ' &7 - &f10% Coal Ore' + - ' &7 - &f9% Redstone Ore' + - ' &7 - &f6% Lapis Ore' + - ' &7 - &f4% Iron Ore' + - ' &7 - &f3% Gold Ore' + - ' &7 - &f2% Diamond Ore' + - ' &7 - &f1% Emerald Ore' + - '&7' + - '&3Price: &f$150,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '4': + has-next-level: + type: COBBLESTONE + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the generator rates!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + no-next-level: + type: COBBLESTONE + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the generator rates!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + minecarts-limit: + item: '&' + '1': + has-next-level: + type: MINECART + name: '&d&lMinecart Increase &a(Available)' + lore: + - '&7' + - '&dNext Level: &e2' + - '&7' + - '&7Purchasing the minecart upgrade' + - '&7will increase your island''s' + - '&7max minecarts limit.' + - '&7' + - '&dAmount: &f8x Minecarts' + - '&dPrice: &f$1,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: MINECART + name: '&d&lHopper Increase &c(Unavailable)' + lore: + - '&7' + - '&dNext Level: &e2' + - '&7' + - '&7Purchasing the minecart upgrade' + - '&7will increase your island''s' + - '&7max minecarts limit.' + - '&7' + - '&dAmount: &f8x Minecarts' + - '&dPrice: &f$1,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '2': + has-next-level: + type: MINECART + name: '&d&lHopper Increase &a(Available)' + lore: + - '&7' + - '&dNext Level: &e3' + - '&7' + - '&7Purchasing the minecart upgrade' + - '&7will increase your island''s' + - '&7max minecarts limit.' + - '&7' + - '&dAmount: &f16x Minecarts' + - '&dPrice: &f$3,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: MINECART + name: '&d&lHopper Increase &c(Unavailable)' + lore: + - '&7' + - '&dNext Level: &e3' + - '&7' + - '&7Purchasing the minecart upgrade' + - '&7will increase your island''s' + - '&7max minecarts limit.' + - '&7' + - '&dAmount: &f16x Minecarts' + - '&dPrice: &f$3,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '3': + has-next-level: + type: MINECART + name: '&d&lHopper Increase &a(Available)' + lore: + - '&7' + - '&dNext Level: &e4' + - '&7' + - '&7Purchasing the minecart upgrade' + - '&7will increase your island''s' + - '&7max minecarts limit.' + - '&7' + - '&dAmount: &f32x Minecarts' + - '&dPrice: &f$9,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-next-level: + type: MINECART + name: '&d&lHopper Increase &c(Unavailable)' + lore: + - '&7' + - '&dNext Level: &e4' + - '&7' + - '&7Purchasing the minecart upgrade' + - '&7will increase your island''s' + - '&7max minecarts limit.' + - '&7' + - '&dAmount: &f32x Minecarts' + - '&dPrice: &f$9,000,000' + - '&7' + - '&aClick to purchase upgrade.' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + '4': + has-next-level: + type: MINECART + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the minecarts limit!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + no-next-level: + type: MINECART + name: '&c&lMAX LEVEL' + lore: + - '&7You have reached the maximum' + - '&7level of the minecarts limit!' + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/warp-category-icon-edit1_13.yml b/src/main/resources/menus/warp-category-icon-edit1_13.yml deleted file mode 100644 index f70f4c1370..0000000000 --- a/src/main/resources/menus/warp-category-icon-edit1_13.yml +++ /dev/null @@ -1,60 +0,0 @@ -###################################################### -## ## -## SuperiorSkyblock 2 ## -## Developed by Ome_R ## -## ## -###################################################### - -title: '&lCategory: {0}' -previous-menu: true - -pattern: - - '@ @ @ @ @ @ @ @ @' - - '@ ! @ @ @ @ @ ~ @' - - '@ @ @ @ ^ @ @ @ @' - - '@ $ @ @ @ @ @ % @' - - '@ @ @ @ @ @ @ @ @' - -icon-type: '!' -icon-rename: '~' -icon-relore: '$' -icon-confirm: '%' -icon-slots: '^' - -items: - '!': - type: DIAMOND - name: '&6Set Type' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto edit the item type. ))' - '~': - type: ANVIL - name: '&6Set Name' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto edit the item name. ))' - '$': - type: PAPER - name: '&6Set Lore' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto edit the item lore. ))' - '%': - type: EMERALD - name: '&6Confirm Changes' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto confirm all changes. ))' - '^': - type: STONE - -sounds: - '%': - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/warp-category-manage1_13.yml b/src/main/resources/menus/warp-category-manage1_13.yml deleted file mode 100644 index 7bffa5b17d..0000000000 --- a/src/main/resources/menus/warp-category-manage1_13.yml +++ /dev/null @@ -1,48 +0,0 @@ -###################################################### -## ## -## SuperiorSkyblock 2 ## -## Developed by Ome_R ## -## ## -###################################################### - -title: '&lCategory: {0}' -previous-menu: true - -pattern: - - '@ @ @ @ @ @ @ @ @' - - '@ ! @ @ ~ @ @ $ @' - - '@ @ @ @ @ @ @ @ @' - -success-update-sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - -category-rename: '!' -category-icon: '~' -category-warps: '$' - -items: - '!': - type: BOOK - name: '&6Rename Category' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto rename the category. ))' - '~': - type: STONE - lore: - - '&7&oYou can use the following placeholders:' - - '&7&o{0} is used for the warp''s name.' - - '&7&o{1} is used for the warp''s location.' - - '&7&o{2} is used for the warp''s public status.' - - '&7&o(( &f&oRight-Click &7&oto edit the icon. ))' - - '&7&o(( &f&oLeft-Click &7&oto edit the category''s slot. ))' - '$': - type: ENDER_PEARL - name: '&6Island Warps' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto edit the category warps. ))' \ No newline at end of file diff --git a/src/main/resources/menus/warp-icon-edit1_13.yml b/src/main/resources/menus/warp-icon-edit1_13.yml deleted file mode 100644 index 4349c0ce73..0000000000 --- a/src/main/resources/menus/warp-icon-edit1_13.yml +++ /dev/null @@ -1,60 +0,0 @@ -###################################################### -## ## -## SuperiorSkyblock 2 ## -## Developed by Ome_R ## -## ## -###################################################### - -title: '&lWarp: {0}' -previous-menu: true - -pattern: - - '@ @ @ @ @ @ @ @ @' - - '@ ! @ @ @ @ @ ~ @' - - '@ @ @ @ ^ @ @ @ @' - - '@ $ @ @ @ @ @ % @' - - '@ @ @ @ @ @ @ @ @' - -icon-type: '!' -icon-rename: '~' -icon-relore: '$' -icon-confirm: '%' -icon-slots: '^' - -items: - '!': - type: DIAMOND - name: '&6Set Type' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto edit the item type. ))' - '~': - type: ANVIL - name: '&6Set Name' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto edit the item name. ))' - '$': - type: PAPER - name: '&6Set Lore' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto edit the item lore. ))' - '%': - type: EMERALD - name: '&6Confirm Changes' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto confirm all changes. ))' - '^': - type: STONE - -sounds: - '%': - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/warp-manage1_13.yml b/src/main/resources/menus/warp-manage1_13.yml deleted file mode 100644 index 15b1b9dea9..0000000000 --- a/src/main/resources/menus/warp-manage1_13.yml +++ /dev/null @@ -1,58 +0,0 @@ -###################################################### -## ## -## SuperiorSkyblock 2 ## -## Developed by Ome_R ## -## ## -###################################################### - -title: '&lWarp: {0}' -previous-menu: true - -pattern: - - '@ @ @ @ @ @ @ @ @' - - '@ @ ! @ % @ $ @ @' - - '@ @ @ @ ~ @ @ @ @' - - '@ @ @ @ @ @ @ @ @' - -success-update-sound: - type: ENTITY_EXPERIENCE_ORB_PICKUP - volume: 0.2 - pitch: 0.2 - -warp-rename: '!' -warp-icon: '~' -warp-location: '$' -warp-private: '%' - -items: - '!': - type: BOOK - name: '&6Rename Warp' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto rename the warp. ))' - '~': - type: STONE - lore: - - '&f ' - - '&f ' - - '&7&oYou can use the following placeholders:' - - '&7&o{0} is used for the warp''s name.' - - '&7&o{1} is used for the warp''s location.' - - '&7&o{2} is used for the warp''s public status.' - - '&7&o(( &f&oClick &7&oto edit the icon. ))' - '$': - type: ENDER_PEARL - name: '&6Warp Location' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto update the warp location. ))' - '%': - type: FEATHER - name: '&6Private Warp' - lore: - - '&f ' - - '&f ' - - '&7&o(( &f&oClick &7&oto toggle warp to the public. ))' \ No newline at end of file From 60fb983d762cc6e6f636966f9064c05a1a0931c5 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 20 Sep 2025 22:11:46 +0200 Subject: [PATCH 309/600] Added admin removeentitylimit command (#2642) --- .../events/IslandRemoveEntityLimitEvent.java | 60 ++++++++++++ .../api/island/DelegateIsland.java | 5 + .../superiorskyblock/api/island/Island.java | 7 ++ .../commands/admin/AdminCommandsMap.java | 1 + .../admin/CmdAdminRemoveEntityLimit.java | 95 +++++++++++++++++++ .../bridge/IslandsDatabaseBridge.java | 6 ++ .../core/events/args/PluginEventArgs.java | 6 ++ .../core/events/plugin/PluginEventType.java | 10 +- .../events/plugin/PluginEventsFactory.java | 12 +++ .../superiorskyblock/core/logging/Debug.java | 1 + .../core/messages/Message.java | 1 + .../superiorskyblock/island/SIsland.java | 14 +++ .../superiorskyblock/island/SpawnIsland.java | 5 + src/main/resources/lang/de-DE.yml | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/tr-TR.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + src/main/resources/plugin.yml | 2 + 26 files changed, 235 insertions(+), 2 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveEntityLimitEvent.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveEntityLimit.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveEntityLimitEvent.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveEntityLimitEvent.java new file mode 100644 index 0000000000..850b135d2b --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandRemoveEntityLimitEvent.java @@ -0,0 +1,60 @@ +package com.bgsoftware.superiorskyblock.api.events; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import org.bukkit.event.Cancellable; + +/** + * IslandRemoveEntityLimitEvent is called when an entity-limit of an island is removed. + */ +public class IslandRemoveEntityLimitEvent extends IslandEvent implements Cancellable { + + @Nullable + private final SuperiorPlayer superiorPlayer; + private final Key entity; + + private boolean cancelled = false; + + /** + * The constructor of the event. + * + * @param superiorPlayer The player that removed the entity limit of an island. + * If set to null, it means the limit was removed via the console. + * @param island The island that the entity limit was removed for. + * @param entity The entity that the limit was removed for. + */ + public IslandRemoveEntityLimitEvent(@Nullable SuperiorPlayer superiorPlayer, Island island, Key entity) { + super(island); + this.superiorPlayer = superiorPlayer; + this.entity = entity; + } + + /** + * Get the player that removed the entity limit. + * If null, it means the limit was removed by console. + */ + @Nullable + public SuperiorPlayer getPlayer() { + return superiorPlayer; + } + + /** + * Get the entity that the limit was removed for. + */ + public Key getEntity() { + return entity; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + +} diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index f970f61576..330c8cc937 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -1563,6 +1563,11 @@ public void setEntityLimit(Key key, int limit) { this.handle.setEntityLimit(key, limit); } + @Override + public void removeEntityLimit(Key key) { + this.handle.removeEntityLimit(key); + } + @Override public CompletableFuture hasReachedEntityLimit(EntityType entityType) { return this.handle.hasReachedEntityLimit(entityType); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java index 961b4f95b6..4faafd2781 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java @@ -2160,6 +2160,13 @@ List> getAllChunksAsync(World.Environment environment, */ void setEntityLimit(Key key, int limit); + /** + * Remove the limit of an entity. + * + * @param key The entity's key to remove it's limit. + */ + void removeEntityLimit(Key key); + /** * A method to check if a specific entity has reached the limit. * diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java index e8d68626c1..f080107a37 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java @@ -46,6 +46,7 @@ public void loadDefaultCommands() { registerCommand(new CmdAdminRecalc()); registerCommand(new CmdAdminReload()); registerCommand(new CmdAdminRemoveBlockLimit()); + registerCommand(new CmdAdminRemoveEntityLimit()); registerCommand(new CmdAdminRemoveRatings()); registerCommand(new CmdAdminResetSettings()); registerCommand(new CmdAdminResetWorld()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveEntityLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveEntityLimit.java new file mode 100644 index 0000000000..c81b7d02ae --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveEntityLimit.java @@ -0,0 +1,95 @@ +package com.bgsoftware.superiorskyblock.commands.admin; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; +import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.messages.Message; +import org.bukkit.command.CommandSender; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class CmdAdminRemoveEntityLimit implements IAdminIslandCommand { + + @Override + public List getAliases() { + return Arrays.asList("removeentitylimit", "rementitylimit"); + } + + @Override + public String getPermission() { + return "superior.admin.removeentitylimit"; + } + + @Override + public String getUsage(java.util.Locale locale) { + return "admin removeentitylimit <" + + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + + Message.COMMAND_ARGUMENT_ENTITY.getMessage(locale) + ">"; + } + + @Override + public String getDescription(java.util.Locale locale) { + return Message.COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT.getMessage(locale); + } + + @Override + public int getMinArgs() { + return 4; + } + + @Override + public int getMaxArgs() { + return 4; + } + + @Override + public boolean canBeExecutedByConsole() { + return true; + } + + @Override + public boolean supportMultipleIslands() { + return true; + } + + @Override + public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { + Key key = Keys.ofEntityType(args[3]); + + int islandsChangedCount = 0; + + for (Island island : islands) { + if (PluginEventsFactory.callIslandRemoveEntityLimitEvent(island, sender, key)) { + ++islandsChangedCount; + island.removeEntityLimit(key); + } + } + + if (islandsChangedCount <= 0) + return; + + if (islandsChangedCount > 1) + Message.CHANGED_ENTITY_LIMIT_ALL.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey())); + else if (targetPlayer == null) + Message.CHANGED_ENTITY_LIMIT_NAME.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), islands.get(0).getName()); + else + Message.CHANGED_ENTITY_LIMIT.send(sender, Formatters.CAPITALIZED_FORMATTER.format(key.getGlobalKey()), targetPlayer.getName()); + } + + @Override + public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { + return args.length == 4 ? CommandTabCompletes.getEntitiesForLimit(args[3]) : Collections.emptyList(); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index fb89ea9b7a..095680acd1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -302,6 +302,12 @@ public static void clearEntityLimits(Island island) { createFilter("island", island))); } + public static void removeEntityLimit(Island island, Key entity) { + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_entity_limits", + createFilter("island", island, new Pair<>("entity", entity.toString())) + )); + } + public static void saveTeamLimit(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_settings", createFilter("island", island), diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java index 0489bb4158..f47a4fa830 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java @@ -437,6 +437,12 @@ public static class IslandRemoveEffect extends IslandDoActionArgs { } + public static class IslandRemoveEntityLimit extends IslandDoActionArgs { + + public Key entity; + + } + public static class IslandRemoveGeneratorRate extends IslandDoActionArgs { public Key block; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java index 3d26de0e42..d05c65ae8e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java @@ -65,6 +65,7 @@ import com.bgsoftware.superiorskyblock.api.events.IslandRateEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRemoveBlockLimitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRemoveEffectEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandRemoveEntityLimitEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRemoveGeneratorRateEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRemoveRatingEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRemoveRoleLimitEvent; @@ -183,6 +184,7 @@ import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRate; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveBlockLimit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveEffect; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveEntityLimit; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveGeneratorRate; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveRating; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandRemoveRoleLimit; @@ -226,8 +228,6 @@ import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.PreIslandCreate; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.SendMessage; -; - public abstract class PluginEventType extends EventType> { private static final List> ALL_TYPES = new LinkedList<>(); @@ -833,6 +833,12 @@ public Event createBukkitEvent(IslandRemoveEffect args) { return new IslandRemoveEffectEvent(args.superiorPlayer, args.island, args.effectType); } }; + public static final PluginEventType ISLAND_REMOVE_ENTITY_LIMIT_EVENT = new PluginEventType(IslandRemoveEntityLimitEvent.class) { + @Override + public Event createBukkitEvent(IslandRemoveEntityLimit args) { + return new IslandRemoveEntityLimitEvent(args.superiorPlayer, args.island, args.entity); + } + }; public static final PluginEventType ISLAND_REMOVE_GENERATOR_RATE_EVENT = new PluginEventType(IslandRemoveGeneratorRateEvent.class) { @Override public Event createBukkitEvent(IslandRemoveGeneratorRate args) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java index 610d58f55f..ed4ed63685 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java @@ -743,6 +743,18 @@ public static boolean callIslandRemoveEffectEvent(Island island, @Nullable Super return !fireEvent(ISLAND_REMOVE_EFFECT_EVENT, islandRemoveEffect).isCancelled(); } + public static boolean callIslandRemoveEntityLimitEvent(Island island, CommandSender commandSender, Key entity) { + return callIslandRemoveEntityLimitEvent(island, commandSenderToSuperiorPlayer(commandSender), entity); + } + + public static boolean callIslandRemoveEntityLimitEvent(Island island, @Nullable SuperiorPlayer superiorPlayer, Key entity) { + IslandRemoveEntityLimit islandRemoveEntityLimit = new IslandRemoveEntityLimit(); + islandRemoveEntityLimit.island = island; + islandRemoveEntityLimit.superiorPlayer = superiorPlayer; + islandRemoveEntityLimit.entity = entity; + return !fireEvent(ISLAND_REMOVE_ENTITY_LIMIT_EVENT, islandRemoveEntityLimit).isCancelled(); + } + public static boolean callIslandRemoveGeneratorRateEvent(Island island, CommandSender commandSender, Key block, Dimension dimension) { return callIslandRemoveGeneratorRateEvent(island, commandSenderToSuperiorPlayer(commandSender), block, dimension); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java index 4bde65c75d..90576d04be 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java @@ -61,6 +61,7 @@ public enum Debug { REMOVE_BLOCK_LIMIT, CLEAR_ENTITY_LIMITS, SET_ENTITY_LIMIT, + REMOVE_ENTITY_LIMIT, SET_TEAM_LIMIT, SET_WARPS_LIMIT, SET_ISLAND_EFFECT, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index bf580d1a24..9adb3e462a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -221,6 +221,7 @@ public enum Message { COMMAND_DESCRIPTION_ADMIN_RECALC, COMMAND_DESCRIPTION_ADMIN_RELOAD, COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT, + COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT, COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS, COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS, COMMAND_DESCRIPTION_ADMIN_RESET_WORLD, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 3054d4b143..acd6e2715b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -3305,6 +3305,20 @@ public void setEntityLimit(Key key, int limit) { IslandsDatabaseBridge.saveEntityLimit(this, key, limit); } + @Override + public void removeEntityLimit(Key key) { + Preconditions.checkNotNull(key, "key parameter cannot be null."); + + Log.debug(Debug.REMOVE_ENTITY_LIMIT, owner.getName(), key); + + IntValue oldEntityLimit = entityLimits.remove(key); + + if (oldEntityLimit == null) + return; + + IslandsDatabaseBridge.removeEntityLimit(this, key); + } + @Override public CompletableFuture hasReachedEntityLimit(EntityType entityType) { Preconditions.checkNotNull(entityType, "entityType parameter cannot be null."); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 74725dcf96..611baca204 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -1740,6 +1740,11 @@ public void setEntityLimit(Key key, int limit) { // Do nothing. } + @Override + public void removeEntityLimit(Key key) { + // Do nothing. + } + @Override public CompletableFuture hasReachedEntityLimit(EntityType entityType) { return hasReachedEntityLimit(entityType, 1); diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 610298252c..7a27abb574 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -260,6 +260,7 @@ COMMAND_DESCRIPTION_ADMIN_RECALC: Berechnet den Wert einer Insel neu. COMMAND_DESCRIPTION_ADMIN_RELOAD: Alle Konfigurationen und Aufgaben des Plugins neu laden. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Entferne ein Blocklimit von einer Insel. +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Alle Bewertungen eines Spielers entfernen. COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Setze eine Welt für eine Insel zurück. diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 1c744fcc5b..7eed63238d 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -192,6 +192,7 @@ COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Rankup an upgrade for an island.' COMMAND_DESCRIPTION_ADMIN_RECALC: 'Re-calculates the worth of an island.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Reload all configurations and tasks of the plugin.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remove a block limit from an island.' +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Remove all ratings given by a player.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 9f5235f969..9e098ce0cb 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -192,6 +192,7 @@ COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Subir de rango una mejora para una isla.' COMMAND_DESCRIPTION_ADMIN_RECALC: 'Vuelve a calcular el valor de una isla.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Recarga todas las configuraciones y tareas del plugin/complemento.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Eliminar el límite de bloques de una isla.' +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Eliminar todas las calificaciones dadas por un jugador.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index e83f7eb3c2..b09f38bb5d 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -195,6 +195,7 @@ COMMAND_DESCRIPTION_ADMIN_PROMOTE: Promouvoir un membre d'une île. COMMAND_DESCRIPTION_ADMIN_RECALC: Re-calculer la valeur d'une île. COMMAND_DESCRIPTION_ADMIN_RELOAD: Recharger toutes les configurations du plugin. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Retirer la limite de bloc d'une île. +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Suppimer toutes les notes attribuées par un joueur. COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Réinitialiser l'île d'un monde précis pour l'île spécifiée. diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 721cfe177e..aa14778e63 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -195,6 +195,7 @@ COMMAND_DESCRIPTION_ADMIN_RANKUP: Potenzia un aggiornamento per un isola. COMMAND_DESCRIPTION_ADMIN_RECALC: Ricalcola il valore di un'isola. COMMAND_DESCRIPTION_ADMIN_RELOAD: Ricarica tutte le configurazioni e le attività del plugin. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Rimuovi il limite di un blocco da un'isola. +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Rimuovi tutte le valutazioni fornite da un giocatore. COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Ripristina il mondo su un''isole.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 599ca84448..381837643a 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -200,6 +200,7 @@ COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Rankup an upgrade for an island.' COMMAND_DESCRIPTION_ADMIN_RECALC: יא לש יווש שדחמ בשחל. COMMAND_DESCRIPTION_ADMIN_RELOAD: ןיגאלפה לש םיצבקה לכ תא שדחמ ןועטל. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remove a block limit from an island.' +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: ןקחש ידי לע ונתנש םיגורידה לכ תא קוחמל. COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 6c5a738816..ba5661f5f7 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -192,6 +192,7 @@ COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Ranguj ulepszenie wyspy.' COMMAND_DESCRIPTION_ADMIN_RECALC: 'Ponownie oblicza wartosc wyspy.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Zaladuj ponownie wszystkie konfiguracje i zadania wtyczki.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Usuń limit bloków z wyspy.' +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Usun limit bytów z wyspy.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Usuń wszystkie oceny wystawione przez gracza.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Zresetuj wszystkie ustawienia wyspy dla konkretnej wyspy.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Zresetuj swiat dla wyspy.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index be52c6884a..17a86ebee0 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -192,6 +192,7 @@ COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Subir o nível de um upgrade para uma ilha.' COMMAND_DESCRIPTION_ADMIN_RECALC: 'Recalcular o valor de uma ilha.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Recarregar todas as configurações e tarefas do plugin.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remover o limite de blocos de uma ilha.' +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Remover todas as avaliações dadas por um jogador.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Redefinir um mundo para uma ilha.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 2d5eb4a35e..00e6da492b 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -192,6 +192,7 @@ COMMAND_DESCRIPTION_ADMIN_RANKUP: 'Повысить уровень улучше COMMAND_DESCRIPTION_ADMIN_RECALC: 'Пересчитать стоимость острова.' COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Перезагрузить все настройки и задачи плагина.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Удалить лимит блоков с острова.' +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Удалить все оценки, выставленные игроком.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Сбросить мир для острова.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 72a3f641e9..6bed96256e 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -249,6 +249,7 @@ COMMAND_DESCRIPTION_ADMIN_RECALC: Bir adanın değerini yeniden hesapla. COMMAND_DESCRIPTION_ADMIN_RELOAD: Eklentinin tüm yapılandırmalarını ve görevlerini yeniden yükle. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Bir adadan blok limitini kaldır. +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Bir oyuncu tarafından verilen tüm değerlendirmeleri kaldır. COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index a07147a54c..3e6a8ab5a7 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -220,6 +220,7 @@ COMMAND_DESCRIPTION_ADMIN_RANKUP: Cập nhật mức độ nâng cấp cho hòn COMMAND_DESCRIPTION_ADMIN_RECALC: Tính lại giá trị của một hòn đảo. COMMAND_DESCRIPTION_ADMIN_RELOAD: Tải lại tất cả các config và tác vụ của plugin. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Xóa giới hạn khối khỏi một hòn đảo.' +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Xóa tất cả các xếp hạng được cung cấp bởi một người chơi. COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index d5eb44a3b5..d92ac7bb9b 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -192,6 +192,7 @@ COMMAND_DESCRIPTION_ADMIN_RANKUP: '为指定岛屿提升等级.' COMMAND_DESCRIPTION_ADMIN_RECALC: '重新计算指定岛屿的价值.' COMMAND_DESCRIPTION_ADMIN_RELOAD: '重载本插件的所有配置和进程.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: '去除指定岛屿的方块数量限制.' +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: '去除指定玩家的所有评分.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: '重置指定岛屿所在的世界.' diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 2e753bbe4c..4371b05196 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -269,6 +269,8 @@ permissions: description: Reload all configurations and tasks of the plugin. superior.admin.removeblocklimit: description: Remove a block limit for an island. + superior.admin.removeentitylimit: + description: Remove an entity limit for an island. superior.admin.removeratings: description: Remove all ratings given by a player. superior.admin.resetsettings: From 018366fabdd43e25c996adf62488f26a50d0438e Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 20 Sep 2025 22:17:23 +0200 Subject: [PATCH 310/600] Fixed default schematics (#2627) --- .../resources/schematics/desert.schematic | Bin 21939 -> 22139 bytes .../resources/schematics/desert1_16.schematic | Bin 25125 -> 25420 bytes src/main/resources/schematics/mycel.schematic | Bin 9943 -> 10376 bytes .../resources/schematics/mycel1_16.schematic | Bin 12157 -> 12044 bytes .../resources/schematics/normal.schematic | Bin 19972 -> 20130 bytes .../resources/schematics/normal1_16.schematic | Bin 22386 -> 23456 bytes .../schematics/normal_nether.schematic | Bin 29449 -> 29211 bytes .../schematics/normal_nether1_16.schematic | Bin 32320 -> 33642 bytes .../schematics/normal_the_end.schematic | Bin 44484 -> 45107 bytes .../schematics/normal_the_end1_12.schematic | Bin 44629 -> 45179 bytes .../schematics/normal_the_end1_16.schematic | Bin 48268 -> 48832 bytes 11 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/schematics/desert.schematic b/src/main/resources/schematics/desert.schematic index 7b2fc1be635bcb21702cd5d5aac868954fcf49a4..d537dc2917347e7e6e68d5257d2f460f143f7fd6 100644 GIT binary patch literal 22139 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 R#&IeFz4nC_zD0ND{{ZbhX4?P& literal 21939 zcmYg%1z40%)GxIlETz(Ipw!YxNTY(3NW+pM&9WdM9ZO3HA}z5f4NLFRUD60F2umX^ zDNDy){eR!Rm*-jLoZmS!@65dOo|!pwhCTWg-hY32%^D-lFW={T^uL#?E-v{ksx6M7 zyYo``p?&5Rt7W`kaI#%r2&$h>^j2DF=}K|e+3S93YtQK_lLz^`l6P;2)CNHh0{|l7 zUOWzxXd$YFFvq3KK~u*J9iSbcXb|3FK|5_ebRdUS?=r@y?wKL zFeT^xXDaaKblY?O5?jt5h^61V>ZX#ri8ffcnvd=cWN$j(!mgLg1!8wr_5v?4ujp=e z7km$zM_R5Am9qn}TfH}jz3fe1ffsLQWf{#{PTS*JPS305t_;j^&<)mL;S519cY6FP z@Zci*=2t;^;0-#v`Ft5rvy)A}f$n5MDxK_h3x#uFTLx?TlZ{XGC3G6r)-%w-5aV#y2mn{h|E$R+6zE7zKXz)<5sHK3*7K9GfU& z#412f8tuS*N_Lp`W8tM2t%}X31yenp@2)O)PzwT1Q!~eb=h@NpslRNIPSSD(t_Lry zS6Z9>cqjwsXDL`T8|Mt!6;uU=r_k4?Y*Q%SpZY&4VLQrU5Uj^LOmpRR&1R41D-_f( zm+5od{55~efbtCL)Ub6xISB;f-Fm7iuzx&%Y$~8N(*e{)P3?6boyyKjD`|}UGVqW0J!*~`CnpgybTbM7Dw%ZJXp!jJq%>s}nzygJw_F`eo7m|GLZ+UF6j zenHL+5g6F75$H_GR6nKgQEZSz`0fP*bSl8-v2WURz-t|W@~7X z#)4Nxz zL>S-rqqUu;?ndGlm@*6Cm(+fgNq@BL_q%fktXi>~I}5Uwi_8e*jt5XmZq`#oKu~UN zWGHvsWDPKf^1hk-5`nn#gtDdDWDeA^$+G=vmG#rjchM|T-*)TAs))#S%(B|sPz0Ez zbbFiA4LoSKHp&QjFv!AUX(QXAi*gUGA1tYt?wE-9SYTLmhiA7-_+n+)BQ0&4JP~pk zLq73aL~E*f%W4}E_w-MT4o@5tb$lL(DEH~^V7rh5<;T}-QSfsVf!GIn$9BG zvpisl`lRZdAj|^oQqsO4rAgydHm)ptSeSxX;&s_zU!-Ko!)-nY666-()7yT-^ZkFc)9 zot8M+vzJ1|qy{Rq#{bBf{~Q(C5S6)u0nk7 zm}}0Uj|!ROWIaxpsj6JhZgYq8pA*c58n3O(gOnd8X#t-lpa6#XF&`{z|FC2W1}vN0``k?^6ixDmj;f1~Ez(Go+HH;xbkSQ(z+1NcI~cBE zU!w4Z6AzM%S7SslYNIf^CdHV{VGgDsXGtGW2vri1)W$eeSSeI|`&~}_G#T%=A;a%N zC;Z=BnUog25hm=k1JlDdS4iF8${ZphmGV>sIw zlksc~scla;-c=Z>W+()FNjWDfXQqelF>kNjKoc!@G>?Gy0W_1li7iAb?Hwxkp~!%; z7i7tJ+=c|X7NqgPfKS2O$$xG+di=UJqBTKV%8_ng#PXtop2qOU(6m);X@zmhlhHjR zvorE2xcN)IAmg}ZDR${H7q&q!rS%N5E~ely7!p`mkOsj3F#L21@sWBpmtoUjx7|A# zZuGM2itO{U$4hQgGbom>j!CNJ^S)ezpA=3@^*(D($Q`Uoy{y^s+9!YiXJ4eM%&ESY z$h|MW{@HwPb)wq4yS-IKth}CdMwx_=l`3!l;Z5;z*wMw^jIgEC_;YE=A{R5gz&5VA z0-i+MZVWTLS*L1X4XEK+m${5Vb(cZDxb6u0@wJ%5L3#U!Knl%E-f?EKg1F~_-y-W@ z(iKgMtmyJ~D<`@aNI=-%tduTUG(rh~G08Ul?JRigd z+hO|YYyp0iH$ykC5ty6OmTYm`OZ@5pY613Vv<=c)oC_|`tOeMG&x1Ch6>ohp6izv< zFWH09l{L+Z+F!z}%NBpEx#kb8s539Cv(x53x6FO#+M+%SYRg37dCm~b+5=q*{xU&T zmFRQ7+MF3`J8p;=@(s}aAsDa534gQ-Ae9j7@lbG4{2(q?DAs|RbR2JeW8HzYi_U@x z9Axi=pI-?`?FmoqNt&tmc2Jx)GU7-!+~PFtl^8n^+wF8v4r*I`(zCb)P3hV`h8jS?ft`-zW%H4~;8;TE7{U$-JB-ai zxBs{<#;of0#f!@~+pa;k+hkodT~rTIOh>Z>qi$BCcQfv0BwRL9h%MeK079SQ$CCnI zxHQDKZPNwSfZI$l47mXF4Nqo#j<5p{?gJ^iQ zLR(^u*@W zgvq9^x3oUa=R98!eC@Ic0cxGm!4E-Pix}#pRyK!p<(YCdC#$1N;XLD@tXe!7D8A1; z!BLZt#_gVV*a)bwYK8#b0Fd_p7MDIDDju*XE-sa#sl6u*p4nP10Lj~cg9cIXQ+uVi z$;1aX=u0||LXf-`Sj)0?lkDPRV7|aqj7mN^7GxV8KD_gk>3)L2Dbf`^)}O2zYl8P( zKZS|g{Fp!<)i4q1Y_gR9A!JV+wWt1h|55+X_chn~M|M;xKOnKkE=7=S&cd3oRpg8H zVrce@E2eJ&`_3~cBT?6EGUN_tUcK@)Ew%gEsLWyZkGkOdkjo?qn|;PI*LEq*hv7d7 z2CD(7wm`3lSfLRq%}a@xAYjMomOrOu5!wx34dh>1IYDPp6k9pbpIkA~K~I|;wIVnn zXdy|7S3TC`vj4^^mG&|pA~rZfkct!!6|W`i0O2$sG(PGMgm3nYipG?ORK^{kR|N5A z$*tDln{;g}u}iKDA|!e2R%=@((z194V5-Gox(Fz~%>qMp1dNoj^1A-jUOrX4nnhzU zgdz-$qVH%sa2EHLx&RKgZx*8v=JK+&Zc;0Uvuu&%KJk(p8InP=5&?cEC#2)Rx*ZQH zjvKaF1SX`>!`HvIEV_%WZAYfg3q?Xda?FZpE;`s9f#qI&G@S3ExG)P{*5}T0<5NEI zpYE-y0X-Enf%q5D0d0=)PJiR?Pv1Um3ZP<7^aA=F<2~HLSD7JEr;;E0$YIaO z(Vf~yp|bGmUKy7TReT>C$LGvXeOvWRX}|G>ry0{qok-L8Sk5HEBzW37R}8>K_}fp( z7cGX^+VW(A)ShzByd*&#_r9c=B870>OEQ6z^L&Vvc|4+YVPL1S!$?kZy}aO51Ja}dR|ioMpc($JU5 zk46EWefjslF{3KTZaksz0x$CYnMthO3Eq$07`smQ%Ez&vF7-hGCf6N&?Rmo7rU%-Z z2XF`}cZApIUjC;;HjdTIPwyg0B8u4$;Jr>2g-|N$Q#Ou$84lMIJlI}LTS%N52G`{O zNF?YC5k<1kd{+0Y#*+D0{1w|BeWltcq37Hexw;$NYJVpM}vuTo>fce*MS+?uLEx!;x@)o(}$+Dx(a*p zY+E4ggq2bsDfsUU%N7cpnI#$skBnRwi(URMN9BdS zwpJtk=D^|u0Rz52_?*8Lkw~cH(%{<09SsG}Pw(Hndcmt`wGUgIWjCj9^9P zY@ovy+D4@!sYh=2w)JJFqG*OK#zw+QnE{_?P#NvH5bkZ__FR;atswW-kE}Irvc8`h zeY)gzjfV$CLb>0#?2w?mZ^g9TJfg#Jz0DR8JFFXb>@8k63TfXZVuwU%JjhZgIo`J& zP51N-rOb1kA8uiNoiF^-HnE5t&1ijIkLns>v~HmKpXABK`xj}uAww;huWcYg7y8rM z$A~DEeP;j9P}8}0;njW4nMP%j%p@aY}nH`XnMnk{D!G)H#`O{74>;IkoK!T|(iJ_vBUBLmq@J-9r}0 z9c+vUMD3++q=+8Dsq{o$1~*aG3;uhps>*A4w>>1sMfPhzzYMtdYY;=_Suk6Oa(}tv zqLI4~QR{2Lx$%+Ac3s78YIP>!hzVZAo0(+oa%%ON$$YaBi!oHZPo70p#nr8V2X%_y zHsh~3*&V?uH)9`FPNwn$U$K*LHP`M4BmB+{<2tnp%q$;+3+x?Ry}_ymQ*PsVQB*jR zcS-tkO&b%jfV2G`#*AxWwMgziZhp8|HfZSw+Pz>{c*`RCOPmCih>CEn*k80_Nsu*+ zU;jZua!8Jq;ogc0uRh4L$Vh13eZDKpICtjw)9u^trP%NK*B&8TS=kLUs>B@!1kP4+ zL{4G&(`2haaszOhIPgc;xz{v z)B_i>V!Wba!Ce&8;H5tU-OA#wmyakvanIbrk)26QVq^ZMiP)Za3t~P%BKGtymMCF1 zzP+R)j`Y`seDS^yfj3w?Z0fGcp-yqSxLX5uR{LB^qgl3y!^g&_bWp8pm6gAVf3XXr6c&xStrYTpl1#3U$t6r#`6OzG`b``?j4jp>X0BdZH3SY{R7oD`Qj*DW`HF zE=M7;_`{26RCTIy~Hg4usq=*k3)T+XmM zumAPr^o|ku)j1Qv*i>7tK&sUf1)<=DetYdxkmR@&!DP@g(J22b6OCugej0ls$5=Or zSe(c)5`kEA?P)=wpVi#s_)39)8*(esPD%cmueE$IjGOI#|fxbnWc5GLSA ztQ(A6nYU;-+Cg}>?XAQu?JrQ)c4!T^{+YfazQ=U}gOAIziF(bUQRX^%VChE%=Shr1 z_&l}X5wXpN!Xlu4dMx>)?a7}+c|d5=%Q51JATkLe-8NWJkVlY;&jPg;K8bn#+AZpr z%(H}Dapn0Glq$@j<)MN6KZx7urKYTScQRUTy;Di}=yj^t$~=18QYcZk?H>FArMhzH z0g^ks_q2FGX!t-c#cH(8aDzcIK~Qk!ef8{sl|{m}G4+Uxf=LIQT3Ue;L2*Rc|I z>_moQwv7dMiNw1ZTFL;u15$Wa}F>RD=BEI$$eyLSv`sSk?$v$2;O#?^p8+rr((cjBL7W8q0{AErsQOt#?hHJS_+FNTc*Gs2;M(%(Wj{7}E4$=n zzm--7lw76XN?x0dFyW9PKCu@rvB2i#X;i=B#?^e$e-+b{Oy#$_7L$!ff)oajIWTg{ zD}W$k9$w^yomTR!Y=m3;-zSzFdK~_x{rWl)y+Kma!X9;1oUMA*@t4QPkXOByV7f=8 zO!Oa*Vj(Y|8B6bqx0uJcJ~Vr8UF<#mZQVK!U%>a7*%N=dwYYVWr=?s2yw*4;d}eZt-L(+lF4Ct z;CCeb=f|Hx<>j;#N|F{~h!)mOY{ZY;Yt5=ng#BvAZ#{Hu1rBujr~n(f?Y)+SSWkh6AMWN%s(vJbDI`S9jSNH_&`s=uG~As7IHt|N~_DA{Ped~ zn=Sia4wuwN+FO^L{X+<4FBtZxdxJ(~iT#d+7OUAswi0gKlISVrl|L=nzba+w?41-G zA0gdR`E4cNz)m=J#Sp)%92mAHsbIQ_7Am}!I;2e(RPYEC+YER+CZn$PMc_F1;?v6$ zK?MjKZo2e8635p6Q5?Mq5bSlXycm(R`M$o+;wFu~Ek+pHzQNMeta9|%0_kqhX-1yc z=Q0LK<}bvO&FPPz(_uoR_jTFTIdr7Ixh@&q z6roO#9glVYJcvY6je{``$nFiOzf3_bDsQZFpA>ENA}_)+uH*uarn7>h7>pqJxL}dqV=nLG+COs9Mfe^ugi+ zq~hHtq4?4mJ|mddtvaCgq)^q{yz2>7#(oAB{TIol^3ry)1gEiUHt|NsC=O^&eUV68 z!_4vbL%RL2VZ2r%Fhezm0hiumE4Uw{(HVhNzBQeUSM7B1+aCGXB2{0BdlUx5jVBl6 z6P6(26=BynfA>}d&Vx9T`F^bG3v^u5`28Qq%*%oE`s$=>b=aldo3kI~Q@CAsCPLkg zELZieS`xhVyxzE26ri2Q9nYh|rPmMu&d-GJjjnKOJ<@;)+mj`})Pbv~Yo#46tx7!I zxjY6If;Zn3_fQ2iI;gX`Nc`$LFY4FdF36Xc69b$VagV;zD9mn9#M42%Ddq^urj2Ev z*N!bQ&myBz*|(fY5~2K@PJlqu%>EM0nJgw3M((z=fKc(A(dj@q&* z_m5}V_amVsMjC!V{I1%Np+|{#+KGow@N=J4=%335B^LVet9;KIt=*cC7tfC%SE-=n?dJ&Ihbg1uxp4Y;KDBz!1P-Exl-b>}HP2u<($;ZESkXcq_?h-oi&a_}(&V2a@kxELE zwa|dF$tCsDPMBoQ1$>V%jevESX2a#L6d;xH!9zk%yMSTgoZ3K)pLkZBUmDK*Dom}v zC-7v7^U%vcR#ZmWSJZpwcB%Oz3hy#=&3w^M>K|G*HM2wj!no1MtpQWFC)*`XBS;&g znWYfMfuz=|tEUO-MHSfpr|?$wZhvB#-)}3@F_fT95`;6*XDY#^590W2S~ah@k5^25 zU3!Y!9h8I{M|zK1%mByS3jGTwuv~4y5hS9;%$lssAdR4Cf<`4TU!F${pk2fruc`sl zbxG13ltey_M zJUtlWgu~lw7v3o~wK$L+{R0X7(V^$XDfAx>h1dmX?#lG;s^vavc|&3ovgT`7G(@A4 zn=gM~3}EnE9rnyY@dM2eF$8#rTdEH{4^+*ycwz_MXWj`F%g*2b()1ciWmgoEuC)Rf zO`IUpC_D%bI!2wV!as;gB~9%%?a=C1)15k8hn=TKRIK#;Qs6?pz!Br1CyhMwyHV;2Ntb0fedG0@Y`1PMr^P~;AI38|{YWE*sH+{L(^1zLQF4Kt5=eEc& zA6>Kh4{w7Hb$K3?p?Pi`e3^unn=u_@+qTa0Xkq6**`9U~!i~c)ldyd&CKyd+$-*MA z&Op*@An~6dG?Vb&??FXF1`>m6w|S^?gP!D{A&v&3?U*Pq(=$j3ZLJ8ea|wWwrqsdN(mF)b^C--~r#JkxwFx^yzNF4*Lp7H^ zH2*iD>L@xB1Z1;E(FKV@^US2_)#w=pMWK$Iewer3ad6#ci3G1Nj- zk*v$lN|7v2N>bMj!|FUJyAW>P&$A~;haWnJ876d${l(iU{M|U5GYS7?x23C{to#K* z)_K^tIBc&RL}L!BLY)v>I;BBWLWbq`_I&BH!mPznR#^$$ShD!!=+s#StX^tqXL z2a7Ch6HsHl$}0~aek%1WpHI$32(}+JZaVJRB%;QM#!<#IQY2%OlJTfvSd9l|E~3}3 z!5cAmnc=vz_DVj^Xb9kaFe3?_v-TEwX;(tIF>q+p#7DJ;=)rp#Maurd^Yt8yNwRo# zD9WcSQKmJmc1E8pdtne9JLf>U!=hqmn>^alBgzG z$3@zi-oxO6qRgvIKR1`h3oLdHwi6R$;rb^Ajt=XKnk|fC$W@aG&%>e8B1Be+7}5=1 zlu4+u^H*&b*I!(De zF$hZh@I~*d7h6hY+JO;FSw>>y1$QC9EuHjA&AF%F98z1R8(PnUyCth4i~oS&90x4;P}QV**W4FMXQZLH4-6H)__gJ^G)lQ5Q<+o*nO6yE=Uh12a zui0uHUIN)OCMPAPL2jZnxB5bhI!|0SufM0!3Miq z+7LCLW1mLW?vS--@o$-0I`AWuRO4+E)jJQ=RP$|<)u-&DYgtQaE+R=}D0M&v`QD{} z4j*E|=RQwj?Wd1fOd6!Bof;oGUAU%}cKO;!N(@HJ6K+6|EPj-~7Df8oxrg1elpHJ8 z2AKU zR)aN&$#VhNWFTqHwHh32etO5ALFB|AT*r?WlXk%-pkNxrSqQ8k^1!ES`QG4D+irHh znMjN%86MttXM)-=n27*5NevfryU4T}WKp&xRVC(A=nLZHVyqzIB&6eK#KRp6L<@NI z;eEdH6^Z2UZXzna;ncbkfNcem>fWfq&&{>4<`i|4^X87Ce2qsZV?XuofeDtbgFE~W z^{cRBDC4@;3K#aK)vAEF(FT7F>=NRO>NTg6)N69JhE8`q<%-io)=MAb;Bnot zb;&~}pK1O=!E*cC;N&P*34$~UB>i=+#xZ41P=9^r zJC?pB`n=9t)q@Neg_JHCP>!u-h!l;|(5bR*J9B7zu7T!L9c0i4x(?!5U7& zJoc#H@~>ByzxQ0-0QUa?>VTBZFEs|DTkX9M#6bdF$`Jy!wdnsSnY3E;yCcr{ZvuYf z!d=ZM922&>fo8#PZCAc3Q}sLGIRNM_hZX665HRCx@k%-k=5bBcoJpSO*=PJwnAl?H zt&k+4@fgCJd2AzP4@TTECrCQIQ`nUv&)Gu6bC9S1;c3gEj#bILS<@pw1r0A5HAGR1 zt@k|*i9zjH1qY4O;B=StJSHmQxF3ADbz=HH=V+(^?2(`4Uj@f)u_d5mhh?%pN>ojt z->N{~`2E?K#?YT-^kjv<$JVbf(Gj$=Zn5o1n$uIb*oYe3+f3_^x`^a=X)mz<)1y0f zSt*O}H^Rh5l0fwoHdRP$`Z|sg{LG69^yT)iNMw3bq;9;$9E%m!DvI$~xtO}Q=Z4w* zNMCMa)|Bq8Am&DU1CPq9XMOwKk6mSm+zpILNM~F_1&AYT%!0psPLUsKB63*c)DjVZ z{Z$vySpAZ|-0c`;86~N4u)NwEox(1_C6~{g4?$jfk^brhnj4ersLQ4BgThA&Q0Npo z0oXrWjYH0i;Ow9yg|1V4JDdJkDge;0DF6*O=qZ)~{XT$R9{uwE4oRQM5EnAjZ|Dc)Vc(#7$`+NGtoiS-r?ThRB z^T~P6_#J+jlc&No|Il3wi2%lwV0ss)lOm65B&wPNST|O5ez1~ zqIo)ZB+X~sq|mYi@W4^W^@Sy2sS|IB5GAID20)>rmz2g-%|uMIoTH2U?Z|GRqsx*n z%iHhGh{;8M7_p}%1%KDa;rzz|gw6bChL~Wpl*tH=RvxiBHTaaNVL4ECQgXcA!IysG zm|%DbqJU9r8BOCu?3fy2fH_(wtUzw-iDz^eDuHzj9@e)7~1bhw=`rIjd@Cf zGLCK{GXBL`XX|4L5{@zAFjuYlKA(IvDo6?Ac(euO_)`dR1XcO%HVkObGQP7$cv=IE z_Z$PKOp}*~|2V>d=7grFOdA~r6Jf1Q8#%ZnW$%e04zl|`C9l*%%ycL=8ed*`FYxS} z&*1FYn>hh{kBe%t(J$q&c|VGyHAlF(Ibrizl+T|yjz_FY?sLz5qwX0K&#U=*U-Wmp zcln69RR*i@rwH9~DO>cEDxhO=qup^ZB1R*_-3&SFPsxf` z;RiR@LnZ8imp4o|t0OI^NA%?_XC<#>uS>S?_E4E!_TU05`wRpEcK)#61O{ST{juHS zUs`wqJiHE;eaq!;meH-Jf1@n}VM3VhiYCWTE+*fSO76(BG>o@1>2ex|6cagWC0S4u z-(evPh~_`Cp`H_Z+g(f~8abnHz-d^|gHQg(XfOcr_|FaW2dMTRS z@A_}t!X2Jfrne&o-Kd!+o3nb?J4Cgr#{(9uWpP*&yZjHbi`#Z zxNrK)TkQ|QtqzCZ%3FQ9miHb0*+K149*vKCXTx=X>?X^XSO8d*Ev0i$V5v>X*xJU;DCej?e{r3|D*f z-)_2fqO)7h*Kn1V^HBjq9RU^FPjO=WDL1$`EoFnypkSmgsde2vUfL%*{;3W`SQYCA>;?QQI0Z%F!Y->@) zXeXr=Q)yY}*P!)mCgJ^qOuA`CAv_|y`f2rdyry0iwtNputvjz0bkw4=S*;TE5cLA{ z0CmdKswM`atSvd1nh^ZJ>UTz|QcM$#GA5;J&850qc~L?-g72DgF8>K1Lzh0*+c+))cDErG_|l7SmwsygPj8tz5N=Qr%!ckP#G^CvA6c z9HkWukacWn)e6q5;Ve*)b^zlvSMTsq$30=xYI{Q9|$4NfX z5nNcIP*N7aulpir1h=hAdOZmj?(a`}&C!oUl*LrxI?CZi&_cf(M5yI(rXHOlXjBwR zs{YuqSPfTB2T}g#;oQwTj~ul+-cqQhmMV~bPEt#4a~~T?^01v(f1JrV!Kpq85AEyc zRJV{yLa`^|wa-;OED=!C1|Z7#s?PiG^Xk#Tbb`guNze65`4oHAdX-G-t8S?a&XE-I zDK-kvkreY0+*QYH_1|~YGI~qF6J4rc{fU-0I`L0YF<*ju&qZuW|9!fxFJvb#la9A| zqe~5qaHOaBa3-V(r1`wZVnOU}S&XQ+Si=Nb;>cJfz96yu7ldZ&`QR00w7teu&s)i)^HL|Fu+ng%$})&YQl?npWEC;mcoJ@m%jalRZw&16X#>ZjCG|@Q zlq$<4DYZ00-<$QH(EG*6}c;|SZ!aVPRvQi-Tc z4o`uBpQVOu5ps#7Vj#{d= z6snu03f!5rYMY}?x5nO8B@XxJx#L1LwDeNOjOr69W6Cu@G}l;r>hm`eu9V!RYxq6P zlsIP;QuWkP>%A>S|1OJF{wFJ*AB0wPT-CS=Z@`4AZ|zwP5`?7-G=5XNDK$AK=~39W zH=bDF)QXrud2F(u&4Re(Y5=PdPx$2Au?KXC>@&fKN?@%3yUs(UBj>!G)waqV}K*?!PXJeUdgdB!~Xz{j;HrP@{I>(-omY)-5rd3$O-#UHeAy zj*@29|CRI8m3aqLc&i#fYl)K#hSOTwv6wthg$Pi(e8vT&o;w(55=$?lmcd$@Ho*Qq zCk4qg5ZB{sOUbkn>3}~-*8ZO71rA^5^8DIRQ*OLQ@=1`_&j_rF7s?nbEr)K+!0f@M zB5!~WFPs#HA}JhSBsPi_Gva?fwFwIwGBAYGw$X+M?Ik}DaWZ@en{>pzzyv(Y9EiuK z(AemQ@`k!78agOOb#4Ad9(DggzVp%oV0}tdOGkGg$i;Sc}XOsCv)I zkSr%A?kiOSZ}V%`FkU0uZ&GAv9S_#9*ljM|Xt{~k@ItpUEU55Xg(Yj)Sn?K^`~_#6yyc$N4opB5aD0idygP3A_sjo4WCQgW zRl%l7mcU|RC!7pa*k56(7rxM_n>yopO^>nCnnJn+T$&8S?TQuFVm#(b8?Xu3^ki%012^{(o}ASlHV4pJ});-(&m$5|-Fz~fP;$vxt~z#}z$Cqr5MkC5{@zq3#fS9S$p z^)3qjPu)W4@c{8(>9Edx^4rt>)v*!uf5M*CyAE$hFk6SD%*n6dINOdZpDyv$&)`E+ zu$HXl${}gRAF@yh?d}#=0Fhw{ZmAGd0idORQW_-hhz#J@lMgyY?yd21I4J-^L52Th zC^$jKZCjXEA4U;LWc(Nj(p3uzDX-0QAg$0OuJ?edq3>`EyAR7AFzf2WkevN;ADhninh0l$Oucfr9=u#1f3LUai3O4g)1#_q(`RW zR~~Y~76k`Yef^)oJmky6?{m-E&lU9YjY1u)`(c&+%oOHV9|R$Xi_G zc?WBpOfKU~#eW9hAp~&=js8zk(S_#?uezG%jP@m8)(E%6K-mpq2VRFQ6N{3}22=pL zDU7vd;r}Iz`)wM;GfObAcwf^&&;wm0yiNfa#a#1WBFg8i<+B*T9n_PD#}P9}R|Uw! zGu9%5yK>_(JX0o->@fVH(68c0x_roUMz?cL)65cRKG`S=9_g#aMY+5a%d4y2m# zflF9Xf$vbh@8$lxIFINV1>kJajXN9)<7fp0U-krF&a6B5u{)11pR9H7QFQO+J+3)z z&N*eZLGBSoE(}CYET7OtE`T`#ps>^C%F|{SA?`$=&K<5P*ot;6g~w`M2(qjR&~O;u za9Gu9Y%p(VKneQ>!C{qUECdBrAUW3V)R!;bKcMhL65CUFDp7b|?Y#4@q_eAIcBsRr z-$xmD&S`aO;1@%X;f(;MU7P?6Uve&7YB{W*(G>My+Wp_}Meg=|N|t!}W2o7y`KGL< zoGcdEJN(dTtyh{C%5x-$$I!yZ1#@9NBrji4x@ln?WW23pBnK6k-)a;4^?bYgR=j-9 z*$j6ptdZhiMTC#tR%f9tI~Y+#cQH4f6}>D{y(u@Cq5CXLRL!8T}jWKHI83= z!H^c0=@g$r?*~m>Lu+nSxJ(o(Nz?ak923=K@djPtSLTwhB|ibJ`0}0xo3mNp+?^kq zhhryQ9~iq(cw3zbm)3sl93?n=2mCcau{vPQUgK8}I9#Rso&v_nfo1ogu>SxPrFp{^ zKW^rqs%P&^HyJcXaGw9y@#FQBhm~gaWz7 zU0peY=p5##oD$j7|CC@14FGz$IE~V{UlX^Bvl(*M5J}E13{l%MkodlJop4UO_91}Z z6hZOl8O8zqP6_>v@dCDRnY01Y0@cbRX9>{nfVu+|dIPH&Jo7^ZGe|ZRASD-P$!E2C z$saovVIi=O_5XtetBo;lrCRnD^upW+^AM9lf7J+B-GJ_cpt^_60GmzEI3z)Vx-B5BGnD))<}~4msVJd%n$9F) zUTamYk}cQQKTrXrT3L4Sw+L8&?cZW?Lc>)sJ53V;SD60UBnd#SB^NI&m0Y+lRa>kVlkYy>#W_IRc!{l;wx8VA5G zp597g{M{di-uQ?)11IW0S}Q2|Sd3vT&RvAc?Lk!gU)LMQVhH|M_(Xq2|NEX7GRgA? zO1>X+s)%LsKR_AxV+gpRz}zNK{NZ0%t6wcTM^j-Fhz4`4LSTut0Q%zEMMZ26eX)|d z!$ac%H!#Nt1SVYzIGpV{oQ!aPGR8M0IjlReu9&?|XKA zVruE8(>KE&5o9aMKR+*yBADIAMPQpcQMp&jjCQ}D><*Tj8)EKls~ZsE2RcywDwc^a zIhHS*d0lqC{PoW^mjNh~^6QW7-mfHIf3QWq@a16If!WpI7_)gXkcg50lwbpmFV$}P zF08GFgkYTQmikjN^}yroDMGWEYg;Ut?;o;_U35`itx6_Y78-Tlura))yI+bzZ%qtu zP3%o(H9z!eg-*SS4^Jjk@)R=|L642HsVMn!Q0%}&YpO+S*!H(&`W6r2V~(S7+XcShELAD30!i z!860)i|@mdJ zx)_->=g9lif!DHk8-heteM2S4B4_mH%P$|zi&fu5b*53xyhii zotPr2#uSJ52@cv`j$jb_Hy1j0)dUl)`#IU|$^^&5bgN0UhuBoao|;#K%X2h!r(Xt= zDy-Fn%8Z&HFY3<>*N$~C6>dXyCNbUoFw3r?)oVe%jxBU)%6L z@p;G0+ToN;9UA!uQAYiq>A@p!)>6m}-P=!jpt)}FbOMIscPS#}`TOMO`b*>iyy6Js zXNJ9n;Wb!~FEU!h$BXF`!&A99&*A~Il=){eq2dd85-c+bhIS)tT@ovz{x+k}OZb$R zu;eF6>+QF$YC9*7;34F{8y{q}He+q*TPwaV48zQ8Pln z0xRD>c_yqH*@w53v{lK*_0tD#v0Z9W(gUM$5@R(~h5K+!Z}CkR=h5%hkE2QG1UfAv zq|p7*ItNc?UngoTZ9}2vFwU(_PkV*Mr8&U(tXFbzX0l&y7{B!)&Gn}xP1%mR(|dBQ zJIFT?wHZAt`^n=US>_K%kTah;!Sj<2%9K!3T9z4bcP5nI)7?i+0aZ|21G1C)4xX8G zkkW+OgGb#j!TXbdw|c7CRvvEm z?xh6MujG%b*YJdJ;x=dsc$7Uyw~sM#V*OqKh^1&H-Vp2Y-B`yLf@ZA3wdUS%JQ@WL zgR`b8=8eQtXt6*Yk<_-|9o$vUcVdVM*|LAYy8yPLcHlc8dC`q^;~yQ26u4kRCXW{( z;q|3$5U zxU|ztVJ!gnDaAXWCb9g*gV+s%=NSaAjuy|OaS%Z2>-0UL|&WhBW0$pG$JbUVh_=JGa`4@)E?)xjbJByt@|(rXd; z^HD%`*P#fTXp|<=s!z%aWal}^R+@|8l#vQWrNW21YJ^HQ4Co2DAC!%|WHe=F^R6cZ zh2+DCu+<=}m2p_M+V72X-z5m>>3IwZaO=TSrnROwby>2M)KS6tY0zHCY+_s?}a1jsO2Nah*X;ZP6MM5|9$OfOJ9-`@NLV5)dhZikGG$ z&45G!rG*v{L`nb=kkFA{rAZS63|#_92ays=LJ38xbSZ+sJKi^M=KWZ+_F8A}bI$BD zd!N~BzVBOLXj)b^C2cLE9E!)=3#R|kB05@aVhHz?|KxBE(lqojA2xn!q$0wg$?S(= zWkmlLr8CEdD|1db%WrB#Hne|>WeJlx}5W}PELSkcy$^w7cKEifJ{?JO_D3}9FCQ(?NOVATgCF^d{Vt3I-x zUAIjVAQ77zP1l?&OYmV8Q08CKRM!>--B=;K8eR=lW>Ogtr-#894cyf;E;puXnlM{7 z9*HnB%WyFI;#rnb!GowWpYiNm=XDbQ=O5)eHqwrI9y=6dXzUdwnc@n#mUFS$TTOD2 zh`n)MHgzo`><3HGdmN5&70)Fak7Tm$Xyz|hWggHtui1s0z)AO3Jr0RYzu#!9!dC*k z(`HG1+4qB=0LZrO*gY^-9AO9h+^{DYeOQ~4tHgA^?@xm94qiR>;*TA3%BtHZ1givk zFhB!*UtmUf5f|3N5;;stX+g^b|0Pn`{YGt^D%(>)tCIW%SuQTZ1xRT-;nBTZ-yk6b zDYT3Q*M#wS!p?>&#Kj8+aoMzP3}EALRT=GvRKOub(x>3?e!{?QZM_j;P{kBi^e*)L z>cH#=C!Qe92B1Fo{acwh{e+|QIEOyi4_OymgZ{*a9WgiO;S~0rvFlqn&SJ-yegp9mX2~* zt+fT?2d;`e^NaI&Cr&4FnCpGYaE_%ZAfA=@NV&9=ov9=EcIX0;;~9( zFNr&;O`$2sRI~klio0IzfOX_RL!EnyB_* z3E#Pv$_lPNu5Z0i%i(Qy6fhru90#L)%J`pTelmsTp!W2^dv2e<5Km)e6=Xb0RHwZ$ zdZNNffDnT7G1^vnjNmTA5ZF+fAH<={TpWNnHP@pFfv6+os!}00XVC}unF=CtVqvlRfRd=>cS-cHDulhrHmtETR?ObU1smToM&eu;9uO>{!R z!z-T0)+1##mbL>#k`WKCoAA79Cm`gZOxZ{TON2Jp)mBq}A>p7KR#xQ4f?!yWfQxB6 zp;h)=NS=t?y9Dwm& zM=3y=Vv&ewB4dCxJIi@1b;LL-cOQ*#PMeE#%W1MXbdS7tE5h9DOj-_3!OY6K0*WrE zDt%r9G0T~s{d{oLQrXtyx5!L#-P*I6^WVRA(@G$6kneTS6Ux1RvEr@`;RBY&zU@VR zA3hw(Lnoq;bUz~Fz7>0on8c{>VNOd-TM{MP3_#Qlba)_(Jj`1|emtKmq+hwoRyr3& zWDK#HzhSs}cDVlnjE$*`L=j1dQTm6gf$ub#6&7w8EI(?^UUSjvZjIf1i=L5xm;>l5 zKIq$018G{PH7~#`_^f@OF%kH{lrLHRYE7Hm(mqeM5i|M*V*Y@Dttd*`Y zd*RQ1RUqQTX}UG0qPt(fOz=ZDh zHnz_5-$N4@?|)&ciJ!M4o@`IZJ*kqk$Y29FoeG>!t>NriM7UgEj6gCC#7ymL@>Dwwj+IfOo#V0D)44)NXb0n`E(g z)-RpenH)`D;GM58KulkU{93=#>1mL(@%ngRG7ucs4@<1)wJ2p+NYLRo&?qE?=|BiT zO;VrVAWaHtlDK`UGvz;fpD|d{g2%lNW>C*X!J(wbXY5S!r<~0%e2SwtPI^^r=&r`= zFdAsod9}E^jx(oAWdyo!@#cmXAS_fM%d>M5Zk5DlAiku}9|W*q^TL~zsKy2V8=A9v zQSJ0mhGavRras=4tb|*+SyQ-syX3c9`zz<|I2zdQ&Re--IZ=u)!K# z*gf5~UCVQ6c_rBJ(FhW9r!Fkcoi2haj&lc+WTnH&syE)OQmaYmEhr#=;I~hT_X>hY zkdfAd4o@I*L`|2HJyJX($dv^FPIgHN)EfB`R&pp}Mty`=+L3cp+VSfr_nChkIJlpH zwkzpgFpdxl%StuNt^ImV3AWR4DbVR@%)+8|4E*6_0ZZMamoMuTkCG;)_1O+JUmrs>+}~y_+f16c!mz)RAHVQ2tBy-D6NPR7B!7^q90<0taCgmj zE#^&G&-2HyZ;MLmnTrg*8Q`BUfM7hQUtVS%gJw2e6TyDM6DVIpDT9tK-BHO#=VV}1 z<5oYpRzDdStee)94(tBAz#^dX-`GPD>`OVTmvly4@yEvGkJmQ|#p*~o;-4p;xfS$j z#1*-~eJf67C;2SXZjU!6!oQE`Pl=2lo9acMZAc|i(3Jlgt@Ni0L9O+WYuB80yto@u z=gRtflV5wXDY{K1&;`6ujmr`+*#=B`%npeum|TD1m}Bn=_rs*WDr)=~6BpBx{j0wa7r@!_mXTbsZ9^-iRG*)W_G-{r-6jLN8i`! zts#r@)@t9)mv@93$sSl_B}N_^Q+GBmxu)25+W-te!n)$ty;gc<1847WNz znwo)7f|@p9P3Q*&Qa%t1NyzhOneoJQZ6Z);iZmwxYy_+7UF zb4L07=#{b*s*bT-m3ZZ(GNI}(vQZ**y6whly4tE^#6+C>wb1pflvBEH>#~9BXs5+~ z`kSKpXy}ss2Usf~D43oO>;VIv2F=;EEdo!wuqh`ke8*h9|j!vjJuMyv#Lfk0% zIhfYHTuM5o>3odZZC-gEws=}>?^rovGxy|y@7$9lz$SXy{V}EJHu~YG_3wBgjETj^ zuHBgPg)W;0j;Qj|X~~tcYpU>LK#jtqwy1D5 zVFagkV`BcQQ-4>3W4}^4?*H2f`PSs;7mie)mZiE`$D=oMh_5(H*D6WT4nRyw(c)P@ zsSN#gEhJHNjkJ*`-I2N?V6G_j$T%ardYg;y*UnSlUEC?P=ICnx+W+D|HN zyt_>|bDTu)C2b{_Rs_po&N@YLxh>YWE~DD!4AQ;r`W%pY$0*Sy(wtT=)K>)yUNPvyxO7hk8lLc_ZCBId{TotsemfCa$n{D;>0Z^{ zdpUFU#&nVR ztBwm6mDv@IkNEJt(6wl1q_sMjsQ`-Erl;y2L`cFkL|v2{x) zAlS{JoBJAbcO}W$4+)x|7((nBVH6eEE@`OW)Q$T6b@W-uMi|JR(V7D4EP_;pzK%Bf zWzJ#tiJ{{Ea?wWhoM!1C=a=|z|D*J!NSxc43gW)?F*ma~ro3HS;7hD#^+UodggJgv&l$mpjf6lipBVYjK|!s6%Om{|uDmJ=hzO5< z;jO-~%osWd=E`G6{L85xABpG=S9_l`7I4|fDuVm~_-MCw7L8}>I(QixW^kjKm2DbV zt`ow%8F)Nihhh6hNh#yQ;H3A=GWR&K@8D!D;F@xameIUzZh^$0A(eZvu!5p(z=<|U zkAa)2hz1UWa|@V(M05rmaa}YfV|DANsfy8so2KCN?}2&AXU6J1lQL?AYTwNRnw;bm zI6*?C0k2I?DX6o4}2-pnS+ay>HHqN zkO(JwjXji^eeB?%q2gHhRCB9h|E*G#7>F=a0niX~$f0;FFP94pI50D`wvK?DDwqZ&FJ?3S z44D^(fHNvw9jKvTUNT%i&WB}1T>$i>q6}K~6uJZvE9P#{P*SiQKO|JSC!O&ft~6zy zoy$W}8LUO4%8ddYdOe__$^{vIh9OBq&MRE_Lp`<8{APou!l14{Wf#ud1=GU;i$7E0 za_A6p!zM}5&WBibOiUgjeCiq*R0!WXQBkq7R2yb} zUcJfrS$?e5*x51!d!&3Yh~>nLeI6uFOvJ)eSMjiSv{{a3MLY{BIj9Wf0fc;<%_Q6= zH(%DeyR{1W&_}+;Kd82|7_)h@=XPuWJD>jceTr8$;pH9|4w`Wh7 ziAkL4VIwx%`LieVAWfxiKa$D@c(x?n({W3jPBF(%)N)X&jn(y+mcJKH_N${5PrJhR z{kB^B0a)$a>FE#v+Dz>@ZQ8f=+ig0TmYzBq2V_l;mYJoegil@^Ev~g4`R}cyI%hs? f+V}tMe7blrJLVV21wz3b=4I diff --git a/src/main/resources/schematics/desert1_16.schematic b/src/main/resources/schematics/desert1_16.schematic index 96e8206c32ef02afce5d1229a53b4bf3a8f650a4..0b8e01555705d9776a4473a729fadee8dbcd8cd9 100644 GIT binary patch literal 25420 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 literal 25125 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 Avj6}9 diff --git a/src/main/resources/schematics/mycel.schematic b/src/main/resources/schematics/mycel.schematic index 3cb2fbcbfdb1d0be682a45dd71bffb2e26abae6b..abfeb781d7735c8f750379e3a4df35956162124d 100644 GIT binary patch literal 10376 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 diff --git a/src/main/resources/schematics/mycel1_16.schematic b/src/main/resources/schematics/mycel1_16.schematic index 52566ebe1a47cbc4b3b6744ce4324cbe9263c31d..1fb3edaedffa60408ece5bf91d5edbde1de2e28d 100644 GIT binary patch literal 12044 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 literal 12157 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 diff --git a/src/main/resources/schematics/normal.schematic b/src/main/resources/schematics/normal.schematic index 8c8dc3bb04cee337687b59b0a767e13b76be31eb..5f3a8d9abbcc5150a3168ca7096811241dd04494 100644 GIT binary patch literal 20130 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 Bx+VYs literal 19972 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 literal 22386 zcmZU)bx<5l^e&7o?haX;4ek)!9Re(iy9N*L1lQp1&f@OyCO8BqxLa^{*URtTs_&~? zcmC+-bk&@mo~b!q=R8k0MHDj3|GwVGbCi2)aF@*0s_j>3e1Ne!o=w@tf}}=| z|I#s}rxPWb7R43jZ|sOc4YVAYrVK-n$~jCn3!djkw`-R@i}fmn^{9K=_24n7*e}!| zeM&q&J~8s_`<_z|6=h`+zILy-abAZB);HPv)~>FXmG_gkyFAwSyYMrIy`4WsxxXJq zm)IQgT;Ep(eB3U#wg#56&d&X>{r|&VP_7Xb?cnQha~@Uq`06tFU($V-pV!+-T$iYS zBa`>r(Q>WIy8rcH9!2NF-LI%{OMd|$uj8Fpx-S2h-3}xb3X!&F2dvy|{jP_{@Wz$% zQ^sS)-%DD{ug~+>L=LRVM#6%>+)sDzuqrw2jUW<{# zs$Zki^RG9o-Q{!A>StwM*_d?!uk-Cek31o-r>Q>Kdy!ANi*w%FM+uAM4mZtMaX4CAfsHz~ zdjIO|mqnagDzh}mco{Pk^<%lx>Wgh;FvfG%C->&+j<+^I8!Zk$nHKV$b&|>s>86~% zmCJL#aCQ@1uNTFMct30o6UB-6J8J)y7;s_(?{<@-jW%Bs-UY8WbQKZa4ehS-9XQ7k z?&^7ncD-*7ml_F02=KG|znV|FVH7QX1ratL?;B_VnGU!gu zDd8o;Xh*RQQ9?c&;?GL)h&|4%IW48(JpKuqR z(Ylj5cvzlTk!f4`YuFSxT*z2<+{rS@v)y24ySLGUWr>RISns7 zjU&WySgn%=?`AH2>RH2^+rd-aB~@pgk#svdYvY{wcb?m#V^_lM^lgN#!G3GqX^OmZ zG5oIcm3~aM>b2#4GonOq`0f|7`O?M8Tk-zaus&X^$WHN9zeV9*LSbT+9kbTP^X$;i zKYU7S*@XXXJRkf^!^#!${&Ak9a=y*-+BvgzZr4=2k!7V%_?zj)eb84T#dd!HZrP6o zY2)m25c!DWLb2XILQX zgea~vS=S&N3fiV+A)&J#=96dYm$w)B?|Eq^JWhoC&*}VdvuO6J$m?|!Z_2?{DtoD1^MOcDL6k$k#i7Qxl!`Z;o#>OUI4-;e>=bNJJ4!dPq1C z)}aTnLaXfET-IcVbzc?3ymUFoW+qUt`(N$T4={kNtOqlk;>AvFZ9$pr5XG^-HAW-<}4~~>F}G%;7?u7vsqjxx+Z?pLYcIcZaSmY*PF{E zCJL|D$~C>5ms{S_zlOh`?pil;y8JHFuC<6te^I<_70DX?xI8dYsqy!Cy2@H(@4TO} zzcK6*dcRv~-2auD_v7;6tdzq4YQWyJOK?qi;pXCxDz2AAV8qDmksLwzGw`XPtWH%i zEJl~gE`)AL;$QJAz0`)!F(P8o5~-}rbP`aiI6W`WczX7t#7vNd1l}f;7@K^3Ra;f) zH>Q-ud`#}C4?kJ3&2YM=;-9AFC64MLe_Rfh3n%_g;H@;er18UU>Wi~x_{g8Z@mFN& zg2Xb;Z~ZkZB=#ir$6tg#wVt=e5HEZ8-Ff8w@SQN6^3+jU7v+My=gf_RZ z-1O72GX052m|9`t^P}YE`Xq=tY%Z?#yeKum{|yyDfs{$1M06LH%QSt zD(1TwGV(bs=1aM8oasLqk3HClPTQx9g=Rk*(ZlWh9;?~ESaI>@qDeyM zB+Qoo0h@q)kRj)F;T9luwKm^W+vQ`?pwW+p^@KmhRb#_5# za)q9pmCoI)v1k7+8UrZb_-{>!h*ShopPV+^b1wqZghD={2Qm%R+KW~$HPB*FtDm9cY zV1XMt64~96K(0xClePyj9?U+J@}Y1I{)&nLvyDw{En*fN7r0vC$M;aQlneud)VUqbZ|~i#G4~jf{_Fbgv=$ zt3PoMJr#8GUpatH%@x7F)#+L9GlJXc^Y@i-6migL?Q+{|3|^vLm4Up?s<`N!giO=RRSqegY&?^7IHj32a`+p~TV*6U_*Af_XL z(6Q3WEkeFFhd2Zs+VlqR$e-WKjJ3jDFNBzpNS4%-aK?pl~JbjT14Qtc&fo8@#Z9( zKR{cCa*dDhTS~{&`TB}`V-V$_6(nCC$Loe2WaRvke6hxS6zvfobMq57qD3CZ&FQ*G zL>^fhVAJD6Pto_xdz^@?66NZ+_@G2Ln&K^&c|{(T+AI1;_k=r-P&8UF2hvL6tK^ivO1Bums_{1-J8lYf_O@{` z*5svJj4$P%Klkp@uJbN>7L(! zn*6_~1D$L|BH6zU5l-PI0+U(C;bGzenO4I3;;dYg@fm?(W9Z!G7Wq1yT$4A}x`6G+ zNvn}OI?wcKS=L+ElbjK0ZgbW`Di@sb#P$fped<3;xN7odi2HDaitX&hF0k8oJrT)v z8!6*}j!Z^M51eOJYLe-A`6L;+%#dsI@*RcXYwFR=hnCY|Wwxcx6>c^+hf`I}wIdQV zf)TU7*aDEbqeFWee z4o`0_R=NE8?`Zq&DGCGd=UFk=qsD@!(kyYs|K%IC(rTjh ze(G1j*2bBMQ?m45%(Pe90`jjTUwIDqf-@?vyI3-yBBa$KQ*YC*hnmJR-ljI)V>dUW zGff&y(27yK(4ZP!Vb?jE{K~X25xTJ-#^&sCq~8p6v(ZJr_p+yuE?~NpCiwhw-ek#w zcL)V~+7Na_J)Qb`=qB~Z(B~5$FEsP892&3xRbwLBo_8}J(`&75nLje{D$Ox|)7;kO z5z}RYj;ImJSdQvZ>5-ENAr&@DguOt=Z6ejYt~B%LK74mr^5`fY1vuZm>x?<+e$*LD zTQj`tHkkN6kN3^!O51mUT#lft7T(xLvr z^P4WeQTr3$vsUu zN`VW*qo&+2(H_4R_UG-Sf3mo7w!;X%ik}bkIK?+6!j{PMaM;=PTxE=nOYW0-7hvtG z;zim1s=K|iXBm=zKY|HVC~GyB=pev7atdH&Elo7L;n)K(!qRjEmGq^iB1M16@M?m^ zdj{BUr}w6gZMT|}cY&@SP7}Re2)6^Gz6CGFfMDFsP{h(u>%Tw$;wRXbt_BM+smP$|RjC=*-K;v~l&k2=cYn3&=u@uk zmYK+tW!XEU2H#Dos2XW{u9pr7QImGrT*kv^DkxWK{9?Wp{loC-XzOPYM6jbxAmfJU zlQ%%4)BpW!`){s01&fiex2tH8W}`y2m~*{YwU}JJ-gCI}cop8)z$G_{##|jb?)MD0 ztrhgWxt}Sv*GC~q)`mH9$=n+fYmAL3DCrhmqS=a#d9I;LJE<8;Q@y`(Xl)kWO0*nK zmXR8pte)i(wVk)|A{7e%kfCSjz>j?M+ah%xmKs(O`Y00Zx9@lf-j`wq{0WU3APuk8 zr(J7TiJzj_ycm{5GT%cbfh#{%?ga~#R%DqBhEoU)8q^$LFmSt4(K+lHMb>Nmvs${! zAC|Thb4SQMzORVjiV|U7+SB>1KXA#$MW6;V$im$u$*;>Eu zvj{*e&MZd94A=-kiD$raSq~`r8j80o7*qc$)$6?Ncn&%h<1}+0OOeCcW|*Ee;SlAI zICp&j?oF8Xl2zCzW61Fcaus0>SHBzq(k(Slmobv#o-`qHA+z!T7sd0 znT36EHLYNbY#1i&dwhiQZX9UP)J2A~OFKe%EZNP>2s4RC_`)id8uKs_@m@-7)+V1l z+@fRxHyj-ppPmS-9@QE?EI#z+uT^i*Xq(FN$KsRsOJOKdeVo)~wpihDX%cZ6->e-7<9L z0UgKm#(?TC`x2sb-Gm4W$(V)x{lt{L8G5p_{gmP zJ*i%BccOBvU#=ced#Z@MK3rE~ugBCH<%&FS56AfIv;8&N5P1CM|9-J`@|TF>?K-@6 z!tZI2$iXnT)BDXx^d&Co(+3Aq+2wY{tM&fA^+Mq<@_u={`|i@JEb?-XmFL!c^0xm` zO;W74Ge4e-{uX+DJh}B>ZD+Q1$a#5sCaRst?GSn0+sfPc{ctxoEXbDIW$>tF$(EPn z@9+Ky@8azIyfrY|h*ZmJsQ>cg`9R^%DA~$w(yM3}fBWszk5;Y~x1L#Y90PJ4<2bpE zy90I+_;VbBW*hr#S8jeYSHYjMVLlQd(9SfxlQ||GHaBh@fP>UDImX0_FR|bsav0)` z0RAU2@6KEdqHCMoS(ut5Z+7=uzHY(!FIU>AJ{)FD ztM3;8dfOsDuWw`sczuTlWXky-Uv;IoIP!&evZW>3kO%-8KoeYAOxZ+Xp!i*YCd@O% z(%)Z$f@E9jm$mDpBc&?j>#tVm6l8|`KfIQ%**tu5YW-JQ`JJYbVR2`5Q?9u(v9=II zkdIXlG$}#mN68TZK76=@TXNbFc*a!iJyPtb$EA%h<_KNrQ>DS!OM$;_GZ$csCT@bk z516uBg4qG*-C+%@PFp4EaUBI8tWR$={;1%w#bL|oC)#Qw6!ftJ&>=AkxUDJF))gaoVK=Ff6X1`V%D=Lv3~ zHfWB&bPmpa{}FfW=d`G-aNL4@DhO#hN0<^ZY$wFMKi3Ljk?pr3xbePv#cfXQrtrv2CPieP)&RQQo_7>_+JzY`SEwDH9Dq~{761Lg6 zpH4abvvHr89(0NoqbW!3^IPjOD4HgHQa--VtWMAO5NYFm++upSG_uk z)c=-w6inz4Bi2wBJKsS^mXa7P*~+qA2GPoLk_5`%tOMQMp0sC~`bTn!nBv^?8FD+T zh5WpAb5G>G8t8V1bCcchO>`%5eYrDbSzF7c|j@PW!chpIFF3_T5HuXBm8Ql$R`5}j*?#Oe6N~|+|s7#Mpq^$Hs!wCYT+yB6-ArZcG<64 z8nm7bAJ1>+i341oEN_~RMYfmSR1ANKOrUMeE}<=dGm(M*4Hst6zk@n1u`%eMA*c+5 zj*_FL^)zkLj*=^;0s?;y+I*{TqSYq2=d9QQ=P(n6SD2e;g2RQ{+pHpOS$*!I*h_d4 zJ5D0y2&0B{g0XwDQ#0Wvev@gxe5#ys4TbVUzECOOYCkgDk60bn?z3f6SjLp_(S_Vq zVJ{ztOd5Vz&<`tgQbZ5=)J@``j|5?vndG%)b69b}JAAl`Fv!Oc`OKP%FY_;n3L-&Y zZ!VfmFP@J;83xf&c&4M5sW{8SPDPoYw@uTamvV0W0m45KJ?t~LpbM+q?`|cWW5mT} z9_d13;$!Rv^d_8{95(IsM9Jep4C2z)JCSl_;lea#

    v@p!C0khYWC-fwv<`ga2V z8t6hshv>Lu^@DYG>AgE7#!lQ!E!ZM5@I;alIr`$>v-75$EmTG_It(XH8h6KX)3~~P zoGH!MkT4_EdZk0Ev_6lJ9f`B>h`?>C&$1IrQ#eRa@ywwX7n8Fj2!8^hecqj!#I)9N zH4pddk_xivi874!+M0C)nvPr3;tQfhWt}CfX#g3sL#IG0yzS2N-?@PN4>sz+;`|bR zdkS=gsb~uN+SIkUy%+B4@~}$ES3a;NizsGs)g829IcdbE3)yuGHg^=1aVaS?=JA=08}U;J+f|o8!++F+y*ScCX-%Df{Hp0Hs+Re zyqUF{ri}O*GFW&c6*!9rfT-YG9RI8#ivtzVNpLZ-(37G{Ed4yG3UjUl+tM__&G8H^=I0_3gqUUye^Xb>PMk)7 zDB#I4D5Zmn4>1kl=l>#;Km(H}5pqI4*J-^1?kc({BP{A*8Ri57f6rq*5XQf%aXdMIk~TzqCMOGDV^V4lZH|E6jQODU4sCVLPwP5DGZaCbf#xfy##omO zo({*Oz|ffWs*m+pY#CU$aR}?mEZKd z*8>Ovu}L5Ki*W~d_%5)#s*}(5MgjIXrGFZ{L!G+EYKh(?g5s;LN?oS-SNhm5C|@n} zsaKQ0l1I^zMy!jo*Z?)e-TKB#ou4m%ko@$iUX})KkN3>C;W(E`miy)Qm8kZuDGPbO z*8k1)e#76(N9)n(v}Ej-j_og-d!y}d+p~ej#y>N`3n`c<%qO9kte%npg^g^Hm5w8aEOD^luvpSx1zJ8itQuQtxIL2B1F%QcW9Dd1LRYk z8&2o9rEwz%bq*^PJ+b8Xs;sjn4le8S^VQ%bhIK1GQQHO-vH?luH@-&N#fY?qd5iSC zAI^G-gKt#d*!C^?3p?|%Zvl{5qMO3bc$OoyrNU0I{wz^lnS-;FCdIR4N*;UmQ4|E; zOZCVqfy5f^>61oq{&kY%zWH*HGA?mLsINHP$x0Stnol5IaJCZwc_x%Q)zgMN&r`sEFY7?n z_G$g^8J3!cAt{u3XgxI|mHa}{>5vLvCs5rUAl@FzVqZ_=Q+C1VB^Qpb4B(tdn6{wS zz{Dr|f$haNo}#CWgI`Bo26bSl915(A-8zZIK0tsB;UQ3AkzWj$vl9yGqx7h__QcQ9 zJpP-~YdPYAxX=xPB?lss7$N=YDAb?9mng*r-b(P70G!E4vDas&?Z)H$M2#DYv9km2uyI4w%fFZMD zXeEvD-yJB0!`L8p@jaukLV>EH0zq{SieVjzr0`P%Wty?a4H_Ikz)(>kr>ep8>{n=2 zAMv0s-?KZu#>QW*Q9Pro5j1ZzqEa5&m_{&=iXN(M?Jr?nU&E|&%bJW>NzJ28P~KCK zI%}-qo9SbMp($-uS@Tth4qGRo6)y%+rJ0lTcL^W9mJ+{)%$WvCA!EBCeMu0-u|B_o zoCc0W1r3KR$hyKJg8xpl(;&O$2@*Ca4!gR!y+CAFRsDBtC?3xKd^$Kjnm73Vm8j2`?Fpv9#MQfFRyw3j? zxFj>UKI$j(8n495JQx$GSIN|(>qN9S%+ZDutW<986>^S3W2-b=s#}xS^Kfl;dfsJ= ztcHw=`M5u}ze0$2mJz^TjM`f$2awY23_z&$LBSc*% zp>QM;UqcgG#;JSTlQsT~N?(}~`9arce9$#Kw$F2gbr#i-@=3-jiL7ZY_0?Sut+Qy& zB8@82>Je~}29)&sjmgnd0lrdMp4$I(tEuO#2+CzDEy|~;eF|73B{lyTuxXh%EkRS9 zkakYy94F^zotqTm(~JEPi!IdiwG-6E%7z#r-!*Y;8mBO4Dw;gv7F4NejBzxuICYB= zZR?Dhohzx&3xoB#v-5T%mMVle^rRz~WCSOuRyBiimB!4dn;cRo&HGZTr-wAawV$m* z5G%KEaoaxaFpBGip_YVxD{`}PrpnK^yV46BU!z2WOn-cGvdV^HvlL|kO_b^S;Tctl zb`2D`hW=cXilP2~GT&FQQtF*ZQ+^dS;2VKgv%a)G3vcYxSTZ{OHm;0j(tSRTy#|R# zod)W#=72&ABcwqiA+b6#*-oPoq?e-Hpm9j6mqNLedG%j3T%~ETE&;<_g|E3g~tIs8JR-hWGH`mOYI=~5x?EAeO z_8G@~tuXxtAz(INyw#=W|cIV{9@=O+Yfz+OUQ#u7+Fh@{vB>oqT zpgNSUS7-0kje(TFR{#Htq@n0oHN}msLE@wZHs>D*oc;HoN_bAuO9jgALc(?x0EgH) zyV*61AUELFPI$4oH4pEo2WIs8;VtP*F+HKyEl*Zag!R8lrUYSNoRaa4?d4xa%{xuB zhSu`t7D8Ib!@;0Pz87s54X1NpGypO%z#n$m-&{u%xC>tH=?G=n`E*Yx^YAAm)JwBY z3vH{@ibB0{q*E7sR}chVPOF2^Unh;ncw^IUkG3kJaR=5b_I=2kDT^y0jaZ2CnUej) z3Po(3S?%{q01hoDzVe&)^_6U!@$_Gex%ecs&$l<)1PqI|H9wr23U2s&*2Bu2FUYto z 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 V{oOGC+rH4r{{xb@^-^q01OOlB!V3TZ diff --git a/src/main/resources/schematics/normal_nether.schematic b/src/main/resources/schematics/normal_nether.schematic index 088cfdbcb0ec98e338ba884606fc5200919aa6cf..d4d24a96ca54a9e2f2a42fecc275f5b66c693b4d 100644 GIT binary patch literal 29211 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
    bk?-t6=R7a{~2|hI7{{trK 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 T>+P;me!)X#gjMeOGXwtz%;J#I diff --git a/src/main/resources/schematics/normal_nether1_16.schematic b/src/main/resources/schematics/normal_nether1_16.schematic index 3b8fc3c6a94c29af6524ee1a1a3e0aa97b697674..09a4c23350c11a4243e1eac7266f0726b9816e92 100644 GIT binary patch literal 33642 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 MB8)4HMX^x+A2uA!F8}}l literal 32320 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

    wZWXyw#3^%?Cg~) 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 literal 44629 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Ơ*Gi6qn!nj{VYx?PERd2q-6wEYEAuLXt@IAukcsTym|C6?*g@|V^-$lw&W@a}ix#H65OChGW=G5C z`qQb=b5FpdO+0R&tEeD)^4J{n^|5HtD8Ft>A3W-$Gd}dqY-FV1RrK6ob>A$TTqkIp co35MtIX7BRojuo_I|sjuz2sH$_+OC!2iJ3U!2kdN diff --git a/src/main/resources/schematics/normal_the_end1_16.schematic b/src/main/resources/schematics/normal_the_end1_16.schematic index ffbdbf7cafeca596c9244b5abcef41c61160a363..41dee13aa7caa5d85f7405d181366de4575bfd78 100644 GIT binary patch literal 48832 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≻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 Y;BKv-DSUwXzWw*XV31MWtd;kCd literal 48268 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 g`{c8iAARxS=db?zSJ(5uE Date: Sat, 20 Sep 2025 22:18:11 +0200 Subject: [PATCH 311/600] Added built-in placeholders to some menu titles (#2632) --- .../core/menu/impl/MenuIslandBannedPlayers.java | 5 +++++ .../superiorskyblock/core/menu/impl/MenuIslandMembers.java | 6 ++++++ .../superiorskyblock/core/menu/impl/MenuIslandRatings.java | 5 +++++ .../superiorskyblock/core/menu/impl/MenuIslandVisitors.java | 5 +++++ src/main/resources/menus/banned-players.yml | 2 +- src/main/resources/menus/banned-players1_12.yml | 2 +- src/main/resources/menus/banned-players1_13.yml | 2 +- src/main/resources/menus/island-ratings.yml | 2 +- src/main/resources/menus/island-ratings1_13.yml | 2 +- src/main/resources/menus/members.yml | 2 +- src/main/resources/menus/members1_12.yml | 2 +- src/main/resources/menus/members1_13.yml | 2 +- src/main/resources/menus/unique-visitors.yml | 5 ++++- src/main/resources/menus/unique-visitors1_12.yml | 5 ++++- src/main/resources/menus/unique-visitors1_13.yml | 5 ++++- src/main/resources/menus/visitors.yml | 5 ++++- src/main/resources/menus/visitors1_12.yml | 5 ++++- src/main/resources/menus/visitors1_13.yml | 5 ++++- 18 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBannedPlayers.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBannedPlayers.java index d3efe852e4..b55db89420 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBannedPlayers.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandBannedPlayers.java @@ -54,6 +54,11 @@ public Island getIsland() { return this.island; } + @Override + public String replaceTitle(String title) { + return title.replace("{0}", String.valueOf(island.getBannedPlayers().size())); + } + @Override protected List requestObjects() { return island.getBannedPlayers(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandMembers.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandMembers.java index c6f312052e..40297ce6d4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandMembers.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandMembers.java @@ -61,6 +61,12 @@ public Island getIsland() { return this.island; } + @Override + public String replaceTitle(String title) { + return title.replace("{0}", String.valueOf(island.getIslandMembers(true).size())). + replace("{1}", String.valueOf(island.getTeamLimit())); + } + @Override protected List requestObjects() { return island.getIslandMembers(true); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java index 6d8d76b5ec..88a6a12d5c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java @@ -69,6 +69,11 @@ public Island getIsland() { return this.island; } + @Override + public String replaceTitle(String title) { + return title.replace("{0}", String.valueOf(island.getTotalRating())); + } + @Override protected List requestObjects() { return new SequentialListBuilder() diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java index 8f80c59512..c26e274897 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandVisitors.java @@ -76,6 +76,11 @@ public Island getIsland() { return island; } + @Override + public String replaceTitle(String title) { + return title.replace("{0}", String.valueOf(island.getIslandVisitors(false).size())); + } + @Override protected List requestObjects() { return island.getIslandVisitors(false); diff --git a/src/main/resources/menus/banned-players.yml b/src/main/resources/menus/banned-players.yml index b304f4c567..70381a1152 100644 --- a/src/main/resources/menus/banned-players.yml +++ b/src/main/resources/menus/banned-players.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Banned Players' +title: '&lIsland Banned Players ({0})' previous-menu: true pattern: diff --git a/src/main/resources/menus/banned-players1_12.yml b/src/main/resources/menus/banned-players1_12.yml index c40187a181..e3e179a3b7 100644 --- a/src/main/resources/menus/banned-players1_12.yml +++ b/src/main/resources/menus/banned-players1_12.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Banned Players' +title: '&lIsland Banned Players ({0})' previous-menu: true pattern: diff --git a/src/main/resources/menus/banned-players1_13.yml b/src/main/resources/menus/banned-players1_13.yml index 0a6017bc9d..61655a4862 100644 --- a/src/main/resources/menus/banned-players1_13.yml +++ b/src/main/resources/menus/banned-players1_13.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Banned Players' +title: '&lIsland Banned Players ({0})' previous-menu: true pattern: diff --git a/src/main/resources/menus/island-ratings.yml b/src/main/resources/menus/island-ratings.yml index 7b7555c15c..1ce37e2648 100644 --- a/src/main/resources/menus/island-ratings.yml +++ b/src/main/resources/menus/island-ratings.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Ratings (%superior_island_rating%/5)' +title: '&lIsland Ratings ({0}/5)' previous-menu: true pattern: diff --git a/src/main/resources/menus/island-ratings1_13.yml b/src/main/resources/menus/island-ratings1_13.yml index 5f423f11ca..2c46a5edcb 100644 --- a/src/main/resources/menus/island-ratings1_13.yml +++ b/src/main/resources/menus/island-ratings1_13.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Ratings (%superior_island_rating%/5)' +title: '&lIsland Ratings ({0}/5)' previous-menu: true pattern: diff --git a/src/main/resources/menus/members.yml b/src/main/resources/menus/members.yml index ddcbfe16c8..55d3a10c74 100644 --- a/src/main/resources/menus/members.yml +++ b/src/main/resources/menus/members.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Members' +title: '&lIsland Members ({0}/{1})' previous-menu: true pattern: diff --git a/src/main/resources/menus/members1_12.yml b/src/main/resources/menus/members1_12.yml index 2756fbca86..23f3f79e51 100644 --- a/src/main/resources/menus/members1_12.yml +++ b/src/main/resources/menus/members1_12.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Members' +title: '&lIsland Members ({0}/{1})' previous-menu: true pattern: diff --git a/src/main/resources/menus/members1_13.yml b/src/main/resources/menus/members1_13.yml index 5d684d2c32..d0598837ef 100644 --- a/src/main/resources/menus/members1_13.yml +++ b/src/main/resources/menus/members1_13.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Members' +title: '&lIsland Members ({0}/{1})' previous-menu: true pattern: diff --git a/src/main/resources/menus/unique-visitors.yml b/src/main/resources/menus/unique-visitors.yml index e2d60ab557..bcfe0b9095 100644 --- a/src/main/resources/menus/unique-visitors.yml +++ b/src/main/resources/menus/unique-visitors.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Visitors ({0})' +title: '&lIsland Unique Visitors ({0})' previous-menu: true pattern: @@ -29,6 +29,9 @@ items: lore: - '&7Island Owner: {1}' - '&7Last Time Joined: {3}' + - '' + - '&7Left-Click to expel the player.' + - '&7Right-Click to invite the player.' '%': type: PAPER name: '{0}Previous Page' diff --git a/src/main/resources/menus/unique-visitors1_12.yml b/src/main/resources/menus/unique-visitors1_12.yml index d3272e3409..6491657a76 100644 --- a/src/main/resources/menus/unique-visitors1_12.yml +++ b/src/main/resources/menus/unique-visitors1_12.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Visitors ({0})' +title: '&lIsland Unique Visitors ({0})' previous-menu: true pattern: @@ -29,6 +29,9 @@ items: lore: - '&7Island Owner: {1}' - '&7Last Time Joined: {3}' + - '' + - '&7Left-Click to expel the player.' + - '&7Right-Click to invite the player.' '%': type: PAPER name: '{0}Previous Page' diff --git a/src/main/resources/menus/unique-visitors1_13.yml b/src/main/resources/menus/unique-visitors1_13.yml index a6c7b2bbb3..1680bf42bc 100644 --- a/src/main/resources/menus/unique-visitors1_13.yml +++ b/src/main/resources/menus/unique-visitors1_13.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Visitors ({0})' +title: '&lIsland Unique Visitors ({0})' previous-menu: true pattern: @@ -28,6 +28,9 @@ items: lore: - '&7Island Owner: {1}' - '&7Last Time Joined: {3}' + - '' + - '&7Left-Click to expel the player.' + - '&7Right-Click to invite the player.' '%': type: PAPER name: '{0}Previous Page' diff --git a/src/main/resources/menus/visitors.yml b/src/main/resources/menus/visitors.yml index 23043e6146..3e131e1885 100644 --- a/src/main/resources/menus/visitors.yml +++ b/src/main/resources/menus/visitors.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Visitors' +title: '&lIsland Visitors ({0})' previous-menu: true pattern: @@ -29,6 +29,9 @@ items: name: '&e{0}' lore: - '&7Island Owner: {1}' + - '' + - '&7Left-Click to expel the player.' + - '&7Right-Click to invite the player.' '%': type: PAPER name: '{0}Previous Page' diff --git a/src/main/resources/menus/visitors1_12.yml b/src/main/resources/menus/visitors1_12.yml index d47d6c278f..56b3fee0d4 100644 --- a/src/main/resources/menus/visitors1_12.yml +++ b/src/main/resources/menus/visitors1_12.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Visitors' +title: '&lIsland Visitors ({0})' previous-menu: true pattern: @@ -29,6 +29,9 @@ items: name: '&e{0}' lore: - '&7Island Owner: {1}' + - '' + - '&7Left-Click to expel the player.' + - '&7Right-Click to invite the player.' '%': type: PAPER name: '{0}Previous Page' diff --git a/src/main/resources/menus/visitors1_13.yml b/src/main/resources/menus/visitors1_13.yml index 490d9bff48..72b797405f 100644 --- a/src/main/resources/menus/visitors1_13.yml +++ b/src/main/resources/menus/visitors1_13.yml @@ -5,7 +5,7 @@ ## ## ###################################################### -title: '&lIsland Visitors' +title: '&lIsland Visitors ({0})' previous-menu: true pattern: @@ -28,6 +28,9 @@ items: name: '&e{0}' lore: - '&7Island Owner: {1}' + - '' + - '&7Left-Click to expel the player.' + - '&7Right-Click to invite the player.' '%': type: PAPER name: '{0}Previous Page' From 35cb366ddc58660e6605b54eb52e0d74211baf0a Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 20 Sep 2025 22:24:59 +0200 Subject: [PATCH 312/600] Added admin resetpermissions command (#2644) --- .../IslandClearRolesPrivilegesEvent.java | 8 +- .../commands/admin/AdminCommandsMap.java | 1 + .../admin/CmdAdminResetPermissions.java | 82 +++++++++++++++++++ .../events/plugin/PluginEventsFactory.java | 4 + .../core/messages/Message.java | 4 + src/main/resources/lang/de-DE.yml | 4 + src/main/resources/lang/en-US.yml | 4 + src/main/resources/lang/es-ES.yml | 4 + src/main/resources/lang/fr-FR.yml | 4 + src/main/resources/lang/it-IT.yml | 4 + src/main/resources/lang/iw-IL.yml | 4 + src/main/resources/lang/pl-PL.yml | 8 +- src/main/resources/lang/pt-BR.yml | 4 + src/main/resources/lang/ru-RU.yml | 4 + src/main/resources/lang/tr-TR.yml | 4 + src/main/resources/lang/vi-VN.yml | 4 + src/main/resources/lang/zh-CN.yml | 4 + src/main/resources/plugin.yml | 2 + 18 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetPermissions.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearRolesPrivilegesEvent.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearRolesPrivilegesEvent.java index c51b1ccd7f..1997409700 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearRolesPrivilegesEvent.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandClearRolesPrivilegesEvent.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.api.events; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.event.Cancellable; @@ -17,16 +18,17 @@ public class IslandClearRolesPrivilegesEvent extends IslandEvent implements Canc * The constructor of the event. * * @param island The island that the privileges were cleared in. - * @param superiorPlayer The player that cleared the privileges. + * @param superiorPlayer The player that cleared the privileges, or null if it was done by console. */ - public IslandClearRolesPrivilegesEvent(Island island, SuperiorPlayer superiorPlayer) { + public IslandClearRolesPrivilegesEvent(Island island, @Nullable SuperiorPlayer superiorPlayer) { super(island); this.superiorPlayer = superiorPlayer; } /** - * Get the player that cleared the privileges to the other player. + * Get the player that cleared the privileges to the island, or null if it was done by console. */ + @Nullable public SuperiorPlayer getPlayer() { return superiorPlayer; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java index f080107a37..4e9910d4ea 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java @@ -48,6 +48,7 @@ public void loadDefaultCommands() { registerCommand(new CmdAdminRemoveBlockLimit()); registerCommand(new CmdAdminRemoveEntityLimit()); registerCommand(new CmdAdminRemoveRatings()); + registerCommand(new CmdAdminResetPermissions()); registerCommand(new CmdAdminResetSettings()); registerCommand(new CmdAdminResetWorld()); registerCommand(new CmdAdminSchematic()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetPermissions.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetPermissions.java new file mode 100644 index 0000000000..2437f6fa89 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetPermissions.java @@ -0,0 +1,82 @@ +package com.bgsoftware.superiorskyblock.commands.admin; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.messages.Message; +import org.bukkit.command.CommandSender; + +import java.util.Collections; +import java.util.List; + +public class CmdAdminResetPermissions implements IAdminIslandCommand { + + @Override + public List getAliases() { + return Collections.singletonList("resetpermissions"); + } + + @Override + public String getPermission() { + return "superior.admin.resetpermissions"; + } + + @Override + public String getUsage(java.util.Locale locale) { + return "admin resetpermissions <" + + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + ">"; + } + + @Override + public String getDescription(java.util.Locale locale) { + return Message.COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS.getMessage(locale); + } + + @Override + public int getMinArgs() { + return 3; + } + + @Override + public int getMaxArgs() { + return 3; + } + + @Override + public boolean canBeExecutedByConsole() { + return true; + } + + @Override + public boolean supportMultipleIslands() { + return true; + } + + @Override + public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { + int islandsChangedCount = 0; + + for (Island island : islands) { + if (PluginEventsFactory.callIslandClearRolesPrivilegesEvent(island, sender)) { + ++islandsChangedCount; + island.resetPermissions(); + } + } + + if (islandsChangedCount <= 0) + return; + + if (islands.size() != 1) + Message.PERMISSIONS_RESET_ALL.send(sender); + else if (targetPlayer == null) + Message.PERMISSIONS_RESET_NAME.send(sender, islands.get(0).getName()); + else + Message.PERMISSIONS_RESET.send(sender, targetPlayer.getName()); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java index ed4ed63685..910ccff519 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java @@ -476,6 +476,10 @@ public static boolean callIslandClearRatingsEvent(Island island, @Nullable Super return !fireEvent(ISLAND_CLEAR_RATINGS_EVENT, islandClearRatings).isCancelled(); } + public static boolean callIslandClearRolesPrivilegesEvent(Island island, CommandSender commandSender) { + return callIslandClearRolesPrivilegesEvent(island, commandSenderToSuperiorPlayer(commandSender)); + } + public static boolean callIslandClearRolesPrivilegesEvent(Island island, SuperiorPlayer superiorPlayer) { IslandClearRolesPrivileges islandClearRolesPrivileges = new IslandClearRolesPrivileges(); islandClearRolesPrivileges.island = island; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 9adb3e462a..294a5b4503 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -223,6 +223,7 @@ public enum Message { COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT, COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT, COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS, + COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS, COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS, COMMAND_DESCRIPTION_ADMIN_RESET_WORLD, COMMAND_DESCRIPTION_ADMIN_SCHEMATIC, @@ -638,6 +639,9 @@ public void send(CommandSender sender, Locale locale, Object... args) { OPEN_MENU_WHILE_SLEEPING, PANEL_TOGGLE_OFF, PANEL_TOGGLE_ON, + PERMISSIONS_RESET, + PERMISSIONS_RESET_ALL, + PERMISSIONS_RESET_NAME, PERMISSIONS_RESET_PLAYER, PERMISSIONS_RESET_ROLES, PERMISSION_CHANGED, diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 7a27abb574..1d60621570 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -262,6 +262,7 @@ COMMAND_DESCRIPTION_ADMIN_RELOAD: Alle Konfigurationen und Aufgaben des Plugins COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Entferne ein Blocklimit von einer Insel. COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Alle Bewertungen eines Spielers entfernen. +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Setze eine Welt für eine Insel zurück. COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Schaltpläne für das Plugin erstellen. @@ -795,6 +796,9 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' +PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' +PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' +PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lInsel | &7Alle Berechtigungen für {0} erfolgreich auf Standardwerte zurückgesetzt!' PERMISSIONS_RESET_ROLES: '&e&lInsel | &7Alle Berechtigungen der Insel erfolgreich diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 7eed63238d..f20592414f 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -194,6 +194,7 @@ COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Reload all configurations and tasks of the pl COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remove a block limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Remove all ratings given by a player.' +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Create schematics for the plugin.' @@ -627,6 +628,9 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' +PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' +PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' +PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lIsland | &7Successfully reset all the permissions for {0} to default values!' PERMISSIONS_RESET_ROLES: '&e&lIsland | &7Successfully reset all the permissions of the island to default values!' PLACEHOLDER_NO: 'No' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 9e098ce0cb..11d97a9c69 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -194,6 +194,7 @@ COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Recarga todas las configuraciones y tareas de COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Eliminar el límite de bloques de una isla.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Eliminar todas las calificaciones dadas por un jugador.' +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Cree schematics para el plugin.' @@ -627,6 +628,9 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' +PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' +PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' +PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lIsla | &7¡Restableció correctamente todos los permisos de {0} a los valores predeterminados!' PERMISSIONS_RESET_ROLES: '&e&lIsla | &7¡Restableció con éxito todos los permisos de la isla a los valores predeterminados!' PLACEHOLDER_NO: 'No' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index b09f38bb5d..e863343754 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -197,6 +197,7 @@ COMMAND_DESCRIPTION_ADMIN_RELOAD: Recharger toutes les configurations du plugin. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Retirer la limite de bloc d'une île. COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Suppimer toutes les notes attribuées par un joueur. +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Réinitialiser l'île d'un monde précis pour l'île spécifiée. COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Créer des schematics pour le plugin. @@ -629,6 +630,9 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' +PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' +PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' +PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lIle | &7Réinitialisation de toutes les permissions de {0} !' PERMISSIONS_RESET_ROLES: '&e&lIle | &7Réinitialisation de toutes les permissions de l''île !' PLACEHOLDER_NO: 'No' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index aa14778e63..2339ab759b 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -196,6 +196,7 @@ COMMAND_DESCRIPTION_ADMIN_RECALC: Ricalcola il valore di un'isola. COMMAND_DESCRIPTION_ADMIN_RELOAD: Ricarica tutte le configurazioni e le attività del plugin. COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Rimuovi il limite di un blocco da un'isola. COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Rimuovi tutte le valutazioni fornite da un giocatore. COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Ripristina il mondo su un''isole.' @@ -635,6 +636,9 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' +PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' +PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' +PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lIsola | &7Successfully reset all the permissions for {0} to default values!' PERMISSIONS_RESET_ROLES: '&e&lIsola | &7Successfully reset all the permissions of the island to default values!' PLACEHOLDER_NO: 'No' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 381837643a..61125db89f 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -202,6 +202,7 @@ COMMAND_DESCRIPTION_ADMIN_RELOAD: ןיגאלפה לש םיצבקה לכ תא ש COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remove a block limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: ןקחש ידי לע ונתנש םיגורידה לכ תא קוחמל. +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: ןיגאלפל שדח הנבמ רוציל. @@ -649,6 +650,9 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' +PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' +PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' +PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lIsland | &7Successfully reset all the permissions for {0} to default values!' PERMISSIONS_RESET_ROLES: '&e&lIsland | &7Successfully reset all the permissions of the island to default values!' PLACEHOLDER_NO: 'No' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index ba5661f5f7..e13cdbfb6e 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -194,6 +194,7 @@ COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Zaladuj ponownie wszystkie konfiguracje i zad COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Usuń limit bloków z wyspy.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Usun limit bytów z wyspy.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Usuń wszystkie oceny wystawione przez gracza.' +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Zresetuj wszystkie uprawnienia wyspy dla konkretnej wyspy.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Zresetuj wszystkie ustawienia wyspy dla konkretnej wyspy.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Zresetuj swiat dla wyspy.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Utwórz schematy dla wtyczki.' @@ -627,8 +628,11 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Successfully removed data for {0} from path {1}.' -PERMISSIONS_RESET_PLAYER: '&e&lWyspa | &7Pomyslnie zresetuj wszystkie uprawnienia dla {0} do wartosci domyslnych!' -PERMISSIONS_RESET_ROLES: '&e&lWyspa | &7Pomyslnie zresetuj wszystkie uprawnienia wyspy do wartosci domyslnych!' +PERMISSIONS_RESET: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia wyspy gracza {0} do wartosci domyslnych!' +PERMISSIONS_RESET_ALL: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia wszystkich wysp do wartosci domyslnych!' +PERMISSIONS_RESET_NAME: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia wyspy {0} do wartosci domyslnych!' +PERMISSIONS_RESET_PLAYER: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia dla {0} do wartosci domyslnych!' +PERMISSIONS_RESET_ROLES: '&e&lWyspa | &7Pomyslnie zresetowano wszystkie uprawnienia wyspy do wartosci domyslnych!' PLACEHOLDER_NO: 'No' PLACEHOLDER_YES: 'Yes' PLAYER_ALREADY_BANNED: '&c&lBlad | &7Ten gracz jest juz zbanowany.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 17a86ebee0..6351fc067d 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -194,6 +194,7 @@ COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Recarregar todas as configurações e tarefas COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Remover o limite de blocos de uma ilha.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Remover todas as avaliações dadas por um jogador.' +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Redefinir um mundo para uma ilha.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Criar esquemas para o plugin.' @@ -627,6 +628,9 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lData | &7Dados removidos com sucesso para {0} do caminho {1}.' +PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' +PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' +PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lIlha | &7Redefiniu com sucesso todas as permissões para {0} para os valores padrão!' PERMISSIONS_RESET_ROLES: '&e&lIlha | &7Redefiniu com sucesso todas as permissões da ilha para os valores padrão!' PLACEHOLDER_NO: 'Não' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 00e6da492b..34ffce3d4c 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -194,6 +194,7 @@ COMMAND_DESCRIPTION_ADMIN_RELOAD: 'Перезагрузить все настр COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Удалить лимит блоков с острова.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: 'Удалить все оценки, выставленные игроком.' +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Сбросить мир для острова.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Создать схемы для плагина.' @@ -627,6 +628,9 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lДанные | &7Успешно удалены данные для {0} из пути {1}.' +PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' +PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' +PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lОстров | &7Успешно сброшены все разрешения для {0} на значения по умолчанию!' PERMISSIONS_RESET_ROLES: '&e&lОстров | &7Успешно сброшены все разрешения острова на значения по умолчанию!' PLACEHOLDER_NO: 'Нет' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 6bed96256e..8256073973 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -252,6 +252,7 @@ COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: Bir adadan blok limitini kaldır. COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Bir oyuncu tarafından verilen tüm değerlendirmeleri kaldır. +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Bir ada için bir dünyayı sıfırla. COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Eklenti için şematikler oluştur. @@ -747,6 +748,9 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lVeri | &7{0} için {1} yolundan veri başarıyla kaldırıldı.' +PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' +PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' +PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lAda | &7{0} için tüm izinler varsayılan değerlere başarıyla sıfırlandı!' PERMISSIONS_RESET_ROLES: '&e&lAda | &7Adanın tüm izinleri varsayılan değerlere başarıyla diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 3e6a8ab5a7..ccc96e42f6 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -223,6 +223,7 @@ COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: 'Xóa giới hạn khối khỏi m COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Xóa tất cả các xếp hạng được cung cấp bởi một người chơi. +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Tái tạo lại thế giới cho một hòn đảo.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Tạo các schematic cho plugin. @@ -708,6 +709,9 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&lDữ liệu | &7Đã xóa thành công dữ liệu cho {0} từ đường dẫn {1}.' +PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' +PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' +PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&lĐảo | &7Thành công đặt lại tất cả các quyền cho {0} thành giá trị mặc định!' PERMISSIONS_RESET_ROLES: '&e&lĐảo | &7Thành công đặt lại tất cả các quyền của hòn đảo thành giá trị mặc định!' PLACEHOLDER_NO: 'No' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index d92ac7bb9b..4c8aefc808 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -194,6 +194,7 @@ COMMAND_DESCRIPTION_ADMIN_RELOAD: '重载本插件的所有配置和进程.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: '去除指定岛屿的方块数量限制.' COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: '去除指定玩家的所有评分.' +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: '重置指定岛屿所在的世界.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: '从插件创建结构文件.' @@ -627,6 +628,9 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&l数据 | &7成功删除了路径 {1} 下的数据 {0}.' +PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' +PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' +PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' PERMISSIONS_RESET_PLAYER: '&e&l岛屿 | &7成功将玩家 {0} 的权限重置回默认状态!' PERMISSIONS_RESET_ROLES: '&e&l岛屿 | &7成功将该岛屿上的所有权限重置为默认状态!' PLACEHOLDER_NO: '否' diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 4371b05196..81f33894c5 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -273,6 +273,8 @@ permissions: description: Remove an entity limit for an island. superior.admin.removeratings: description: Remove all ratings given by a player. + superior.admin.resetpermissions: + description: Reset all island permissions for a specific island. superior.admin.resetsettings: description: Reset all island settings for a specific island. superior.admin.resetworld: From b45f82dbbe81730266c3ee971328c1c3d15140ed Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 20 Sep 2025 22:26:19 +0200 Subject: [PATCH 313/600] Added tamed animal damage privilege (#2649) --- .../island/privilege/IslandPrivileges.java | 1 + .../region/RegionManagerServiceImpl.java | 3 +- .../world/BukkitEntities.java | 5 +++ src/main/resources/config.yml | 1 + src/main/resources/menus/permissions.yml | 33 +++++++++++++++++++ src/main/resources/menus/permissions1_16.yml | 33 +++++++++++++++++++ src/main/resources/menus/permissions1_17.yml | 33 +++++++++++++++++++ src/main/resources/menus/permissions1_20.yml | 33 +++++++++++++++++++ src/main/resources/menus/permissions1_21.yml | 33 +++++++++++++++++++ src/main/resources/menus/permissions1_9.yml | 33 +++++++++++++++++++ 10 files changed, 207 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index c16f0a2d5f..b5be0f8e25 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -83,6 +83,7 @@ public class IslandPrivileges { public static final IslandPrivilege SET_WARP = register("SET_WARP", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SIGN_INTERACT = register("SIGN_INTERACT"); public static final IslandPrivilege SPAWNER_BREAK = register("SPAWNER_BREAK"); + public static final IslandPrivilege TAMED_ANIMAL_DAMAGE = register("TAMED_ANIMAL_DAMAGE"); @Nullable public static final IslandPrivilege TURTLE_EGG_TRAMPING = register("TURTLE_EGG_TRAMPING", !ServerVersion.isLegacy()); public static final IslandPrivilege UNCOOP_MEMBER = register("UNCOOP_MEMBER", IslandPrivilege.Type.COMMAND); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 1766b4ba71..0df348d1cb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -346,7 +346,8 @@ public InteractionResult handleEntityDamage(Entity damager, Entity entity) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); - IslandPrivilege islandPrivilege = BukkitEntities.getCategory(entity.getType()).getDamagePrivilege(); + IslandPrivilege islandPrivilege = BukkitEntities.isTameable(entity) ? IslandPrivileges.TAMED_ANIMAL_DAMAGE : + BukkitEntities.getCategory(entity.getType()).getDamagePrivilege(); interactionResult = handleInteractionInternal(damagerSource.get(), entityLocation, islandPrivilege, 0, true, false); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java index fb79e3e396..43cba76f9b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java @@ -23,6 +23,7 @@ import org.bukkit.entity.Pig; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; +import org.bukkit.entity.Tameable; import org.bukkit.entity.Vehicle; import org.bukkit.inventory.AbstractHorseInventory; import org.bukkit.inventory.HorseInventory; @@ -166,6 +167,10 @@ public static EntityCategory getCategory(EntityType entityType) { return ENTITY_CATEGORIES_CACHE.getOrDefault(entityType, EntityCategory.UNKNOWN); } + public static boolean isTameable(Entity entity) { + return entity instanceof Tameable && ((Tameable) entity).isTamed(); + } + public static boolean isHorse(Entity entity) { return entity instanceof Horse || entity.getType() == CAMEL_TYPE || (ServerVersion.isAtLeast(ServerVersion.v1_11) && (entity instanceof Mule || entity instanceof Donkey)); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 7d982d2b01..0ec5ecc47a 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -257,6 +257,7 @@ island-roles: - MONSTER_SPAWN - RANKUP - SPAWNER_BREAK + - TAMED_ANIMAL_DAMAGE mod: id: 1 name: 'Moderator' diff --git a/src/main/resources/menus/permissions.yml b/src/main/resources/menus/permissions.yml index cfb3371f5c..5e2a3779dc 100644 --- a/src/main/resources/menus/permissions.yml +++ b/src/main/resources/menus/permissions.yml @@ -2077,6 +2077,39 @@ permissions: volume: 0.2 pitch: 0.2 + tamed_animal_damage: + display-menu: true + permission-enabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 + uncoop_member: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_16.yml b/src/main/resources/menus/permissions1_16.yml index 1527cbc59e..71504795d2 100644 --- a/src/main/resources/menus/permissions1_16.yml +++ b/src/main/resources/menus/permissions1_16.yml @@ -2206,6 +2206,39 @@ permissions: volume: 0.2 pitch: 0.2 + tamed_animal_damage: + display-menu: true + permission-enabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 + uncoop_member: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_17.yml b/src/main/resources/menus/permissions1_17.yml index 4d41a99341..7a94f65b08 100644 --- a/src/main/resources/menus/permissions1_17.yml +++ b/src/main/resources/menus/permissions1_17.yml @@ -2272,6 +2272,39 @@ permissions: volume: 0.2 pitch: 0.2 + tamed_animal_damage: + display-menu: true + permission-enabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 + uncoop_member: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_20.yml b/src/main/resources/menus/permissions1_20.yml index cc297d6a02..fd5c3dc3b1 100644 --- a/src/main/resources/menus/permissions1_20.yml +++ b/src/main/resources/menus/permissions1_20.yml @@ -2311,6 +2311,39 @@ permissions: volume: 0.2 pitch: 0.2 + tamed_animal_damage: + display-menu: true + permission-enabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 + uncoop_member: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_21.yml b/src/main/resources/menus/permissions1_21.yml index e27ef995cd..0a930cba8e 100644 --- a/src/main/resources/menus/permissions1_21.yml +++ b/src/main/resources/menus/permissions1_21.yml @@ -2311,6 +2311,39 @@ permissions: volume: 0.2 pitch: 0.2 + tamed_animal_damage: + display-menu: true + permission-enabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 + uncoop_member: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_9.yml b/src/main/resources/menus/permissions1_9.yml index aa436a7ed0..e0411d368c 100644 --- a/src/main/resources/menus/permissions1_9.yml +++ b/src/main/resources/menus/permissions1_9.yml @@ -2110,6 +2110,39 @@ permissions: volume: 0.2 pitch: 0.2 + tamed_animal_damage: + display-menu: true + permission-enabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 + uncoop_member: display-menu: true permission-enabled: From ec15078ed5ec0c4c6c44781c2467e2fea34a6087 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 20 Sep 2025 22:28:48 +0200 Subject: [PATCH 314/600] Added the ability to use admin show command without an argument (#2645) --- .../commands/admin/CmdAdminShow.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java index fa3ad3774d..37c1bc7a42 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java @@ -9,7 +9,9 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; +import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -52,9 +54,9 @@ public String getPermission() { @Override public String getUsage(java.util.Locale locale) { - return "admin show <" + + return "admin show [" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + - Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + ">"; + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "]"; } @Override @@ -64,7 +66,7 @@ public String getDescription(java.util.Locale locale) { @Override public int getMinArgs() { - return 3; + return 2; } @Override @@ -83,7 +85,13 @@ public boolean supportMultipleIslands() { } @Override - public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { + public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + Island island = args.length == 2 ? CommandArguments.getIslandWhereStanding(plugin, sender).getIsland() : + CommandArguments.getIsland(plugin, sender, args[2]).getIsland(); + + if (island == null) + return; + java.util.Locale locale = PlayerLocales.getLocale(sender); long lastTime = island.getLastTimeUpdate(); @@ -286,6 +294,12 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab Message.CUSTOM.send(sender, infoMessage.toString(), false); } + @Override + public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + return args.length == 3 ? CommandTabCompletes.getOnlinePlayersWithIslands(plugin, args[2], false, null) + : Collections.emptyList(); + } + private static Optional collectIslandData(Locale locale, Supplier> dataFunction, Supplier> customDataFunction, From 57416100dc839966170edef503061b26ea58cdda Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 21 Sep 2025 11:50:05 +0300 Subject: [PATCH 315/600] Fixed detection of signs in schematics in 1.12 (#2660) --- .../core/schematic/SchematicBlock.java | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java index 70897ac71f..3b506738a7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java @@ -20,9 +20,6 @@ public class SchematicBlock { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final String SIGN_ID = ServerVersion.isLegacy() ? "Sign" : "minecraft:sign"; - private static final String CHEST_ID = ServerVersion.isLegacy() ? "Chest" : "minecraft:chest"; - private final Location location; private final int blockId; @Nullable @@ -90,23 +87,21 @@ public void doPrePlace(Island island) { throw new RuntimeException("Detected tile-entity data with no 'id' key."); } - if (id.equalsIgnoreCase(SIGN_ID)) { + if (isSignId(id)) { if (this.tileEntityData.containsKey("front_text")) { backFrontSignLinesReplace(this.tileEntityData, island); } else { legacySignLinesReplace(this.tileEntityData, island); } - } else if (id.equalsIgnoreCase(CHEST_ID)) { - if (plugin.getSettings().getDefaultContainers().isEnabled()) { - String inventoryType = this.tileEntityData.getString("inventoryType").orElse(null); - if (inventoryType != null) { - try { - InventoryType containerType = InventoryType.valueOf(inventoryType); - ListTag items = plugin.getSettings().getDefaultContainers().getContents(containerType); - if (items != null) - this.tileEntityData.setTag("Items", items.copy()); - } catch (Exception ignored) { - } + } else if (plugin.getSettings().getDefaultContainers().isEnabled() && isChestId(id)) { + String inventoryType = this.tileEntityData.getString("inventoryType").orElse(null); + if (inventoryType != null) { + try { + InventoryType containerType = InventoryType.valueOf(inventoryType); + ListTag items = plugin.getSettings().getDefaultContainers().getContents(containerType); + if (items != null) + this.tileEntityData.setTag("Items", items.copy()); + } catch (Exception ignored) { } } } @@ -117,7 +112,7 @@ public boolean shouldPostPlace() { return false; String id = this.tileEntityData.getString("id").orElse(null); - return id != null && id.equalsIgnoreCase(SIGN_ID); + return id != null && isSignId(id); } public void doPostPlace(Island island) { @@ -198,6 +193,14 @@ public SchematicBlock setLocation(Location newBlockLoc) { return new SchematicBlock(newBlockLoc, this.blockId, this.extra); } + private static boolean isSignId(String id) { + return id.equals("Sign") || id.equals("minecraft:sign"); + } + + private static boolean isChestId(String id) { + return id.equals("Chest") || id.equals("minecraft:chest"); + } + public static class Extra { @Nullable From 06739a68799d463b3fa3747b696f82115a315ea1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 21 Sep 2025 14:48:54 +0300 Subject: [PATCH 316/600] Fixed errors with cached schematics when multiple worlds exist or when asp is used (#2661 #2659) --- .../nms/v1_12_R1/NMSWorldImpl.java | 6 +- .../world/WorldEditSessionDataImpl.java | 130 +++++++++++++ .../v1_12_R1/world/WorldEditSessionImpl.java | 101 ++++------ .../nms/v1_16_R3/NMSWorldImpl.java | 5 + .../world/WorldEditSessionDataImpl.java | 179 ++++++++++++++++++ .../v1_16_R3/world/WorldEditSessionImpl.java | 117 ++++++------ .../nms/v1_17/NMSWorldImpl.java | 5 + .../v1_17/world/WorldEditSessionDataImpl.java | 167 ++++++++++++++++ .../nms/v1_17/world/WorldEditSessionImpl.java | 169 ++++++++++------- .../nms/v1_18/NMSWorldImpl.java | 5 + .../v1_18/world/WorldEditSessionDataImpl.java | 167 ++++++++++++++++ .../nms/v1_18/world/WorldEditSessionImpl.java | 147 +++++++------- .../nms/v1_19/NMSWorldImpl.java | 5 + .../v1_19/world/WorldEditSessionDataImpl.java | 167 ++++++++++++++++ .../nms/v1_19/world/WorldEditSessionImpl.java | 147 +++++++------- .../nms/v1_20_3/NMSWorldImpl.java | 5 + .../world/WorldEditSessionDataImpl.java | 167 ++++++++++++++++ .../v1_20_3/world/WorldEditSessionImpl.java | 143 +++++++------- .../nms/v1_20_4/NMSWorldImpl.java | 5 + .../world/WorldEditSessionDataImpl.java | 167 ++++++++++++++++ .../v1_20_4/world/WorldEditSessionImpl.java | 145 +++++++------- .../nms/v1_21/NMSWorldImpl.java | 5 + .../v1_21/world/WorldEditSessionDataImpl.java | 167 ++++++++++++++++ .../nms/v1_21/world/WorldEditSessionImpl.java | 145 +++++++------- .../nms/v1_21_3/NMSWorldImpl.java | 5 + .../world/WorldEditSessionDataImpl.java | 167 ++++++++++++++++ .../v1_21_3/world/WorldEditSessionImpl.java | 144 +++++++------- .../nms/v1_21_4/NMSWorldImpl.java | 5 + .../world/WorldEditSessionDataImpl.java | 167 ++++++++++++++++ .../v1_21_4/world/WorldEditSessionImpl.java | 144 +++++++------- .../nms/v1_21_5/NMSWorldImpl.java | 5 + .../world/WorldEditSessionDataImpl.java | 167 ++++++++++++++++ .../v1_21_5/world/WorldEditSessionImpl.java | 144 +++++++------- .../nms/v1_21_7/NMSWorldImpl.java | 5 + .../world/WorldEditSessionDataImpl.java | 167 ++++++++++++++++ .../v1_21_7/world/WorldEditSessionImpl.java | 144 +++++++------- .../nms/v1_8_R3/NMSWorldImpl.java | 5 + .../world/WorldEditSessionDataImpl.java | 130 +++++++++++++ .../v1_8_R3/world/WorldEditSessionImpl.java | 97 ++++------ .../superiorskyblock/nms/NMSWorld.java | 2 + .../nms/world/WorldEditSession.java | 8 +- .../schematic/SchematicsManagerImpl.java | 9 +- .../impl/CachedSuperiorSchematic.java | 48 +++-- .../schematic/impl/SuperiorSchematic.java | 13 +- 44 files changed, 3162 insertions(+), 880 deletions(-) create mode 100644 NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionDataImpl.java diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java index 5a44a982a9..1ae7a488dc 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java @@ -25,7 +25,6 @@ import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockDoubleStep; import net.minecraft.server.v1_12_R1.BlockPosition; -import net.minecraft.server.v1_12_R1.Blocks; import net.minecraft.server.v1_12_R1.EnumParticle; import net.minecraft.server.v1_12_R1.IBlockData; import net.minecraft.server.v1_12_R1.IChatBaseComponent; @@ -329,6 +328,11 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionDataImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..9ce265b1dc --- /dev/null +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionDataImpl.java @@ -0,0 +1,130 @@ +package com.bgsoftware.superiorskyblock.nms.v1_12_R1.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.server.v1_12_R1.BlockPosition; +import net.minecraft.server.v1_12_R1.ChunkCoordIntPair; +import net.minecraft.server.v1_12_R1.IBlockData; +import org.bukkit.Location; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lights = new LinkedList<>(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + List lights) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = getChunkCoordX(entry.getKey()); + int currChunkPosZAxis = getChunkCoordZ(entry.getKey()); + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, entry.getValue())); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPosition blockPosition = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPosition.getX() - baseBlockPosXAxis, + blockPosition.getY() - baseBlockPosYAxis, blockPosition.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPosition blockPosition = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPosition.getX() - baseBlockPosXAxis, + blockPosition.getY() - baseBlockPosYAxis, blockPosition.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lights.forEach(lightPosition -> { + this.lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkCoordIntPair.a(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + chunks.put(newPos, chunkDataPositioned.object); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List lights) { + this.lights.forEach(lightPositioned -> { + BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset); + lights.add(newPos); + }); + } + + private static int getChunkCoordX(long i) { + return (int) (i & 4294967295L); + } + + private static int getChunkCoordZ(long i) { + return (int) (i >>> 32 & 4294967295L); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + +} \ No newline at end of file diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java index 4ee7aae50f..cfb7e5833a 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/world/WorldEditSessionImpl.java @@ -18,6 +18,7 @@ import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import net.minecraft.server.v1_12_R1.BiomeBase; import net.minecraft.server.v1_12_R1.Block; import net.minecraft.server.v1_12_R1.BlockBed; @@ -34,14 +35,12 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_12_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; import org.bukkit.craftbukkit.v1_12_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_12_R1.generator.CustomChunkGenerator; import org.bukkit.generator.ChunkGenerator; import java.util.Arrays; import java.util.Collections; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -57,24 +56,35 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final List lights = new LinkedList<>(); - private WorldServer worldServer; + private Dimension dimension; - private Location baseLocationForCache = null; + @Nullable + private WorldServer worldServer; public static WorldEditSessionImpl obtain(WorldServer worldServer) { return POOL.obtain().initialize(worldServer); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(WorldServer worldServer) { + private WorldEditSessionImpl initialize(WorldServer worldServer) { this.worldServer = worldServer; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld()); return this; } + private WorldEditSessionImpl initialize(Dimension dimension) { + this.worldServer = null; + this.dimension = dimension; + return this; + } + @Override public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag blockEntityData) { @@ -112,6 +122,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -129,8 +141,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(org.bukkit.Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); @@ -158,8 +169,7 @@ public void applyBlocks(org.bukkit.Chunk bukkitChunk) { @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> worldServer.setTypeAndData(data.getKey(), data.getValue(), 3)); @@ -203,56 +213,30 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lights); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - int chunkPosXAxisDelta = (location.getBlockX() >> 4) - (baseLocationForCache.getBlockX() >> 4); - int chunkPosZAxisDelta = (location.getBlockZ() >> 4) - (baseLocationForCache.getBlockZ() >> 4); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); - - WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); - - WorldEditSessionImpl worldEditSession = obtain(worldServer); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkCoordIntPair.a(getChunkCoordX(entry.getKey()) + chunkPosXAxisDelta, - getChunkCoordZ(entry.getKey()) + chunkPosZAxisDelta); - worldEditSession.chunks.put(newPos, entry.getValue()); - } - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPosition newPos = blockToUpdatePair.getKey().a(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - - this.blockEntities.forEach(blockEntityPair -> { - BlockPosition newPos = blockEntityPair.getKey().a(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - - this.lights.forEach(lightPosition -> { - BlockPosition newPos = lightPosition.a(xAxisDelta, 0, zAxisDelta); - worldEditSession.lights.add(newPos); - }); - - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.lights); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -265,31 +249,26 @@ public void release() { private boolean isValidPosition(BlockPosition blockPosition) { return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 && blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 && - blockPosition.getY() >= 0 && blockPosition.getY() < worldServer.getHeight(); - } - - private static int getChunkCoordX(long i) { - return (int) (i & 4294967295L); + blockPosition.getY() >= 0 && blockPosition.getY() < 256; } - private static int getChunkCoordZ(long i) { - return (int) (i >>> 32 & 4294967295L); - } - - private class ChunkData { + public class ChunkData { private final ChunkSection[] chunkSections = new ChunkSection[16]; - public ChunkData(long chunkKey) { + private ChunkData(long chunkKey) { ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32)); createChunkSections(); - runCustomWorldGenerator(chunkCoord); + if (worldServer != null) + runCustomWorldGenerator(chunkCoord); } private void createChunkSections() { + boolean hasSkyLight = dimension.getEnvironment() != World.Environment.THE_END; + for (int i = 0; i < this.chunkSections.length; ++i) { int chunkSectionPos = i << 4; - this.chunkSections[i] = EmptyCounterChunkSection.of(new ChunkSection(chunkSectionPos, worldServer.worldProvider.m())); + this.chunkSections[i] = EmptyCounterChunkSection.of(new ChunkSection(chunkSectionPos, hasSkyLight)); } } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java index b8b74a8d58..c3243d2a2b 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java @@ -328,6 +328,11 @@ public WorldEditSession createEditSession(org.bukkit.World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionDataImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..ae15292b48 --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionDataImpl.java @@ -0,0 +1,179 @@ +package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.server.v1_16_R3.BlockPosition; +import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; +import net.minecraft.server.v1_16_R3.ChunkSection; +import net.minecraft.server.v1_16_R3.HeightMap; +import net.minecraft.server.v1_16_R3.IBlockData; +import org.bukkit.Location; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + Set lightenChunks) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = ChunkCoordIntPair.getX(entry.getKey()); + int currChunkPosZAxis = ChunkCoordIntPair.getZ(entry.getKey()); + WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); + + List> lights; + if (isStarLightInterface || chunkData.lights().isEmpty()) { + lights = Collections.emptyList(); + } else { + lights = new LinkedList<>(); + chunkData.lights().forEach(lightPosition -> { + lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), + chunkData.heightmaps(), lights); + + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPosition blockPos = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPosition blockPos = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lightenChunks.forEach(lightPosition -> { + this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, + lightPosition.z - baseChunkPosZAxis, null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, + int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, + Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkCoordIntPair.pair(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + + List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + chunkDataPositioned.object.lights.forEach(lightPositioned -> { + lights.add(new BlockPosition(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset)); + }); + + chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, + chunkDataPositioned.object.heightmaps, lights)); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { + this.lightenChunks.forEach(lightPositioned -> { + ChunkCoordIntPair newPos = new ChunkCoordIntPair(baseChunkPosXAxis + lightPositioned.xOffset, + baseChunkPosZAxis + lightPositioned.zOffset); + lightenChunks.add(newPos); + }); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + + private static class PositionedChunkData { + + private final ChunkSection[] chunkSections; + private final Map heightmaps; + private final List> lights; + + public PositionedChunkData(ChunkSection[] chunkSections, + Map heightmaps, + List> lights) { + this.chunkSections = chunkSections; + this.heightmaps = heightmaps; + this.lights = lights; + } + + } + +} diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java index 9a105259e5..0446890ebe 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/WorldEditSessionImpl.java @@ -19,6 +19,7 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import net.minecraft.server.v1_16_R3.BiomeBase; import net.minecraft.server.v1_16_R3.BiomeStorage; import net.minecraft.server.v1_16_R3.Block; @@ -45,7 +46,6 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_16_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_16_R3.generator.CustomChunkGenerator; import org.bukkit.generator.ChunkGenerator; @@ -54,7 +54,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -82,24 +81,35 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private WorldServer worldServer; + private Dimension dimension; - private Location baseLocationForCache = null; + @Nullable + private WorldServer worldServer; public static WorldEditSessionImpl obtain(WorldServer worldServer) { return POOL.obtain().initialize(worldServer); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(WorldServer worldServer) { + private WorldEditSessionImpl initialize(WorldServer worldServer) { this.worldServer = worldServer; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld()); return this; } + private WorldEditSessionImpl initialize(Dimension dimension) { + this.worldServer = null; + this.dimension = dimension; + return this; + } + @Override public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag blockEntityData) { @@ -166,6 +176,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -183,8 +195,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(org.bukkit.Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); ChunkCoordIntPair chunkCoord = chunk.getPos(); @@ -228,8 +239,7 @@ public void applyBlocks(org.bukkit.Chunk bukkitChunk) { @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> worldServer.setTypeAndData(data.getKey(), data.getValue(), 3)); @@ -260,65 +270,31 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); - - int chunkPosXAxisDelta = (location.getBlockX() >> 4) - (baseLocationForCache.getBlockX() >> 4); - int chunkPosZAxisDelta = (location.getBlockZ() >> 4) - (baseLocationForCache.getBlockZ() >> 4); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); - - WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - WorldEditSessionImpl worldEditSession = obtain(worldServer); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkCoordIntPair.pair(ChunkCoordIntPair.getX(entry.getKey()) + chunkPosXAxisDelta, - ChunkCoordIntPair.getZ(entry.getKey()) + chunkPosZAxisDelta); - - ChunkSection[] sections = entry.getValue().chunkSections; - Map heightmaps = entry.getValue().heightmaps; - List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - entry.getValue().lights.forEach(blockPos -> { - lights.add(blockPos.add(xAxisDelta, 0, zAxisDelta)); - }); - - ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); - worldEditSession.chunks.put(newPos, newChunkData); - } - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPosition newPos = blockToUpdatePair.getKey().add(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - - this.blockEntities.forEach(blockEntityPair -> { - BlockPosition newPos = blockEntityPair.getKey().add(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - - this.lightenChunks.forEach(lightenChunk -> { - worldEditSession.lightenChunks.add(new ChunkCoordIntPair( - lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); - }); - - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, + baseBlockPosZAxis, this, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -328,19 +304,23 @@ public void release() { POOL.release(this); } + public ChunkData createChunkData(ChunkSection[] chunkSections, Map heightmaps, List lights) { + return new ChunkData(chunkSections, heightmaps, lights); + } + private boolean isValidPosition(BlockPosition blockPosition) { return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 && blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 && - blockPosition.getY() >= 0 && blockPosition.getY() < worldServer.getHeight(); + blockPosition.getY() >= 0 && blockPosition.getY() < 256; } - private class ChunkData { + public class ChunkData { private final ChunkSection[] chunkSections; private final Map heightmaps; private final List lights; - public ChunkData(long chunkKey) { + private ChunkData(long chunkKey) { this(new ChunkSection[16], new EnumMap<>(HeightMap.Type.class), new LinkedList<>()); ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair(chunkKey); @@ -363,15 +343,28 @@ public ChunkData(long chunkKey) { } createHeightmaps(tempChunk); - runCustomWorldGenerator(tempChunk); + if (worldServer != null) + runCustomWorldGenerator(tempChunk); } - public ChunkData(ChunkSection[] chunkSections, Map heightmaps, List lights) { + private ChunkData(ChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } + public ChunkSection[] chunkSections() { + return this.chunkSections; + } + + public Map heightmaps() { + return this.heightmaps; + } + + public List lights() { + return this.lights; + } + private void createChunkSections() { for (int i = 0; i < this.chunkSections.length; ++i) { int chunkSectionPos = i << 4; diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index b08d500c3d..d16944e462 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -351,6 +351,11 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionDataImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..af398734af --- /dev/null +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionDataImpl.java @@ -0,0 +1,167 @@ +package com.bgsoftware.superiorskyblock.nms.v1_17.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Location; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + Set lightenChunks) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); + int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); + WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); + + List> lights; + if (isStarLightInterface || chunkData.lights().isEmpty()) { + lights = Collections.emptyList(); + } else { + lights = new LinkedList<>(); + chunkData.lights().forEach(lightPosition -> { + lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), + chunkData.heightmaps(), lights); + + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPos blockPos = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPos blockPos = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lightenChunks.forEach(lightPosition -> { + this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, + lightPosition.z - baseChunkPosZAxis, null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, + int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, + Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + + List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + chunkDataPositioned.object.lights.forEach(lightPositioned -> { + lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset)); + }); + + chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, + chunkDataPositioned.object.heightmaps, lights)); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { + this.lightenChunks.forEach(lightPositioned -> { + ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, + baseChunkPosZAxis + lightPositioned.zOffset); + lightenChunks.add(newPos); + }); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + + private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, + List> lights) { + } + +} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java index dcb88662ff..405695b9fc 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java @@ -20,14 +20,17 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; @@ -41,6 +44,8 @@ import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.ProtoTickList; import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; @@ -48,7 +53,6 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage; @@ -58,7 +62,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -86,21 +89,36 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private ServerLevel serverLevel; + private Dimension dimension; + private LevelHeightAccessor levelHeightAccessor; - private Location baseLocationForCache = null; + @Nullable + private ServerLevel serverLevel; public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(ServerLevel serverLevel) { + private WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + this.levelHeightAccessor = serverLevel; + return this; + } + + private WorldEditSessionImpl initialize(Dimension dimension) { + DimensionType dimensionType = getDimensionTypeFromDimension(dimension); + this.serverLevel = null; + this.dimension = dimension; + this.levelHeightAccessor = createLevelHeightAccessor(dimensionType.minY(), dimensionType.height()); return this; } @@ -154,7 +172,7 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) chunkData.lights.add(blockPos); - LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; int blockX = blockPos.getX() & 15; int blockY = blockPos.getY(); @@ -170,6 +188,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -187,8 +207,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); ChunkPos chunkPos = levelChunk.getPos(); @@ -231,8 +250,7 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -275,88 +293,85 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); - - int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); - int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - - WorldEditSessionImpl worldEditSession = obtain(serverLevel); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, - ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); - - LevelChunkSection[] sections = entry.getValue().chunkSections; - Map heightmaps = entry.getValue().heightmaps; - List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - entry.getValue().lights.forEach(blockPos -> { - lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); - }); - - ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); - worldEditSession.chunks.put(newPos, newChunkData); - } - - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - - this.blockEntities.forEach(blockEntityPair -> { - BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - - this.lightenChunks.forEach(lightenChunk -> { - worldEditSession.lightenChunks.add(new ChunkPos( - lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); - }); - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, + baseBlockPosZAxis, this, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); this.serverLevel = null; this.dimension = null; + this.levelHeightAccessor = null; POOL.release(this); } + public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + return new ChunkData(chunkSections, heightmaps, lights); + } + private boolean isValidPosition(BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); + !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); + } + + private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + + Registry registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.LEVEL_STEM_REGISTRY); + return registry.getOrThrow(resourceKey).type(); + } + + private static LevelHeightAccessor createLevelHeightAccessor(int minY, int height) { + return new LevelHeightAccessor() { + @Override + public int getHeight() { + return height; + } + + @Override + public int getMinBuildHeight() { + return minY; + } + }; } - private class ChunkData { + public class ChunkData { private final LevelChunkSection[] chunkSections; private final Map heightmaps; private final List lights; - public ChunkData(long chunkKey) { - this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + private ChunkData(long chunkKey) { + this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); @@ -365,32 +380,44 @@ public ChunkData(long chunkKey) { ProtoTickList blockTickScheduler = new ProtoTickList<>(block -> { return block == null || block.defaultBlockState().isAir(); - }, chunkPos, serverLevel); + }, chunkPos, levelHeightAccessor); ProtoTickList fluidTickScheduler = new ProtoTickList<>((fluid) -> { return fluid == null || fluid == Fluids.EMPTY; - }, chunkPos, serverLevel); + }, chunkPos, levelHeightAccessor); ProtoChunk tempChunk; - try { - tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, blockTickScheduler, fluidTickScheduler, serverLevel, serverLevel); + tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, blockTickScheduler, fluidTickScheduler, levelHeightAccessor, serverLevel); } catch (Throwable error) { - tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, blockTickScheduler, fluidTickScheduler, serverLevel); + tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, blockTickScheduler, fluidTickScheduler, levelHeightAccessor); } createHeightmaps(tempChunk); - runCustomWorldGenerator(tempChunk); + if (serverLevel != null) + runCustomWorldGenerator(tempChunk); } - public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } + public LevelChunkSection[] chunkSections() { + return this.chunkSections; + } + + public Map heightmaps() { + return this.heightmaps; + } + + public List lights() { + return this.lights; + } + private void createChunkSections() { for (int i = 0; i < this.chunkSections.length; ++i) { - int chunkSectionPos = serverLevel.getSectionYFromSectionIndex(i); + int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i); try { this.chunkSections[i] = new LevelChunkSection(chunkSectionPos, null, serverLevel, true); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index 4c7c343887..149c666c20 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -354,6 +354,11 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionDataImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..8c145adfdd --- /dev/null +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionDataImpl.java @@ -0,0 +1,167 @@ +package com.bgsoftware.superiorskyblock.nms.v1_18.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Location; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + Set lightenChunks) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); + int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); + WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); + + List> lights; + if (isStarLightInterface || chunkData.lights().isEmpty()) { + lights = Collections.emptyList(); + } else { + lights = new LinkedList<>(); + chunkData.lights().forEach(lightPosition -> { + lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), + chunkData.heightmaps(), lights); + + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPos blockPos = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPos blockPos = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lightenChunks.forEach(lightPosition -> { + this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, + lightPosition.z - baseChunkPosZAxis, null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, + int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, + Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + + List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + chunkDataPositioned.object.lights.forEach(lightPositioned -> { + lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset)); + }); + + chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, + chunkDataPositioned.object.heightmaps, lights)); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { + this.lightenChunks.forEach(lightPositioned -> { + ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, + baseChunkPosZAxis + lightPositioned.zOffset); + lightenChunks.add(newPos); + }); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + + private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, + List> lights) { + } + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java index 00ef8dd103..f2299e7b70 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java @@ -19,16 +19,18 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; @@ -42,13 +44,14 @@ import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; @@ -57,7 +60,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -82,21 +84,36 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private ServerLevel serverLevel; + private Dimension dimension; + private LevelHeightAccessor levelHeightAccessor; - private Location baseLocationForCache = null; + @Nullable + private ServerLevel serverLevel; public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(ServerLevel serverLevel) { + private WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + this.levelHeightAccessor = serverLevel; + return this; + } + + private WorldEditSessionImpl initialize(Dimension dimension) { + DimensionType dimensionType = getDimensionTypeFromDimension(dimension); + this.serverLevel = null; + this.dimension = dimension; + this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); return this; } @@ -150,7 +167,7 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) chunkData.lights.add(blockPos); - LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; int blockX = blockPos.getX() & 15; int blockY = blockPos.getY(); @@ -166,6 +183,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -183,8 +202,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); ChunkPos chunkPos = levelChunk.getPos(); @@ -219,8 +237,7 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -263,88 +280,71 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); - - int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); - int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); - - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - WorldEditSessionImpl worldEditSession = obtain(serverLevel); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, - ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); - - LevelChunkSection[] sections = entry.getValue().chunkSections; - Map heightmaps = entry.getValue().heightmaps; - List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - entry.getValue().lights.forEach(blockPos -> { - lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); - }); - ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); - worldEditSession.chunks.put(newPos, newChunkData); - } - - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - - this.blockEntities.forEach(blockEntityPair -> { - BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - - this.lightenChunks.forEach(lightenChunk -> { - worldEditSession.lightenChunks.add(new ChunkPos( - lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); - }); - - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, + baseBlockPosZAxis, this, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); this.serverLevel = null; this.dimension = null; + this.levelHeightAccessor = null; POOL.release(this); } + public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + return new ChunkData(chunkSections, heightmaps, lights); + } + private boolean isValidPosition(BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); + !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); } - private class ChunkData { + private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + + Registry registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.LEVEL_STEM_REGISTRY); + return registry.getOrThrow(resourceKey).typeHolder().value(); + } + + public class ChunkData { private final LevelChunkSection[] chunkSections; private final Map heightmaps; private final List lights; - public ChunkData(long chunkKey) { - this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + private ChunkData(long chunkKey) { + this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); @@ -354,24 +354,37 @@ public ChunkData(long chunkKey) { createChunkSections(biomesRegistry); ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), serverLevel, biomesRegistry, null); + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); createHeightmaps(tempChunk); - runCustomWorldGenerator(tempChunk); + if (serverLevel != null) + runCustomWorldGenerator(tempChunk); } - public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } + public LevelChunkSection[] chunkSections() { + return this.chunkSections; + } + + public Map heightmaps() { + return this.heightmaps; + } + + public List lights() { + return this.lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); for (int i = 0; i < this.chunkSections.length; ++i) { - int chunkSectionPos = serverLevel.getSectionYFromSectionIndex(i); + int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index c275992f62..52747b6f8f 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -358,6 +358,11 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionDataImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..ae41146158 --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionDataImpl.java @@ -0,0 +1,167 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Location; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + Set lightenChunks) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); + int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); + WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); + + List> lights; + if (isStarLightInterface || chunkData.lights().isEmpty()) { + lights = Collections.emptyList(); + } else { + lights = new LinkedList<>(); + chunkData.lights().forEach(lightPosition -> { + lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), + chunkData.heightmaps(), lights); + + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPos blockPos = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPos blockPos = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lightenChunks.forEach(lightPosition -> { + this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, + lightPosition.z - baseChunkPosZAxis, null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, + int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, + Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + + List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + chunkDataPositioned.object.lights.forEach(lightPositioned -> { + lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset)); + }); + + chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, + chunkDataPositioned.object.heightmaps, lights)); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { + this.lightenChunks.forEach(lightPositioned -> { + ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, + baseChunkPosZAxis + lightPositioned.zOffset); + lightenChunks.add(newPos); + }); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + + private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, + List> lights) { + } + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java index e6df77c7af..c016a815b1 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java @@ -20,17 +20,20 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; @@ -44,13 +47,14 @@ import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage; @@ -59,7 +63,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -85,21 +88,36 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private ServerLevel serverLevel; + private Dimension dimension; + private LevelHeightAccessor levelHeightAccessor; - private Location baseLocationForCache = null; + @Nullable + private ServerLevel serverLevel; public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(ServerLevel serverLevel) { + private WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + this.levelHeightAccessor = serverLevel; + return this; + } + + private WorldEditSessionImpl initialize(Dimension dimension) { + DimensionType dimensionType = getDimensionTypeFromDimension(dimension); + this.serverLevel = null; + this.dimension = dimension; + this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); return this; } @@ -153,7 +171,7 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) chunkData.lights.add(blockPos); - LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; int blockX = blockPos.getX() & 15; int blockY = blockPos.getY(); @@ -169,6 +187,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -186,8 +206,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -223,8 +242,7 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -267,88 +285,70 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); - - int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); - int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - - WorldEditSessionImpl worldEditSession = obtain(serverLevel); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, - ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); - - LevelChunkSection[] sections = entry.getValue().chunkSections; - Map heightmaps = entry.getValue().heightmaps; - List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - entry.getValue().lights.forEach(blockPos -> { - lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); - }); - - ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); - worldEditSession.chunks.put(newPos, newChunkData); - } - - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - this.blockEntities.forEach(blockEntityPair -> { - BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - - this.lightenChunks.forEach(lightenChunk -> { - worldEditSession.lightenChunks.add(new ChunkPos( - lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); - }); - - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, + baseBlockPosZAxis, this, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); this.serverLevel = null; this.dimension = null; + this.levelHeightAccessor = null; POOL.release(this); } + public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + return new ChunkData(chunkSections, heightmaps, lights); + } + private boolean isValidPosition(BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); + !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); } - private class ChunkData { + private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public class ChunkData { private final LevelChunkSection[] chunkSections; private final Map heightmaps; private final List lights; - public ChunkData(long chunkKey) { - this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + private ChunkData(long chunkKey) { + this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); @@ -358,24 +358,37 @@ public ChunkData(long chunkKey) { createChunkSections(biomesRegistry); ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), serverLevel, biomesRegistry, null); + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); createHeightmaps(tempChunk); - runCustomWorldGenerator(tempChunk); + if (serverLevel != null) + runCustomWorldGenerator(tempChunk); } - public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } + public LevelChunkSection[] chunkSections() { + return this.chunkSections; + } + + public Map heightmaps() { + return this.heightmaps; + } + + public List lights() { + return this.lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); for (int i = 0; i < this.chunkSections.length; ++i) { - int chunkSectionPos = serverLevel.getSectionYFromSectionIndex(i); + int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i); PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biome, PalettedContainer.Strategy.SECTION_BIOMES); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index 3e0e5a2f5e..3a169aa41d 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -362,6 +362,11 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionDataImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..9bdfaf2f74 --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionDataImpl.java @@ -0,0 +1,167 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Location; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + Set lightenChunks) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); + int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); + WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); + + List> lights; + if (isStarLightInterface || chunkData.lights().isEmpty()) { + lights = Collections.emptyList(); + } else { + lights = new LinkedList<>(); + chunkData.lights().forEach(lightPosition -> { + lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), + chunkData.heightmaps(), lights); + + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPos blockPos = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPos blockPos = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lightenChunks.forEach(lightPosition -> { + this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, + lightPosition.z - baseChunkPosZAxis, null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, + int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, + Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + + List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + chunkDataPositioned.object.lights.forEach(lightPositioned -> { + lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset)); + }); + + chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, + chunkDataPositioned.object.heightmaps, lights)); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { + this.lightenChunks.forEach(lightPositioned -> { + ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, + baseChunkPosZAxis + lightPositioned.zOffset); + lightenChunks.add(newPos); + }); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + + private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, + List> lights) { + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java index 7a06e3e09a..08a8f4eee7 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java @@ -20,21 +20,24 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import com.google.gson.JsonParseException; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; @@ -49,13 +52,14 @@ import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome; import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; @@ -66,7 +70,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -94,21 +97,36 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private ServerLevel serverLevel; + private Dimension dimension; + private LevelHeightAccessor levelHeightAccessor; - private Location baseLocationForCache = null; + @Nullable + private ServerLevel serverLevel; public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(ServerLevel serverLevel) { + private WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + this.levelHeightAccessor = serverLevel; + return this; + } + + private WorldEditSessionImpl initialize(Dimension dimension) { + DimensionType dimensionType = getDimensionTypeFromDimension(dimension); + this.serverLevel = null; + this.dimension = dimension; + this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); return this; } @@ -162,7 +180,7 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) chunkData.lights.add(blockPos); - LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; int blockX = blockPos.getX() & 15; int blockY = blockPos.getY(); @@ -178,6 +196,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -195,8 +215,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -232,8 +251,7 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -269,78 +287,49 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); - - int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); - int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - - WorldEditSessionImpl worldEditSession = obtain(serverLevel); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, - ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); - - LevelChunkSection[] sections = entry.getValue().chunkSections; - Map heightmaps = entry.getValue().heightmaps; - List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - entry.getValue().lights.forEach(blockPos -> { - lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); - }); - - ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); - worldEditSession.chunks.put(newPos, newChunkData); - } - - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - this.blockEntities.forEach(blockEntityPair -> { - BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - - this.lightenChunks.forEach(lightenChunk -> { - worldEditSession.lightenChunks.add(new ChunkPos( - lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); - }); - - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, + baseBlockPosZAxis, this, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); this.serverLevel = null; this.dimension = null; + this.levelHeightAccessor = null; POOL.release(this); } + public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + return new ChunkData(chunkSections, heightmaps, lights); + } + private boolean isValidPosition(BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); + !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); } private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { @@ -395,14 +384,25 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } } - private class ChunkData { + private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public class ChunkData { private final LevelChunkSection[] chunkSections; private final Map heightmaps; private final List lights; public ChunkData(long chunkKey) { - this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); @@ -412,18 +412,31 @@ public ChunkData(long chunkKey) { createChunkSections(biomesRegistry); ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), serverLevel, biomesRegistry, null); + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); createHeightmaps(tempChunk); - runCustomWorldGenerator(tempChunk); + if (serverLevel != null) + runCustomWorldGenerator(tempChunk); } - public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } + public LevelChunkSection[] chunkSections() { + return this.chunkSections; + } + + public Map heightmaps() { + return this.heightmaps; + } + + public List lights() { + return this.lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index 561e6889d8..eaa3dd747f 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -362,6 +362,11 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionDataImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..8175642aec --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionDataImpl.java @@ -0,0 +1,167 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Location; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + Set lightenChunks) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); + int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); + WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); + + List> lights; + if (isStarLightInterface || chunkData.lights().isEmpty()) { + lights = Collections.emptyList(); + } else { + lights = new LinkedList<>(); + chunkData.lights().forEach(lightPosition -> { + lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), + chunkData.heightmaps(), lights); + + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPos blockPos = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPos blockPos = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lightenChunks.forEach(lightPosition -> { + this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, + lightPosition.z - baseChunkPosZAxis, null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, + int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, + Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + + List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + chunkDataPositioned.object.lights.forEach(lightPositioned -> { + lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset)); + }); + + chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, + chunkDataPositioned.object.heightmaps, lights)); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { + this.lightenChunks.forEach(lightPositioned -> { + ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, + baseChunkPosZAxis + lightPositioned.zOffset); + lightenChunks.add(newPos); + }); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + + private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, + List> lights) { + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java index 586fa6d244..3040645e92 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java @@ -20,21 +20,24 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import com.google.gson.JsonParseException; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; @@ -49,13 +52,14 @@ import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; @@ -66,7 +70,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -94,21 +97,36 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private ServerLevel serverLevel; + private Dimension dimension; + private LevelHeightAccessor levelHeightAccessor; - private Location baseLocationForCache = null; + @Nullable + private ServerLevel serverLevel; public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(ServerLevel serverLevel) { + private WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + this.levelHeightAccessor = serverLevel; + return this; + } + + private WorldEditSessionImpl initialize(Dimension dimension) { + DimensionType dimensionType = getDimensionTypeFromDimension(dimension); + this.serverLevel = null; + this.dimension = dimension; + this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); return this; } @@ -162,7 +180,7 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) chunkData.lights.add(blockPos); - LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; int blockX = blockPos.getX() & 15; int blockY = blockPos.getY(); @@ -178,6 +196,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -195,8 +215,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -232,8 +251,7 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -269,78 +287,49 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); - - int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); - int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - - WorldEditSessionImpl worldEditSession = obtain(serverLevel); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, - ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); - - LevelChunkSection[] sections = entry.getValue().chunkSections; - Map heightmaps = entry.getValue().heightmaps; - List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - entry.getValue().lights.forEach(blockPos -> { - lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); - }); - - ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); - worldEditSession.chunks.put(newPos, newChunkData); - } - - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - this.blockEntities.forEach(blockEntityPair -> { - BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - - this.lightenChunks.forEach(lightenChunk -> { - worldEditSession.lightenChunks.add(new ChunkPos( - lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); - }); - - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, + baseBlockPosZAxis, this, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); this.serverLevel = null; this.dimension = null; + this.levelHeightAccessor = null; POOL.release(this); } + public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + return new ChunkData(chunkSections, heightmaps, lights); + } + private boolean isValidPosition(BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); + !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); } private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { @@ -395,14 +384,25 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } } - private class ChunkData { + private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public class ChunkData { private final LevelChunkSection[] chunkSections; private final Map heightmaps; private final List lights; - public ChunkData(long chunkKey) { - this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + private ChunkData(long chunkKey) { + this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); @@ -411,18 +411,31 @@ public ChunkData(long chunkKey) { createChunkSections(biomesRegistry); ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), serverLevel, biomesRegistry, null); + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); createHeightmaps(tempChunk); - runCustomWorldGenerator(tempChunk); + if (serverLevel != null) + runCustomWorldGenerator(tempChunk); } - public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } + public LevelChunkSection[] chunkSections() { + return this.chunkSections; + } + + public Map heightmaps() { + return this.heightmaps; + } + + public List lights() { + return this.lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index 7c9ce327ec..42971f4c84 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -413,6 +413,11 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionDataImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..e8cfad922a --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionDataImpl.java @@ -0,0 +1,167 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Location; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + Set lightenChunks) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); + int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); + WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); + + List> lights; + if (isStarLightInterface || chunkData.lights().isEmpty()) { + lights = Collections.emptyList(); + } else { + lights = new LinkedList<>(); + chunkData.lights().forEach(lightPosition -> { + lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), + chunkData.heightmaps(), lights); + + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPos blockPos = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPos blockPos = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lightenChunks.forEach(lightPosition -> { + this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, + lightPosition.z - baseChunkPosZAxis, null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, + int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, + Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + + List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + chunkDataPositioned.object.lights.forEach(lightPositioned -> { + lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset)); + }); + + chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, + chunkDataPositioned.object.heightmaps, lights)); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { + this.lightenChunks.forEach(lightPositioned -> { + ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, + baseChunkPosZAxis + lightPositioned.zOffset); + lightenChunks.add(newPos); + }); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + + private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, + List> lights) { + } + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java index 7fa630d260..2521e965b6 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java @@ -20,20 +20,23 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import com.google.gson.JsonParseException; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; @@ -48,13 +51,14 @@ import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; @@ -64,7 +68,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -92,21 +95,36 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private ServerLevel serverLevel; + private Dimension dimension; + private LevelHeightAccessor levelHeightAccessor; - private Location baseLocationForCache = null; + @Nullable + private ServerLevel serverLevel; public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(ServerLevel serverLevel) { + private WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + this.levelHeightAccessor = serverLevel; + return this; + } + + private WorldEditSessionImpl initialize(Dimension dimension) { + DimensionType dimensionType = getDimensionTypeFromDimension(dimension); + this.serverLevel = null; + this.dimension = dimension; + this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); return this; } @@ -160,7 +178,7 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) chunkData.lights.add(blockPos); - LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; int blockX = blockPos.getX() & 15; int blockY = blockPos.getY(); @@ -176,6 +194,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -193,8 +213,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -230,8 +249,7 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -267,78 +285,49 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); - - int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); - int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - - WorldEditSessionImpl worldEditSession = obtain(serverLevel); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, - ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); - - LevelChunkSection[] sections = entry.getValue().chunkSections; - Map heightmaps = entry.getValue().heightmaps; - List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - entry.getValue().lights.forEach(blockPos -> { - lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); - }); - - ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); - worldEditSession.chunks.put(newPos, newChunkData); - } - - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - this.blockEntities.forEach(blockEntityPair -> { - BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - - this.lightenChunks.forEach(lightenChunk -> { - worldEditSession.lightenChunks.add(new ChunkPos( - lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); - }); - - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, + baseBlockPosZAxis, this, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); this.serverLevel = null; this.dimension = null; + this.levelHeightAccessor = null; POOL.release(this); } + public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + return new ChunkData(chunkSections, heightmaps, lights); + } + private boolean isValidPosition(BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); + !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); } private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { @@ -393,14 +382,25 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } } - private class ChunkData { + private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public class ChunkData { private final LevelChunkSection[] chunkSections; private final Map heightmaps; private final List lights; - public ChunkData(long chunkKey) { - this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + private ChunkData(long chunkKey) { + this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); @@ -410,18 +410,31 @@ public ChunkData(long chunkKey) { createChunkSections(biomesRegistry); ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), serverLevel, biomesRegistry, null); + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); createHeightmaps(tempChunk); - runCustomWorldGenerator(tempChunk); + if (serverLevel != null) + runCustomWorldGenerator(tempChunk); } - public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } + public LevelChunkSection[] chunkSections() { + return this.chunkSections; + } + + public Map heightmaps() { + return this.heightmaps; + } + + public List lights() { + return this.lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index a5ba998cc6..c6ba9d88ec 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -413,6 +413,11 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionDataImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..5ed73c252e --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionDataImpl.java @@ -0,0 +1,167 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Location; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + Set lightenChunks) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); + int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); + WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); + + List> lights; + if (isStarLightInterface || chunkData.lights().isEmpty()) { + lights = Collections.emptyList(); + } else { + lights = new LinkedList<>(); + chunkData.lights().forEach(lightPosition -> { + lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), + chunkData.heightmaps(), lights); + + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPos blockPos = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPos blockPos = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lightenChunks.forEach(lightPosition -> { + this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, + lightPosition.z - baseChunkPosZAxis, null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, + int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, + Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + + List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + chunkDataPositioned.object.lights.forEach(lightPositioned -> { + lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset)); + }); + + chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, + chunkDataPositioned.object.heightmaps, lights)); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { + this.lightenChunks.forEach(lightPositioned -> { + ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, + baseChunkPosZAxis + lightPositioned.zOffset); + lightenChunks.add(newPos); + }); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + + private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, + List> lights) { + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java index 65b374bd47..21c4372495 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java @@ -20,20 +20,22 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import com.google.gson.JsonParseException; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; @@ -48,13 +50,14 @@ import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; @@ -64,7 +67,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -92,21 +94,36 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private ServerLevel serverLevel; + private Dimension dimension; + private LevelHeightAccessor levelHeightAccessor; - private Location baseLocationForCache = null; + @Nullable + private ServerLevel serverLevel; public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(ServerLevel serverLevel) { + private WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + this.levelHeightAccessor = serverLevel; + return this; + } + + private WorldEditSessionImpl initialize(Dimension dimension) { + DimensionType dimensionType = getDimensionTypeFromDimension(dimension); + this.serverLevel = null; + this.dimension = dimension; + this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); return this; } @@ -160,7 +177,7 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) chunkData.lights.add(blockPos); - LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; int blockX = blockPos.getX() & 15; int blockY = blockPos.getY(); @@ -176,6 +193,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -193,8 +212,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -230,8 +248,7 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -267,78 +284,49 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); - - int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); - int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - - WorldEditSessionImpl worldEditSession = obtain(serverLevel); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, - ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); - - LevelChunkSection[] sections = entry.getValue().chunkSections; - Map heightmaps = entry.getValue().heightmaps; - List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - entry.getValue().lights.forEach(blockPos -> { - lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); - }); - - ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); - worldEditSession.chunks.put(newPos, newChunkData); - } - - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - this.blockEntities.forEach(blockEntityPair -> { - BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - - this.lightenChunks.forEach(lightenChunk -> { - worldEditSession.lightenChunks.add(new ChunkPos( - lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); - }); - - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, + baseBlockPosZAxis, this, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); this.serverLevel = null; this.dimension = null; + this.levelHeightAccessor = null; POOL.release(this); } + public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + return new ChunkData(chunkSections, heightmaps, lights); + } + private boolean isValidPosition(BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); + !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); } private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { @@ -393,14 +381,25 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } } - private class ChunkData { + private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + Registry registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getValue(resourceKey).type().value(); + } + + public class ChunkData { private final LevelChunkSection[] chunkSections; private final Map heightmaps; private final List lights; - public ChunkData(long chunkKey) { - this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + private ChunkData(long chunkKey) { + this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); @@ -410,18 +409,31 @@ public ChunkData(long chunkKey) { createChunkSections(biomesRegistry); ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), serverLevel, biomesRegistry, null); + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); createHeightmaps(tempChunk); - runCustomWorldGenerator(tempChunk); + if (serverLevel != null) + runCustomWorldGenerator(tempChunk); } - public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } + public LevelChunkSection[] chunkSections() { + return this.chunkSections; + } + + public Map heightmaps() { + return this.heightmaps; + } + + public List lights() { + return this.lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index 7944975c93..64534b2702 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -413,6 +413,11 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionDataImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..f106d6dab6 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionDataImpl.java @@ -0,0 +1,167 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Location; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + Set lightenChunks) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); + int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); + WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); + + List> lights; + if (isStarLightInterface || chunkData.lights().isEmpty()) { + lights = Collections.emptyList(); + } else { + lights = new LinkedList<>(); + chunkData.lights().forEach(lightPosition -> { + lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), + chunkData.heightmaps(), lights); + + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPos blockPos = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPos blockPos = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lightenChunks.forEach(lightPosition -> { + this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, + lightPosition.z - baseChunkPosZAxis, null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, + int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, + Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + + List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + chunkDataPositioned.object.lights.forEach(lightPositioned -> { + lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset)); + }); + + chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, + chunkDataPositioned.object.heightmaps, lights)); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { + this.lightenChunks.forEach(lightPositioned -> { + ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, + baseChunkPosZAxis + lightPositioned.zOffset); + lightenChunks.add(newPos); + }); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + + private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, + List> lights) { + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java index 589b935ce8..018203c6a3 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java @@ -20,20 +20,22 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import com.google.gson.JsonParseException; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; @@ -48,13 +50,14 @@ import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; @@ -64,7 +67,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -92,21 +94,36 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private ServerLevel serverLevel; + private Dimension dimension; + private LevelHeightAccessor levelHeightAccessor; - private Location baseLocationForCache = null; + @Nullable + private ServerLevel serverLevel; public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(ServerLevel serverLevel) { + private WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + this.levelHeightAccessor = serverLevel; + return this; + } + + private WorldEditSessionImpl initialize(Dimension dimension) { + DimensionType dimensionType = getDimensionTypeFromDimension(dimension); + this.serverLevel = null; + this.dimension = dimension; + this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); return this; } @@ -160,7 +177,7 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) chunkData.lights.add(blockPos); - LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; int blockX = blockPos.getX() & 15; int blockY = blockPos.getY(); @@ -176,6 +193,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -193,8 +212,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -230,8 +248,7 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -267,78 +284,49 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); - - int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); - int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - - WorldEditSessionImpl worldEditSession = obtain(serverLevel); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, - ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); - - LevelChunkSection[] sections = entry.getValue().chunkSections; - Map heightmaps = entry.getValue().heightmaps; - List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - entry.getValue().lights.forEach(blockPos -> { - lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); - }); - - ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); - worldEditSession.chunks.put(newPos, newChunkData); - } - - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - this.blockEntities.forEach(blockEntityPair -> { - BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - - this.lightenChunks.forEach(lightenChunk -> { - worldEditSession.lightenChunks.add(new ChunkPos( - lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); - }); - - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, + baseBlockPosZAxis, this, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); this.serverLevel = null; this.dimension = null; + this.levelHeightAccessor = null; POOL.release(this); } + public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + return new ChunkData(chunkSections, heightmaps, lights); + } + private boolean isValidPosition(BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); + this.levelHeightAccessor.isInsideBuildHeight(blockPos.getY()); } private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { @@ -393,14 +381,25 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } } - private class ChunkData { + private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + Registry registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getValue(resourceKey).type().value(); + } + + public class ChunkData { private final LevelChunkSection[] chunkSections; private final Map heightmaps; private final List lights; - public ChunkData(long chunkKey) { - this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + private ChunkData(long chunkKey) { + this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); @@ -409,18 +408,31 @@ public ChunkData(long chunkKey) { createChunkSections(biomesRegistry); ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), serverLevel, biomesRegistry, null); + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); createHeightmaps(tempChunk); - runCustomWorldGenerator(tempChunk); + if (serverLevel != null) + runCustomWorldGenerator(tempChunk); } - public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } + public LevelChunkSection[] chunkSections() { + return this.chunkSections; + } + + public Map heightmaps() { + return this.heightmaps; + } + + public List lights() { + return this.lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java index 1e8f368bbd..7a2f4c2c8b 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java @@ -413,6 +413,11 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionDataImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..ff6bd9d987 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionDataImpl.java @@ -0,0 +1,167 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Location; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + Set lightenChunks) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); + int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); + WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); + + List> lights; + if (isStarLightInterface || chunkData.lights().isEmpty()) { + lights = Collections.emptyList(); + } else { + lights = new LinkedList<>(); + chunkData.lights().forEach(lightPosition -> { + lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), + chunkData.heightmaps(), lights); + + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPos blockPos = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPos blockPos = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lightenChunks.forEach(lightPosition -> { + this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, + lightPosition.z - baseChunkPosZAxis, null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, + int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, + Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + + List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + chunkDataPositioned.object.lights.forEach(lightPositioned -> { + lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset)); + }); + + chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, + chunkDataPositioned.object.heightmaps, lights)); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { + this.lightenChunks.forEach(lightPositioned -> { + ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, + baseChunkPosZAxis + lightPositioned.zOffset); + lightenChunks.add(newPos); + }); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + + private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, + List> lights) { + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java index f498d1d81a..ba05a35f7e 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java @@ -20,20 +20,22 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import com.google.gson.JsonParseException; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; @@ -48,13 +50,14 @@ import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; @@ -64,7 +67,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -92,21 +94,36 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private ServerLevel serverLevel; + private Dimension dimension; + private LevelHeightAccessor levelHeightAccessor; - private Location baseLocationForCache = null; + @Nullable + private ServerLevel serverLevel; public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(ServerLevel serverLevel) { + private WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + this.levelHeightAccessor = serverLevel; + return this; + } + + private WorldEditSessionImpl initialize(Dimension dimension) { + DimensionType dimensionType = getDimensionTypeFromDimension(dimension); + this.serverLevel = null; + this.dimension = dimension; + this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); return this; } @@ -160,7 +177,7 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) chunkData.lights.add(blockPos); - LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; int blockX = blockPos.getX() & 15; int blockY = blockPos.getY(); @@ -176,6 +193,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -193,8 +212,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -230,8 +248,7 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -267,78 +284,49 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); - - int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); - int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - - WorldEditSessionImpl worldEditSession = obtain(serverLevel); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, - ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); - - LevelChunkSection[] sections = entry.getValue().chunkSections; - Map heightmaps = entry.getValue().heightmaps; - List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - entry.getValue().lights.forEach(blockPos -> { - lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); - }); - - ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); - worldEditSession.chunks.put(newPos, newChunkData); - } - - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - this.blockEntities.forEach(blockEntityPair -> { - BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - - this.lightenChunks.forEach(lightenChunk -> { - worldEditSession.lightenChunks.add(new ChunkPos( - lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); - }); - - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, + baseBlockPosZAxis, this, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); this.serverLevel = null; this.dimension = null; + this.levelHeightAccessor = null; POOL.release(this); } + public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + return new ChunkData(chunkSections, heightmaps, lights); + } + private boolean isValidPosition(BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); + this.levelHeightAccessor.isInsideBuildHeight(blockPos.getY()); } private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { @@ -392,14 +380,25 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } } - private class ChunkData { + private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + Registry registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getValue(resourceKey).type().value(); + } + + public class ChunkData { private final LevelChunkSection[] chunkSections; private final Map heightmaps; private final List lights; - public ChunkData(long chunkKey) { - this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + private ChunkData(long chunkKey) { + this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); @@ -408,18 +407,31 @@ public ChunkData(long chunkKey) { createChunkSections(biomesRegistry); ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), serverLevel, biomesRegistry, null); + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); createHeightmaps(tempChunk); - runCustomWorldGenerator(tempChunk); + if (serverLevel != null) + runCustomWorldGenerator(tempChunk); } - public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } + public LevelChunkSection[] chunkSections() { + return this.chunkSections; + } + + public Map heightmaps() { + return this.heightmaps; + } + + public List lights() { + return this.lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java index e2d312956b..23b74156e0 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java @@ -405,6 +405,11 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionDataImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..b103f02cbd --- /dev/null +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionDataImpl.java @@ -0,0 +1,167 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Location; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private static final boolean isStarLightInterface = ((Supplier) () -> { + try { + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + }).get(); + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + Set lightenChunks) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); + int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); + WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); + + List> lights; + if (isStarLightInterface || chunkData.lights().isEmpty()) { + lights = Collections.emptyList(); + } else { + lights = new LinkedList<>(); + chunkData.lights().forEach(lightPosition -> { + lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), + chunkData.heightmaps(), lights); + + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPos blockPos = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPos blockPos = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, + blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lightenChunks.forEach(lightPosition -> { + this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, + lightPosition.z - baseChunkPosZAxis, null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, + int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, + Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + + List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); + chunkDataPositioned.object.lights.forEach(lightPositioned -> { + lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset)); + }); + + chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, + chunkDataPositioned.object.heightmaps, lights)); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { + this.lightenChunks.forEach(lightPositioned -> { + ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, + baseChunkPosZAxis + lightPositioned.zOffset); + lightenChunks.add(newPos); + }); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + + private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, + List> lights) { + } + +} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java index a98c34a085..5aa9151d4c 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java @@ -20,22 +20,24 @@ import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import com.google.gson.JsonParseException; import com.mojang.logging.LogUtils; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.util.ProblemReporter; import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; @@ -50,6 +52,8 @@ import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.ValueInput; @@ -58,7 +62,6 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.generator.ChunkGenerator; @@ -69,7 +72,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -99,21 +101,36 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - private ServerLevel serverLevel; + private Dimension dimension; + private LevelHeightAccessor levelHeightAccessor; - private Location baseLocationForCache = null; + @Nullable + private ServerLevel serverLevel; public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(ServerLevel serverLevel) { + private WorldEditSessionImpl initialize(ServerLevel serverLevel) { this.serverLevel = serverLevel; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); + this.levelHeightAccessor = serverLevel; + return this; + } + + private WorldEditSessionImpl initialize(Dimension dimension) { + DimensionType dimensionType = getDimensionTypeFromDimension(dimension); + this.serverLevel = null; + this.dimension = dimension; + this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); return this; } @@ -167,7 +184,7 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) chunkData.lights.add(blockPos); - LevelChunkSection levelChunkSection = chunkData.chunkSections[serverLevel.getSectionIndex(blockPos.getY())]; + LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; int blockX = blockPos.getX() & 15; int blockY = blockPos.getY(); @@ -183,6 +200,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -200,8 +219,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); ChunkPos chunkPos = levelChunk.getPos(); @@ -237,8 +255,7 @@ public void applyBlocks(Chunk bukkitChunk) { @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); @@ -279,78 +296,49 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); - - int chunkPosXAxisDelta = SectionPos.blockToSectionCoord(location.getBlockX()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockX()); - int chunkPosZAxisDelta = SectionPos.blockToSectionCoord(location.getBlockZ()) - SectionPos.blockToSectionCoord(baseLocationForCache.getBlockZ()); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - - WorldEditSessionImpl worldEditSession = obtain(serverLevel); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkPos.asLong(ChunkPos.getX(entry.getKey()) + chunkPosXAxisDelta, - ChunkPos.getZ(entry.getKey()) + chunkPosZAxisDelta); - - LevelChunkSection[] sections = entry.getValue().chunkSections; - Map heightmaps = entry.getValue().heightmaps; - List lights = entry.getValue().lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - entry.getValue().lights.forEach(blockPos -> { - lights.add(blockPos.offset(xAxisDelta, 0, zAxisDelta)); - }); - - ChunkData newChunkData = new ChunkData(sections, heightmaps, lights); - worldEditSession.chunks.put(newPos, newChunkData); - } - - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPos newPos = blockToUpdatePair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - this.blockEntities.forEach(blockEntityPair -> { - BlockPos newPos = blockEntityPair.getKey().offset(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - - this.lightenChunks.forEach(lightenChunk -> { - worldEditSession.lightenChunks.add(new ChunkPos( - lightenChunk.x + chunkPosXAxisDelta, lightenChunk.z + chunkPosZAxisDelta)); - }); - - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, + baseBlockPosZAxis, this, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); this.serverLevel = null; this.dimension = null; + this.levelHeightAccessor = null; POOL.release(this); } + public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + return new ChunkData(chunkSections, heightmaps, lights); + } + private boolean isValidPosition(BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); + this.levelHeightAccessor.isInsideBuildHeight(blockPos.getY()); } private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { @@ -406,14 +394,25 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } } - private class ChunkData { + private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + Registry registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getValue(resourceKey).type().value(); + } + + public class ChunkData { private final LevelChunkSection[] chunkSections; private final Map heightmaps; private final List lights; - public ChunkData(long chunkKey) { - this(new LevelChunkSection[serverLevel.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), + private ChunkData(long chunkKey) { + this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); ChunkPos chunkPos = new ChunkPos(chunkKey); @@ -423,18 +422,31 @@ public ChunkData(long chunkKey) { createChunkSections(biomesRegistry); ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), serverLevel, biomesRegistry, null); + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); createHeightmaps(tempChunk); - runCustomWorldGenerator(tempChunk); + if (serverLevel != null) + runCustomWorldGenerator(tempChunk); } - public ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { + private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { this.chunkSections = chunkSections; this.heightmaps = heightmaps; this.lights = lights; } + public LevelChunkSection[] chunkSections() { + return this.chunkSections; + } + + public Map heightmaps() { + return this.heightmaps; + } + + public List lights() { + return this.lights; + } + private void createChunkSections(Registry biomesRegistry) { Holder biome = CraftBiome.bukkitToMinecraftHolder( IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java index 735beff363..97d3653cab 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java @@ -330,6 +330,11 @@ public WorldEditSession createEditSession(World world) { return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); } + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + @Override public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionDataImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionDataImpl.java new file mode 100644 index 0000000000..85ef5fc6db --- /dev/null +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionDataImpl.java @@ -0,0 +1,130 @@ +package com.bgsoftware.superiorskyblock.nms.v1_8_R3.world; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.server.v1_8_R3.BlockPosition; +import net.minecraft.server.v1_8_R3.ChunkCoordIntPair; +import net.minecraft.server.v1_8_R3.IBlockData; +import org.bukkit.Location; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class WorldEditSessionDataImpl implements WorldEditSession.Data { + + private final List> chunks = new LinkedList<>(); + private final List> blocksToUpdate = new LinkedList<>(); + private final List> blockEntities = new LinkedList<>(); + private final List> lights = new LinkedList<>(); + + public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, + List> blocksToUpdate, + List> blockEntities, + List lights) { + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; + + // Convert chunk data + Iterator> chunksIterator = chunks.entryIterator(); + while (chunksIterator.hasNext()) { + Long2ObjectMapView.Entry entry = chunksIterator.next(); + int currChunkPosXAxis = getChunkCoordX(entry.getKey()); + int currChunkPosZAxis = getChunkCoordZ(entry.getKey()); + this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, + currChunkPosZAxis - baseChunkPosZAxis, entry.getValue())); + } + + // Convert blocksToUpdate + blocksToUpdate.forEach(blockToUpdate -> { + BlockPosition blockPosition = blockToUpdate.getKey(); + this.blocksToUpdate.add(new PositionedObject<>(blockPosition.getX() - baseBlockPosXAxis, + blockPosition.getY() - baseBlockPosYAxis, blockPosition.getZ() - baseBlockPosZAxis, + blockToUpdate.getValue())); + }); + + // Convert blockEntities + blockEntities.forEach(blockEntity -> { + BlockPosition blockPosition = blockEntity.getKey(); + this.blockEntities.add(new PositionedObject<>(blockPosition.getX() - baseBlockPosXAxis, + blockPosition.getY() - baseBlockPosYAxis, blockPosition.getZ() - baseBlockPosZAxis, + blockEntity.getValue())); + }); + + // Convert lights + lights.forEach(lightPosition -> { + this.lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, + lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, + null)); + }); + } + + public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, Long2ObjectMapView chunks) { + this.chunks.forEach(chunkDataPositioned -> { + long newPos = ChunkCoordIntPair.a(baseChunkPosXAxis + chunkDataPositioned.xOffset, + baseChunkPosZAxis + chunkDataPositioned.zOffset); + chunks.put(newPos, chunkDataPositioned.object); + }); + } + + public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { + this.blocksToUpdate.forEach(blockToUpdatePositioned -> { + BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, + baseBlockPosYAxis + blockToUpdatePositioned.yOffset, + baseBlockPosZAxis + blockToUpdatePositioned.zOffset); + blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); + }); + } + + public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { + this.blockEntities.forEach(blockEntityPositioned -> { + BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + blockEntityPositioned.xOffset, + baseBlockPosYAxis + blockEntityPositioned.yOffset, + baseBlockPosZAxis + blockEntityPositioned.zOffset); + blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); + }); + } + + public void readLights(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List lights) { + this.lights.forEach(lightPositioned -> { + BlockPosition newPos = new BlockPosition(baseBlockPosXAxis + lightPositioned.xOffset, + baseBlockPosYAxis + lightPositioned.yOffset, + baseBlockPosZAxis + lightPositioned.zOffset); + lights.add(newPos); + }); + } + + private static int getChunkCoordX(long i) { + return (int) (i & 4294967295L); + } + + private static int getChunkCoordZ(long i) { + return (int) (i >>> 32 & 4294967295L); + } + + private static class PositionedObject { + + private final int xOffset; + private final int yOffset; + private final int zOffset; + private final V object; + + PositionedObject(int xOffset, int zOffset, V object) { + this(xOffset, 0, zOffset, object); + } + + PositionedObject(int xOffset, int yOffset, int zOffset, V object) { + this.xOffset = xOffset; + this.yOffset = yOffset; + this.zOffset = zOffset; + this.object = object; + } + + } + +} \ No newline at end of file diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java index 734779e13e..6272163029 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java @@ -17,6 +17,7 @@ import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.google.common.base.Preconditions; import net.minecraft.server.v1_8_R3.BiomeBase; import net.minecraft.server.v1_8_R3.Block; import net.minecraft.server.v1_8_R3.BlockBed; @@ -46,6 +47,9 @@ public class WorldEditSessionImpl implements WorldEditSession { + private static final ReflectMethod WORLD_SERVER_UPDATE_LIGHT_PAPER = new ReflectMethod<>( + net.minecraft.server.v1_8_R3.World.class, "updateLight", EnumSkyBlock.class, BlockPosition.class); + private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @@ -54,24 +58,35 @@ public class WorldEditSessionImpl implements WorldEditSession { private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); private final List lights = new LinkedList<>(); - private WorldServer worldServer; + private Dimension dimension; - private Location baseLocationForCache = null; + @Nullable + private WorldServer worldServer; public static WorldEditSessionImpl obtain(WorldServer worldServer) { return POOL.obtain().initialize(worldServer); } + public static WorldEditSessionImpl obtain(Dimension dimension) { + return POOL.obtain().initialize(dimension); + } + private WorldEditSessionImpl() { } - public WorldEditSessionImpl initialize(WorldServer worldServer) { + private WorldEditSessionImpl initialize(WorldServer worldServer) { this.worldServer = worldServer; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(worldServer.getWorld()); return this; } + private WorldEditSessionImpl initialize(Dimension dimension) { + this.worldServer = null; + this.dimension = dimension; + return this; + } + @Override public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag blockEntityData) { @@ -110,6 +125,8 @@ public void setBlock(Location location, int combinedId, @Nullable CompoundTag st @Override public List getAffectedChunks() { + Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); + if (chunks.isEmpty()) return Collections.emptyList(); @@ -127,8 +144,7 @@ public List getAffectedChunks() { @Override public void applyBlocks(org.bukkit.Chunk bukkitChunk) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call applyBlocks on WorldEditSession cache object"); + Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); @@ -154,13 +170,9 @@ public void applyBlocks(org.bukkit.Chunk bukkitChunk) { chunk.e(); } - private static final ReflectMethod WORLD_SERVER_UPDATE_LIGHT_PAPER = new ReflectMethod<>( - net.minecraft.server.v1_8_R3.World.class, "updateLight", EnumSkyBlock.class, BlockPosition.class); - @Override public void finish(Island island) { - if (baseLocationForCache != null) - throw new IllegalStateException("Cannot call finish on WorldEditSession cache object"); + Preconditions.checkState(this.worldServer != null, "Cannot call WorldEditSession#finish on partial initialized session"); // Update blocks blocksToUpdate.forEach(data -> worldServer.setTypeAndData(data.getKey(), data.getValue(), 3)); @@ -203,56 +215,30 @@ public void finish(Island island) { } @Override - public void markForCache(Location location) { - this.baseLocationForCache = location.clone(); + public Data readData(Location baseLocation) { + return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lights); } @Override - public WorldEditSession buildFromCache(Location location) { - if (this.baseLocationForCache == null) - throw new IllegalStateException("Cannot call buildFromCache for non-cache WorldEditSessions"); - - int chunkPosXAxisDelta = (location.getBlockX() >> 4) - (baseLocationForCache.getBlockX() >> 4); - int chunkPosZAxisDelta = (location.getBlockZ() >> 4) - (baseLocationForCache.getBlockZ() >> 4); - int xAxisDelta = location.getBlockX() - baseLocationForCache.getBlockX(); - int zAxisDelta = location.getBlockZ() - baseLocationForCache.getBlockZ(); + public void applyData(Data data, Location baseLocation) { + WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - WorldServer worldServer = ((CraftWorld) location.getWorld()).getHandle(); - - WorldEditSessionImpl worldEditSession = obtain(worldServer); + int baseBlockPosXAxis = baseLocation.getBlockX(); + int baseBlockPosYAxis = baseLocation.getBlockY(); + int baseBlockPosZAxis = baseLocation.getBlockZ(); + int baseChunkPosXAxis = baseBlockPosXAxis >> 4; + int baseChunkPosZAxis = baseBlockPosZAxis >> 4; // We need to transform all data to the new base location values - Iterator> chunksIterator = this.chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - long newPos = ChunkCoordIntPair.a(getChunkCoordX(entry.getKey()) + chunkPosXAxisDelta, - getChunkCoordZ(entry.getKey()) + chunkPosZAxisDelta); - worldEditSession.chunks.put(newPos, entry.getValue()); - } - - this.blocksToUpdate.forEach(blockToUpdatePair -> { - BlockPosition newPos = blockToUpdatePair.getKey().a(xAxisDelta, 0, zAxisDelta); - worldEditSession.blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePair.getValue())); - }); - - this.blockEntities.forEach(blockEntityPair -> { - BlockPosition newPos = blockEntityPair.getKey().a(xAxisDelta, 0, zAxisDelta); - worldEditSession.blockEntities.add(new Pair<>(newPos, blockEntityPair.getValue())); - }); - this.lights.forEach(lightPosition -> { - BlockPosition newPos = lightPosition.a(xAxisDelta, 0, zAxisDelta); - worldEditSession.lights.add(newPos); - }); - - return worldEditSession; + dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, this.chunks); + dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); + dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); + dataImpl.readLights(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.lights); } @Override public void release() { - if (this.baseLocationForCache != null) - return; - this.chunks.clear(); this.blocksToUpdate.clear(); this.blockEntities.clear(); @@ -265,21 +251,14 @@ public void release() { private boolean isValidPosition(BlockPosition blockPosition) { return blockPosition.getX() >= -30000000 && blockPosition.getZ() >= -30000000 && blockPosition.getX() < 30000000 && blockPosition.getZ() < 30000000 && - blockPosition.getY() >= 0 && blockPosition.getY() < worldServer.getHeight(); + blockPosition.getY() >= 0 && blockPosition.getY() < 256; } - private static int getChunkCoordX(long i) { - return (int) (i & 4294967295L); - } - - private static int getChunkCoordZ(long i) { - return (int) (i >>> 32 & 4294967295L); - } + public class ChunkData { - private class ChunkData { private final ChunkSection[] chunkSections = new ChunkSection[16]; - public ChunkData(long chunkKey) { + private ChunkData(long chunkKey) { ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32)); createChunkSections(); runCustomWorldGenerator(chunkCoord); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java index e4f46517a5..a9b6b6d471 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java @@ -72,6 +72,8 @@ default SignType getSignType(Block block) { WorldEditSession createEditSession(World world); + WorldEditSession createPartialEditSession(Dimension dimension); + ChunkReader createChunkReader(Chunk chunk); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java index a3bfdb23d5..46f4c3c353 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/world/WorldEditSession.java @@ -20,8 +20,12 @@ public interface WorldEditSession extends ObjectsPool.Releasable { void finish(Island island); - void markForCache(Location baseLocation); + Data readData(Location baseLocation); - WorldEditSession buildFromCache(Location baseLocation); + void applyData(Data data, Location baseLocation); + + interface Data { + + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index d3b40cb794..2d6f914ec3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -120,8 +120,13 @@ public void cacheSchematics() { for (Schematic schematic : this.schematicsContainer.getSchematics().values()) { if (schematic instanceof SuperiorSchematic) { - schematic = new CachedSuperiorSchematic((SuperiorSchematic) schematic); - cachedSchematic = true; + try { + schematic = new CachedSuperiorSchematic((SuperiorSchematic) schematic); + cachedSchematic = true; + } catch (Throwable error) { + Log.warn("Cannot cache schematic ", schematic.getName(), ", skipping..."); + error.printStackTrace(); + } } newSchematics.add(schematic); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java index 564793dfc9..92162c4b7a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; +import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; @@ -14,16 +15,16 @@ import com.bgsoftware.superiorskyblock.core.schematic.SchematicBlock; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.world.WorldGenerator; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.bgsoftware.superiorskyblock.world.schematic.BaseSchematic; -import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.World; import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.function.Consumer; @@ -31,10 +32,14 @@ public class CachedSuperiorSchematic extends BaseSchematic implements Schematic private final Int2ObjectMapView cachedSessions = CollectionsFactory.createInt2ObjectArrayMap(); private final SuperiorSchematic baseSchematic; + private final Dimension schematicDimension; public CachedSuperiorSchematic(SuperiorSchematic baseSchematic) { super(baseSchematic.getName(), KeyMaps.createEmptyMap()); this.baseSchematic = baseSchematic; + this.schematicDimension = getSchematicDimension(baseSchematic.getName()); + if (!(WorldGenerator.getWorldGenerator(this.schematicDimension) instanceof IslandsGenerator)) + throw new IllegalStateException("Cannot use cached schematics with custom generators"); populateCache(); } @@ -85,7 +90,8 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long if (worldEditSessionCache == null) throw new IllegalStateException("Cannot find cache for (" + chunkX + "," + chunkZ + ")"); - WorldEditSession worldEditSession = worldEditSessionCache.session.buildFromCache(location); + WorldEditSession worldEditSession = plugin.getNMSWorld().createEditSession(location.getWorld()); + worldEditSession.applyData(worldEditSessionCache.sessionData, location); worldEditSessionCache.prePlaceTasks.forEach(schematicBlock -> { schematicBlock.doPrePlace(island); @@ -174,20 +180,15 @@ private void populateCache16Size() { } private WorldEditSessionCache createSessionCache(int x, int z) { - World islandsWorld = null; - for (World world : Bukkit.getWorlds()) { - if (plugin.getProviders().getWorldsProvider().isIslandsWorld(world)) { - islandsWorld = world; - break; - } - } - Preconditions.checkState(islandsWorld != null, "Cannot find valid islands world"); - Location location = new Location(islandsWorld, x, plugin.getSettings().getIslandHeight() - 1, z); + Location location = new Location(null, x, plugin.getSettings().getIslandHeight() - 1, z); List prePlaceTasks = new LinkedList<>(); List postPlaceTasks = new LinkedList<>(); - WorldEditSession session = this.baseSchematic.createSessionWithSchematicBlocks(location, prePlaceTasks, postPlaceTasks); - session.markForCache(location); - return new WorldEditSessionCache(session, prePlaceTasks, postPlaceTasks, location); + + WorldEditSession worldEditSession = plugin.getNMSWorld().createPartialEditSession(this.schematicDimension); + this.baseSchematic.populateSessionWithSchematicBlocks(worldEditSession, location, prePlaceTasks, postPlaceTasks); + WorldEditSession.Data sessionData = worldEditSession.readData(location); + worldEditSession.release(); + return new WorldEditSessionCache(sessionData, prePlaceTasks, postPlaceTasks, location); } private static int posKey(int x, int z) { @@ -209,15 +210,24 @@ private static int calculateCacheSize() { } } + private static Dimension getSchematicDimension(String name) { + for (Dimension dimension : Dimension.values()) { + if (name.endsWith("_" + dimension.getName().toLowerCase(Locale.ENGLISH))) + return dimension; + } + + return plugin.getSettings().getWorlds().getDefaultWorldDimension(); + } + private static class WorldEditSessionCache { - private final WorldEditSession session; + private final WorldEditSession.Data sessionData; private final List prePlaceTasks; private final List postPlaceTasks; private final Location baseLocation; - WorldEditSessionCache(WorldEditSession session, List prePlaceTasks, List postPlaceTasks, Location baseLocation) { - this.session = session; + WorldEditSessionCache(WorldEditSession.Data sessionData, List prePlaceTasks, List postPlaceTasks, Location baseLocation) { + this.sessionData = sessionData; this.prePlaceTasks = prePlaceTasks; this.postPlaceTasks = postPlaceTasks; this.baseLocation = baseLocation; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java index 127b58c928..29a9d0d01e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java @@ -204,10 +204,8 @@ public void pasteSchematic(Island island, Location location, Runnable callback, } } - public WorldEditSession createSessionWithSchematicBlocks(Location location, List prePlaceTasks, - List postPlaceTasks) { - WorldEditSession worldEditSession = plugin.getNMSWorld().createEditSession(location.getWorld()); - + public void populateSessionWithSchematicBlocks(WorldEditSession worldEditSession, Location location, + List prePlaceTasks, List postPlaceTasks) { Location min = this.data.offset.applyToLocation(location); VarintArray.Itr blockIdsIterator = new VarintArray(this.data.blockIds).iterator(); @@ -234,8 +232,6 @@ public WorldEditSession createSessionWithSchematicBlocks(Location location, List if (blockIdsIterator.hasNext()) throw new IllegalStateException("Not all blocks were read from varint iterator"); - - return worldEditSession; } public void finishPlaceSchematic(WorldEditSession worldEditSession, List postPlaceTasks, @@ -331,7 +327,8 @@ private void pasteSchematicAsyncInternal(Island island, Location location, long long placeProfiler = Profiler.start(ProfileType.SCHEMATIC_BLOCKS_PLACE, getName()); - WorldEditSession worldEditSession = createSessionWithSchematicBlocks(location, prePlaceTasks, postPlaceTasks); + WorldEditSession worldEditSession = plugin.getNMSWorld().createEditSession(location.getWorld()); + populateSessionWithSchematicBlocks(worldEditSession, location, prePlaceTasks, postPlaceTasks); prePlaceTasks.forEach(schematicBlock -> { schematicBlock.doPrePlace(island); @@ -360,7 +357,7 @@ public List getAffectedChunks() { public Runnable onTeleportCallback() { return this.onTeleportCallback; } - + public SuperiorSchematic copy(String newName) { return new SuperiorSchematic(newName, this.data, this.cachedCounts); } From b6842a71adb0a45f4a0f25a9495ee5c522f017c8 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sun, 21 Sep 2025 13:50:41 +0200 Subject: [PATCH 317/600] Fixed breaking warp sign when deleting it (#2663) --- .../com/bgsoftware/superiorskyblock/island/warp/SignWarp.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java index 1567d7ac2f..bb98916ce4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java @@ -46,7 +46,7 @@ public static void trySignWarpBreak(IslandWarp islandWarp, CommandSender command // Detected warp sign signBlock.setType(Material.AIR); - signBlock.getWorld().dropItemNaturally(warpLocation, new ItemStack(Material.SIGN)); + signBlock.getWorld().dropItemNaturally(warpLocation, new ItemStack(blockState.getType())); Message.DELETE_WARP_SIGN_BROKE.send(commandSender); } From 135a6c1c64bb75a9befa314e6c7b7f3589d85145 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 21 Sep 2025 15:41:05 +0300 Subject: [PATCH 318/600] Fix island world border is disappearing after respawning in the island (#2662) --- .../listener/PlayersListener.java | 19 +++++++++++++++++++ .../player/respawn/RespawnActions.java | 16 ++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java index 765c5645a4..823a6ad68b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java @@ -504,6 +504,24 @@ private void onPlayerRespawn(GameEvent e) { } } + private void onPlayerRespawnMonitor(GameEvent e) { + Location respawnLocation = e.getArgs().bukkitEvent.getRespawnLocation(); + Player player = e.getArgs().player; + + BukkitExecutor.sync(() -> { + if (!player.isOnline()) + return; + + Island respawnAtIsland = plugin.getGrid().getIslandAt(respawnLocation); + if (respawnAtIsland != null) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); + superiorPlayer.updateWorldBorder(respawnAtIsland); + } + }, 2L); + + + } + /* INTERNAL */ private void registerListeners() { @@ -520,6 +538,7 @@ private void registerListeners() { registerCallback(GameEventType.INVENTORY_CLICK_EVENT, GameEventPriority.LOWEST, this::onIslandChestInteract); registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.NORMAL, this::onPlayerFall); registerCallback(GameEventType.PLAYER_RESPAWN_EVENT, GameEventPriority.NORMAL, this::onPlayerRespawn); + registerCallback(GameEventType.PLAYER_RESPAWN_EVENT, GameEventPriority.MONITOR, this::onPlayerRespawnMonitor); // PlayerChat should be on LOWEST priority so other chat plugins don't conflict. registerCallback(GameEventType.PLAYER_CHAT_EVENT, GameEventPriority.LOWEST, this::onPlayerChatLowest); registerCallback(GameEventType.PLAYER_CHAT_EVENT, GameEventPriority.NORMAL, this::onPlayerChat); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/respawn/RespawnActions.java b/src/main/java/com/bgsoftware/superiorskyblock/player/respawn/RespawnActions.java index 2c4a70d513..cc4190f746 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/respawn/RespawnActions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/respawn/RespawnActions.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerRespawnEvent; @@ -37,7 +38,8 @@ public boolean canPerform(PlayerRespawnEvent event) { public void perform(PlayerRespawnEvent event) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(event.getPlayer()); assert superiorPlayer.getIsland() != null; - superiorPlayer.teleport(superiorPlayer.getIsland()); + superiorPlayer.teleport(superiorPlayer.getIsland(), + result -> onTeleportCallback(superiorPlayer, result)); } }); @@ -52,7 +54,8 @@ public boolean canPerform(PlayerRespawnEvent event) { @Override public void perform(PlayerRespawnEvent event) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(event.getPlayer()); - superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); + superiorPlayer.teleport(plugin.getGrid().getSpawnIsland(), + result -> onTeleportCallback(superiorPlayer, result)); } }); @@ -84,4 +87,13 @@ private static RespawnAction register(RespawnAction respawnAction) { return respawnAction; } + private static void onTeleportCallback(SuperiorPlayer superiorPlayer, boolean result) { + if (result) { + BukkitExecutor.sync(() -> { + if (superiorPlayer.isOnline()) + superiorPlayer.updateWorldBorder(superiorPlayer.getIsland()); + }, 2L); + } + } + } From b65ff2aa242b29398f72b67ffe4990729ae18ba9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 21 Sep 2025 15:52:02 +0300 Subject: [PATCH 319/600] Fix concurrent error in 1.12 and 1.8 related to chunks (#2661) --- .../com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java index b01dbc77e6..9fadb8823f 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSUtils.java @@ -49,7 +49,7 @@ public class NMSUtils { private static final ReflectMethod TILE_ENTITY_LOAD = new ReflectMethod<>( TileEntity.class, "a", NBTTagCompound.class); - private static final Map chunkLoadersMap = Maps.newHashMap(); + private static final Map chunkLoadersMap = Maps.newConcurrentMap(); private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java index b3ce4fe2d9..59bd858840 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSUtils.java @@ -41,7 +41,7 @@ public class NMSUtils { private static final ReflectField CHUNK_LOADER = new ReflectField<>( ChunkProviderServer.class, IChunkLoader.class, "chunkLoader"); - private static final Map chunkLoadersMap = Maps.newHashMap(); + private static final Map chunkLoadersMap = Maps.newConcurrentMap(); public static final ObjectsPool> BLOCK_POS_POOL = ObjectsPools.createNewPool(() -> new BlockPosition.MutableBlockPosition(0, 0, 0)); From a82d5da18fa0f73483a2e4809a99099208876096 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sun, 21 Sep 2025 15:01:57 +0200 Subject: [PATCH 320/600] Expanded island previews options (#2624) --- .../api/config/SettingsManager.java | 38 +++++++++++++++ .../api/island/DelegateIslandPreview.java | 6 +++ .../api/island/IslandPreview.java | 6 +++ .../admin/CmdAdminSetIslandPreview.java | 2 +- .../config/SettingsContainer.java | 29 +++++++++--- .../config/SettingsManagerImpl.java | 21 +++++++-- .../config/section/GlobalSection.java | 5 -- .../config/section/IslandPreviewsSection.java | 33 +++++++++++++ .../core/menu/MenuActions.java | 2 +- .../core/messages/Message.java | 1 + .../island/GridManagerImpl.java | 46 +++++++++---------- .../island/preview/SIslandPreview.java | 10 +++- .../listener/BukkitListeners.java | 2 +- .../listener/FeaturesListener.java | 30 +++++++++++- .../region/RegionManagerServiceImpl.java | 26 +++++------ src/main/resources/config.yml | 26 ++++++++--- src/main/resources/lang/de-DE.yml | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/tr-TR.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + 28 files changed, 230 insertions(+), 65 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandPreviewsSection.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index da47133248..26614267a2 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; @@ -610,9 +611,18 @@ public interface SettingsManager { * List of preview-island locations. * Represented by a map with keys as schematic names, and values as locations for the preview islands. * Config-path: preview-islands + * + * @deprecated See {@link #getIslandPreviews()} */ + @Deprecated Map getPreviewIslands(); + /** + * All settings related to the island previews. + * Config path: island-previews + */ + IslandPreviews getIslandPreviews(); + /** * Whether vanished players should be hidden from command tab completes or not. * Config-path: tab-complete-hide-vanished @@ -1289,5 +1299,33 @@ interface IslandChests { } + interface IslandPreviews { + + /** + * The game mode that will be set for the player when they enter preview mode. + * Config-path: island-previews.game-mode + */ + GameMode getGameMode(); + + /** + * The maximum distance a player can move before the preview mode is canceled. + * Config-path: island-previews.max-distance + */ + int getMaxDistance(); + + /** + * A list of commands that cannot be executed by players in preview mode. + * Config-path: island-previews.blocked-commands + */ + List getBlockedCommands(); + + /** + * List of island preview locations. + * Represented by a map with keys as schematic names, and values as locations for the preview islands. + * Config-path: island-previews.locations + */ + Map getLocations(); + + } } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java index 2487daebab..13daf669ae 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.api.island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import org.bukkit.GameMode; import org.bukkit.Location; public class DelegateIslandPreview implements IslandPreview { @@ -36,6 +37,11 @@ public String getIslandName() { return this.handle.getIslandName(); } + @Override + public GameMode getPreviousGameMode() { + return this.handle.getPreviousGameMode(); + } + @Override public void handleConfirm() { this.handle.handleConfirm(); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPreview.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPreview.java index c0d5d16338..1fe2077667 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPreview.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandPreview.java @@ -2,6 +2,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import org.bukkit.GameMode; import org.bukkit.Location; /** @@ -37,6 +38,11 @@ public interface IslandPreview { */ String getIslandName(); + /** + * Get the game mode that the player had before the preview started. + */ + GameMode getPreviousGameMode(); + /** * Handle confirmation of creation of the island. */ diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java index 4799600a23..c8ec1af86f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java @@ -70,7 +70,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ } try { - plugin.getSettings().updateValue("preview-islands." + schematic.getName(), schematicPreviewLocation); + plugin.getSettings().updateValue("island-previews.locations." + schematic.getName(), schematicPreviewLocation); } catch (Exception error) { Log.entering("ENTER", schematicPreviewLocation); Log.error(error, "An unexpected error occurred while setting schematic preview:"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 0a860a807f..bb6013912e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -35,6 +35,7 @@ import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.world.Dimensions; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.configuration.ConfigurationSection; @@ -209,7 +210,10 @@ public class SettingsContainer { public final int islandChestsDefaultSize; public final Map> commandAliases; public final KeySet valuableBlocks; - public final Map islandPreviewLocations; + public final GameMode islandPreviewsGameMode; + public final int islandPreviewsMaxDistance; + public final List islandPreviewsBlockedCommands; + public final Map islandPreviewsLocations; public final boolean tabCompleteHideVanished; public final boolean dropsUpgradePlayersMultiply; public final long protectedMessageDelay; @@ -532,18 +536,29 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config this.commandAliases = Collections.unmodifiableMap(commandAliases); valuableBlocks = KeySets.unmodifiableKeySet( KeySets.createHashSet(KeyIndicator.MATERIAL, config.getStringList("valuable-blocks"))); - Map islandPreviewLocations = new HashMap<>(); - if (config.isConfigurationSection("preview-islands")) { - for (String schematic : config.getConfigurationSection("preview-islands").getKeys(false)) { + GameMode islandPreviewsGameMode; + String islandPreviewsGameModeName = config.getString("island-previews.game-mode", "SPECTATOR").toUpperCase(Locale.ENGLISH); + try { + islandPreviewsGameMode = GameMode.valueOf(islandPreviewsGameModeName); + } catch (IllegalArgumentException error) { + islandPreviewsGameMode = GameMode.SPECTATOR; + Log.warnFromFile("config.yml", "Invalid game mode ", islandPreviewsGameModeName + ", using SPECTATOR instead."); + } + this.islandPreviewsGameMode = islandPreviewsGameMode; + islandPreviewsMaxDistance = config.getInt("island-previews.max-distance", 100); + islandPreviewsBlockedCommands = Collections.unmodifiableList(config.getStringList("island-previews.blocked-commands")); + Map islandPreviewsLocations = new HashMap<>(); + if (config.isConfigurationSection("island-previews.locations")) { + for (String schematic : config.getConfigurationSection("island-previews.locations").getKeys(false)) { try { - islandPreviewLocations.put(schematic.toLowerCase(Locale.ENGLISH), Serializers.LOCATION_SERIALIZER - .deserialize(config.getString("preview-islands." + schematic))); + islandPreviewsLocations.put(schematic.toLowerCase(Locale.ENGLISH), Serializers.LOCATION_SERIALIZER + .deserialize(config.getString("island-previews.locations." + schematic))); } catch (Exception error) { Log.warnFromFile("config.yml", "Cannot deserialize island preview for ", schematic, ", skipping..."); } } } - this.islandPreviewLocations = Collections.unmodifiableMap(islandPreviewLocations); + this.islandPreviewsLocations = Collections.unmodifiableMap(islandPreviewsLocations); tabCompleteHideVanished = config.getBoolean("tab-complete-hide-vanished", true); dropsUpgradePlayersMultiply = config.getBoolean("drops-upgrade-players-multiply", false); protectedMessageDelay = config.getLong("protected-message-delay", 60L); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index f74ab7fd4e..e6dee4c08d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -16,6 +16,7 @@ import com.bgsoftware.superiorskyblock.config.section.GlobalSection; import com.bgsoftware.superiorskyblock.config.section.IslandChestsSection; import com.bgsoftware.superiorskyblock.config.section.IslandNamesSection; +import com.bgsoftware.superiorskyblock.config.section.IslandPreviewsSection; import com.bgsoftware.superiorskyblock.config.section.IslandRolesSection; import com.bgsoftware.superiorskyblock.config.section.SpawnSection; import com.bgsoftware.superiorskyblock.config.section.StackedBlocksSection; @@ -46,7 +47,7 @@ public class SettingsManagerImpl extends Manager implements SettingsManager { private static final String[] IGNORED_SECTIONS = new String[]{ "config.yml", "ladder", "commands-cooldown", "containers", "event-commands", "command-aliases", - "preview-islands", "default-values.block-limits", "default-values.entity-limits", + "island-previews.locations", "default-values.block-limits", "default-values.entity-limits", "default-values.role-limits", "stacked-blocks.limits", "default-values.generator" }; @@ -63,6 +64,7 @@ public class SettingsManagerImpl extends Manager implements SettingsManager { private final AFKIntegrationsSection afkIntegrations = new AFKIntegrationsSection(); private final DefaultContainersSection defaultContainers = new DefaultContainersSection(); private final IslandChestsSection islandChests = new IslandChestsSection(); + private final IslandPreviewsSection islandPreviews = new IslandPreviewsSection(); public SettingsManagerImpl(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -424,7 +426,7 @@ public long getHomeWarmup() { @Override public long getVisitWarmup() { - return this.global.getHomeWarmup(); + return this.global.getVisitWarmup(); } @Override @@ -558,8 +560,14 @@ public Set getValuableBlocks() { } @Override + @Deprecated public Map getPreviewIslands() { - return this.global.getPreviewIslands(); + return this.islandPreviews.getLocations(); + } + + @Override + public IslandPreviewsSection getIslandPreviews() { + return this.islandPreviews; } @Override @@ -665,7 +673,7 @@ public void updateValue(String path, Object value) throws IOException { CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(file); cfg.syncWithConfig(file, plugin.getResource("config.yml"), "config.yml", - "ladder", "commands-cooldown", "containers", "event-commands", "command-aliases", "preview-islands"); + "ladder", "commands-cooldown", "containers", "event-commands", "command-aliases", "island-previews.locations"); cfg.set(path, value); @@ -693,9 +701,14 @@ private void loadContainerFromConfig(YamlConfiguration cfg) throws ManagerLoadEx this.afkIntegrations.setContainer(container); this.defaultContainers.setContainer(container); this.islandChests.setContainer(container); + this.islandPreviews.setContainer(container); } private void convertData(YamlConfiguration cfg) { + if (cfg.isConfigurationSection("preview-islands")) { + cfg.set("island-previews.locations", cfg.getConfigurationSection("preview-islands")); + cfg.set("preview-islands", null); + } if (cfg.isBoolean("disband-inventory-clear")) { if (cfg.getBoolean("disband-inventory-clear")) { cfg.set("clear-on-disband", Arrays.asList("ENDER_CHEST", "INVENTORY")); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index 613b36bd14..29528e5108 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; -import org.bukkit.Location; import java.math.BigInteger; import java.math.RoundingMode; @@ -334,10 +333,6 @@ public Set getValuableBlocks() { return getContainer().valuableBlocks; } - public Map getPreviewIslands() { - return getContainer().islandPreviewLocations; - } - public boolean isTabCompleteHideVanished() { return getContainer().tabCompleteHideVanished; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandPreviewsSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandPreviewsSection.java new file mode 100644 index 0000000000..aabcdecf62 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandPreviewsSection.java @@ -0,0 +1,33 @@ +package com.bgsoftware.superiorskyblock.config.section; + +import com.bgsoftware.superiorskyblock.api.config.SettingsManager; +import com.bgsoftware.superiorskyblock.config.SettingsContainerHolder; +import org.bukkit.GameMode; +import org.bukkit.Location; + +import java.util.List; +import java.util.Map; + +public class IslandPreviewsSection extends SettingsContainerHolder implements SettingsManager.IslandPreviews { + + @Override + public GameMode getGameMode() { + return getContainer().islandPreviewsGameMode; + } + + @Override + public int getMaxDistance() { + return getContainer().islandPreviewsMaxDistance; + } + + @Override + public List getBlockedCommands() { + return getContainer().islandPreviewsBlockedCommands; + } + + @Override + public Map getLocations() { + return getContainer().islandPreviewsLocations; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java index c6a4170db3..c62d08c0bc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuActions.java @@ -100,7 +100,7 @@ public static void simulateIslandCreationClick(SuperiorPlayer clickedPlayer, Str // Checking for preview of islands. if (isPreviewMode) { - Location previewLocation = plugin.getSettings().getPreviewIslands().get(schematic.getName().toLowerCase(Locale.ENGLISH)); + Location previewLocation = plugin.getSettings().getIslandPreviews().getLocations().get(schematic.getName().toLowerCase(Locale.ENGLISH)); if (previewLocation != null) { plugin.getGrid().startIslandPreview(clickedPlayer, schematic, islandName); return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 294a5b4503..f50cb655a0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -532,6 +532,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { ISLAND_NAME_NONE, ISLAND_OPENED, ISLAND_OWNER_NONE, + ISLAND_PREVIEW_BLOCK_COMMAND, ISLAND_PREVIEW_CANCEL, ISLAND_PREVIEW_CANCEL_DISTANCE, ISLAND_PREVIEW_CANCEL_TEXT, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index 7d65b71ec9..3967d7d369 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -156,50 +156,50 @@ public UUID getServerUUID() { } @Override - public void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonus, Biome biome, String islandName) { + public void createIsland(SuperiorPlayer superiorPlayer, String schematicName, BigDecimal bonus, Biome biome, String islandName) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); - Preconditions.checkNotNull(schemName, "schemName parameter cannot be null."); + Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); Preconditions.checkNotNull(bonus, "bonus parameter cannot be null."); Preconditions.checkNotNull(biome, "biome parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); - createIsland(superiorPlayer, schemName, bonus, biome, islandName, false); + createIsland(superiorPlayer, schematicName, bonus, biome, islandName, false); } @Override - public void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonus, Biome biome, String islandName, boolean offset) { + public void createIsland(SuperiorPlayer superiorPlayer, String schematicName, BigDecimal bonus, Biome biome, String islandName, boolean offset) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); - Preconditions.checkNotNull(schemName, "schemName parameter cannot be null."); + Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); Preconditions.checkNotNull(bonus, "bonus parameter cannot be null."); Preconditions.checkNotNull(biome, "biome parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); - createIsland(superiorPlayer, schemName, bonus, BigDecimal.ZERO, biome, islandName, false); + createIsland(superiorPlayer, schematicName, bonus, BigDecimal.ZERO, biome, islandName, false); } @Override - public void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonusWorth, + public void createIsland(SuperiorPlayer superiorPlayer, String schematicName, BigDecimal bonusWorth, BigDecimal bonusLevel, Biome biome, String islandName, boolean offset) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); - Preconditions.checkNotNull(schemName, "schemName parameter cannot be null."); + Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); Preconditions.checkNotNull(bonusWorth, "bonusWorth parameter cannot be null."); Preconditions.checkNotNull(bonusLevel, "bonusLevel parameter cannot be null."); Preconditions.checkNotNull(biome, "biome parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); - createIsland(superiorPlayer, schemName, bonusWorth, bonusLevel, biome, islandName, offset, null); + createIsland(superiorPlayer, schematicName, bonusWorth, bonusLevel, biome, islandName, offset, null); } @Override - public void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bonusWorth, + public void createIsland(SuperiorPlayer superiorPlayer, String schematicName, BigDecimal bonusWorth, BigDecimal bonusLevel, Biome biome, String islandName, boolean offset, @Nullable BlockOffset spawnOffset) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); - Preconditions.checkNotNull(schemName, "schemName parameter cannot be null."); + Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); Preconditions.checkNotNull(bonusWorth, "bonusWorth parameter cannot be null."); Preconditions.checkNotNull(bonusLevel, "bonusLevel parameter cannot be null."); Preconditions.checkNotNull(biome, "biome parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); Island.Builder builder = Island.newBuilder() .setOwner(superiorPlayer) - .setSchematicName(schemName) + .setSchematicName(schematicName) .setName(islandName); if (!offset) { @@ -254,7 +254,7 @@ private void createIslandInternalAsync(IslandBuilderImpl builder, Biome biome, b builder.islandName, offset, biome, schematic.getName()); // Removing any active previews for the player. - boolean updateGamemode = this.islandPreviews.endIslandPreview(builder.owner) != null; + boolean updateGameMode = this.islandPreviews.endIslandPreview(builder.owner) != null; if (!PluginEventsFactory.callPreIslandCreateEvent(builder.owner, builder.islandName)) return; @@ -274,7 +274,7 @@ private void createIslandInternalAsync(IslandBuilderImpl builder, Biome biome, b try { createIslandInternalOnSuccessCallback(builder, biome, offset, spawnOffset, - schematic, updateGamemode, startTime, islandCreationResult); + schematic, updateGameMode, startTime, islandCreationResult); return; } catch (Throwable runtimeError) { error = runtimeError; @@ -297,7 +297,7 @@ private void createIslandInternalAsync(IslandBuilderImpl builder, Biome biome, b private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Biome biome, boolean offset, @Nullable BlockOffset spawnOffset, Schematic schematic, - boolean updateGamemode, long startTime, + boolean updateGameMode, long startTime, IslandCreationAlgorithm.IslandCreationResult islandCreationResult) { switch (islandCreationResult.getStatus()) { case NAME_OCCUPIED: @@ -353,7 +353,7 @@ private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Bi island.setIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension(), homeLocation); BukkitExecutor.sync(() -> builder.owner.runIfOnline(player -> { - if (updateGamemode) + if (updateGameMode) player.setGameMode(GameMode.SURVIVAL); if (!teleportPlayer) { @@ -414,9 +414,9 @@ public boolean hasActiveCreateRequest(SuperiorPlayer superiorPlayer) { } @Override - public void startIslandPreview(SuperiorPlayer superiorPlayer, String schemName, String islandName) { - Preconditions.checkNotNull(schemName, "schemName parameter cannot be null."); - startIslandPreview(superiorPlayer, plugin.getSchematics().getSchematic(schemName), islandName); + public void startIslandPreview(SuperiorPlayer superiorPlayer, String schematicName, String islandName) { + Preconditions.checkNotNull(schematicName, "schematicName parameter cannot be null."); + startIslandPreview(superiorPlayer, plugin.getSchematics().getSchematic(schematicName), islandName); } public void startIslandPreview(SuperiorPlayer superiorPlayer, Schematic schematic, String islandName) { @@ -424,12 +424,12 @@ public void startIslandPreview(SuperiorPlayer superiorPlayer, Schematic schemati Preconditions.checkNotNull(schematic, "schematic parameter cannot be null."); Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); - Location previewLocation = plugin.getSettings().getPreviewIslands().get(schematic.getName().toLowerCase(Locale.ENGLISH)); + Location previewLocation = plugin.getSettings().getIslandPreviews().getLocations().get(schematic.getName().toLowerCase(Locale.ENGLISH)); if (previewLocation != null && previewLocation.getWorld() != null) { superiorPlayer.teleport(previewLocation, result -> { if (result) { - this.islandPreviews.startIslandPreview(new SIslandPreview(superiorPlayer, previewLocation, schematic, islandName)); - BukkitExecutor.ensureMain(() -> superiorPlayer.runIfOnline(player -> player.setGameMode(GameMode.SPECTATOR))); + this.islandPreviews.startIslandPreview(new SIslandPreview(superiorPlayer, previewLocation, schematic, islandName, superiorPlayer.asPlayer().getGameMode())); + BukkitExecutor.ensureMain(() -> superiorPlayer.runIfOnline(player -> player.setGameMode(plugin.getSettings().getIslandPreviews().getGameMode()))); Message.ISLAND_PREVIEW_START.send(superiorPlayer, schematic.getName()); } }); @@ -445,7 +445,7 @@ public void cancelIslandPreview(SuperiorPlayer superiorPlayer) { superiorPlayer.runIfOnline(player -> { BukkitExecutor.ensureMain(() -> superiorPlayer.teleport(plugin.getGrid().getSpawnIsland(), teleportResult -> { if (teleportResult && superiorPlayer.isOnline()) - player.setGameMode(GameMode.SURVIVAL); + player.setGameMode(islandPreview.getPreviousGameMode()); })); PlayerChat.remove(player); }); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java b/src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java index 7d7436ac9d..ec1006d43a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/preview/SIslandPreview.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; import com.google.common.base.Preconditions; +import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.entity.Player; @@ -20,12 +21,14 @@ public class SIslandPreview implements IslandPreview { private final Location previewLocation; private final Schematic schematic; private final String islandName; + private final GameMode previousGameMode; - public SIslandPreview(SuperiorPlayer superiorPlayer, Location previewLocation, Schematic schematic, String islandName) { + public SIslandPreview(SuperiorPlayer superiorPlayer, Location previewLocation, Schematic schematic, String islandName, GameMode previousGameMode) { this.superiorPlayer = superiorPlayer; this.previewLocation = previewLocation; this.schematic = schematic; this.islandName = islandName; + this.previousGameMode = previousGameMode; Player player = superiorPlayer.asPlayer(); Preconditions.checkNotNull(player, "Cannot start island preview to an offline player."); @@ -77,6 +80,11 @@ public String getIslandName() { return this.islandName; } + @Override + public GameMode getPreviousGameMode() { + return this.previousGameMode; + } + @Override public void handleConfirm() { MenuIslandCreationConfig creationConfig = plugin.getProviders().getMenusProvider().getIslandCreationConfig(this.schematic); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java index 7d721dfbd8..28e579116e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitListeners.java @@ -41,7 +41,7 @@ public void registerListeners() { if (plugin.getSettings().isAutoBlocksTracking()) new BlockChangesListener(this.plugin); - if (!plugin.getSettings().getPreviewIslands().isEmpty()) + if (!plugin.getSettings().getIslandPreviews().getLocations().isEmpty()) new IslandPreviewListener(this.plugin); safeEventsRegister(new BukkitEventsListener(this.plugin)); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java index c8a46ddff9..6f93479a29 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/FeaturesListener.java @@ -4,6 +4,7 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandPreview; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.region.RegionManagerService; @@ -145,7 +146,7 @@ private void onObsidianClick(GameEvent e) { /* VISITORS BLOCKED COMMANDS */ - private void onPlayerCommand(GameEvent e) { + private void onPlayerCommandAsVisitor(GameEvent e) { Player player = e.getArgs().player; // We do not care about spawn island, and therefore only island worlds are relevant. @@ -175,6 +176,29 @@ private void onPlayerCommand(GameEvent e) { } } + /* PREVIEW BLOCKED COMMANDS */ + + private void onPlayerCommandWhilePreview(GameEvent e) { + Player player = e.getArgs().player; + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); + + if (superiorPlayer.hasBypassModeEnabled()) + return; + + IslandPreview islandPreview = plugin.getGrid().getIslandPreview(superiorPlayer); + if (islandPreview == null) + return; + + String[] message = e.getArgs().command.toLowerCase(Locale.ENGLISH).split(" "); + + String commandLabel = message[0].toCharArray()[0] == '/' ? message[0].substring(1) : message[0]; + + if (plugin.getSettings().getIslandPreviews().getBlockedCommands().stream().anyMatch(commandLabel::contains)) { + e.setCancelled(); + Message.ISLAND_PREVIEW_BLOCK_COMMAND.send(superiorPlayer); + } + } + /* BLOCKS TRACKING */ private void onChunkLoad(GameEvent e) { @@ -267,7 +291,9 @@ private void registerListeners() { if (plugin.getSettings().isObsidianToLava()) registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.HIGHEST, this::onObsidianClick); if (!plugin.getSettings().getBlockedVisitorsCommands().isEmpty()) - registerCallback(GameEventType.PLAYER_COMMAND_EVENT, GameEventPriority.HIGHEST, this::onPlayerCommand); + registerCallback(GameEventType.PLAYER_COMMAND_EVENT, GameEventPriority.HIGHEST, this::onPlayerCommandAsVisitor); + if (!plugin.getSettings().getIslandPreviews().getBlockedCommands().isEmpty()) + registerCallback(GameEventType.PLAYER_COMMAND_EVENT, GameEventPriority.HIGHEST, this::onPlayerCommandWhilePreview); registerCallback(GameEventType.CHUNK_LOAD_EVENT, GameEventPriority.MONITOR, this::onChunkLoad); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 0df348d1cb..774c645d4a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -566,6 +566,19 @@ public MoveResult handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, Island fromIsland = null; boolean lookupFromIsland = true; + //Checking for out of distance from preview location. + IslandPreview islandPreview = plugin.getGrid().getIslandPreview(superiorPlayer); + if (islandPreview != null) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location islandPreviewLocation = islandPreview.getLocation(wrapper.getHandle()); + if (!islandPreviewLocation.getWorld().equals(to.getWorld()) || + islandPreviewLocation.distance(to) > plugin.getSettings().getIslandPreviews().getMaxDistance()) { + islandPreview.handleEscape(); + return MoveResult.ISLAND_PREVIEW_MOVED_TOO_FAR; + } + } + } + if (from.getBlockX() != to.getBlockX() || from.getBlockZ() != to.getBlockZ()) { // Handle moving while in teleport warmup. BukkitTask teleportTask = superiorPlayer.getTeleportTask(); @@ -575,19 +588,6 @@ public MoveResult handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, Message.TELEPORT_WARMUP_CANCEL.send(superiorPlayer); } - //Checking for out of distance from preview location. - IslandPreview islandPreview = plugin.getGrid().getIslandPreview(superiorPlayer); - if (islandPreview != null) { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location islandPreviewLocation = islandPreview.getLocation(wrapper.getHandle()); - if (!islandPreviewLocation.getWorld().equals(to.getWorld()) || - islandPreviewLocation.distanceSquared(to) > 10000) { - islandPreview.handleEscape(); - return MoveResult.ISLAND_PREVIEW_MOVED_TOO_FAR; - } - } - } - MoveResult moveResult; Island toIsland = plugin.getGrid().getIslandAt(to); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 0ec5ecc47a..c8ec443e7d 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -817,13 +817,25 @@ command-aliases: # These blocks require the "VALUABLE_BREAK" permission in order to break them. valuable-blocks: [ ] -# Set preview locations for schematics. -# You can disable this feature by setting the section to 'preview-islands: {}' -# Make sure you follow the location format: ', , , ' -preview-islands: - normal: world, 0, 100, 0 - mycel: world, 0, 100, 0 - desert: world, 0, 100, 0 +# Settings related to the island previews. +island-previews: + # The game mode that will be set for the player when they enter preview mode. + # Use ADVENTURE, CREATIVE, SPECTATOR or SURVIVAL. + game-mode: SPECTATOR + + # The maximum distance a player can move before the preview mode is canceled. + max-distance: 100 + + # A list of commands that cannot be executed by players in preview mode. + blocked-commands: [] + + # Preview locations for schematics. + # You can disable this feature by setting the section to 'locations: []' + # Make sure you follow the location format: ', , , , , ' + locations: + normal: world, 0, 100, 0 + mycel: world, 0, 100, 0 + desert: world, 0, 100, 0 # Should vanished players be hidden in tab completes? tab-complete-hide-vanished: true diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 1d60621570..de487503cf 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -618,6 +618,7 @@ ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsland | &7Die Insel wurde erfolgreich der Öffentlichkeit zugänglich gemacht.' ISLAND_OWNER_NONE: None +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVorschau | &7Du hast sich zu weit entfernt und befindest dich nicht mehr im Vorschaumodus.' ISLAND_PREVIEW_CANCEL: '&e&lVorschau | &7Du hast den Vorschaumodus abgebrochen.' diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index f20592414f..547c0dadb4 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -499,6 +499,7 @@ ISLAND_INFO_WORTH: '&e&lIsland | &7Worth: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsland | &7Successfully opened the island to the public.' ISLAND_OWNER_NONE: None +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPreview | &7You went too far away, and you are no longer in preview mode.' ISLAND_PREVIEW_CANCEL: '&e&lPreview | &7You cancelled the preview mode.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 11d97a9c69..9b04635c1e 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -499,6 +499,7 @@ ISLAND_INFO_WORTH: '&e&lIsla | &7Valor: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsla | &7Abrió con éxito la isla al público.' ISLAND_OWNER_NONE: None +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVista Previa | &7Fuiste demasiado lejos y ya no estás en modo de vista previa.' ISLAND_PREVIEW_CANCEL: '&e&lVista Previa | &7Cancelaste el modo de vista previa.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index e863343754..1d75ee982c 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -501,6 +501,7 @@ ISLAND_INFO_WORTH: '&e&lIle | &7Valeur: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIle | &7L''île est désormais ouverte au public.' ISLAND_OWNER_NONE: None +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPrévisualisation | &7Vous vous êtes trop éloigné(e). La prévisualisation à donc été désactivée.' ISLAND_PREVIEW_CANCEL: '&e&lPrévisualisation | &7Vous avez annulé(e) la prévisualisation.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRMER' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 2339ab759b..3cbf00ab1b 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -507,6 +507,7 @@ ISLAND_INFO_WORTH: '&e&lIsola | &7Valore: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIsola | &7Aperta con successo l''isola al pubblico.' ISLAND_OWNER_NONE: None +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lAnteprima | &7Sei andato troppo lontano, non sei più in modalità anteprima.' ISLAND_PREVIEW_CANCEL: '&e&lAnteprima | &7Hai annullato la modalità di anteprima.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFERMA' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 61125db89f..86317fc790 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -517,6 +517,7 @@ ISLAND_INFO_WORTH: '&e&lיא | &7יווש: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lיא | &7החלצהב רוביצל חתפנ יאה.' ISLAND_OWNER_NONE: None +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPreview | &7You went too far away, and you are no longer in preview mode.' ISLAND_PREVIEW_CANCEL: '&e&lPreview | &7You cancelled the preview mode.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRM' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index e13cdbfb6e..39753384e1 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -499,6 +499,7 @@ ISLAND_INFO_WORTH: '&e&lWyspa | &7Wartosc: {0}' ISLAND_NAME_NONE: Brak ISLAND_OPENED: '&e&lWyspa | &7Pomyslnie zmieniles status wyspy na publiczny.' ISLAND_OWNER_NONE: Brak +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lBlad | &7Nie mozesz uzyc tej komendy w trybie podgladu.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lPodglad | &7Odszedles za daleko, nie jestes juz w trybie podgladu.' ISLAND_PREVIEW_CANCEL: '&e&lPodglad | &7Anulowales tryb podgladu.' ISLAND_PREVIEW_CONFIRM_TEXT: 'POTWIERDZ' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 6351fc067d..c4bbeb4945 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -499,6 +499,7 @@ ISLAND_INFO_WORTH: '&e&lIlha | &7Valor: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lIlha | &7A ilha foi aberta com sucesso ao público.' ISLAND_OWNER_NONE: None +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lVisualizar | &7Você foi muito longe e não está mais no modo de visualização.' ISLAND_PREVIEW_CANCEL: '&e&lVisualizar | &7Você cancelou o modo de visualização.' ISLAND_PREVIEW_CONFIRM_TEXT: 'CONFIRMAR' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 34ffce3d4c..6222d480b0 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -499,6 +499,7 @@ ISLAND_INFO_WORTH: '&e&lОстров | &7Стоимость: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lОстров | &7Остров успешно открыт для публики.' ISLAND_OWNER_NONE: None +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lПредпросмотр | &7Вы отошли слишком далеко, и режим предпросмотра больше не активен.' ISLAND_PREVIEW_CANCEL: '&e&lПредпросмотр | &7Вы отменили режим предпросмотра.' ISLAND_PREVIEW_CONFIRM_TEXT: 'ПОДТВЕРДИТЬ' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 8256073973..01c9abf5f0 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -588,6 +588,7 @@ ISLAND_INFO_WORTH: '&e&lAda | &7Değer: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lAda | &7Ada başarıyla halka açıldı.' ISLAND_OWNER_NONE: None +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lÖnizleme | &7Çok uzaklaştın ve artık önizleme modunda değilsin.' ISLAND_PREVIEW_CANCEL: '&e&lÖnizleme | &7Önizleme modunu iptal ettin.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index ccc96e42f6..92d24414e5 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -555,6 +555,7 @@ ISLAND_INFO_WORTH: '&e&lĐảo | &7Đáng giá: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&lĐảo | &7Mở đảo thành công cho công cộng.' ISLAND_OWNER_NONE: None +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&lXem Trước | &7Bạn đã đi ra quá xa và thoát chế độ xem trước.' ISLAND_PREVIEW_CANCEL: '&e&lXem Trước | &7Bạn đã hủy chế độ xem trước.' ISLAND_PREVIEW_CONFIRM_TEXT: 'DONG-Y' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 4c8aefc808..49e5ccea12 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -499,6 +499,7 @@ ISLAND_INFO_WORTH: '&e&l岛屿 | &7价值: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&l岛屿 | &7成功将岛屿设置为对公众开放.' ISLAND_OWNER_NONE: None +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&l结构 | &7你离得太远离了, 已自动退出预览模式.' ISLAND_PREVIEW_CANCEL: '&e&l结构 | &7你退出了预览模式.' ISLAND_PREVIEW_CONFIRM_TEXT: '确认' From 88de74a08a3f297f3b7adadac55ae95a5713ae01 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 21 Sep 2025 16:39:53 +0300 Subject: [PATCH 321/600] Implement islands-caching mechanism for position lookups for faster island lookups (#2654) --- .../container/DefaultIslandsContainer.java | 128 ++++++++++++++---- 1 file changed, 102 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index 47c4d03fef..c44fbbf6db 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -25,15 +25,21 @@ import org.bukkit.Bukkit; import org.bukkit.Location; +import java.lang.ref.WeakReference; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; public class DefaultIslandsContainer implements IslandsContainer { + private static final int MAX_ISLANDS_POSITION_CACHE = 250; + private final Synchronized> islandsByPositions = Synchronized.of(new IslandPosition2ObjectMap<>()); private final Map islandsByUUID = new ConcurrentHashMap<>(); @@ -41,11 +47,12 @@ public class DefaultIslandsContainer implements IslandsContainer { private final EnumerateSet notifiedValues = new EnumerateSet<>(SortingType.values()); + private final IslandsCache islandsCache = new IslandsCache(); + private final SuperiorSkyblockPlugin plugin; public DefaultIslandsContainer(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - } @Override @@ -56,23 +63,25 @@ public void addIsland(Island island) { Preconditions.checkNotNull(defaultWorld, "Default world information cannot be null!"); - this.islandsByPositions.write(islandsByPositions -> { - try (IslandPosition islandPosition = IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ())) { + try (IslandPosition islandPosition = IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ())) { + // Insert to cache if we can access it + accessIslandsCache(islandsCache -> islandsCache.insert(islandPosition, island)); + + this.islandsByPositions.write(islandsByPositions -> { islandsByPositions.put(islandPosition, island); - } - if (plugin.getProviders().hasCustomWorldsSupport()) { - // We don't know the logic of the custom worlds support, therefore we add a position - // for every possible world, so there won't be issues with detecting islands later. - for (Dimension dimension : Dimension.values()) { - if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { - runWithCustomWorld(defaultWorld, center, island, dimension, - islandPosition -> islandsByPositions.put(islandPosition, island)); + if (plugin.getProviders().hasCustomWorldsSupport()) { + // We don't know the logic of the custom worlds support, therefore we add a position + // for every possible world, so there won't be issues with detecting islands later. + for (Dimension dimension : Dimension.values()) { + if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { + runWithCustomWorld(defaultWorld, center, island, dimension, + islandPositionCustomWorld -> islandsByPositions.put(islandPositionCustomWorld, island)); + } } } - } - }); - + }); + } this.islandsByUUID.put(island.getUniqueId(), island); @@ -89,20 +98,23 @@ public void removeIsland(Island island) { Preconditions.checkNotNull(defaultWorld, "Default world information cannot be null!"); - this.islandsByPositions.write(islandsByPositions -> { - try (IslandPosition islandPosition = IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ())) { + try (IslandPosition islandPosition = IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ())) { + // Remove from cache if we can access it + accessIslandsCache(islandsCache -> islandsCache.remove(islandPosition)); + + this.islandsByPositions.write(islandsByPositions -> { islandsByPositions.remove(islandPosition, island); - } - if (plugin.getProviders().hasCustomWorldsSupport()) { - for (Dimension dimension : Dimension.values()) { - if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { - runWithCustomWorld(defaultWorld, center, island, dimension, - islandPosition -> islandsByPositions.remove(islandPosition, island)); + if (plugin.getProviders().hasCustomWorldsSupport()) { + for (Dimension dimension : Dimension.values()) { + if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { + runWithCustomWorld(defaultWorld, center, island, dimension, + islandPositionCustomWorld -> islandsByPositions.remove(islandPositionCustomWorld, island)); + } } } - } - }); + }); + } islandsByUUID.remove(island.getUniqueId()); @@ -144,8 +156,9 @@ public int getIslandsAmount() { public Island getIslandAt(Location location) { Island island; try (IslandPosition islandPosition = IslandPosition.of(location)) { - island = this.islandsByPositions.readAndGet(islandsByPositions -> - islandsByPositions.get(islandPosition)); + island = readIslandsCache(islandsCache -> islandsCache.get(islandPosition), + () -> this.islandsByPositions.readAndGet(islandsByPositions -> + islandsByPositions.get(islandPosition))); } return island == null || !island.isInside(location) ? null : island; } @@ -260,4 +273,67 @@ private void runWithCustomWorld(WorldInfo defaultWorld, BlockPosition center, Is } } + private void accessIslandsCache(Consumer consumer) { + if (Bukkit.isPrimaryThread()) { + consumer.accept(islandsCache); + } + } + + private R readIslandsCache(Function function, Supplier onInvalidAccess) { + if (Bukkit.isPrimaryThread()) { + return function.apply(islandsCache); + } + + return onInvalidAccess.get(); + } + + private class IslandsCache { + + // Implemented with CacheHolder so IslandPositions with no islands will not trigger access to global `islandsByPositions` + private final IslandPosition2ObjectMap islandsByPositionCache = new IslandPosition2ObjectMap<>(); + + private Island get(IslandPosition islandPosition) { + CacheHolder holder = islandsByPositionCache.get(islandPosition); + if (holder != null) + return holder.island.get(); + + Island island = islandsByPositions.readAndGet(islandsByPositions -> + islandsByPositions.get(islandPosition)); + + insert(islandPosition, island); + + return island; + } + + private void insert(IslandPosition islandPosition, Island island) { + if (islandsByPositionCache.size() > MAX_ISLANDS_POSITION_CACHE) { + // Remove one position + Iterator iterator = islandsByPositionCache.entrySet().iterator(); + if (iterator.hasNext()) { + iterator.next(); + iterator.remove(); + } + } + + islandsByPositionCache.put(islandPosition, island == null ? CacheHolder.NULL : new CacheHolder(island)); + } + + private void remove(IslandPosition islandPosition) { + this.islandsByPositionCache.remove(islandPosition); + } + + } + + private static class CacheHolder { + + private static final CacheHolder NULL = new CacheHolder(null); + + private final WeakReference island; + + CacheHolder(Island island) { + this.island = new WeakReference<>(island); + } + + } + } From 6b5dc683fb283654b37398e66c263ad3dea464bf Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 21 Sep 2025 16:42:41 +0300 Subject: [PATCH 322/600] Fixed NPE errors when using cached schematics in 1.8 (#2661) --- .../nms/v1_8_R3/world/WorldEditSessionImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java index 6272163029..d3bd51eacf 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java @@ -265,9 +265,11 @@ private ChunkData(long chunkKey) { } private void createChunkSections() { + boolean hasSkyLight = dimension.getEnvironment() != World.Environment.THE_END; + for (int i = 0; i < this.chunkSections.length; ++i) { int chunkSectionPos = i << 4; - this.chunkSections[i] = new ChunkSection(chunkSectionPos, !worldServer.worldProvider.o()); + this.chunkSections[i] = new ChunkSection(chunkSectionPos, hasSkyLight); } } From 973d2fae2868b06fdcde38795d76b601eaa6ef41 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sun, 21 Sep 2025 15:46:39 +0200 Subject: [PATCH 323/600] Added home teleport and visitor home teleport events (#2664) --- .../api/events/IslandHomeTeleportEvent.java | 54 +++++++++++++++++++ .../IslandVisitorHomeTeleportEvent.java | 54 +++++++++++++++++++ .../api/events/IslandWarpTeleportEvent.java | 8 +-- .../commands/player/CmdTeleport.java | 6 +++ .../commands/player/CmdVisit.java | 15 +++--- .../core/events/args/PluginEventArgs.java | 12 +++++ .../core/events/plugin/PluginEventType.java | 18 ++++++- .../events/plugin/PluginEventsFactory.java | 16 ++++++ 8 files changed, 171 insertions(+), 12 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandHomeTeleportEvent.java create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandVisitorHomeTeleportEvent.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandHomeTeleportEvent.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandHomeTeleportEvent.java new file mode 100644 index 0000000000..9004d87b56 --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandHomeTeleportEvent.java @@ -0,0 +1,54 @@ +package com.bgsoftware.superiorskyblock.api.events; + +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import org.bukkit.event.Cancellable; + +/** + * IslandHomeTeleportEvent is called when a player teleports to island home. + */ +public class IslandHomeTeleportEvent extends IslandEvent implements Cancellable { + + private final SuperiorPlayer superiorPlayer; + private final Dimension dimension; + private boolean cancelled = false; + + /** + * The constructor of the event. + * + * @param island The island that the player teleports to. + * @param superiorPlayer The player who teleports to the island home. + * @param dimension The dimension that the player teleports to. + */ + public IslandHomeTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Dimension dimension) { + super(island); + this.superiorPlayer = superiorPlayer; + this.dimension = dimension; + } + + /** + * Get the player who teleports to the island home. + */ + public SuperiorPlayer getPlayer() { + return superiorPlayer; + } + + /** + * Get the dimension that the player teleports to. + */ + public Dimension getDimension() { + return this.dimension; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + +} diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandVisitorHomeTeleportEvent.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandVisitorHomeTeleportEvent.java new file mode 100644 index 0000000000..9662902ebb --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandVisitorHomeTeleportEvent.java @@ -0,0 +1,54 @@ +package com.bgsoftware.superiorskyblock.api.events; + +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import org.bukkit.event.Cancellable; + +/** + * IslandVisitorHomeTeleportEvent is called when a player teleports to island visitor home. + */ +public class IslandVisitorHomeTeleportEvent extends IslandEvent implements Cancellable { + + private final SuperiorPlayer superiorPlayer; + private final Dimension dimension; + private boolean cancelled = false; + + /** + * The constructor of the event. + * + * @param island The island that the player teleports to. + * @param superiorPlayer The player who teleports to the island visitor home. + * @param dimension The dimension that the player teleports to. + */ + public IslandVisitorHomeTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Dimension dimension) { + super(island); + this.superiorPlayer = superiorPlayer; + this.dimension = dimension; + } + + /** + * Get the player who teleports to the island visitor home. + */ + public SuperiorPlayer getPlayer() { + return superiorPlayer; + } + + /** + * Get the dimension that the player teleports to. + */ + public Dimension getDimension() { + return this.dimension; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } + +} diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWarpTeleportEvent.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWarpTeleportEvent.java index bb489203bc..9e1cb9cc4f 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWarpTeleportEvent.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/events/IslandWarpTeleportEvent.java @@ -17,9 +17,9 @@ public class IslandWarpTeleportEvent extends IslandEvent implements Cancellable /** * The constructor of the event. * - * @param island The island that the player talks in. - * @param superiorPlayer The player who sent the message. - * @param islandWarp The island warp the player teleports to. + * @param island The island that the player teleports to. + * @param superiorPlayer The player who teleports to the island warp. + * @param islandWarp The island warp that the player teleports to. */ public IslandWarpTeleportEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { super(island); @@ -28,7 +28,7 @@ public IslandWarpTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Isl } /** - * Get the player who banned the other player. + * Get the player who teleports to the island warp. */ public SuperiorPlayer getPlayer() { return superiorPlayer; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java index cf5d60562b..b64c37943d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeleport.java @@ -2,10 +2,12 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import org.bukkit.command.CommandSender; @@ -61,6 +63,10 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); + Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); + + if (!PluginEventsFactory.callIslandHomeTeleportEvent(island, superiorPlayer, dimension)) + return; EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getHomeWarmup(), unused -> teleportToIsland(superiorPlayer, island)); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java index da19bc5ef1..64ccc7e3ac 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java @@ -73,9 +73,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); Dimension dimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); - IslandWorlds.accessIslandWorldAsync(targetIsland, dimension, true, islandWorldResult -> { - islandWorldResult.ifLeft(world -> teleportPlayerInternal(targetIsland, superiorPlayer)); - }); + if (!PluginEventsFactory.callIslandVisitorHomeTeleportEvent(targetIsland, superiorPlayer, dimension)) + return; + + IslandWorlds.accessIslandWorldAsync(targetIsland, dimension, true, islandWorldResult -> + islandWorldResult.ifLeft(world -> teleportPlayerInternal(targetIsland, superiorPlayer))); } @Override @@ -119,10 +121,9 @@ private static void teleportPlayerInternal(Island targetIsland, SuperiorPlayer s Location finalVisitLocation = visitLocation; - EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getVisitWarmup(), afterWarmup -> { - teleportPlayerNoWarmup(superiorPlayer, targetIsland, finalVisitLocation, isVisitorSign, - afterWarmup /*checkIslandLock*/, true); - }); + EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getVisitWarmup(), afterWarmup -> + teleportPlayerNoWarmup(superiorPlayer, targetIsland, finalVisitLocation, + isVisitorSign, afterWarmup /*checkIslandLock*/, true)); } private static void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island island, Location visitLocation, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java index f47a4fa830..e0a374e68c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/args/PluginEventArgs.java @@ -371,6 +371,12 @@ public static class IslandGenerateBlock extends PluginEventArgs { } + public static class IslandHomeTeleport extends IslandDoActionArgs { + + public Dimension dimension; + + } + public static class IslandInvite extends IslandDoActionArgs { public SuperiorPlayer targetPlayer; @@ -545,6 +551,12 @@ public static class IslandUpgrade extends IslandDoActionArgs { } + public static class IslandVisitorHomeTeleport extends IslandDoActionArgs { + + public Dimension dimension; + + } + public static class IslandWarpTeleport extends IslandWarpDoActionArgs { } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java index d05c65ae8e..73a9e299ea 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java @@ -53,6 +53,7 @@ import com.bgsoftware.superiorskyblock.api.events.IslandEnterPortalEvent; import com.bgsoftware.superiorskyblock.api.events.IslandEnterProtectedEvent; import com.bgsoftware.superiorskyblock.api.events.IslandGenerateBlockEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandHomeTeleportEvent; import com.bgsoftware.superiorskyblock.api.events.IslandInviteEvent; import com.bgsoftware.superiorskyblock.api.events.IslandJoinEvent; import com.bgsoftware.superiorskyblock.api.events.IslandKickEvent; @@ -82,6 +83,7 @@ import com.bgsoftware.superiorskyblock.api.events.IslandUncoopPlayerEvent; import com.bgsoftware.superiorskyblock.api.events.IslandUnlockWorldEvent; import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandVisitorHomeTeleportEvent; import com.bgsoftware.superiorskyblock.api.events.IslandWarpTeleportEvent; import com.bgsoftware.superiorskyblock.api.events.IslandWorldResetEvent; import com.bgsoftware.superiorskyblock.api.events.IslandWorthCalculatedEvent; @@ -172,6 +174,7 @@ import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnterPortal; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandEnterProtected; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandGenerateBlock; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandHomeTeleport; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandInvite; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandJoin; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandKick; @@ -201,6 +204,7 @@ import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUncoopPlayer; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUnlockWorld; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandUpgrade; +import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandVisitorHomeTeleport; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWarpTeleport; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorldReset; import static com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs.IslandWorthCalculated; @@ -761,6 +765,12 @@ public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent ISLAND_HOME_TELEPORT_EVENT = new PluginEventType(IslandHomeTeleportEvent.class) { + @Override + public Event createBukkitEvent(IslandHomeTeleport args) { + return new IslandHomeTeleportEvent(args.island, args.superiorPlayer, args.dimension); + } + }; public static final PluginEventType ISLAND_INVITE_EVENT = new PluginEventType(IslandInviteEvent.class) { @Override public Event createBukkitEvent(IslandInvite args) { @@ -983,7 +993,13 @@ public void applyBukkitToPluginEvent(Event bukkitEvent, PluginEvent ISLAND_WARP_TELEPORT_EVENT = new PluginEventType(IslandUpgradeEvent.class) { + public static final PluginEventType ISLAND_VISITOR_HOME_TELEPORT_EVENT = new PluginEventType(IslandVisitorHomeTeleportEvent.class) { + @Override + public Event createBukkitEvent(IslandVisitorHomeTeleport args) { + return new IslandVisitorHomeTeleportEvent(args.island, args.superiorPlayer, args.dimension); + } + }; + public static final PluginEventType ISLAND_WARP_TELEPORT_EVENT = new PluginEventType(IslandWarpTeleportEvent.class) { @Override public Event createBukkitEvent(IslandWarpTeleport args) { return new IslandWarpTeleportEvent(args.island, args.superiorPlayer, args.islandWarp); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java index 910ccff519..bc079710f9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java @@ -628,6 +628,14 @@ public static PluginEvent callIslandGenerateBlockEvent(Isla return fireEvent(ISLAND_GENERATE_BLOCK_EVENT, islandGenerateBlock); } + public static boolean callIslandHomeTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Dimension dimension) { + IslandHomeTeleport islandHomeTeleport = new IslandHomeTeleport(); + islandHomeTeleport.island = island; + islandHomeTeleport.superiorPlayer = superiorPlayer; + islandHomeTeleport.dimension = dimension; + return !fireEvent(ISLAND_HOME_TELEPORT_EVENT, islandHomeTeleport).isCancelled(); + } + public static boolean callIslandInviteEvent(Island island, SuperiorPlayer superiorPlayer, SuperiorPlayer targetPlayer) { IslandInvite islandInvite = new IslandInvite(); islandInvite.island = island; @@ -948,6 +956,14 @@ public static PluginEvent callIslandUpgradeEvent(Island island, @ return fireEvent(ISLAND_UPGRADE_EVENT, islandUpgrade); } + public static boolean callIslandVisitorHomeTeleportEvent(Island island, SuperiorPlayer superiorPlayer, Dimension dimension) { + IslandVisitorHomeTeleport islandVisitorHomeTeleport = new IslandVisitorHomeTeleport(); + islandVisitorHomeTeleport.island = island; + islandVisitorHomeTeleport.superiorPlayer = superiorPlayer; + islandVisitorHomeTeleport.dimension = dimension; + return !fireEvent(ISLAND_VISITOR_HOME_TELEPORT_EVENT, islandVisitorHomeTeleport).isCancelled(); + } + public static boolean callIslandWarpTeleportEvent(Island island, SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { IslandWarpTeleport islandWarpTeleport = new IslandWarpTeleport(); islandWarpTeleport.island = island; From da9de1005e3123685a48d04bd9bf43e62ae53cbf Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 21 Sep 2025 16:53:23 +0300 Subject: [PATCH 324/600] Fixed more NPE errors when using cached schematics in 1.8 (#2661) --- .../nms/v1_8_R3/world/WorldEditSessionImpl.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java index d3bd51eacf..e126c147e3 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/world/WorldEditSessionImpl.java @@ -34,14 +34,12 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_8_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; import org.bukkit.craftbukkit.v1_8_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_8_R3.generator.CustomChunkGenerator; import org.bukkit.generator.ChunkGenerator; import java.util.Arrays; import java.util.Collections; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -261,7 +259,8 @@ public class ChunkData { private ChunkData(long chunkKey) { ChunkCoordIntPair chunkCoord = new ChunkCoordIntPair((int) chunkKey, (int) (chunkKey >> 32)); createChunkSections(); - runCustomWorldGenerator(chunkCoord); + if (worldServer != null) + runCustomWorldGenerator(chunkCoord); } private void createChunkSections() { From b58767de7658c4dd446b067d2e670f4b802166a8 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 21 Sep 2025 17:16:00 +0300 Subject: [PATCH 325/600] Removed usage of IslandPosition instance for faster island lookups (#2654) --- .../superiorskyblock/core/IslandPosition.java | 84 +------ .../collections/IslandPosition2ObjectMap.java | 216 +----------------- .../container/DefaultIslandsContainer.java | 101 ++++---- 3 files changed, 60 insertions(+), 341 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java index 031e5e7010..754d51270e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java @@ -1,95 +1,19 @@ package com.bgsoftware.superiorskyblock.core; -import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import org.bukkit.Location; -import java.util.Objects; - -public class IslandPosition implements ObjectsPool.Releasable, AutoCloseable { - - private static final ObjectsPool POOL = new ObjectsPool<>(IslandPosition::new); +public class IslandPosition { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - @Nullable - protected String worldName; - protected int x; - protected int z; - - @Nullable - protected Long cachedPackedPos = null; - - protected IslandPosition() { - } - - private IslandPosition initialize(@Nullable String worldName, int x, int z) { - this.worldName = worldName; - this.x = x; - this.z = z; - this.cachedPackedPos = null; - return this; - } - - public static IslandPosition of(Location location) { - return of(LazyWorldLocation.getWorldName(location), location.getBlockX(), location.getBlockZ()); - } - - public static IslandPosition of(String worldName, int locX, int locZ) { - return of(worldName, locX, locZ, true); + private IslandPosition() { } - public static IslandPosition of(String worldName, int locX, int locZ, boolean fromPool) { + public static long calculatePackedPosFromLocation(int locX, int locZ) { int radius = plugin.getSettings().getMaxIslandSize() * 3; int x = (Math.abs(locX) + (radius / 2)) / radius; int z = (Math.abs(locZ) + (radius / 2)) / radius; - - IslandPosition islandPosition = fromPool ? POOL.obtain() : new IslandPosition(); - - return islandPosition.initialize(plugin.getProviders().hasCustomWorldsSupport() ? worldName : null, - locX < 0 ? -x : x, locZ < 0 ? -z : z); - } - - public String getWorldName() { - return worldName; - } - - public long pack() { - return this.cachedPackedPos != null ? this.cachedPackedPos : - (this.cachedPackedPos = IslandPosition.calculatePackedPos(this)); - } - - @Override - public void release() { - this.worldName = null; - POOL.release(this); - } - - @Override - public void close() { - this.release(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - IslandPosition that = (IslandPosition) o; - return x == that.x && z == that.z && Objects.equals(worldName, that.worldName); - } - - @Override - public int hashCode() { - return Objects.hash(worldName, x, z); - } - - @Override - public String toString() { - return "IslandPosition{x=" + x + ",z=" + z + "}"; - } - - public static long calculatePackedPos(IslandPosition islandPosition) { - return calculatePackedPos(islandPosition.x, islandPosition.z); + return calculatePackedPos(x, z); } public static long calculatePackedPos(int posX, int posZ) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/IslandPosition2ObjectMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/IslandPosition2ObjectMap.java index 925660d7a3..6c0bd6367c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/IslandPosition2ObjectMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/IslandPosition2ObjectMap.java @@ -2,63 +2,33 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.IslandPosition; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import java.util.AbstractCollection; -import java.util.AbstractMap; -import java.util.AbstractSet; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.NoSuchElementException; -import java.util.Set; import java.util.function.Supplier; -public class IslandPosition2ObjectMap extends AbstractMap { +public class IslandPosition2ObjectMap { - @Nullable - private KeySet keySet; @Nullable private Values values; - @Nullable - private EntrySet entrySet; private final Map> backendMap = new LinkedHashMap<>(); private int size = 0; - @Override public int size() { return this.size; } - @Override public boolean isEmpty() { return this.size == 0; } - @Override - public boolean containsKey(Object key) { - return get(key) != null; - } - - @Override - public boolean containsValue(Object value) { - return value != null && super.containsValue(value); - } - - @Override - public V get(Object key) { - return key instanceof IslandPosition ? get((IslandPosition) key) : null; - } - - @Nullable - public V get(IslandPosition islandPosition) { - return get(islandPosition.getWorldName(), islandPosition.pack()); - } - @Nullable public V get(String worldName, long packedPos) { Long2ObjectMapView worldBackendData = this.backendMap.get(worldName); @@ -78,12 +48,6 @@ public V computeIfAbsent(String worldName, long packedPos, Supplier newValue) }); } - @Nullable - @Override - public V put(IslandPosition islandPosition, V value) { - return put(islandPosition.getWorldName(), islandPosition.pack(), value); - } - @Nullable public V put(String worldName, long packedPos, V value) { Long2ObjectMapView worldBackendData = this.backendMap.computeIfAbsent(worldName, n -> @@ -97,16 +61,6 @@ public V put(String worldName, long packedPos, V value) { return oldValue; } - @Override - public V remove(Object key) { - return key instanceof IslandPosition ? remove((IslandPosition) key) : null; - } - - @Nullable - public V remove(IslandPosition islandPosition) { - return remove(islandPosition.getWorldName(), islandPosition.pack()); - } - @Nullable public V remove(String worldName, long packedPos) { Long2ObjectMapView worldBackendData = this.backendMap.get(worldName); @@ -130,70 +84,16 @@ private V onRemove(@Nullable V removedValue) { return removedValue; } - @Override public void clear() { this.backendMap.clear(); this.size = 0; } @NotNull - @Override - public Set keySet() { - return this.keySet == null ? (this.keySet = new KeySet()) : this.keySet; - } - - @NotNull - @Override public Collection values() { return this.values == null ? (this.values = new Values()) : this.values; } - @NotNull - @Override - public Set> entrySet() { - return this.entrySet == null ? (this.entrySet = new EntrySet()) : this.entrySet; - } - - private class KeySet extends AbstractSet { - - @Override - public int size() { - return IslandPosition2ObjectMap.this.size(); - } - - @Override - public boolean isEmpty() { - return IslandPosition2ObjectMap.this.isEmpty(); - } - - @Override - public boolean contains(Object o) { - return IslandPosition2ObjectMap.this.containsKey(o); - } - - @NotNull - @Override - public Iterator iterator() { - return new KeySetItr(); - } - - @Override - public void clear() { - IslandPosition2ObjectMap.this.clear(); - } - - private class KeySetItr extends Itr { - - private final MutableIslandPosition mutableIslandPosition = new MutableIslandPosition(); - - @Override - protected IslandPosition getNext() { - return this.mutableIslandPosition.reset(this.currentWorld, this.currentPosition); - } - } - - } - private class Values extends AbstractCollection { @Override @@ -208,7 +108,7 @@ public boolean isEmpty() { @Override public boolean contains(Object o) { - return IslandPosition2ObjectMap.this.containsValue(o); + throw new UnsupportedOperationException(); } @NotNull @@ -233,101 +133,9 @@ protected V getNext() { } - private class EntrySet extends AbstractSet> { - - @Override - public int size() { - return IslandPosition2ObjectMap.this.size(); - } - - @Override - public boolean isEmpty() { - return IslandPosition2ObjectMap.this.isEmpty(); - } - - @Override - public boolean contains(Object o) { - IslandPosition key = null; - - if (o instanceof Entry) { - o = ((Entry) o).getKey(); - } - - if (o instanceof IslandPosition) - key = (IslandPosition) o; - - return key != null && IslandPosition2ObjectMap.this.containsKey(o); - } - - @NotNull - @Override - public Iterator> iterator() { - return new EntrySetItr(); - } - - @Override - public void clear() { - IslandPosition2ObjectMap.this.clear(); - } - - private class EntrySetItr extends Itr> { - - private final MutableIslandPosition mutableIslandPosition = new MutableIslandPosition(); - private final EntryImpl mutableEntry = new EntryImpl(); - - @Override - protected Entry getNext() { - return mutableEntry.reset( - this.mutableIslandPosition.reset(this.currentWorld, this.currentPosition), - this.currentValue); - } - - private class EntryImpl implements Entry { - - private IslandPosition islandPosition; - private V cachedValue; - - EntryImpl() { - - } - - EntryImpl reset(IslandPosition islandPosition, V value) { - this.islandPosition = islandPosition; - this.cachedValue = value; - return this; - } - - @Override - public IslandPosition getKey() { - return this.islandPosition; - } - - @Override - public V getValue() { - return this.cachedValue; - } - - @Override - public V setValue(V v) { - V oldValue = this.cachedValue; - this.cachedValue = v; - - Long2ObjectMapView worldBackendData = IslandPosition2ObjectMap.this.backendMap - .get(this.islandPosition.getWorldName()); - - worldBackendData.put(this.islandPosition.pack(), this.cachedValue); - - return oldValue; - } - } - - } - - } - private abstract class Itr implements Iterator { - protected final Iterator>> worldsIterator; + protected final Iterator>> worldsIterator; protected Iterator> currentWorldIterator = Collections.emptyIterator(); protected String currentWorld; protected long currentPosition; @@ -349,7 +157,7 @@ public final T next() { throw new NoSuchElementException(); } - Entry> nextWorld = this.worldsIterator.next(); + Map.Entry> nextWorld = this.worldsIterator.next(); this.currentWorldIterator = nextWorld.getValue().entryIterator(); this.currentWorld = nextWorld.getKey(); } @@ -375,20 +183,4 @@ public final void remove() { } } - private static class MutableIslandPosition extends IslandPosition { - - public MutableIslandPosition() { - super(); - } - - public MutableIslandPosition reset(String worldName, long packedPos) { - this.worldName = worldName; - this.x = IslandPosition.getXFromPacked(packedPos); - this.z = IslandPosition.getZFromPacked(packedPos); - this.cachedPackedPos = packedPos; - return this; - } - - } - } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index c44fbbf6db..e640828b31 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.IslandPosition; +import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.collections.IslandPosition2ObjectMap; @@ -63,25 +64,25 @@ public void addIsland(Island island) { Preconditions.checkNotNull(defaultWorld, "Default world information cannot be null!"); - try (IslandPosition islandPosition = IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ())) { - // Insert to cache if we can access it - accessIslandsCache(islandsCache -> islandsCache.insert(islandPosition, island)); - - this.islandsByPositions.write(islandsByPositions -> { - islandsByPositions.put(islandPosition, island); - - if (plugin.getProviders().hasCustomWorldsSupport()) { - // We don't know the logic of the custom worlds support, therefore we add a position - // for every possible world, so there won't be issues with detecting islands later. - for (Dimension dimension : Dimension.values()) { - if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { - runWithCustomWorld(defaultWorld, center, island, dimension, - islandPositionCustomWorld -> islandsByPositions.put(islandPositionCustomWorld, island)); - } + long packedPos = IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ()); + + // Insert to cache if we can access it + accessIslandsCache(islandsCache -> islandsCache.insert(defaultWorld.getName(), packedPos, island)); + + this.islandsByPositions.write(islandsByPositions -> { + islandsByPositions.put(defaultWorld.getName(), packedPos, island); + + if (plugin.getProviders().hasCustomWorldsSupport()) { + // We don't know the logic of the custom worlds support, therefore we add a position + // for every possible world, so there won't be issues with detecting islands later. + for (Dimension dimension : Dimension.values()) { + if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { + runWithCustomWorld(defaultWorld, center, island, dimension, (worldName, customWorldPackedPos) -> + islandsByPositions.put(worldName, customWorldPackedPos, island)); } } - }); - } + } + }); this.islandsByUUID.put(island.getUniqueId(), island); @@ -98,23 +99,22 @@ public void removeIsland(Island island) { Preconditions.checkNotNull(defaultWorld, "Default world information cannot be null!"); - try (IslandPosition islandPosition = IslandPosition.of(defaultWorld.getName(), center.getX(), center.getZ())) { - // Remove from cache if we can access it - accessIslandsCache(islandsCache -> islandsCache.remove(islandPosition)); + long packedPos = IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ()); - this.islandsByPositions.write(islandsByPositions -> { - islandsByPositions.remove(islandPosition, island); + // Remove from cache if we can access it + accessIslandsCache(islandsCache -> islandsCache.remove(defaultWorld.getName(), packedPos)); - if (plugin.getProviders().hasCustomWorldsSupport()) { - for (Dimension dimension : Dimension.values()) { - if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { - runWithCustomWorld(defaultWorld, center, island, dimension, - islandPositionCustomWorld -> islandsByPositions.remove(islandPositionCustomWorld, island)); - } + this.islandsByPositions.write(islandsByPositions -> { + islandsByPositions.remove(defaultWorld.getName(), packedPos); + + if (plugin.getProviders().hasCustomWorldsSupport()) { + for (Dimension dimension : Dimension.values()) { + if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { + runWithCustomWorld(defaultWorld, center, island, dimension, islandsByPositions::remove); } } - }); - } + } + }); islandsByUUID.remove(island.getUniqueId()); @@ -154,12 +154,11 @@ public int getIslandsAmount() { @Nullable @Override public Island getIslandAt(Location location) { - Island island; - try (IslandPosition islandPosition = IslandPosition.of(location)) { - island = readIslandsCache(islandsCache -> islandsCache.get(islandPosition), - () -> this.islandsByPositions.readAndGet(islandsByPositions -> - islandsByPositions.get(islandPosition))); - } + long packedPos = IslandPosition.calculatePackedPosFromLocation(location.getBlockX(), location.getBlockZ()); + String worldName = LazyWorldLocation.getWorldName(location); + Island island = readIslandsCache(islandsCache -> islandsCache.get(worldName, packedPos), + () -> this.islandsByPositions.readAndGet(islandsByPositions -> + islandsByPositions.get(worldName, packedPos))); return island == null || !island.isInside(location) ? null : island; } @@ -264,12 +263,10 @@ else if (sortingType == SortingTypes.BY_RATING) } private void runWithCustomWorld(WorldInfo defaultWorld, BlockPosition center, Island island, - Dimension dimension, Consumer consumer) { + Dimension dimension, CustomWorldConsumer consumer) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); if (worldInfo != null && !worldInfo.equals(defaultWorld)) { - try (IslandPosition islandPosition = IslandPosition.of(worldInfo.getName(), center.getX(), center.getZ())) { - consumer.accept(islandPosition); - } + consumer.apply(worldInfo.getName(), IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ())); } } @@ -287,39 +284,45 @@ private R readIslandsCache(Function function, Supplier o return onInvalidAccess.get(); } + private interface CustomWorldConsumer { + + void apply(String worldName, long packedPos); + + } + private class IslandsCache { // Implemented with CacheHolder so IslandPositions with no islands will not trigger access to global `islandsByPositions` private final IslandPosition2ObjectMap islandsByPositionCache = new IslandPosition2ObjectMap<>(); - private Island get(IslandPosition islandPosition) { - CacheHolder holder = islandsByPositionCache.get(islandPosition); + private Island get(String worldName, long packedPos) { + CacheHolder holder = islandsByPositionCache.get(worldName, packedPos); if (holder != null) return holder.island.get(); Island island = islandsByPositions.readAndGet(islandsByPositions -> - islandsByPositions.get(islandPosition)); + islandsByPositions.get(worldName, packedPos)); - insert(islandPosition, island); + insert(worldName, packedPos, island); return island; } - private void insert(IslandPosition islandPosition, Island island) { + private void insert(String worldName, long packedPos, Island island) { if (islandsByPositionCache.size() > MAX_ISLANDS_POSITION_CACHE) { // Remove one position - Iterator iterator = islandsByPositionCache.entrySet().iterator(); + Iterator iterator = islandsByPositionCache.values().iterator(); if (iterator.hasNext()) { iterator.next(); iterator.remove(); } } - islandsByPositionCache.put(islandPosition, island == null ? CacheHolder.NULL : new CacheHolder(island)); + islandsByPositionCache.put(worldName, packedPos, island == null ? CacheHolder.NULL : new CacheHolder(island)); } - private void remove(IslandPosition islandPosition) { - this.islandsByPositionCache.remove(islandPosition); + private void remove(String worldName, long packedPos) { + this.islandsByPositionCache.remove(worldName, packedPos); } } From fae2ab671aef89d42dfea317329183497760ba51 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 22 Sep 2025 12:06:13 +0300 Subject: [PATCH 326/600] Fix spawn island is loaded too early, causing world detection to not pass (#2666) --- .../core/events/plugin/PluginEventType.java | 6 ++++++ .../core/events/plugin/PluginEventsFactory.java | 4 ++++ .../superiorskyblock/island/GridManagerImpl.java | 1 + .../listener/IslandFlagsListener.java | 11 ++++++++--- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java index 73a9e299ea..f9a43b1a46 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java @@ -248,6 +248,12 @@ public Event createBukkitEvent(Empty args) { return null; } }; + public static final PluginEventType SPAWN_UPDATE_EVENT = new PluginEventType(null) { + @Override + public Event createBukkitEvent(Empty args) { + return null; + } + }; public static final PluginEventType ATTEMPT_PLAYER_SEND_MESSAGE_EVENT = new PluginEventType(AttemptPlayerSendMessageEvent.class) { @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java index bc079710f9..c6b74f961b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java @@ -60,6 +60,10 @@ public static void callCommandsUpdateEvent() { fireEvent(COMMANDS_UPDATE_EVENT, Empty.INSTANCE); } + public static void callSpawnUpdateEvent() { + fireEvent(SPAWN_UPDATE_EVENT, Empty.INSTANCE); + } + public static boolean callAttemptPlayerSendMessageEvent(SuperiorPlayer receiver, String messageType, Object... args) { AttemptPlayerSendMessage attemptPlayerSendMessage = new AttemptPlayerSendMessage(); attemptPlayerSendMessage.receiver = receiver; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index 3967d7d369..bbe441ab0f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -142,6 +142,7 @@ public void loadData() { public void updateSpawn() { try { this.spawnIsland = new SpawnIsland(); + PluginEventsFactory.callSpawnUpdateEvent(); } catch (ManagerLoadException error) { ManagerLoadException.handle(error); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java index 6103e32dcb..99bb76fe50 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; @@ -44,18 +45,21 @@ public class IslandFlagsListener extends AbstractGameEventListener { private final Int2ObjectMapView originalFireballsDamager = CollectionsFactory.createInt2ObjectArrayMap(); - private final World spawnIslandWorld; + private World spawnIslandWorld; public IslandFlagsListener(SuperiorSkyblockPlugin plugin) { super(plugin); + this.registerListeners(); + } + + /* INTERNAL EVENTS */ + private void onSpawnUpdate() { // We want to optimize island checks only for island worlds // However, if the spawn world is not an islands world, we want to check it as well. Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter( plugin.getSettings().getWorlds().getDefaultWorldDimension()); this.spawnIslandWorld = spawnLocation.getWorld(); - - this.registerListeners(); } /* ENTITY SPAWNING */ @@ -387,6 +391,7 @@ private void registerListeners() { registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.LOWEST, this::onEndermanGrief); registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onEggLay); registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.LOWEST, this::onPoisonAttack); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, this::onSpawnUpdate); } private boolean shouldIgnoreWorldEvents(@Nullable World world) { From f7b03a5c749ae0aa54b883c470dc6c017806d61d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 22 Sep 2025 12:29:59 +0300 Subject: [PATCH 327/600] Enabled schematics lights-update by default --- .../bgsoftware/superiorskyblock/config/SettingsContainer.java | 2 +- src/main/resources/config.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index bb6013912e..ad4bfdb5cd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -498,7 +498,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config homeWarmup = config.getLong("home-warmup", 0); visitWarmup = config.getLong("visit-warmup", 0); liquidUpdate = config.getBoolean("liquid-update", false); - lightsUpdate = config.getBoolean("lights-update", false); + lightsUpdate = config.getBoolean("lights-update", true); pvpWorlds = Collections.unmodifiableList(config.getStringList("pvp-worlds")); stopLeaving = config.getBoolean("stop-leaving", false); valuesMenu = config.getBoolean("values-menu", true); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index c8ec443e7d..45b090b1bb 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -671,7 +671,7 @@ liquid-update: false # Should lights get updated when pasting schematics? # Enabling this can drop performance a bit. -lights-update: false +lights-update: true # A list of worlds that PvP will be enabled between island members. pvp-worlds: @@ -827,7 +827,7 @@ island-previews: max-distance: 100 # A list of commands that cannot be executed by players in preview mode. - blocked-commands: [] + blocked-commands: [ ] # Preview locations for schematics. # You can disable this feature by setting the section to 'locations: []' From 9fc6cee393a517f31280a20b781320dccf465705 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 22 Sep 2025 13:44:31 +0300 Subject: [PATCH 328/600] Fix incorrectly registering `onSpawnUpdate` --- .../superiorskyblock/listener/IslandFlagsListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java index 99bb76fe50..1bd4a55103 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java @@ -391,7 +391,7 @@ private void registerListeners() { registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.LOWEST, this::onEndermanGrief); registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onEggLay); registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.LOWEST, this::onPoisonAttack); - plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, this::onSpawnUpdate); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SPAWN_UPDATE_EVENT, this::onSpawnUpdate); } private boolean shouldIgnoreWorldEvents(@Nullable World world) { From 8e1d541eba81646405a5c9a36a8f705bb953a6e5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 22 Sep 2025 13:49:40 +0300 Subject: [PATCH 329/600] Potential fix for islands not detected correctly (#2654) --- .../island/container/DefaultIslandsContainer.java | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index e640828b31..f40765ec7a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -27,7 +27,6 @@ import org.bukkit.Location; import java.lang.ref.WeakReference; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -39,8 +38,6 @@ public class DefaultIslandsContainer implements IslandsContainer { - private static final int MAX_ISLANDS_POSITION_CACHE = 250; - private final Synchronized> islandsByPositions = Synchronized.of(new IslandPosition2ObjectMap<>()); private final Map islandsByUUID = new ConcurrentHashMap<>(); @@ -295,6 +292,7 @@ private class IslandsCache { // Implemented with CacheHolder so IslandPositions with no islands will not trigger access to global `islandsByPositions` private final IslandPosition2ObjectMap islandsByPositionCache = new IslandPosition2ObjectMap<>(); + @Nullable private Island get(String worldName, long packedPos) { CacheHolder holder = islandsByPositionCache.get(worldName, packedPos); if (holder != null) @@ -308,16 +306,7 @@ private Island get(String worldName, long packedPos) { return island; } - private void insert(String worldName, long packedPos, Island island) { - if (islandsByPositionCache.size() > MAX_ISLANDS_POSITION_CACHE) { - // Remove one position - Iterator iterator = islandsByPositionCache.values().iterator(); - if (iterator.hasNext()) { - iterator.next(); - iterator.remove(); - } - } - + private void insert(String worldName, long packedPos, @Nullable Island island) { islandsByPositionCache.put(worldName, packedPos, island == null ? CacheHolder.NULL : new CacheHolder(island)); } From fe90fa4456a688016a29cd57ba3633197f6d64ea Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Mon, 22 Sep 2025 20:20:54 +0200 Subject: [PATCH 330/600] Fixed island names coloring (#2568) --- .../api/island/DelegateIsland.java | 11 +++++ .../superiorskyblock/api/island/Island.java | 28 ++++++++++--- .../api/island/SortingType.java | 4 +- .../container/DelegateIslandsContainer.java | 10 +++++ .../island/container/IslandsContainer.java | 16 ++++++++ .../commands/CommandTabCompletes.java | 4 +- .../commands/admin/CmdAdminCount.java | 4 +- .../commands/admin/CmdAdminName.java | 15 +++---- .../commands/player/CmdName.java | 3 +- .../bridge/IslandsDatabaseBridge.java | 5 ++- .../core/formatting/impl/ChatFormatter.java | 3 +- .../impl/TopIslandsSelfIslandButton.java | 4 +- .../core/messages/Message.java | 2 + .../island/GridManagerImpl.java | 3 +- .../superiorskyblock/island/IslandNames.java | 41 +++++++++++++------ .../superiorskyblock/island/SIsland.java | 39 +++++++++++++----- .../superiorskyblock/island/SpawnIsland.java | 10 +++++ .../container/DefaultIslandsContainer.java | 18 +++++++- .../island/top/SortingComparators.java | 4 +- .../top/metadata/IslandSortMetadata.java | 2 +- .../placeholders/PlaceholdersServiceImpl.java | 10 ++--- src/main/resources/lang/de-DE.yml | 14 ++++--- src/main/resources/lang/en-US.yml | 14 ++++--- src/main/resources/lang/es-ES.yml | 14 ++++--- src/main/resources/lang/fr-FR.yml | 14 ++++--- src/main/resources/lang/it-IT.yml | 14 ++++--- src/main/resources/lang/iw-IL.yml | 14 ++++--- src/main/resources/lang/pl-PL.yml | 14 ++++--- src/main/resources/lang/pt-BR.yml | 14 ++++--- src/main/resources/lang/ru-RU.yml | 14 ++++--- src/main/resources/lang/tr-TR.yml | 14 ++++--- src/main/resources/lang/vi-VN.yml | 14 ++++--- src/main/resources/lang/zh-CN.yml | 14 ++++--- 33 files changed, 269 insertions(+), 135 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index 330c8cc937..138f748345 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -787,10 +787,21 @@ public void setName(String islandName) { } @Override + @Deprecated public String getRawName() { return this.handle.getRawName(); } + @Override + public String getStrippedName() { + return this.handle.getStrippedName(); + } + + @Override + public String getFormattedName() { + return this.handle.getFormattedName(); + } + @Override public String getDescription() { return this.handle.getDescription(); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java index 4faafd2781..d6821f15ac 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java @@ -1091,11 +1091,6 @@ List> getAllChunksAsync(World.Environment environment, */ boolean isSpawn(); - /** - * Get the name of the island. - */ - String getName(); - /** * Set the name of the island. * @@ -1104,10 +1099,31 @@ List> getAllChunksAsync(World.Environment environment, void setName(String islandName); /** - * Get the name of the island, unformatted. + * Get the name of the island in respect to color-support. + * This method will call {@link #getFormattedName()} or {@link #getStrippedName()}, depends on color-support. + */ + String getName(); + + /** + * Get the name of the island in its stripped form. + * + * @deprecated See {@link #getStrippedName()} */ + @Deprecated String getRawName(); + /** + * Get the name of the island in its stripped form. + * Unlike {@link #getName()}, this method will always return the stripped form of the name. + */ + String getStrippedName(); + + /** + * Get the name of the island in its color-formatted form. + * Unlike {@link #getName()}, this method will always return the color-formatted form of the name. + */ + String getFormattedName(); + /** * Get the description of the island. */ diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/SortingType.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/SortingType.java index 92b2ecf605..5a11446c7d 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/SortingType.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/SortingType.java @@ -15,8 +15,8 @@ public class SortingType implements Comparator, Enumerable { private static int ordinalCounter = 0; private static final Comparator ISLAND_NAMES_COMPARATOR = (o1, o2) -> { - String firstName = o1.getName().isEmpty() ? o1.getOwner() == null ? "null" : o1.getOwner().getName() : o1.getName(); - String secondName = o2.getName().isEmpty() ? o2.getOwner() == null ? "null" : o2.getOwner().getName() : o2.getName(); + String firstName = o1.getStrippedName().isEmpty() ? o1.getOwner() == null ? "null" : o1.getOwner().getName() : o1.getStrippedName(); + String secondName = o2.getStrippedName().isEmpty() ? o2.getOwner() == null ? "null" : o2.getOwner().getName() : o2.getStrippedName(); return firstName.compareTo(secondName); }; diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/DelegateIslandsContainer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/DelegateIslandsContainer.java index e3c90840ad..b7137f7d4c 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/DelegateIslandsContainer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/DelegateIslandsContainer.java @@ -32,6 +32,16 @@ public Island getIslandByUUID(UUID uuid) { return this.handle.getIslandByUUID(uuid); } + @Override + public Island getIslandByName(String name) { + return this.handle.getIslandByName(name); + } + + @Override + public void updateIslandName(Island island, String oldName) { + this.handle.updateIslandName(island, oldName); + } + @Nullable @Override @Deprecated diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/IslandsContainer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/IslandsContainer.java index c1679c3e84..6b45e1aa7f 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/IslandsContainer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/IslandsContainer.java @@ -34,6 +34,22 @@ public interface IslandsContainer { @Nullable Island getIslandByUUID(UUID uuid); + /** + * Get an island by its name. + * + * @param name The name of the island. + */ + @Nullable + Island getIslandByName(String name); + + /** + * Update an island with a new name. + * + * @param island The island to update. + * @param oldName The old name of the island. + */ + void updateIslandName(Island island, String oldName); + /** * Get an island by its leader's uuid. * diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index 083ea53b9a..960bba6a57 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -101,8 +101,8 @@ public static List getOnlinePlayersWithIslands(SuperiorSkyblockPlugin pl if (predicate == null || predicate.test(onlinePlayer, onlineIsland)) { if (onlinePlayer.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) tabArguments.add(onlinePlayer.getName()); - if (onlineIsland != null && onlineIsland.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) - tabArguments.add(onlineIsland.getName()); + if (onlineIsland != null && onlineIsland.getStrippedName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) + tabArguments.add(onlineIsland.getStrippedName()); } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminCount.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminCount.java index 353fe67e57..bc3912f675 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminCount.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminCount.java @@ -77,8 +77,8 @@ public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sen if (playerIsland != null) { if (player.getName().toLowerCase(Locale.ENGLISH).contains(argument)) list.add(player.getName()); - if (!playerIsland.getName().isEmpty() && playerIsland.getName().toLowerCase(Locale.ENGLISH).contains(argument)) - list.add(playerIsland.getName()); + if (!playerIsland.getStrippedName().isEmpty() && playerIsland.getStrippedName().toLowerCase(Locale.ENGLISH).contains(argument)) + list.add(playerIsland.getStrippedName()); } } } else if (args.length == 4) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java index 2f78e72928..781f17aa6a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java @@ -78,16 +78,17 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab String oldName = island.getName(); island.setName(islandName); - String coloredName = plugin.getSettings().getIslandNames().isColorSupport() ? - Formatters.COLOR_FORMATTER.format(islandName) : islandName; + String coloredName = island.getName(); - for (Player player : Bukkit.getOnlinePlayers()) - Message.NAME_ANNOUNCEMENT.send(player, sender.getName(), coloredName); - - if (targetPlayer == null) + if (targetPlayer == null) { + for (Player player : Bukkit.getOnlinePlayers()) + Message.NAME_ANNOUNCEMENT_OTHER_NAME.send(player, sender.getName(), oldName, coloredName); Message.CHANGED_NAME_OTHER_NAME.send(sender, oldName, coloredName); - else + } else { + for (Player player : Bukkit.getOnlinePlayers()) + Message.NAME_ANNOUNCEMENT_OTHER.send(player, sender.getName(), targetPlayer.getName(), coloredName); Message.CHANGED_NAME_OTHER.send(sender, targetPlayer.getName(), coloredName); + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java index de56930d50..38bd669ec9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java @@ -79,8 +79,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer island.setName(islandName); - String coloredName = plugin.getSettings().getIslandNames().isColorSupport() ? - Formatters.COLOR_FORMATTER.format(islandName) : islandName; + String coloredName = island.getName(); for (Player player : Bukkit.getOnlinePlayers()) Message.NAME_ANNOUNCEMENT.send(player, superiorPlayer.getName(), coloredName); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index 095680acd1..081c4255d3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -28,6 +28,7 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.database.serialization.IslandsSerializer; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; +import com.bgsoftware.superiorskyblock.island.IslandNames; import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; import com.bgsoftware.superiorskyblock.world.Dimensions; import org.bukkit.Location; @@ -167,7 +168,7 @@ public static void clearRolePermissions(Island island) { public static void saveName(Island island) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", createFilter("uuid", island), - new Pair<>("name", island.getName()) + new Pair<>("name", IslandNames.getNameForDatabase(island)) )); } @@ -651,7 +652,7 @@ public static void insertIsland(Island island, @Nullable List dir new Pair<>("levels_bonus", island.getBonusLevel() + ""), new Pair<>("locked", island.isLocked()), new Pair<>("ignored", island.isIgnored()), - new Pair<>("name", island.getName()), + new Pair<>("name", IslandNames.getNameForDatabase(island)), new Pair<>("description", island.getDescription()), new Pair<>("generated_schematics", LegacyMasks.convertGeneratedSchematicsMask(island.getGeneratedSchematics())), new Pair<>("unlocked_worlds", LegacyMasks.convertUnlockedWorldsMask(island.getUnlockedWorlds())), diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/ChatFormatter.java b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/ChatFormatter.java index 2ece0fc315..0c522a7cb8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/ChatFormatter.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/formatting/impl/ChatFormatter.java @@ -27,8 +27,7 @@ private ChatFormatter() { @Override public String format(ChatFormatter.ChatFormatArgs args) { String islandNameFormat = Message.NAME_CHAT_FORMAT.getMessage(PlayerLocales.getDefaultLocale(), - args.island == null ? "" : plugin.getSettings().getIslandNames().isColorSupport() ? - Formatters.COLOR_FORMATTER.format(args.island.getName()) : args.island.getName()); + args.island == null ? "" : args.island.getName()); return args.format .replace("{island-level}", String.valueOf(args.island == null ? 0 : args.island.getIslandLevel())) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TopIslandsSelfIslandButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TopIslandsSelfIslandButton.java index 09cce317c4..1b9ef6a41b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TopIslandsSelfIslandButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/TopIslandsSelfIslandButton.java @@ -114,9 +114,7 @@ public static ItemStack modifyViewItem(MenuTopIslands.View menuView, Island isla ItemBuilder itemBuilder = islandItem.getBuilder().asSkullOf(islandOwner); String islandName = !plugin.getSettings().getIslandNames().isIslandTop() || - island.getName().isEmpty() ? islandOwner.getName() : - plugin.getSettings().getIslandNames().isColorSupport() ? - Formatters.COLOR_FORMATTER.format(island.getName()) : island.getName(); + island.getName().isEmpty() ? islandOwner.getName() : island.getName(); itemBuilder.replaceName("{0}", islandName) .replaceName("{1}", String.valueOf(place)) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index f50cb655a0..4853a98d0c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -595,6 +595,8 @@ public void send(CommandSender sender, Locale locale, Object... args) { MODULE_LOADED_SUCCESS, MODULE_UNLOADED_SUCCESS, NAME_ANNOUNCEMENT, + NAME_ANNOUNCEMENT_OTHER, + NAME_ANNOUNCEMENT_OTHER_NAME, NAME_BLACKLISTED, NAME_CHAT_FORMAT, NAME_SAME_AS_PLAYER, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index bbe441ab0f..bea2567426 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -549,8 +549,7 @@ public Island getIslandByUUID(UUID uuid) { @Override public Island getIsland(String islandName) { Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); - String inputName = Formatters.STRIP_COLOR_FORMATTER.format(islandName); - return getIslands().stream().filter(island -> island.getRawName().equalsIgnoreCase(inputName)).findFirst().orElse(null); + return this.islandsContainer.getIslandByName(islandName); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandNames.java b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandNames.java index 87421c5d2f..ee1aa0ee85 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandNames.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandNames.java @@ -5,8 +5,10 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; +import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; +import javax.annotation.Nullable; import java.util.Locale; public class IslandNames { @@ -17,23 +19,23 @@ private IslandNames() { } - public static boolean isValidName(SuperiorPlayer superiorPlayer, Island currentIsland, String islandName) { + public static boolean isValidName(SuperiorPlayer superiorPlayer, @Nullable Island currentIsland, String islandName) { return isValidName(superiorPlayer.asPlayer(), currentIsland, islandName); } public static boolean isValidName(CommandSender sender, Island currentIsland, String islandName) { - String coloredName = plugin.getSettings().getIslandNames().isColorSupport() ? - Formatters.COLOR_FORMATTER.format(islandName) : islandName; - String strippedName = plugin.getSettings().getIslandNames().isColorSupport() ? - Formatters.STRIP_COLOR_FORMATTER.format(coloredName) : islandName; + String strippedName = Formatters.STRIP_COLOR_FORMATTER.format(islandName); - if (strippedName.length() > plugin.getSettings().getIslandNames().getMaxLength()) { - Message.NAME_TOO_LONG.send(sender); + int maxLength = plugin.getSettings().getIslandNames().getMaxLength(); + int minLength = plugin.getSettings().getIslandNames().getMinLength(); + + if (strippedName.length() > maxLength) { + Message.NAME_TOO_LONG.send(sender, maxLength); return false; } - if (strippedName.length() < plugin.getSettings().getIslandNames().getMinLength()) { - Message.NAME_TOO_SHORT.send(sender); + if (strippedName.length() < minLength) { + Message.NAME_TOO_SHORT.send(sender, minLength); return false; } @@ -48,12 +50,17 @@ public static boolean isValidName(CommandSender sender, Island currentIsland, St return false; } - if (currentIsland != null && currentIsland.getName().equalsIgnoreCase(islandName)) { - Message.SAME_NAME_CHANGE.send(sender); - return false; + if (currentIsland != null) { + String formattedName = Formatters.COLOR_FORMATTER.format(islandName); + + if (currentIsland.getFormattedName().equalsIgnoreCase(formattedName)) { + Message.SAME_NAME_CHANGE.send(sender); + return false; + } } - if (plugin.getGrid().getIsland(islandName) != null) { + Island islandWithName = plugin.getGrid().getIsland(strippedName); + if (islandWithName != null && islandWithName != currentIsland) { Message.ISLAND_ALREADY_EXIST.send(sender); return false; } @@ -61,4 +68,12 @@ public static boolean isValidName(CommandSender sender, Island currentIsland, St return true; } + public static String getNameForDatabase(Island island) { + return island.getFormattedName().replace(ChatColor.COLOR_CHAR, '&'); + } + + public static String getNameForLookup(String name) { + return Formatters.STRIP_COLOR_FORMATTER.format(name).toLowerCase(Locale.ENGLISH); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index acd6e2715b..af267d2705 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -268,8 +268,8 @@ protected IslandCache create() { private volatile String paypal; private volatile boolean isLocked; private volatile boolean isTopIslandsIgnored; - private volatile String islandName; - private volatile String islandRawName; + private volatile String formattedName; + private volatile String strippedName; private volatile String description; private volatile Biome biome = null; @@ -284,8 +284,7 @@ public SIsland(IslandBuilderImpl builder) { this.center = new SBlockPosition(builder.center); this.creationTime = builder.creationTime; - this.islandName = builder.islandName; - this.islandRawName = Formatters.STRIP_COLOR_FORMATTER.format(this.islandName); + setNameInternal(builder.islandName); this.schematicName = builder.islandType; this.discord = builder.discord; this.paypal = builder.paypal; @@ -1747,27 +1746,47 @@ public boolean isSpawn() { @Override public String getName() { - return plugin.getSettings().getIslandNames().isColorSupport() ? islandName : islandRawName; + return plugin.getSettings().getIslandNames().isColorSupport() ? getFormattedName() : getStrippedName(); } @Override public void setName(String islandName) { Preconditions.checkNotNull(islandName, "islandName parameter cannot be null."); - Log.debug(Debug.SET_NAME, owner.getName(), islandName); + String strippedName = Formatters.STRIP_COLOR_FORMATTER.format(islandName); - if (Objects.equals(islandName, this.islandName)) + Log.debug(Debug.SET_NAME, owner.getName(), strippedName); + + String oldName = this.strippedName; + + setNameInternal(islandName); + + if (Objects.equals(strippedName, oldName)) return; - this.islandName = islandName; - this.islandRawName = Formatters.STRIP_COLOR_FORMATTER.format(this.islandName); + plugin.getGrid().getIslandsContainer().updateIslandName(this, oldName); IslandsDatabaseBridge.saveName(this); } + private void setNameInternal(String name) { + this.formattedName = Formatters.COLOR_FORMATTER.format(name); + this.strippedName = Formatters.STRIP_COLOR_FORMATTER.format(name); + } + @Override public String getRawName() { - return islandRawName; + return getStrippedName(); + } + + @Override + public String getStrippedName() { + return this.strippedName; + } + + @Override + public String getFormattedName() { + return this.formattedName; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 611baca204..c6975dedff 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -999,6 +999,16 @@ public String getRawName() { return ""; } + @Override + public String getStrippedName() { + return ""; + } + + @Override + public String getFormattedName() { + return ""; + } + @Override public String getDescription() { return ""; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index f40765ec7a..7041ccfe75 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -16,6 +16,7 @@ import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.bgsoftware.superiorskyblock.island.IslandNames; import com.bgsoftware.superiorskyblock.island.top.SortingComparators; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.island.top.metadata.IslandSortMetadata; @@ -40,6 +41,7 @@ public class DefaultIslandsContainer implements IslandsContainer { private final Synchronized> islandsByPositions = Synchronized.of(new IslandPosition2ObjectMap<>()); private final Map islandsByUUID = new ConcurrentHashMap<>(); + private final Map islandsByNames = new ConcurrentHashMap<>(); private final Map>> sortedIslands = new ConcurrentHashMap<>(); @@ -82,6 +84,7 @@ public void addIsland(Island island) { }); this.islandsByUUID.put(island.getUniqueId(), island); + this.islandsByNames.put(IslandNames.getNameForLookup(island.getStrippedName()), island); sortedIslands.values().forEach(sortedIslands -> { sortedIslands.write(_sortedIslands -> _sortedIslands.add(island)); @@ -113,7 +116,8 @@ public void removeIsland(Island island) { } }); - islandsByUUID.remove(island.getUniqueId()); + this.islandsByUUID.remove(island.getUniqueId()); + this.islandsByNames.remove(IslandNames.getNameForLookup(island.getStrippedName())); sortedIslands.values().forEach(sortedIslands -> { sortedIslands.write(_sortedIslands -> _sortedIslands.remove(island)); @@ -126,6 +130,18 @@ public Island getIslandByUUID(UUID uuid) { return this.islandsByUUID.get(uuid); } + @Override + public Island getIslandByName(String name) { + return this.islandsByNames.get(IslandNames.getNameForLookup(name)); + } + + @Override + public void updateIslandName(Island island, String oldName) { + Island currentIsland = this.islandsByNames.remove(IslandNames.getNameForLookup(oldName)); + if (currentIsland == island) + this.islandsByNames.put(IslandNames.getNameForLookup(island.getStrippedName()), island); + } + @Nullable @Override public Island getIslandAtPosition(int position, SortingType sortingType) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingComparators.java b/src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingComparators.java index c01d8d08f8..a2a4603385 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingComparators.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingComparators.java @@ -17,8 +17,8 @@ public class SortingComparators { public final static Comparator BANK_TRANSACTIONS_COMPARATOR = Comparator.comparingInt(BankTransaction::getPosition); private final static Comparator ISLAND_NAMES_COMPARATOR = (o1, o2) -> { - String firstName = o1.getName().isEmpty() ? o1.getOwner().getName() : o1.getName(); - String secondName = o2.getName().isEmpty() ? o2.getOwner().getName() : o2.getName(); + String firstName = o1.getStrippedName().isEmpty() ? o1.getOwner().getName() : o1.getStrippedName(); + String secondName = o2.getStrippedName().isEmpty() ? o2.getOwner().getName() : o2.getStrippedName(); return firstName.compareTo(secondName); }; public final static Comparator WORTH_COMPARATOR = (o1, o2) -> { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/top/metadata/IslandSortMetadata.java b/src/main/java/com/bgsoftware/superiorskyblock/island/top/metadata/IslandSortMetadata.java index 1882725836..629b6ff3d4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/top/metadata/IslandSortMetadata.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/top/metadata/IslandSortMetadata.java @@ -10,7 +10,7 @@ public abstract class IslandSortMetadata> implem protected IslandSortMetadata(Island island) { this.island = island; - this.islandName = island.getName().isEmpty() ? island.getOwner().getName() : island.getName(); + this.islandName = island.getStrippedName().isEmpty() ? island.getOwner().getName() : island.getStrippedName(); } public Island getIsland() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index a48bfa6f06..3f15887f78 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -251,13 +251,11 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { island.getIslandLevel().toString()) .put("locked", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isLocked(), superiorPlayer.getUserLocale())) - .put("name", (island, superiorPlayer) -> - plugin.getSettings().getIslandNames().isColorSupport() ? - Formatters.COLOR_FORMATTER.format(island.getName()) : island.getName()) + .put("name", (island, superiorPlayer) -> island.getName()) + .put("name_formatted", (island, superiorPlayer) -> island.getFormattedName()) .put("name_leader", (island, superiorPlayer) -> - island.getName().isEmpty() ? island.getOwner().getName() : - plugin.getSettings().getIslandNames().isColorSupport() ? - Formatters.COLOR_FORMATTER.format(island.getName()) : island.getName()) + island.getName().isEmpty() ? island.getOwner().getName() : island.getName()) + .put("name_stripped", (island, superiorPlayer) -> island.getStrippedName()) .put("nether_unlocked", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isNetherEnabled(), superiorPlayer.getUserLocale())) .put("normal_unlocked", (island, superiorPlayer) -> diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index de487503cf..e594410d80 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -124,9 +124,9 @@ CHANGED_MOB_DROPS_ALL: '&e&lUpgrades | &7Der Mob-Drop-Multiplikator aller Inseln erfolgreich aktualisiert.' CHANGED_MOB_DROPS_NAME: '&e&lUpgrades | &7Der Mob-Drop-Multiplikator von {0} wurde erfolgreich aktualisiert.' -CHANGED_NAME: '&e&lInsel | &7Du hast den Namen Ihrer Insel in {0} geändert.' -CHANGED_NAME_OTHER: '&e&lInsel | &7Du hast den Namen der Insel {0} in {1} geändert.' -CHANGED_NAME_OTHER_NAME: '&e&lInsel | &7Du hast den Namen von {0} in {1} geändert.' +CHANGED_NAME: '&e&lInsel | &7Du hast den Namen Ihrer Insel in {0}&7 geändert.' +CHANGED_NAME_OTHER: '&e&lInsel | &7Du hast den Namen der Insel {0} in {1}&7 geändert.' +CHANGED_NAME_OTHER_NAME: '&e&lInsel | &7Du hast den Namen von {0}&7 in {1}&7 geändert.' CHANGED_PAYPAL: '&e&lIsland | &7Island paypal erfolgreich auf {0} geändert.' CHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Das Limit der Rolle {0} für die Insel von {1} wurde erfolgreich aktualisiert.' @@ -707,12 +707,14 @@ MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Das Modul wurde erfolgreich entladen.' MODULES_LIST: '&fModule ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' -NAME_ANNOUNCEMENT: '&e&lInsel | &7{0} hat seinen Inselnamen in {1} geändert.' +NAME_ANNOUNCEMENT: '&e&lInsel | &7{0} hat seinen Inselnamen in {1}&7 geändert.' +NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lError | &7Du kannst diesen Namen nicht verwenden.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lFehler | &7Du kannst keine Spielernamen als Inselnamen verwenden.' -NAME_TOO_LONG: '&c&lError | &7Inselnamen dürfen nicht länger als 16 Zeichen sein.' -NAME_TOO_SHORT: '&c&lError | &7Inselnamen dürfen nicht kürzer als 3 Zeichen sein.' +NAME_TOO_LONG: '&c&lError | &7Inselnamen dürfen nicht länger als {0} Zeichen sein.' +NAME_TOO_SHORT: '&c&lError | &7Inselnamen dürfen nicht kürzer als {0} Zeichen sein.' NO_BAN_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um Spieler zu bannen.' NO_CLOSE_BYPASS: '&c&lError | &7Diese Insel ist nicht für die Öffentlichkeit zugänglich.' NO_CLOSE_PERMISSION: '&c&lError | &7Du musst mindestens {0} sein, um die Insel für diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 547c0dadb4..7ad33d2e3a 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -85,9 +85,9 @@ CHANGED_LANGUAGE: '&e&lLanguage | &7Successfully changed your language to Englis CHANGED_MOB_DROPS: '&e&lUpgrades | &7Successfully updated the mob drops multiplier of {0}''s island.' CHANGED_MOB_DROPS_ALL: '&e&lUpgrades | &7Successfully updated the mob drops multiplier of all the islands.' CHANGED_MOB_DROPS_NAME: '&e&lUpgrades | &7Successfully updated the mob drops multiplier of {0}.' -CHANGED_NAME: '&e&lIsland | &7You changed your island''s name to {0}.' -CHANGED_NAME_OTHER: '&e&lIsland | &7You changed the {0} island''s name to {1}.' -CHANGED_NAME_OTHER_NAME: '&e&lIsland | &7You changed the name of {0} to {1}.' +CHANGED_NAME: '&e&lIsland | &7You changed your island''s name to {0}&7.' +CHANGED_NAME_OTHER: '&e&lIsland | &7You changed the {0} island''s name to {1}&7.' +CHANGED_NAME_OTHER_NAME: '&e&lIsland | &7You changed the name of {0}&7 to {1}&7.' CHANGED_PAYPAL: '&e&lIsland | &7Successfully changed island paypal to {0}.' CHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}''s island.' CHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for all the islands.' @@ -569,12 +569,14 @@ MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Successfully unloaded the module.' MODULES_LIST: '&fModules ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' -NAME_ANNOUNCEMENT: '&e&lIsland | &7{0} changed his island name to {1}.' +NAME_ANNOUNCEMENT: '&e&lIsland | &7{0} changed his island name to {1}&7.' +NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lError | &7You cannot use that name.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lError | &7You cannot use player names as island names.' -NAME_TOO_LONG: '&c&lError | &7Island names cannot be more than 16 chars long.' -NAME_TOO_SHORT: '&c&lError | &7Island names cannot be less than 3 chars long.' +NAME_TOO_LONG: '&c&lError | &7Island names cannot be more than {0} chars long.' +NAME_TOO_SHORT: '&c&lError | &7Island names cannot be less than {0} chars long.' NO_BAN_PERMISSION: '&c&lError | &7You must be at least {0} in order to ban players.' NO_CLOSE_BYPASS: '&c&lError | &7This island is not opened to the public.' NO_CLOSE_PERMISSION: '&c&lError | &7You must be at least {0} in order to close the island to the public.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 9b04635c1e..7e05868153 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -85,9 +85,9 @@ CHANGED_LANGUAGE: '&e&lIdioma/Language | &7Cambió correctamente su idioma al in CHANGED_MOB_DROPS: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de drop de los mobs de la isla de {0}.' CHANGED_MOB_DROPS_ALL: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de drop de los mobs de todas las islas.' CHANGED_MOB_DROPS_NAME: '&e&lMejoras| &7Se actualizó con éxito el multiplicador de drop de los mobs de {0}.' -CHANGED_NAME: '&e&lIsla | &7Cambiaste el nombre de tu isla a {0}.' -CHANGED_NAME_OTHER: '&e&lIsla | &7Cambiaste el nombre de la {0} isla a {1}.' -CHANGED_NAME_OTHER_NAME: '&e&lIsla | &7Cambiaste el nombre de {0} a {1}.' +CHANGED_NAME: '&e&lIsla | &7Cambiaste el nombre de tu isla a {0}&7.' +CHANGED_NAME_OTHER: '&e&lIsla | &7Cambiaste el nombre de la {0} isla a {1}&7.' +CHANGED_NAME_OTHER_NAME: '&e&lIsla | &7Cambiaste el nombre de {0}&7 a {1}&7.' CHANGED_PAYPAL: '&e&lIsla | &7Se cambió el PayPal de la isla {0}.' CHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}''s island.' CHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for all the islands.' @@ -569,12 +569,14 @@ MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Successfully unloaded the module.' MODULES_LIST: '&fModules ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' -NAME_ANNOUNCEMENT: '&e&lIsla | &7{0} cambió el nombre de su isla a {1}.' +NAME_ANNOUNCEMENT: '&e&lIsla | &7{0} cambió el nombre de su isla a {1}&7.' +NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lError | &7No puedes usar ese nombre.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lError | &7No puedes usar nombres de jugadores como nombres de islas.' -NAME_TOO_LONG: '&c&lError | &7Los nombres de las islas no pueden tener más de 16 caracteres.' -NAME_TOO_SHORT: '&c&lError | &7Los nombres de las islas no pueden tener menos de 3 caracteres.' +NAME_TOO_LONG: '&c&lError | &7Los nombres de las islas no pueden tener más de {0} caracteres.' +NAME_TOO_SHORT: '&c&lError | &7Los nombres de las islas no pueden tener menos de {0} caracteres.' NO_BAN_PERMISSION: '&c&lError | &7Debes ser al menos {0} para prohibir a los jugadores' NO_CLOSE_BYPASS: '&c&lError | &7Esta isla no está abierta al público.' NO_CLOSE_PERMISSION: '&c&lError | &7Debes tener al menos {0} para poder cerrar la isla al público.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 1d75ee982c..a5ecb613ac 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -85,9 +85,9 @@ CHANGED_LANGUAGE: '&e&lLangage | &7Langue définie sur: Français.' CHANGED_MOB_DROPS: '&e&lAméliorations | &7Vous avez changé le multiplicateur de drops des mobs de l''île de {0}.' CHANGED_MOB_DROPS_ALL: '&e&lAméliorations | &7Vous avez changé le multiplicateur de drops des mobs de toutes les îles.' CHANGED_MOB_DROPS_NAME: '&e&lAméliorations | &7Vous avez changé le multiplacteur de drops des mobs de {0}.' -CHANGED_NAME: '&e&lIle | &7Vous avez changé le nom de votre île pour {0}.' -CHANGED_NAME_OTHER: '&e&lIle | &7Vous avez changé le nom de l''île de {0} pour {1}.' -CHANGED_NAME_OTHER_NAME: '&e&lIle | &7Vous avez changé le nom de {0} pour {1}.' +CHANGED_NAME: '&e&lIle | &7Vous avez changé le nom de votre île pour {0}&7.' +CHANGED_NAME_OTHER: '&e&lIle | &7Vous avez changé le nom de l''île de {0} pour {1}&7.' +CHANGED_NAME_OTHER_NAME: '&e&lIle | &7Vous avez changé le nom de {0}&7 pour {1}&7.' CHANGED_PAYPAL: '&e&lIle | &7Vous avez changé le paypal de l''île pour {0}.' CHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}''s island.' CHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for all the islands.' @@ -571,12 +571,14 @@ MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Module désactivé.' MODULES_LIST: '&fModules ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' -NAME_ANNOUNCEMENT: '&e&lIle | &7{0} a changé le nom de son île sur {1}.' +NAME_ANNOUNCEMENT: '&e&lIle | &7{0} a changé le nom de son île sur {1}&7.' +NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lErreur | &7Vous ne pouvez pas utiliser ce nom.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lErreur | &7Vous ne pouvez pas utiliser le pseudonyme d''un joueur comme nom d''île.' -NAME_TOO_LONG: '&c&lErreur | &7Les noms d''îles ne peuvent pas contenir plus de 16 caractères.' -NAME_TOO_SHORT: '&c&lErreur | &7Les noms d''îles ne peuvent pas contenir moins de 2 caractères.' +NAME_TOO_LONG: '&c&lErreur | &7Les noms d''îles ne peuvent pas contenir plus de {0} caractères.' +NAME_TOO_SHORT: '&c&lErreur | &7Les noms d''îles ne peuvent pas contenir moins de {0} caractères.' NO_ISLANDS_TO_PURGE: '&c&lErreur | &7Il n''y a aucune îles à purger.' NO_BAN_PERMISSION: '&c&lErreur | &7Vous devez être {0} afin de bannir un joueur.' NO_CLOSE_BYPASS: '&c&lErreur | &7Cette île n''est pas ouverte au public.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 3cbf00ab1b..4d605fabc4 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -88,9 +88,9 @@ CHANGED_LANGUAGE: '&e&lLanguage | &7Lingua cambiata in Italiano.' CHANGED_MOB_DROPS: '&e&lAggiornamenti | &7Aggiornata con successo il moltiplicatore dei drops dei mob nell''isola di {0}.' CHANGED_MOB_DROPS_ALL: '&e&lAggiornamenti | &7Aggiornata con successo il moltiplicatore dei drops dei mob in tutte le isole.' CHANGED_MOB_DROPS_NAME: '&e&lAggiornamenti | &7Aggiornata con successo il moltiplicatore dei drops dei mob di {0}.' -CHANGED_NAME: '&e&lIsola | &7Hai cambiato il nome della tua isola in {0}.' -CHANGED_NAME_OTHER: '&e&lIsola | &7Hai cambiato il nome della tua isola da {0} a {1}.' -CHANGED_NAME_OTHER_NAME: '&e&lIsola | &7Hai cambiato il nome dell''isola di {0} a {1}.' +CHANGED_NAME: '&e&lIsola | &7Hai cambiato il nome della tua isola in {0}&7.' +CHANGED_NAME_OTHER: '&e&lIsola | &7Hai cambiato il nome della tua isola da {0} a {1}&7.' +CHANGED_NAME_OTHER_NAME: '&e&lIsola | &7Hai cambiato il nome dell''isola di {0}&7 a {1}&7.' CHANGED_PAYPAL: '&e&lIsola | &7Paypal dell''isola cambiato con successo in {0}.' CHANGED_ROLE_LIMIT: '&e&lAggiornamenti | &7Aggiornata con successo il limite per il ruolo {0} per l''isola di {1}.' CHANGED_ROLE_LIMIT_ALL: '&e&lAggiornamenti | &7Aggiornata con successo il limite per il ruolo {0} di tutte le isole.' @@ -577,12 +577,14 @@ MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Modulo disabilitato con successo.' MODULES_LIST: '&fModuli ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' -NAME_ANNOUNCEMENT: '&e&lIsola | &7{0} ha cambiato il nome della sua isola in {1}.' +NAME_ANNOUNCEMENT: '&e&lIsola | &7{0} ha cambiato il nome della sua isola in {1}&7.' +NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lErrore | &7Non puoi usare quel nome.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lErrore | &7Non puoi usare i nomi dei giocatori come nome dell''isola.' -NAME_TOO_LONG: '&c&lErrore | &7I nomi delle isole non possono avere una lunghezza superiore a 16 caratteri.' -NAME_TOO_SHORT: '&c&lErrore | &7I nomi delle isole non possono avere una lunghezza inferiore a 3 caratteri.' +NAME_TOO_LONG: '&c&lErrore | &7I nomi delle isole non possono avere una lunghezza superiore a {0} caratteri.' +NAME_TOO_SHORT: '&c&lErrore | &7I nomi delle isole non possono avere una lunghezza inferiore a {0} caratteri.' NO_BAN_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per poter vietare i giocatori.' NO_CLOSE_BYPASS: '&c&lErrore | &7Quest''isola non è aperta al pubblico.' NO_CLOSE_PERMISSION: '&c&lErrore | &7Devi essere almeno {0} per chiudere l''isola al pubblico.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 86317fc790..2cab5f8112 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -90,9 +90,9 @@ CHANGED_MOB_DROPS_ALL: '&e&lםיגורדש | &7החלצהב ןכדוע םייא סונוב.' CHANGED_MOB_DROPS_NAME: '&e&lםיגורדש | &7החלצהב ןכדוע {0} יאה לש םיבומ לש םיטירפה סונוב.' -CHANGED_NAME: '&e&lיא | &7{0} ל ךלש יאה לש םשה תא תיניש.' -CHANGED_NAME_OTHER: '&e&lיא | &7{1} ל {0} לש יאה לש םשה תא תיניש.' -CHANGED_NAME_OTHER_NAME: '&e&lיא | &7{1} ל {0} יאה לש םשה תא תיניש.' +CHANGED_NAME: '&e&lIsland | &7You changed your island''s name to {0}&7.' +CHANGED_NAME_OTHER: '&e&lIsland | &7You changed the {0} island''s name to {1}&7.' +CHANGED_NAME_OTHER_NAME: '&e&lIsland | &7You changed the name of {0}&7 to {1}&7.' CHANGED_PAYPAL: '&e&lיא | &7{0} ל החלצהב ןכדוע יאה לש לאפייפה.' CHANGED_ROLE_LIMIT: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for {1}''s island.' CHANGED_ROLE_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the limit of the role {0} for all the islands.' @@ -591,12 +591,14 @@ MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Successfully unloaded the module.' MODULES_LIST: '&fModules ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' -NAME_ANNOUNCEMENT: '&e&lיא | &7{1} ל ולש יאה םש תא הניש {0}.' +NAME_ANNOUNCEMENT: '&e&lIsland | &7{0} changed his island name to {1}&7.' +NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lהאיגש | &7הזה םשב שמתשהל לוכי אל התא.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lError | &7You cannot use player names as island names.' -NAME_TOO_LONG: '&c&lהאיגש | &7םיוות 16 מ לעמ תויהל םילוכי אל םייא לש תומש.' -NAME_TOO_SHORT: '&c&lהאיגש | &7םיוות 3 מ תוחפ תויהל םילוכי אל םייא לש תומש.' +NAME_TOO_LONG: '&c&lהאיגש | &7םיוות {0} מ לעמ תויהל םילוכי אל םייא לש תומש.' +NAME_TOO_SHORT: '&c&lהאיגש | &7םיוות {0} מ תוחפ תויהל םילוכי אל םייא לש תומש.' NO_BAN_PERMISSION: '&c&lהאיגש | &7םינקחש קיחרהל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' NO_CLOSE_BYPASS: '&c&lהאיגש | &7רוביצל חותפ אל הזה יאה.' NO_CLOSE_PERMISSION: '&c&lהאיגש | &7רוביצל יאה תא רוגסל תנמ לע {0} תגרדב תוחפל תויהל בייח התא.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 39753384e1..f138ffd8cc 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -85,9 +85,9 @@ CHANGED_LANGUAGE: '&e&lJezyk | &7Pomyslnie zmieniono jezyk na angielski.' CHANGED_MOB_DROPS: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wypadania mobów z wyspy {0}.' CHANGED_MOB_DROPS_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wypadania z mobów na wszystkich wyspach.' CHANGED_MOB_DROPS_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano mnoznik wypadania mobów wynoszacy {0}.' -CHANGED_NAME: '&e&lWyspa | &7Zmieniles nazwe swojej wyspy na {0}.' -CHANGED_NAME_OTHER: '&e&lWyspa | &7Zmieniles nazwe wyspy {0} na {1}.' -CHANGED_NAME_OTHER_NAME: '&e&lWyspa | &7Zmieniles nazwe {0} na {1}.' +CHANGED_NAME: '&e&lWyspa | &7Zmieniles nazwe swojej wyspy na {0}&7.' +CHANGED_NAME_OTHER: '&e&lWyspa | &7Zmieniles nazwe wyspy {0} na {1}&7.' +CHANGED_NAME_OTHER_NAME: '&e&lWyspa | &7Zmieniles nazwe {0}&7 na {1}&7.' CHANGED_PAYPAL: '&e&lWyspa | &7Pomyslnie zmieniono paypal wyspy na {0}.' CHANGED_ROLE_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit roli {0} dla wyspy {1}.' CHANGED_ROLE_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit roli {0} dla wszystkich wysp.' @@ -569,12 +569,14 @@ MODULE_UNLOADED_SUCCESS: '&e&lModul | &7Pomyslnie wyladowano modul.' MODULES_LIST: '&fModuly ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f,' -NAME_ANNOUNCEMENT: '&e&lWyspa | &7{0} zmienil nazwe swojej wyspy na {1}.' +NAME_ANNOUNCEMENT: '&e&lWyspa | &7{0} zmienil nazwe swojej wyspy na {1}&7.' +NAME_ANNOUNCEMENT_OTHER: '&e&lWyspa | &7{0} zmienil nazwe wyspy {1} na {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lWyspa | &7{0} zmienil nazwe {1}&7 na {2}&7.' NAME_BLACKLISTED: '&c&lBlad | &7Nie mozesz uzywac tej nazwy.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lBlad | &7Nie mozesz uzywac nazw graczy jako nazw wysp.' -NAME_TOO_LONG: '&c&lBlad | &7Nazwy wysp nie moga miec wiecej niz 16 znaków.' -NAME_TOO_SHORT: '&c&lBlad | &7Nazwy wysp nie moga miec mniej niz 3 znaki.' +NAME_TOO_LONG: '&c&lBlad | &7Nazwy wysp nie moga miec wiecej niz {0} znaków.' +NAME_TOO_SHORT: '&c&lBlad | &7Nazwy wysp nie moga miec mniej niz {0} znaki.' NO_BAN_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby blokowac graczy.' NO_CLOSE_BYPASS: '&c&lBlad | &7Ta wyspa nie jest otwarta dla publicznosci.' NO_CLOSE_PERMISSION: '&c&lBlad | &7Musisz miec co najmniej {0}, aby zamknac wyspe dla publicznosci.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index c4bbeb4945..335444e072 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -85,9 +85,9 @@ CHANGED_LANGUAGE: '&e&lIdioma | &7Seu idioma foi alterado com sucesso para Ingl CHANGED_MOB_DROPS: '&e&lMelhorias | &7O multiplicador de drops de mobs da ilha de {0} foi atualizado com sucesso.' CHANGED_MOB_DROPS_ALL: '&e&lMelhorias | &7O multiplicador de drops de mobs de todas as ilhas foi atualizado com sucesso.' CHANGED_MOB_DROPS_NAME: '&e&lMelhorias | &7O multiplicador de drops de mobs de {0} foi atualizado com sucesso.' -CHANGED_NAME: '&e&lIlha | &7Você alterou o nome da sua ilha para {0}.' -CHANGED_NAME_OTHER: '&e&lIlha | &7Você alterou o nome da ilha de {0} para {1}.' -CHANGED_NAME_OTHER_NAME: '&e&lIlha | &7Você alterou o nome de {0} para {1}.' +CHANGED_NAME: '&e&lIlha | &7Você alterou o nome da sua ilha para {0}&7.' +CHANGED_NAME_OTHER: '&e&lIlha | &7Você alterou o nome da ilha de {0} para {1}&7.' +CHANGED_NAME_OTHER_NAME: '&e&lIlha | &7Você alterou o nome de {0}&7 para {1}&7.' CHANGED_PAYPAL: '&e&lIlha | &7O PayPal da ilha foi atualizado para {0}.' CHANGED_ROLE_LIMIT: '&e&lMelhorias | &7O limite do cargo {0} para a ilha de {1} foi atualizado com sucesso.' CHANGED_ROLE_LIMIT_ALL: '&e&lMelhorias | &7O limite do cargo {0} para todas as ilhas foi atualizado com sucesso.' @@ -569,12 +569,14 @@ MODULE_UNLOADED_SUCCESS: '&e&lMódulo | &7Descarregado o módulo com sucesso.' MODULES_LIST: '&fMódulos ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' -NAME_ANNOUNCEMENT: '&e&lIlha | &7{0} alterou o nome da ilha para {1}.' +NAME_ANNOUNCEMENT: '&e&lIlha | &7{0} alterou o nome da ilha para {1}&7.' +NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lErro | &7Você não pode usar esse nome.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lErro | &7Você não pode usar nomes de jogadores como nomes de ilhas.' -NAME_TOO_LONG: '&c&lErro | &7Os nomes de ilhas não podem ter mais de 16 caracteres.' -NAME_TOO_SHORT: '&c&lErro | &7Os nomes de ilhas não podem ter menos de 3 caracteres.' +NAME_TOO_LONG: '&c&lErro | &7Os nomes de ilhas não podem ter mais de {0} caracteres.' +NAME_TOO_SHORT: '&c&lErro | &7Os nomes de ilhas não podem ter menos de {0} caracteres.' NO_BAN_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para banir jogadores.' NO_CLOSE_BYPASS: '&c&lErro | &7Esta ilha não está aberta ao público.' NO_CLOSE_PERMISSION: '&c&lErro | &7Você deve ter pelo menos {0} para fechar a ilha ao público.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 6222d480b0..df6d037a33 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -85,9 +85,9 @@ CHANGED_LANGUAGE: '&e&lЯзык | &7Успешно изменен ваш язы CHANGED_MOB_DROPS: '&e&lУлучшения | &7Успешно обновлен множитель дропа мобов для острова {0}.' CHANGED_MOB_DROPS_ALL: '&e&lУлучшения | &7Успешно обновлен множитель дропа мобов для всех островов.' CHANGED_MOB_DROPS_NAME: '&e&lУлучшения | &7Успешно обновлен множитель дропа мобов для {0}.' -CHANGED_NAME: '&e&lОстров | &7Вы изменили название вашего острова на {0}.' -CHANGED_NAME_OTHER: '&e&lОстров | &7Вы изменили название острова {0} на {1}.' -CHANGED_NAME_OTHER_NAME: '&e&lОстров | &7Вы изменили имя {0} на {1}.' +CHANGED_NAME: '&e&lОстров | &7Вы изменили название вашего острова на {0}&7.' +CHANGED_NAME_OTHER: '&e&lОстров | &7Вы изменили название острова {0} на {1}&7.' +CHANGED_NAME_OTHER_NAME: '&e&lОстров | &7Вы изменили имя {0}&7 на {1}&7.' CHANGED_PAYPAL: '&e&lОстров | &7Успешно изменен PayPal острова на {0}.' CHANGED_ROLE_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит роли {0} для острова {1}.' CHANGED_ROLE_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит роли {0} для всех островов.' @@ -569,12 +569,14 @@ MODULE_UNLOADED_SUCCESS: '&e&lМодуль | &7Успешно выгружен MODULES_LIST: '&fМодули ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' -NAME_ANNOUNCEMENT: '&e&lОстров | &7{0} изменил имя своего острова на {1}.' +NAME_ANNOUNCEMENT: '&e&lОстров | &7{0} изменил имя своего острова на {1}&7.' +NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lОшибка | &7Вы не можете использовать это имя.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lОшибка | &7Вы не можете использовать имена игроков в качестве имен островов.' -NAME_TOO_LONG: '&c&lОшибка | &7Имена островов не могут превышать 16 символов.' -NAME_TOO_SHORT: '&c&lОшибка | &7Имена островов не могут быть короче 3 символов.' +NAME_TOO_LONG: '&c&lОшибка | &7Имена островов не могут превышать {0} символов.' +NAME_TOO_SHORT: '&c&lОшибка | &7Имена островов не могут быть короче {0} символов.' NO_BAN_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы забанить игроков.' NO_CLOSE_BYPASS: '&c&lОшибка | &7Этот остров не открыт для публики.' NO_CLOSE_PERMISSION: '&c&lОшибка | &7Вам нужно быть как минимум {0}, чтобы закрыть остров для публики.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 01c9abf5f0..1cf25bcfc1 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -117,9 +117,9 @@ CHANGED_MOB_DROPS_ALL: '&e&lYükseltmeler | &7Tüm adaların mob düşürme çar güncellendi.' CHANGED_MOB_DROPS_NAME: '&e&lYükseltmeler | &7{0} adasının mob düşürme çarpanı başarıyla güncellendi.' -CHANGED_NAME: '&e&lAda | &7Adanın adını {0} olarak değiştirdin.' -CHANGED_NAME_OTHER: '&e&lAda | &7{0} adasının adını {1} olarak değiştirdin.' -CHANGED_NAME_OTHER_NAME: '&e&lAda | &7{0} adının adını {1} olarak değiştirdin.' +CHANGED_NAME: '&e&lAda | &7Adanın adını {0}&7 olarak değiştirdin.' +CHANGED_NAME_OTHER: '&e&lAda | &7{0} adasının adını {1}&7 olarak değiştirdin.' +CHANGED_NAME_OTHER_NAME: '&e&lAda | &7{0}&7 adının adını {1}&7 olarak değiştirdin.' CHANGED_PAYPAL: '&e&lAda | &7Ada paypalı başarıyla {0} olarak değiştirildi.' CHANGED_ROLE_LIMIT: '&e&lYükseltmeler | &7{0} rolünün {1}''in adası için limiti başarıyla güncellendi.' @@ -671,12 +671,14 @@ MODULE_UNLOADED_SUCCESS: '&e&lModül | &7Modül başarıyla kaldırıldı.' MODULES_LIST: '&fModüller ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' -NAME_ANNOUNCEMENT: '&e&lAda | &7{0} adasının adını {1} olarak değiştirdi.' +NAME_ANNOUNCEMENT: '&e&lAda | &7{0} adasının adını {1}&7 olarak değiştirdi.' +NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lHata | &7Bu adı kullanamazsın.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lHata | &7Oyuncu adlarını ada adı olarak kullanamazsın.' -NAME_TOO_LONG: '&c&lHata | &7Ada adları 16 karakterden uzun olamaz.' -NAME_TOO_SHORT: '&c&lHata | &7Ada adları 3 karakterden kısa olamaz.' +NAME_TOO_LONG: '&c&lHata | &7Ada adları {0} karakterden uzun olamaz.' +NAME_TOO_SHORT: '&c&lHata | &7Ada adları {0} karakterden kısa olamaz.' NO_BAN_PERMISSION: '&c&lHata | &7Oyuncuları yasaklayabilmek için en az {0} olmalısın.' NO_CLOSE_BYPASS: '&c&lHata | &7Bu ada halka açık değil.' NO_CLOSE_PERMISSION: '&c&lHata | &7Adanı halka kapatabilmek için en az {0} olmalısın.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 92d24414e5..2d7307d428 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -102,9 +102,9 @@ CHANGED_MOB_DROPS_ALL: '&e&lNâng Cấp | &7Thay đổi thành công tỉ lệ r của tất cả các đảo.' CHANGED_MOB_DROPS_NAME: '&e&lNâng Cấp | &7Thay đổi thành công tỉ lệ rơi đồ quái vật của đảo {0}.' -CHANGED_NAME: '&e&lĐảo | &7Bạn đã thay đổi tên đảo bạn thành {0}.' -CHANGED_NAME_OTHER: '&e&lĐảo | &7Bạn đã thay đổi tên đảo của {0} thành {1}.' -CHANGED_NAME_OTHER_NAME: '&e&lĐảo | &7Bạn đã thay đổi tên của {0} thành {1}.' +CHANGED_NAME: '&e&lĐảo | &7Bạn đã thay đổi tên đảo bạn thành {0}&7.' +CHANGED_NAME_OTHER: '&e&lĐảo | &7Bạn đã thay đổi tên đảo của {0} thành {1}&7.' +CHANGED_NAME_OTHER_NAME: '&e&lĐảo | &7Bạn đã thay đổi tên của {0}&7 thành {1}&7.' CHANGED_PAYPAL: '&e&lNâng Cấp | &7Thay đổi thành công paypal của đảo thành {0}.' CHANGED_ROLE_LIMIT: '&e&lNâng Cấp | &7Thành công nâng cấp giới hạn của vai trò {0} cho đảo của {1}.' CHANGED_ROLE_LIMIT_ALL: '&e&lNâng Cấp | &7Thành công nâng cấp giới hạn của vai trò {0} cho tất cả các đảo.' @@ -633,12 +633,14 @@ MODULE_UNLOADED_SUCCESS: '&e&lModule | &7Đã hủy tải thành công module.' MODULES_LIST: '&fModules ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' -NAME_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã thay đổi tên đảo của anh/cô ấy thành {1}.' +NAME_ANNOUNCEMENT: '&e&lĐảo | &7{0} đã thay đổi tên đảo của anh/cô ấy thành {1}&7.' +NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&lLỗi | &7Bạn không thể sử dụng tên này.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&lLỗi | &7Bạn không thể dùng tên người chơi là tên đảo.' -NAME_TOO_LONG: '&c&lLỗi | &7Tên đảo không thể dài hơn 16 kí tự.' -NAME_TOO_SHORT: '&c&lLỗi | &7Tên đảo không thể ngắn hơn 3 ký tự.' +NAME_TOO_LONG: '&c&lLỗi | &7Tên đảo không thể dài hơn {0} kí tự.' +NAME_TOO_SHORT: '&c&lLỗi | &7Tên đảo không thể ngắn hơn {0} ký tự.' NO_BAN_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để cấm người chơi.' NO_CLOSE_BYPASS: '&c&lLỗi | &7Hòn đảo này không mở cửa cho công cộng.' NO_CLOSE_PERMISSION: '&c&lLỗi | &7Bạn phải có quyền {0} để đóng đảo với công cộng.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 49e5ccea12..3cda266d5d 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -85,9 +85,9 @@ CHANGED_LANGUAGE: '&e&l语言 | &7成功将你的语言修改为了简体中文. CHANGED_MOB_DROPS: '&e&l升级 | &7成功更新了玩家 {0} 的岛屿掉落物翻倍量.' CHANGED_MOB_DROPS_ALL: '&e&l升级 | &7成功更新了所有岛屿的掉落物翻倍量.' CHANGED_MOB_DROPS_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的掉落物翻倍量.' -CHANGED_NAME: '&e&l岛屿 | &7你将岛屿的名称修改为了 {0}.' -CHANGED_NAME_OTHER: '&e&l岛屿 | &7你将玩家 {0} 的岛屿名称修改为了 {1}.' -CHANGED_NAME_OTHER_NAME: '&e&l岛屿 | &7你将岛屿 {0} 的名称修改为了 {1}.' +CHANGED_NAME: '&e&l岛屿 | &7你将岛屿的名称修改为了 {0}&7.' +CHANGED_NAME_OTHER: '&e&l岛屿 | &7你将玩家 {0} 的岛屿名称修改为了 {1}&7.' +CHANGED_NAME_OTHER_NAME: '&e&l岛屿 | &7你将岛屿 {0}&7 的名称修改为了 {1}&7.' CHANGED_PAYPAL: '&e&l岛屿 | &7成功将岛屿的 Paypal 支付链接修改为了 {0}.' CHANGED_ROLE_LIMIT: '&e&l升级 | &7成功更新了玩家 {1} 的岛屿角色 {0} 的限制.' CHANGED_ROLE_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的角色 {0} 限制.' @@ -569,12 +569,14 @@ MODULE_UNLOADED_SUCCESS: '&e&l模块 | &7成功卸载了模块.' MODULES_LIST: '&f模块 ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' -NAME_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 将岛屿名称修改为了 {1}.' +NAME_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 将岛屿名称修改为了 {1}&7.' +NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' NAME_BLACKLISTED: '&c&l错误 | &7你不能使用该名称.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&l错误 | &7你不能将玩家名称作为岛屿名称.' -NAME_TOO_LONG: '&c&l错误 | &7岛屿名称不能超过 16 个字符.' -NAME_TOO_SHORT: '&c&l错误 | &7岛屿名称不能短于 3 个字符.' +NAME_TOO_LONG: '&c&l错误 | &7岛屿名称不能超过 {0} 个字符.' +NAME_TOO_SHORT: '&c&l错误 | &7岛屿名称不能短于 {0} 个字符.' NO_BAN_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可封禁玩家.' NO_CLOSE_BYPASS: '&c&l错误 | &7该岛屿不对公众开放.' NO_CLOSE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将岛屿对公众开放.' From 38dc05ce4363a7b49194cea649251f704e29dcfa Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 24 Sep 2025 12:17:47 +0300 Subject: [PATCH 331/600] Revert the island-cache lookups --- .../container/DefaultIslandsContainer.java | 70 +------------------ 1 file changed, 2 insertions(+), 68 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index 7041ccfe75..e9d2be4e3a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -27,15 +27,11 @@ import org.bukkit.Bukkit; import org.bukkit.Location; -import java.lang.ref.WeakReference; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Supplier; public class DefaultIslandsContainer implements IslandsContainer { @@ -47,8 +43,6 @@ public class DefaultIslandsContainer implements IslandsContainer { private final EnumerateSet notifiedValues = new EnumerateSet<>(SortingType.values()); - private final IslandsCache islandsCache = new IslandsCache(); - private final SuperiorSkyblockPlugin plugin; public DefaultIslandsContainer(SuperiorSkyblockPlugin plugin) { @@ -66,7 +60,6 @@ public void addIsland(Island island) { long packedPos = IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ()); // Insert to cache if we can access it - accessIslandsCache(islandsCache -> islandsCache.insert(defaultWorld.getName(), packedPos, island)); this.islandsByPositions.write(islandsByPositions -> { islandsByPositions.put(defaultWorld.getName(), packedPos, island); @@ -101,9 +94,6 @@ public void removeIsland(Island island) { long packedPos = IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ()); - // Remove from cache if we can access it - accessIslandsCache(islandsCache -> islandsCache.remove(defaultWorld.getName(), packedPos)); - this.islandsByPositions.write(islandsByPositions -> { islandsByPositions.remove(defaultWorld.getName(), packedPos); @@ -169,9 +159,8 @@ public int getIslandsAmount() { public Island getIslandAt(Location location) { long packedPos = IslandPosition.calculatePackedPosFromLocation(location.getBlockX(), location.getBlockZ()); String worldName = LazyWorldLocation.getWorldName(location); - Island island = readIslandsCache(islandsCache -> islandsCache.get(worldName, packedPos), - () -> this.islandsByPositions.readAndGet(islandsByPositions -> - islandsByPositions.get(worldName, packedPos))); + Island island = this.islandsByPositions.readAndGet(islandsByPositions -> + islandsByPositions.get(worldName, packedPos)); return island == null || !island.isInside(location) ? null : island; } @@ -283,65 +272,10 @@ private void runWithCustomWorld(WorldInfo defaultWorld, BlockPosition center, Is } } - private void accessIslandsCache(Consumer consumer) { - if (Bukkit.isPrimaryThread()) { - consumer.accept(islandsCache); - } - } - - private R readIslandsCache(Function function, Supplier onInvalidAccess) { - if (Bukkit.isPrimaryThread()) { - return function.apply(islandsCache); - } - - return onInvalidAccess.get(); - } - private interface CustomWorldConsumer { void apply(String worldName, long packedPos); } - private class IslandsCache { - - // Implemented with CacheHolder so IslandPositions with no islands will not trigger access to global `islandsByPositions` - private final IslandPosition2ObjectMap islandsByPositionCache = new IslandPosition2ObjectMap<>(); - - @Nullable - private Island get(String worldName, long packedPos) { - CacheHolder holder = islandsByPositionCache.get(worldName, packedPos); - if (holder != null) - return holder.island.get(); - - Island island = islandsByPositions.readAndGet(islandsByPositions -> - islandsByPositions.get(worldName, packedPos)); - - insert(worldName, packedPos, island); - - return island; - } - - private void insert(String worldName, long packedPos, @Nullable Island island) { - islandsByPositionCache.put(worldName, packedPos, island == null ? CacheHolder.NULL : new CacheHolder(island)); - } - - private void remove(String worldName, long packedPos) { - this.islandsByPositionCache.remove(worldName, packedPos); - } - - } - - private static class CacheHolder { - - private static final CacheHolder NULL = new CacheHolder(null); - - private final WeakReference island; - - CacheHolder(Island island) { - this.island = new WeakReference<>(island); - } - - } - } From e4f03446edf21785c94a04b4e08e298062ee0c3a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 24 Sep 2025 12:27:30 +0300 Subject: [PATCH 332/600] Fix old `superior_island_count` placeholder not working (#2670) --- .../service/placeholders/PlaceholdersServiceImpl.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index 3f15887f78..a6c8c5a1db 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -61,7 +61,7 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { private static final Pattern BLOCK_TOTAL_LEVEL_PLACEHOLDER_PATTERN = Pattern.compile("island_block_total_level_(.+)"); private static final Pattern BLOCK_TOTAL_WORTH_PLACEHOLDER_PATTERN = Pattern.compile("island_block_total_worth_(.+)"); private static final Pattern BLOCK_WORTH_PLACEHOLDER_PATTERN = Pattern.compile("island_block_worth_(.+)"); - private static final Pattern COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_block_count_(.+)"); + private static final Pattern COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_count_(.+)"); private static final Pattern DATA_PLACEHOLDER_PATTERN = Pattern.compile("island_data_(.+)"); private static final Pattern EFFECT_PLACEHOLDER_PATTERN = Pattern.compile("island_effect_(.+)"); private static final Pattern ENTITY_COUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_entity_count_(.+)"); @@ -623,7 +623,8 @@ private static Optional parsePlaceholdersForIsland(@Nullable Island isla } if (superiorPlayer != null) { - if ((matcher = BLOCK_COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + if ((matcher = BLOCK_COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches() || + (matcher = COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); return Optional.of(island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName)) + ""); } else if ((matcher = BLOCK_LEVEL_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { @@ -647,9 +648,6 @@ private static Optional parsePlaceholdersForIsland(@Nullable Island isla String keyName = matcher.group(1); BlockValue blockValue = plugin.getBlockValues().getBlockValue(Keys.ofMaterialAndData(keyName)); return Optional.of(blockValue.getWorth() + ""); - } else if ((matcher = COUNT_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { - String keyName = matcher.group(1); - return Optional.of(island.getBlockCountAsBigInteger(Keys.ofMaterialAndData(keyName)) + ""); } else if ((matcher = DATA_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { String keyName = matcher.group(1); Object data = island.getPersistentDataContainer().get(keyName); From 64417c2b65cf6938916ad89bd9c714126f19157a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 24 Sep 2025 12:50:10 +0300 Subject: [PATCH 333/600] Fix errors regarding islands lookup due to recent changes --- .../com/bgsoftware/superiorskyblock/core/IslandPosition.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java index 754d51270e..e06f05cc2b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandPosition.java @@ -13,7 +13,7 @@ public static long calculatePackedPosFromLocation(int locX, int locZ) { int radius = plugin.getSettings().getMaxIslandSize() * 3; int x = (Math.abs(locX) + (radius / 2)) / radius; int z = (Math.abs(locZ) + (radius / 2)) / radius; - return calculatePackedPos(x, z); + return calculatePackedPos(locX < 0 ? -x : x, locZ < 0 ? -z : z); } public static long calculatePackedPos(int posX, int posZ) { From c2f5e3e0c288f53ec8c5f9ea3ffe01e6c5cb9d0a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 24 Sep 2025 13:39:58 +0300 Subject: [PATCH 334/600] Optimized islands lookup by removing unnecessary locks when not needed (#2654) --- .../api/hooks/LazyWorldsProvider.java | 19 +++- .../commands/player/CmdVisit.java | 2 +- .../island/GridManagerImpl.java | 2 +- .../superiorskyblock/island/SIsland.java | 2 +- .../container/DefaultIslandsContainer.java | 93 ++++++++----------- .../island/container/grid/IslandsGrid.java | 17 ++++ .../container/grid/MultiWorldIslandsGrid.java | 51 ++++++++++ .../grid/SingleWorldIslandsGrid.java | 32 +++++++ 8 files changed, 162 insertions(+), 56 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/IslandsGrid.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/MultiWorldIslandsGrid.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/LazyWorldsProvider.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/LazyWorldsProvider.java index e60c07a260..255e4e7cb6 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/LazyWorldsProvider.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/LazyWorldsProvider.java @@ -61,8 +61,25 @@ default WorldInfo getIslandsWorldInfo(Island island, World.Environment environme * @param island The island to check. * @param worldName The name of the world. * @return The world info for the given name, or null if this name is not an islands world. + * + * @deprecated See {@link #getIslandsWorldInfo(String)} + */ + @Nullable + @Deprecated + default WorldInfo getIslandsWorldInfo(Island island, String worldName) { + return getIslandsWorldInfo(worldName); + } + + /** + * Get the {@link WorldInfo} of the world of an island by its name. + * The world does not have to be loaded. + * + * @param worldName The name of the world. + * @return The world info for the given name, or null if this name is not an islands world. */ @Nullable - WorldInfo getIslandsWorldInfo(Island island, String worldName); + WorldInfo getIslandsWorldInfo(String worldName); + + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java index 64ccc7e3ac..02785154e9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java @@ -132,7 +132,7 @@ private static void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island if (shouldRetryOnNullWorld && visitLocation instanceof LazyWorldLocation && plugin.getProviders().getWorldsProvider() instanceof LazyWorldsProvider) { LazyWorldsProvider worldsProvider = (LazyWorldsProvider) plugin.getProviders().getWorldsProvider(); - WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(island, ((LazyWorldLocation) visitLocation).getWorldName()); + WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(((LazyWorldLocation) visitLocation).getWorldName()); worldsProvider.prepareWorld(island, worldInfo.getDimension(), () -> teleportPlayerNoWarmup(superiorPlayer, island, visitLocation, isVisitorSign, checkIslandLock, false)); return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index bea2567426..f20b7426e1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -780,7 +780,7 @@ public WorldInfo getIslandsWorldInfo(Island island, String worldName) { WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); if (worldsProvider instanceof LazyWorldsProvider) - return ((LazyWorldsProvider) worldsProvider).getIslandsWorldInfo(island, worldName); + return ((LazyWorldsProvider) worldsProvider).getIslandsWorldInfo(worldName); World world = Bukkit.getWorld(worldName); return world == null || !isIslandsWorld(world) ? null : WorldInfo.of(world); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index af267d2705..793a68b7eb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -4840,7 +4840,7 @@ private void warpPlayerWithoutWarmup(SuperiorPlayer superiorPlayer, IslandWarp i if (shouldRetryOnNullWorld && location instanceof LazyWorldLocation && plugin.getProviders().getWorldsProvider() instanceof LazyWorldsProvider) { LazyWorldsProvider worldsProvider = (LazyWorldsProvider) plugin.getProviders().getWorldsProvider(); - WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(this, ((LazyWorldLocation) location).getWorldName()); + WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(((LazyWorldLocation) location).getWorldName()); worldsProvider.prepareWorld(this, worldInfo.getDimension(), () -> warpPlayerWithoutWarmup(superiorPlayer, islandWarp, false)); return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index e9d2be4e3a..d1f934c775 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -2,6 +2,8 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider; +import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer; @@ -12,11 +14,13 @@ import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; -import com.bgsoftware.superiorskyblock.core.collections.IslandPosition2ObjectMap; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.island.IslandNames; +import com.bgsoftware.superiorskyblock.island.container.grid.IslandsGrid; +import com.bgsoftware.superiorskyblock.island.container.grid.MultiWorldIslandsGrid; +import com.bgsoftware.superiorskyblock.island.container.grid.SingleWorldIslandsGrid; import com.bgsoftware.superiorskyblock.island.top.SortingComparators; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.island.top.metadata.IslandSortMetadata; @@ -35,9 +39,9 @@ public class DefaultIslandsContainer implements IslandsContainer { - private final Synchronized> islandsByPositions = Synchronized.of(new IslandPosition2ObjectMap<>()); private final Map islandsByUUID = new ConcurrentHashMap<>(); private final Map islandsByNames = new ConcurrentHashMap<>(); + private final IslandsGrid islandsGrid; private final Map>> sortedIslands = new ConcurrentHashMap<>(); @@ -47,34 +51,26 @@ public class DefaultIslandsContainer implements IslandsContainer { public DefaultIslandsContainer(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; + this.islandsGrid = plugin.getProviders().hasCustomWorldsSupport() ? + new MultiWorldIslandsGrid() : new SingleWorldIslandsGrid(); } @Override public void addIsland(Island island) { BlockPosition center = island.getCenterPosition(); - WorldInfo defaultWorld = plugin.getGrid().getIslandsWorldInfo(island, - plugin.getSettings().getWorlds().getDefaultWorldDimension()); - - Preconditions.checkNotNull(defaultWorld, "Default world information cannot be null!"); - long packedPos = IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ()); - // Insert to cache if we can access it - - this.islandsByPositions.write(islandsByPositions -> { - islandsByPositions.put(defaultWorld.getName(), packedPos, island); - - if (plugin.getProviders().hasCustomWorldsSupport()) { - // We don't know the logic of the custom worlds support, therefore we add a position - // for every possible world, so there won't be issues with detecting islands later. - for (Dimension dimension : Dimension.values()) { - if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { - runWithCustomWorld(defaultWorld, center, island, dimension, (worldName, customWorldPackedPos) -> - islandsByPositions.put(worldName, customWorldPackedPos, island)); - } + if (plugin.getProviders().hasCustomWorldsSupport()) { + // We don't know the logic of the custom worlds support, therefore we add a position + // for every possible world, so there won't be issues with detecting islands later. + for (Dimension dimension : Dimension.values()) { + if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { + islandsGrid.addIsland(dimension, packedPos, island); } } - }); + } else { + islandsGrid.addIsland(null, packedPos, island); + } this.islandsByUUID.put(island.getUniqueId(), island); this.islandsByNames.put(IslandNames.getNameForLookup(island.getStrippedName()), island); @@ -87,24 +83,17 @@ public void addIsland(Island island) { @Override public void removeIsland(Island island) { BlockPosition center = island.getCenterPosition(); - WorldInfo defaultWorld = plugin.getGrid().getIslandsWorldInfo(island, - plugin.getSettings().getWorlds().getDefaultWorldDimension()); - - Preconditions.checkNotNull(defaultWorld, "Default world information cannot be null!"); - long packedPos = IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ()); - this.islandsByPositions.write(islandsByPositions -> { - islandsByPositions.remove(defaultWorld.getName(), packedPos); - - if (plugin.getProviders().hasCustomWorldsSupport()) { - for (Dimension dimension : Dimension.values()) { - if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { - runWithCustomWorld(defaultWorld, center, island, dimension, islandsByPositions::remove); - } + if (plugin.getProviders().hasCustomWorldsSupport()) { + for (Dimension dimension : Dimension.values()) { + if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { + islandsGrid.removeIslandAt(dimension, packedPos); } } - }); + } else { + islandsGrid.removeIslandAt(null, packedPos); + } this.islandsByUUID.remove(island.getUniqueId()); this.islandsByNames.remove(IslandNames.getNameForLookup(island.getStrippedName())); @@ -158,9 +147,23 @@ public int getIslandsAmount() { @Override public Island getIslandAt(Location location) { long packedPos = IslandPosition.calculatePackedPosFromLocation(location.getBlockX(), location.getBlockZ()); - String worldName = LazyWorldLocation.getWorldName(location); - Island island = this.islandsByPositions.readAndGet(islandsByPositions -> - islandsByPositions.get(worldName, packedPos)); + + Island island; + if (plugin.getProviders().hasCustomWorldsSupport()) { + WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); + Dimension dimension; + if (worldsProvider instanceof LazyWorldsProvider) { + String worldName = LazyWorldLocation.getWorldName(location); + WorldInfo worldInfo = ((LazyWorldsProvider) worldsProvider).getIslandsWorldInfo(worldName); + dimension = worldInfo.getDimension(); + } else { + dimension = worldsProvider.getIslandsWorldDimension(location.getWorld()); + } + island = this.islandsGrid.getIslandAt(dimension, packedPos); + } else { + island = this.islandsGrid.getIslandAt(null, packedPos); + } + return island == null || !island.isInside(location) ? null : island; } @@ -264,18 +267,4 @@ else if (sortingType == SortingTypes.BY_RATING) return existingIslands; } - private void runWithCustomWorld(WorldInfo defaultWorld, BlockPosition center, Island island, - Dimension dimension, CustomWorldConsumer consumer) { - WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); - if (worldInfo != null && !worldInfo.equals(defaultWorld)) { - consumer.apply(worldInfo.getName(), IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ())); - } - } - - private interface CustomWorldConsumer { - - void apply(String worldName, long packedPos); - - } - } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/IslandsGrid.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/IslandsGrid.java new file mode 100644 index 0000000000..6e9df5464e --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/IslandsGrid.java @@ -0,0 +1,17 @@ +package com.bgsoftware.superiorskyblock.island.container.grid; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; + +public interface IslandsGrid { + + void addIsland(Dimension dimension, long packedPos, Island island); + + @Nullable + Island removeIslandAt(Dimension dimension, long packedPos); + + @Nullable + Island getIslandAt(Dimension dimension, long packedPos); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/MultiWorldIslandsGrid.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/MultiWorldIslandsGrid.java new file mode 100644 index 0000000000..82058152c9 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/MultiWorldIslandsGrid.java @@ -0,0 +1,51 @@ +package com.bgsoftware.superiorskyblock.island.container.grid; + +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; + +public class MultiWorldIslandsGrid implements IslandsGrid { + + private volatile EnumerateMap store = new EnumerateMap<>(Dimension.values()); + + public MultiWorldIslandsGrid() { + for (Dimension dimension : Dimension.values()) { + this.store.put(dimension, new SingleWorldIslandsGrid()); + } + } + + @Override + public void addIsland(Dimension dimension, long packedPos, Island island) { + ensureCapacity(dimension); + this.store.get(dimension).addIsland(null, packedPos, island); + } + + @Override + public Island removeIslandAt(Dimension dimension, long packedPos) { + ensureCapacity(dimension); + return this.store.get(dimension).removeIslandAt(null, packedPos); + } + + @Override + public Island getIslandAt(Dimension dimension, long packedPos) { + ensureCapacity(dimension); + return this.store.get(dimension).getIslandAt(null, packedPos); + } + + private void ensureCapacity(Dimension dimension) { + if (dimension.ordinal() >= this.store.size()) { + synchronized (this) { + if (dimension.ordinal() >= this.store.size()) { + // Need to increase capacity + EnumerateMap newStore = new EnumerateMap<>(Dimension.values()); + for (Dimension dim : Dimension.values()) { + SingleWorldIslandsGrid currLookupObject = this.store.get(dim); + newStore.put(dim, currLookupObject == null ? new SingleWorldIslandsGrid() : currLookupObject); + } + this.store = newStore; + } + } + } + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java new file mode 100644 index 0000000000..7bee9f9093 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java @@ -0,0 +1,32 @@ +package com.bgsoftware.superiorskyblock.island.container.grid; + +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; +import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.threads.Synchronized; + +public class SingleWorldIslandsGrid implements IslandsGrid { + + private Synchronized> store; + + public SingleWorldIslandsGrid() { + this.store = Synchronized.of(CollectionsFactory.createLong2ObjectLinkedHashMap()); + } + + @Override + public void addIsland(Dimension unused, long packedPos, Island island) { + this.store.write(store -> store.put(packedPos, island)); + } + + @Override + public Island removeIslandAt(Dimension unused, long packedPos) { + return this.store.writeAndGet(store -> store.remove(packedPos)); + } + + @Override + public Island getIslandAt(Dimension unused, long packedPos) { + return this.store.readAndGet(store -> store.get(packedPos)); + } + +} From 066483cb279206f41a97b963f3ac22944e94941c Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 24 Sep 2025 13:59:27 +0300 Subject: [PATCH 335/600] Revert some of the changes from recent commit and fixed multi worlds grid depending on dimension and not world names --- .../api/hooks/LazyWorldsProvider.java | 19 +------- .../commands/player/CmdVisit.java | 2 +- .../island/GridManagerImpl.java | 2 +- .../superiorskyblock/island/SIsland.java | 2 +- .../container/DefaultIslandsContainer.java | 22 ++++----- .../island/container/grid/IslandsGrid.java | 7 ++- .../container/grid/MultiWorldIslandsGrid.java | 47 +++++-------------- .../grid/SingleWorldIslandsGrid.java | 13 ++--- 8 files changed, 32 insertions(+), 82 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/LazyWorldsProvider.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/LazyWorldsProvider.java index 255e4e7cb6..e60c07a260 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/LazyWorldsProvider.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/LazyWorldsProvider.java @@ -61,25 +61,8 @@ default WorldInfo getIslandsWorldInfo(Island island, World.Environment environme * @param island The island to check. * @param worldName The name of the world. * @return The world info for the given name, or null if this name is not an islands world. - * - * @deprecated See {@link #getIslandsWorldInfo(String)} - */ - @Nullable - @Deprecated - default WorldInfo getIslandsWorldInfo(Island island, String worldName) { - return getIslandsWorldInfo(worldName); - } - - /** - * Get the {@link WorldInfo} of the world of an island by its name. - * The world does not have to be loaded. - * - * @param worldName The name of the world. - * @return The world info for the given name, or null if this name is not an islands world. */ @Nullable - WorldInfo getIslandsWorldInfo(String worldName); - - + WorldInfo getIslandsWorldInfo(Island island, String worldName); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java index 02785154e9..64ccc7e3ac 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java @@ -132,7 +132,7 @@ private static void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island if (shouldRetryOnNullWorld && visitLocation instanceof LazyWorldLocation && plugin.getProviders().getWorldsProvider() instanceof LazyWorldsProvider) { LazyWorldsProvider worldsProvider = (LazyWorldsProvider) plugin.getProviders().getWorldsProvider(); - WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(((LazyWorldLocation) visitLocation).getWorldName()); + WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(island, ((LazyWorldLocation) visitLocation).getWorldName()); worldsProvider.prepareWorld(island, worldInfo.getDimension(), () -> teleportPlayerNoWarmup(superiorPlayer, island, visitLocation, isVisitorSign, checkIslandLock, false)); return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index f20b7426e1..bea2567426 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -780,7 +780,7 @@ public WorldInfo getIslandsWorldInfo(Island island, String worldName) { WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); if (worldsProvider instanceof LazyWorldsProvider) - return ((LazyWorldsProvider) worldsProvider).getIslandsWorldInfo(worldName); + return ((LazyWorldsProvider) worldsProvider).getIslandsWorldInfo(island, worldName); World world = Bukkit.getWorld(worldName); return world == null || !isIslandsWorld(world) ? null : WorldInfo.of(world); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 793a68b7eb..af267d2705 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -4840,7 +4840,7 @@ private void warpPlayerWithoutWarmup(SuperiorPlayer superiorPlayer, IslandWarp i if (shouldRetryOnNullWorld && location instanceof LazyWorldLocation && plugin.getProviders().getWorldsProvider() instanceof LazyWorldsProvider) { LazyWorldsProvider worldsProvider = (LazyWorldsProvider) plugin.getProviders().getWorldsProvider(); - WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(((LazyWorldLocation) location).getWorldName()); + WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(this, ((LazyWorldLocation) location).getWorldName()); worldsProvider.prepareWorld(this, worldInfo.getDimension(), () -> warpPlayerWithoutWarmup(superiorPlayer, islandWarp, false)); return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index d1f934c775..1f410c2437 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -2,8 +2,6 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider; -import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.island.container.IslandsContainer; @@ -65,7 +63,9 @@ public void addIsland(Island island) { // for every possible world, so there won't be issues with detecting islands later. for (Dimension dimension : Dimension.values()) { if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { - islandsGrid.addIsland(dimension, packedPos, island); + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); + if (worldInfo != null) + islandsGrid.addIsland(worldInfo.getName(), packedPos, island); } } } else { @@ -88,7 +88,9 @@ public void removeIsland(Island island) { if (plugin.getProviders().hasCustomWorldsSupport()) { for (Dimension dimension : Dimension.values()) { if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { - islandsGrid.removeIslandAt(dimension, packedPos); + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); + if (worldInfo != null) + islandsGrid.removeIslandAt(worldInfo.getName(), packedPos); } } } else { @@ -150,16 +152,8 @@ public Island getIslandAt(Location location) { Island island; if (plugin.getProviders().hasCustomWorldsSupport()) { - WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); - Dimension dimension; - if (worldsProvider instanceof LazyWorldsProvider) { - String worldName = LazyWorldLocation.getWorldName(location); - WorldInfo worldInfo = ((LazyWorldsProvider) worldsProvider).getIslandsWorldInfo(worldName); - dimension = worldInfo.getDimension(); - } else { - dimension = worldsProvider.getIslandsWorldDimension(location.getWorld()); - } - island = this.islandsGrid.getIslandAt(dimension, packedPos); + String worldName = LazyWorldLocation.getWorldName(location); + island = this.islandsGrid.getIslandAt(worldName, packedPos); } else { island = this.islandsGrid.getIslandAt(null, packedPos); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/IslandsGrid.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/IslandsGrid.java index 6e9df5464e..0d58962533 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/IslandsGrid.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/IslandsGrid.java @@ -2,16 +2,15 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; public interface IslandsGrid { - void addIsland(Dimension dimension, long packedPos, Island island); + void addIsland(String worldName, long packedPos, Island island); @Nullable - Island removeIslandAt(Dimension dimension, long packedPos); + Island removeIslandAt(String worldName, long packedPos); @Nullable - Island getIslandAt(Dimension dimension, long packedPos); + Island getIslandAt(String worldName, long packedPos); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/MultiWorldIslandsGrid.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/MultiWorldIslandsGrid.java index 82058152c9..d3e49491a4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/MultiWorldIslandsGrid.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/MultiWorldIslandsGrid.java @@ -1,51 +1,30 @@ package com.bgsoftware.superiorskyblock.island.container.grid; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; -public class MultiWorldIslandsGrid implements IslandsGrid { +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; - private volatile EnumerateMap store = new EnumerateMap<>(Dimension.values()); +public class MultiWorldIslandsGrid implements IslandsGrid { - public MultiWorldIslandsGrid() { - for (Dimension dimension : Dimension.values()) { - this.store.put(dimension, new SingleWorldIslandsGrid()); - } - } + private final Map store = new ConcurrentHashMap<>(); @Override - public void addIsland(Dimension dimension, long packedPos, Island island) { - ensureCapacity(dimension); - this.store.get(dimension).addIsland(null, packedPos, island); + public void addIsland(String worldName, long packedPos, Island island) { + this.store.computeIfAbsent(worldName, d -> new SingleWorldIslandsGrid()) + .addIsland(null, packedPos, island); } @Override - public Island removeIslandAt(Dimension dimension, long packedPos) { - ensureCapacity(dimension); - return this.store.get(dimension).removeIslandAt(null, packedPos); + public Island removeIslandAt(String worldName, long packedPos) { + SingleWorldIslandsGrid worldGrid = this.store.get(worldName); + return worldGrid == null ? null : worldGrid.removeIslandAt(null, packedPos); } @Override - public Island getIslandAt(Dimension dimension, long packedPos) { - ensureCapacity(dimension); - return this.store.get(dimension).getIslandAt(null, packedPos); - } - - private void ensureCapacity(Dimension dimension) { - if (dimension.ordinal() >= this.store.size()) { - synchronized (this) { - if (dimension.ordinal() >= this.store.size()) { - // Need to increase capacity - EnumerateMap newStore = new EnumerateMap<>(Dimension.values()); - for (Dimension dim : Dimension.values()) { - SingleWorldIslandsGrid currLookupObject = this.store.get(dim); - newStore.put(dim, currLookupObject == null ? new SingleWorldIslandsGrid() : currLookupObject); - } - this.store = newStore; - } - } - } + public Island getIslandAt(String worldName, long packedPos) { + SingleWorldIslandsGrid worldGrid = this.store.get(worldName); + return worldGrid == null ? null : worldGrid.getIslandAt(null, packedPos); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java index 7bee9f9093..ec5d351ce2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java @@ -1,31 +1,26 @@ package com.bgsoftware.superiorskyblock.island.container.grid; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; public class SingleWorldIslandsGrid implements IslandsGrid { - private Synchronized> store; - - public SingleWorldIslandsGrid() { - this.store = Synchronized.of(CollectionsFactory.createLong2ObjectLinkedHashMap()); - } + private final Synchronized> store = Synchronized.of(CollectionsFactory.createLong2ObjectLinkedHashMap()); @Override - public void addIsland(Dimension unused, long packedPos, Island island) { + public void addIsland(String unused, long packedPos, Island island) { this.store.write(store -> store.put(packedPos, island)); } @Override - public Island removeIslandAt(Dimension unused, long packedPos) { + public Island removeIslandAt(String unused, long packedPos) { return this.store.writeAndGet(store -> store.remove(packedPos)); } @Override - public Island getIslandAt(Dimension unused, long packedPos) { + public Island getIslandAt(String unused, long packedPos) { return this.store.readAndGet(store -> store.get(packedPos)); } From 620f9122bc485ded4090321893d77f264bcab118 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 24 Sep 2025 14:25:39 +0300 Subject: [PATCH 336/600] Optimized creation of IslandArea objects by reusing the same object for each Island (#2654) --- .../superiorskyblock/core/IslandArea.java | 75 +++++-------------- .../superiorskyblock/island/SIsland.java | 36 ++++----- .../superiorskyblock/island/SpawnIsland.java | 17 +---- 3 files changed, 37 insertions(+), 91 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java index 5a51ab2b42..721b8e8987 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java @@ -2,81 +2,46 @@ import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; -public class IslandArea implements ObjectsPool.Releasable, AutoCloseable { - - private static final ObjectsPool POOL = new ObjectsPool<>(IslandArea::new); +public class IslandArea { private double minX; private double minZ; private double maxX; private double maxZ; - public static IslandArea of(BlockPosition center, double size) { - return of(center, size, true); - } - - public static IslandArea of(BlockPosition center, double size, boolean fromPool) { - return of(center.getX() - size, center.getZ() - size, center.getX() + size, center.getZ() + size, fromPool); - } - - public static IslandArea of(double minX, double minZ, double maxX, double maxZ) { - return of(minX, minZ, maxX, maxZ, true); - } - - public static IslandArea of(double minX, double minZ, double maxX, double maxZ, boolean fromPool) { - IslandArea islandArea = fromPool ? POOL.obtain() : new IslandArea(); - return islandArea.initialize(minX, minZ, maxX, maxZ); + public void update(BlockPosition center, double size) { + update(center.getX() - size, center.getZ() - size, center.getX() + size, center.getZ() + size); } - private IslandArea() { - - } - - private IslandArea initialize(double minX, double minZ, double maxX, double maxZ) { + public void update(double minX, double minZ, double maxX, double maxZ) { this.minX = minX; this.minZ = minZ; this.maxX = maxX; this.maxZ = maxZ; - return this; - } - - public void expand(double size) { - if (size != 0) { - this.minX -= size; - this.minZ -= size; - this.maxX += size; - this.maxZ += size; - } - } - - public void rshift(int shift) { - if (shift != 0) { - this.minX = (int) this.minX >> shift; - this.minZ = (int) this.minZ >> shift; - this.maxX = (int) this.maxX >> shift; - this.maxZ = (int) this.maxZ >> shift; - } } public boolean intercepts(double x, double z) { return x >= this.minX && x <= this.maxX && z >= this.minZ && z <= this.maxZ; } - public IslandArea copy() { - return of(this.minX, this.minZ, this.maxX, this.maxZ); + public boolean expandAndIntercepts(double x, double z, double expandFactor) { + if (expandFactor == 0) + return intercepts(x, z); + double minX = this.minX - expandFactor; + double minZ = this.minZ - expandFactor; + double maxX = this.maxX + expandFactor; + double maxZ = this.maxZ + expandFactor; + return x >= minX && x <= maxX && z >= minZ && z <= maxZ; } - @Override - public void release() { - this.minX = 0; - this.minZ = 0; - this.maxX = 0; - this.maxZ = 0; - POOL.release(this); + public boolean rshiftAndIntercepts(double x, double z, int shiftFactor) { + if (shiftFactor == 0) + return intercepts(x, z); + int minX = (int) this.minX >> shiftFactor; + int minZ = (int) this.minZ >> shiftFactor; + int maxX = (int) this.maxX >> shiftFactor; + int maxZ = (int) this.maxZ >> shiftFactor; + return x >= minX && x <= maxX && z >= minZ && z <= maxZ; } - @Override - public void close() { - release(); - } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index af267d2705..8e8ec5cfb8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -187,7 +187,8 @@ protected IslandCache create() { return new IslandCacheImpl(SIsland.this); } }; - + private final IslandArea entireArea = new IslandArea(); + private final IslandArea protectedArea = new IslandArea(); /* * Island Identifiers */ @@ -394,6 +395,11 @@ public SIsland(IslandBuilderImpl builder) { if (builder.persistentData.length > 0) getPersistentDataContainer().load(builder.persistentData); + int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * + (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); + this.entireArea.update(this.center, islandDistance); + this.protectedArea.update(this.center, getIslandSize()); + this.databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); } @@ -1430,13 +1436,7 @@ public boolean isInside(Location location, double extraRadius) { if (!isIslandWorld(location.getWorld())) return false; - int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * - (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); - - try (IslandArea islandArea = IslandArea.of(this.center, islandDistance)) { - islandArea.expand(extraRadius); - return islandArea.intercepts(location.getBlockX(), location.getBlockZ()); - } + return this.entireArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); } @Override @@ -1452,13 +1452,7 @@ public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) { } private boolean isChunkInside(int chunkX, int chunkZ) { - int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * - (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); - - try (IslandArea islandArea = IslandArea.of(this.center, islandDistance)) { - islandArea.rshift(4); - return islandArea.intercepts(chunkX, chunkZ); - } + return this.entireArea.rshiftAndIntercepts(chunkX, chunkZ, 4); } @Override @@ -1479,10 +1473,7 @@ public boolean isInsideRange(Location location, double extraRadius) { if (!isIslandWorld(location.getWorld())) return false; - try (IslandArea islandArea = IslandArea.of(this.center, getIslandSize())) { - islandArea.expand(extraRadius); - return islandArea.intercepts(location.getBlockX(), location.getBlockZ()); - } + return this.protectedArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); } @Override @@ -1492,10 +1483,7 @@ public boolean isInsideRange(Chunk chunk) { if (!isIslandWorld(chunk.getWorld())) return false; - try (IslandArea islandArea = IslandArea.of(this.center, getIslandSize())) { - islandArea.rshift(4); - return islandArea.intercepts(chunk.getX(), chunk.getZ()); - } + return this.protectedArea.rshiftAndIntercepts(chunk.getX(), chunk.getZ(), 4); } private static boolean isIslandWorld(@Nullable World world) { @@ -2003,6 +1991,8 @@ private void setIslandSizeInternal(IntValue islandSize) { }); } + this.protectedArea.update(this.center, getIslandSize()); + updateBorder(); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index c6975dedff..60c42772c4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -135,8 +135,8 @@ protected IslandCache create() { private final BlockPosition center; private final World spawnWorld; private final WorldInfo spawnWorldInfo; - private final IslandArea islandArea; private final int islandSize; + private final IslandArea islandArea = new IslandArea(); private final float homeYaw; private final float homePitch; @@ -164,7 +164,7 @@ public SpawnIsland() throws ManagerLoadException { this.islandSize = plugin.getSettings().getSpawn().getSize(); this.center = new SBlockPosition(worldName, smartCenter.getBlockX(), smartCenter.getBlockY(), smartCenter.getBlockZ()); - this.islandArea = IslandArea.of(this.center, this.islandSize, false); + this.islandArea.update(this.center, this.islandSize); this.spawnWorldInfo = new WorldInfoImpl(this.spawnWorld.getName(), Dimensions.fromEnvironment(this.spawnWorld.getEnvironment())); this.homeYaw = smartCenter.getYaw(); @@ -811,13 +811,7 @@ public boolean isInside(Location location, double extraRadius) { if (bukkitWorld == null || !bukkitWorld.equals(this.spawnWorld)) return false; - try (IslandArea islandArea = this.islandArea.copy()) { - if (extraRadius != 0) { - islandArea.expand(extraRadius); - } - - return islandArea.intercepts(location.getBlockX(), location.getBlockZ()); - } + return this.islandArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); } @Override @@ -831,10 +825,7 @@ public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) { } public boolean isChunkInside(int chunkX, int chunkZ) { - try (IslandArea islandArea = this.islandArea.copy()) { - islandArea.rshift(4); - return islandArea.intercepts(chunkX, chunkZ); - } + return this.islandArea.rshiftAndIntercepts(chunkX, chunkZ, 4); } @Override From 91a43946f2f997f33b2c50a8cbc6a0677198bcc2 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 26 Sep 2025 19:37:10 +0300 Subject: [PATCH 337/600] Do not save all stacked blocks when server stops (#2655) --- .../superiorskyblock/SuperiorSkyblockPlugin.java | 1 - .../bridge/StackedBlocksDatabaseBridge.java | 5 ----- .../stackedblocks/StackedBlocksManagerImpl.java | 15 --------------- 3 files changed, 21 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index c518a1edc6..f90372a7c9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -341,7 +341,6 @@ public void onDisable() { playersHandler.savePlayers(); gridHandler.saveIslands(); - stackedBlocksHandler.saveStackedBlocks(); } if (loadingStage.isAtLeast(PluginLoadingStage.MODULES_INITIALIZED)) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/StackedBlocksDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/StackedBlocksDatabaseBridge.java index fce40dd0cd..e7f071b344 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/StackedBlocksDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/StackedBlocksDatabaseBridge.java @@ -28,11 +28,6 @@ public static void deleteStackedBlock(StackedBlocksManager stackedBlocks, Stacke )); } - public static void deleteStackedBlocks(StackedBlocksManager stackedBlocks) { - runOperationIfRunning(stackedBlocks.getDatabaseBridge(), databaseBridge -> - databaseBridge.deleteObject("stacked_blocks", null)); - } - private static DatabaseFilter createFilter(Pair... others) { return DatabaseFilter.fromFilters(Arrays.asList(others)); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java index 7406e1c62a..73d81a092c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java @@ -268,21 +268,6 @@ public void forEach(ChunkPosition chunkPosition, Consumer consumer this.stackedBlocksContainer.forEach(chunkPosition, consumer); } - public void saveStackedBlocks() { - StackedBlocksDatabaseBridge.deleteStackedBlocks(this); - - try { - databaseBridge.batchOperations(true); - this.stackedBlocksContainer.forEach(stackedBlock -> { - if (stackedBlock.getAmount() > 1) { - StackedBlocksDatabaseBridge.saveStackedBlock(this, stackedBlock); - } - }); - } finally { - databaseBridge.batchOperations(false); - } - } - private void loadStackedBlock(DatabaseResult resultSet) { Optional location = resultSet.getString("location").map(Serializers.LOCATION_SPACED_SERIALIZER::deserialize); if (!location.isPresent()) { From 89197b16514dddd9c97597802021220c6bd1cac7 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 26 Sep 2025 20:01:10 +0300 Subject: [PATCH 338/600] Use StampedLock instead of ReentrantReadWriteLock for island lookups (#2654) --- .../grid/SingleWorldIslandsGrid.java | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java index ec5d351ce2..d9abfda4c8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/grid/SingleWorldIslandsGrid.java @@ -3,25 +3,52 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.threads.Synchronized; + +import java.util.concurrent.locks.StampedLock; public class SingleWorldIslandsGrid implements IslandsGrid { - private final Synchronized> store = Synchronized.of(CollectionsFactory.createLong2ObjectLinkedHashMap()); + private final Long2ObjectMapView store = CollectionsFactory.createLong2ObjectLinkedHashMap(); + private final StampedLock lock = new StampedLock(); @Override public void addIsland(String unused, long packedPos, Island island) { - this.store.write(store -> store.put(packedPos, island)); + long stamp = this.lock.writeLock(); + try { + this.store.put(packedPos, island); + } finally { + this.lock.unlockWrite(stamp); + } } @Override public Island removeIslandAt(String unused, long packedPos) { - return this.store.writeAndGet(store -> store.remove(packedPos)); + long stamp = this.lock.writeLock(); + Island oldValue; + try { + oldValue = this.store.remove(packedPos); + } finally { + this.lock.unlockWrite(stamp); + } + return oldValue; } @Override public Island getIslandAt(String unused, long packedPos) { - return this.store.readAndGet(store -> store.get(packedPos)); + long stamp = this.lock.tryOptimisticRead(); + Island island = this.store.get(packedPos); + + // Validate that no write occurred while reading + if (!lock.validate(stamp)) { + // Fallback to a proper read lock + stamp = this.lock.readLock(); + try { + island = this.store.get(packedPos); + } finally { + this.lock.unlockRead(stamp); + } + } + return island; } } From f50e291f519263d8d91fda11e367f5f0cb883f6d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 26 Sep 2025 20:17:09 +0300 Subject: [PATCH 339/600] Fixed detection of in-hand item for entity interactions (#2672) --- .../superiorskyblock/listener/ProtectionListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 0d2eb31c48..5806ea933a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -205,7 +205,7 @@ private boolean handleEntityInteract(GameEvent Date: Fri, 26 Sep 2025 21:10:53 +0300 Subject: [PATCH 340/600] Fix other plugins registering custom worlds provider after the islands container is created causes islands to not be found (#2655) --- .../core/events/plugin/PluginEventType.java | 6 ++++ .../events/plugin/PluginEventsFactory.java | 4 +++ .../external/ProvidersManagerImpl.java | 2 ++ .../container/DefaultIslandsContainer.java | 33 ++++++++++++++----- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java index f9a43b1a46..8044cf4c92 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventType.java @@ -254,6 +254,12 @@ public Event createBukkitEvent(Empty args) { return null; } }; + public static final PluginEventType WORLD_PROVIDER_UPDATE_EVENT = new PluginEventType(null) { + @Override + public Event createBukkitEvent(Empty args) { + return null; + } + }; public static final PluginEventType ATTEMPT_PLAYER_SEND_MESSAGE_EVENT = new PluginEventType(AttemptPlayerSendMessageEvent.class) { @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java index c6b74f961b..9459001b59 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsFactory.java @@ -64,6 +64,10 @@ public static void callSpawnUpdateEvent() { fireEvent(SPAWN_UPDATE_EVENT, Empty.INSTANCE); } + public static void callWorldsProviderUpdateEvent() { + fireEvent(WORLD_PROVIDER_UPDATE_EVENT, Empty.INSTANCE); + } + public static boolean callAttemptPlayerSendMessageEvent(SuperiorPlayer receiver, String messageType, Object... args) { AttemptPlayerSendMessage attemptPlayerSendMessage = new AttemptPlayerSendMessage(); attemptPlayerSendMessage.receiver = receiver; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java index c69e58f87b..7b6e42796e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java @@ -29,6 +29,7 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.ServerVersion; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.SpawnerKey; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -183,6 +184,7 @@ public WorldsProvider getWorldsProvider() { public void setWorldsProvider(WorldsProvider worldsProvider) { Preconditions.checkNotNull(worldsProvider, "worldsProvider parameter cannot be null."); this.worldsProvider = worldsProvider; + PluginEventsFactory.callWorldsProviderUpdateEvent(); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index 1f410c2437..9323169aa1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; @@ -39,7 +40,7 @@ public class DefaultIslandsContainer implements IslandsContainer { private final Map islandsByUUID = new ConcurrentHashMap<>(); private final Map islandsByNames = new ConcurrentHashMap<>(); - private final IslandsGrid islandsGrid; + private IslandsGrid islandsGrid; private final Map>> sortedIslands = new ConcurrentHashMap<>(); @@ -51,10 +52,22 @@ public DefaultIslandsContainer(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; this.islandsGrid = plugin.getProviders().hasCustomWorldsSupport() ? new MultiWorldIslandsGrid() : new SingleWorldIslandsGrid(); + plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.WORLD_PROVIDER_UPDATE_EVENT, this::onWorldsProviderUpdate); } @Override public void addIsland(Island island) { + addIslandToGrid(island); + + this.islandsByUUID.put(island.getUniqueId(), island); + this.islandsByNames.put(IslandNames.getNameForLookup(island.getStrippedName()), island); + + sortedIslands.values().forEach(sortedIslands -> { + sortedIslands.write(_sortedIslands -> _sortedIslands.add(island)); + }); + } + + private void addIslandToGrid(Island island) { BlockPosition center = island.getCenterPosition(); long packedPos = IslandPosition.calculatePackedPosFromLocation(center.getX(), center.getZ()); @@ -71,13 +84,6 @@ public void addIsland(Island island) { } else { islandsGrid.addIsland(null, packedPos, island); } - - this.islandsByUUID.put(island.getUniqueId(), island); - this.islandsByNames.put(IslandNames.getNameForLookup(island.getStrippedName()), island); - - sortedIslands.values().forEach(sortedIslands -> { - sortedIslands.write(_sortedIslands -> _sortedIslands.add(island)); - }); } @Override @@ -261,4 +267,15 @@ else if (sortingType == SortingTypes.BY_RATING) return existingIslands; } + private void onWorldsProviderUpdate() { + if (plugin.getProviders().hasCustomWorldsSupport() && islandsGrid instanceof SingleWorldIslandsGrid) { + // We need to upgrade the grid to a MultiWorldIslandsGrid + this.islandsGrid = new MultiWorldIslandsGrid(); + // Re-add all registered islands + for (Island island : this.islandsByUUID.values()) { + addIslandToGrid(island); + } + } + } + } From 45974d47b5d1f4aa73fbfdae6c12b3021f31df85 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 27 Sep 2025 15:02:33 +0300 Subject: [PATCH 341/600] Fixed the ability to poison parrots using cookies on another islands (#2672) --- .../service/region/RegionManagerServiceImpl.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 774c645d4a..76bc6f617f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -86,6 +86,8 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService private static final EntityType LLAMA_TYPE = EnumHelper.getEnum(EntityType.class, "LLAMA"); @Nullable private static final EntityType HAPPY_GHAST_TYPE = EnumHelper.getEnum(EntityType.class, "HAPPY_GHAST"); + @Nullable + private static final EntityType PARROT_TYPE = EnumHelper.getEnum(EntityType.class, "PARROT"); private static final int MAX_PICKUP_DISTANCE = 1; private static EnumerateSet WORLD_PERMISSIONS_CACHE; @@ -305,6 +307,8 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent islandPrivilege = IslandPrivileges.MINECART_OPEN; } else if (entity instanceof Sheep && Materials.isDye(usedItemType)) { islandPrivilege = IslandPrivileges.DYE_SHEEP; + } else if (entityType == PARROT_TYPE && usedItemType == Material.COOKIE) { + islandPrivilege = BukkitEntities.isTameable(entity) ? IslandPrivileges.TAMED_ANIMAL_DAMAGE : IslandPrivileges.ANIMAL_DAMAGE; } else { return InteractionResult.SUCCESS; } From e71f65024a11dadc7196a19cc28a56def790155f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 27 Sep 2025 16:59:47 +0300 Subject: [PATCH 342/600] Fixed errors due to chunk not in bounds when creating new islands (#2674) --- .../superiorskyblock/island/SIsland.java | 10 +++++----- .../DefaultIslandCreationAlgorithm.java | 18 +++++++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 8e8ec5cfb8..5dce6bf8fd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -375,6 +375,11 @@ public SIsland(IslandBuilderImpl builder) { loadIslandWarp(warpRecord.name, warpRecord.location, warpCategory, warpRecord.isPrivate, warpRecord.icon); }); + int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * + (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); + this.entireArea.update(this.center, islandDistance); + this.protectedArea.update(this.center, getIslandSize()); + // We want to save all the limits to the custom block keys plugin.getBlockValues().addCustomBlockKeys(builder.blockLimits.keySet()); @@ -395,11 +400,6 @@ public SIsland(IslandBuilderImpl builder) { if (builder.persistentData.length > 0) getPersistentDataContainer().load(builder.persistentData); - int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * - (plugin.getSettings().isBuildOutsideIsland() ? 1.5 : 1D)); - this.entireArea.update(this.center, islandDistance); - this.protectedArea.update(this.center, getIslandSize()); - this.databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java index ca4adc3f5a..00aa2350e0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java @@ -55,13 +55,21 @@ public CompletableFuture createIsland(UUID islandUUID, Sup } @Override - public CompletableFuture createIsland(Island.Builder builderParam, BlockPosition lastIsland) { - Preconditions.checkNotNull(builderParam, "builder parameter cannot be null."); - Preconditions.checkArgument(builderParam instanceof IslandBuilderImpl, "Cannot create an island from custom builder."); + public CompletableFuture createIsland(Island.Builder builder, BlockPosition lastIsland) { + Preconditions.checkNotNull(builder, "builder parameter cannot be null."); + Preconditions.checkArgument(builder instanceof IslandBuilderImpl, "Cannot create an island from custom builder."); Preconditions.checkNotNull(lastIsland, "lastIsland parameter cannot be null."); + + try { + return createIslandInternal((IslandBuilderImpl) builder, lastIsland); + } catch (Throwable error) { + CompletableFuture result = new CompletableFuture<>(); + result.completeExceptionally(error); + return result; + } + } - IslandBuilderImpl builder = (IslandBuilderImpl) builderParam; - + private CompletableFuture createIslandInternal(IslandBuilderImpl builder, BlockPosition lastIsland) { Schematic schematic = builder.islandType == null ? null : plugin.getSchematics().getSchematic(builder.islandType); Preconditions.checkArgument(builder.owner != null, "Cannot create an island from builder with no valid owner."); From b5d1e36aafa53888d0730371863333680c35ae2b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 27 Sep 2025 17:18:08 +0300 Subject: [PATCH 343/600] Fixed caching schematics throwing errors in 1.17 / 1.18 (#2673) --- .../nms/v1_17/world/WorldEditSessionImpl.java | 13 ++++++------- .../nms/v1_18/world/WorldEditSessionImpl.java | 13 ++++++------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java index 405695b9fc..efedfc59af 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java @@ -45,7 +45,6 @@ import net.minecraft.world.level.chunk.ProtoTickList; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.Fluids; @@ -339,15 +338,15 @@ private boolean isValidPosition(BlockPos blockPos) { } private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { - ResourceKey resourceKey; + ResourceKey resourceKey; switch (dimension.getEnvironment()) { - case NETHER -> resourceKey = LevelStem.NETHER; - case THE_END -> resourceKey = LevelStem.END; - default -> resourceKey = LevelStem.OVERWORLD; + case NETHER -> resourceKey = DimensionType.NETHER_LOCATION; + case THE_END -> resourceKey = DimensionType.END_LOCATION; + default -> resourceKey = DimensionType.OVERWORLD_LOCATION; } - Registry registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.LEVEL_STEM_REGISTRY); - return registry.getOrThrow(resourceKey).type(); + Registry registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY); + return registry.getOrThrow(resourceKey); } private static LevelHeightAccessor createLevelHeightAccessor(int minY, int height) { diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java index f2299e7b70..c9c262cadf 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java @@ -45,7 +45,6 @@ import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Chunk; @@ -326,15 +325,15 @@ private boolean isValidPosition(BlockPos blockPos) { } private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { - ResourceKey resourceKey; + ResourceKey resourceKey; switch (dimension.getEnvironment()) { - case NETHER -> resourceKey = LevelStem.NETHER; - case THE_END -> resourceKey = LevelStem.END; - default -> resourceKey = LevelStem.OVERWORLD; + case NETHER -> resourceKey = DimensionType.NETHER_LOCATION; + case THE_END -> resourceKey = DimensionType.END_LOCATION; + default -> resourceKey = DimensionType.OVERWORLD_LOCATION; } - Registry registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.LEVEL_STEM_REGISTRY); - return registry.getOrThrow(resourceKey).typeHolder().value(); + Registry registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY); + return registry.getOrThrow(resourceKey); } public class ChunkData { From 0d59fb25419854f8534c0f1d8c09a74852c686c5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 27 Sep 2025 19:37:25 +0300 Subject: [PATCH 344/600] Fixed getting SpawnerKey through API does not work properly if it was parsed from a string --- .../core/key/types/MaterialKey.java | 8 ++++++-- .../superiorskyblock/core/key/types/SpawnerKey.java | 13 +++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java index f1a7b3c726..3b83bf952d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/MaterialKey.java @@ -40,8 +40,7 @@ protected MaterialKey create() { if (MaterialKey.this.isAPIKey()) throw new UnsupportedOperationException(); - return new MaterialKey(MaterialKey.this.type, MaterialKey.this.durability, MaterialKey.this.isGlobalType, - MaterialKey.this.materialKeySource, true); + return createAPIKeyForCacheInternal(); } }; @@ -126,6 +125,11 @@ public MaterialKey createAPIKeyInternal() { return this.apiKeyCache.get(); } + protected MaterialKey createAPIKeyForCacheInternal() { + return new MaterialKey(MaterialKey.this.type, MaterialKey.this.durability, MaterialKey.this.isGlobalType, + MaterialKey.this.materialKeySource, true); + } + public Material getMaterial() { return this.type; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/SpawnerKey.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/SpawnerKey.java index 8be612030c..c06a718118 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/SpawnerKey.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/SpawnerKey.java @@ -5,9 +5,9 @@ import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.MaterialKeySource; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.google.common.base.Objects; import org.bukkit.Material; import org.bukkit.entity.EntityType; @@ -34,7 +34,11 @@ public static SpawnerKey of(@Nullable Key spawnerTypeKey) { } private SpawnerKey(@Nullable Key spawnerTypeKey) { - super(SPAWNER_TYPE, (short) 0, spawnerTypeKey == null, MaterialKeySource.BLOCK); + this(spawnerTypeKey, false); + } + + private SpawnerKey(@Nullable Key spawnerTypeKey, boolean apiKey) { + super(SPAWNER_TYPE, (short) 0, spawnerTypeKey == null, MaterialKeySource.BLOCK, apiKey); this.spawnerTypeKey = spawnerTypeKey; } @@ -48,6 +52,11 @@ public String getSubKey() { return this.isGlobalType ? "" : getSubKeyInternal(); } + @Override + protected MaterialKey createAPIKeyForCacheInternal() { + return new SpawnerKey(this.spawnerTypeKey, true); + } + private String getSubKeyInternal() { assert this.spawnerTypeKey != null; return this.spawnerTypeKey.toString(); From a04f45addd588773c8aee75b18305a5b847edab8 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sun, 28 Sep 2025 20:20:31 +0200 Subject: [PATCH 345/600] Added missing sound to Enderman Grief setting (#2676) --- src/main/resources/menus/settings1_13.yml | 4 ++++ src/main/resources/menus/settings1_20.yml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/main/resources/menus/settings1_13.yml b/src/main/resources/menus/settings1_13.yml index 77399611f2..e8c351be54 100644 --- a/src/main/resources/menus/settings1_13.yml +++ b/src/main/resources/menus/settings1_13.yml @@ -222,6 +222,10 @@ settings: lore: - '&7Allow enderman to grief blocks inside your island.' - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 fire_spread: display-menu: true diff --git a/src/main/resources/menus/settings1_20.yml b/src/main/resources/menus/settings1_20.yml index d88bae8a90..9fde712eea 100644 --- a/src/main/resources/menus/settings1_20.yml +++ b/src/main/resources/menus/settings1_20.yml @@ -222,6 +222,10 @@ settings: lore: - '&7Allow enderman to grief blocks inside your island.' - '&7Currently &cDISABLED&7.' + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 fire_spread: display-menu: true From bd8914a4063c085686a026b712e87a82ffafd78d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 28 Sep 2025 21:23:10 +0300 Subject: [PATCH 346/600] Do not print errors when cannot cache schematics (#2675) --- .../superiorskyblock/world/schematic/SchematicsManagerImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index 2d6f914ec3..018b09f55f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -125,7 +125,6 @@ public void cacheSchematics() { cachedSchematic = true; } catch (Throwable error) { Log.warn("Cannot cache schematic ", schematic.getName(), ", skipping..."); - error.printStackTrace(); } } newSchematics.add(schematic); From 6513ab708a1d375822d7092ab04d0a8a04916cb0 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 1 Oct 2025 01:12:21 +0300 Subject: [PATCH 347/600] Fix actions on unloaded chunks do not happen with using SWM (#2677) --- .../nms/v1_16_R3/NMSChunksImpl.java | 15 ++++-- .../nms/v1_16_R3/NMSUtils.java | 37 ++++++++++++-- .../nms/v1_17/NMSChunksImpl.java | 15 ++++-- .../superiorskyblock/nms/v1_17/NMSUtils.java | 43 +++++++++++++--- .../nms/v1_18/NMSChunksImpl.java | 15 ++++-- .../superiorskyblock/nms/v1_18/NMSUtils.java | 42 +++++++++++++--- .../nms/v1_19/NMSChunksImpl.java | 15 ++++-- .../superiorskyblock/nms/v1_19/NMSUtils.java | 47 +++++++++++++++--- .../nms/v1_20_3/NMSChunksImpl.java | 15 ++++-- .../nms/v1_20_3/NMSUtils.java | 47 +++++++++++++++--- .../nms/v1_20_4/NMSChunksImpl.java | 13 +++-- .../nms/v1_20_4/NMSUtils.java | 43 +++++++++++++--- .../nms/v1_21/NMSChunksImpl.java | 15 ++++-- .../superiorskyblock/nms/v1_21/NMSUtils.java | 49 +++++++++++++------ .../nms/v1_21_3/NMSChunksImpl.java | 13 +++-- .../nms/v1_21_3/NMSUtils.java | 36 +++++++++++--- .../nms/v1_21_4/NMSChunksImpl.java | 15 ++++-- .../nms/v1_21_4/NMSUtils.java | 33 ++++++++++--- .../nms/v1_21_5/NMSChunksImpl.java | 13 +++-- .../nms/v1_21_5/NMSUtils.java | 33 ++++++++++--- .../nms/v1_21_7/NMSChunksImpl.java | 13 +++-- .../nms/v1_21_7/NMSUtils.java | 36 +++++++++++--- .../world/chunk/ChunkLoadReason.java | 4 +- 23 files changed, 476 insertions(+), 131 deletions(-) diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java index 52a7a5b7aa..3e6d8ea411 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java @@ -11,8 +11,8 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; @@ -21,6 +21,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_16_R3.crops.CropsTickingTileEntity; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.server.v1_16_R3.BiomeBase; import net.minecraft.server.v1_16_R3.BiomeStorage; @@ -91,7 +92,8 @@ public void setBiome(List chunkPositions, Biome biome, Collection if (chunkPositions.isEmpty()) return; - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(Chunk chunk) { ChunkCoordIntPair chunkCoords = chunk.getPos(); @@ -148,7 +150,8 @@ public void deleteChunks(Island island, List chunkPositions, Runn chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(Chunk chunk) { Arrays.fill(chunk.getSections(), Chunk.a); @@ -236,7 +239,8 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( + ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(Chunk chunk) { ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(), @@ -280,7 +284,8 @@ public CompletableFuture> calculateChunkEntities(Collection chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); List> unloadedEntityTags = new LinkedList<>(); - NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback( + ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(Chunk chunk) { for (org.bukkit.entity.Entity bukkitEntity : chunk.getBukkitChunk().getEntities()) { diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java index 3ee0a2ae1d..8878089821 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java @@ -14,6 +14,8 @@ import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Suppliers; import net.minecraft.server.v1_16_R3.Block; import net.minecraft.server.v1_16_R3.BlockBed; @@ -34,6 +36,7 @@ import net.minecraft.server.v1_16_R3.World; import net.minecraft.server.v1_16_R3.WorldServer; import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_16_R3.CraftChunk; import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; import java.util.Collection; @@ -157,8 +160,10 @@ private static void runActionOnUnloadedChunks(Collection chunks, try { NBTTagCompound chunkCompound = playerChunkMap.read(chunkCoords); - if (chunkCompound == null) + if (chunkCompound == null) { + chunkCallback.onChunkNotExist(chunkPosition); return; + } NBTTagCompound chunkDataCompound = playerChunkMap.getChunkData(worldServer.getTypeKey(), Suppliers.ofInstance(worldServer.getWorldPersistentData()), chunkCompound, chunkCoords, worldServer); @@ -290,13 +295,35 @@ private static boolean isValidPosition(World world, BlockPosition blockPosition) blockPosition.getY() >= 0 && blockPosition.getY() < world.getHeight(); } - public interface ChunkCallback { + public static abstract class ChunkCallback { + + private final ChunkLoadReason chunkLoadReason; + private final boolean isWaitForChunkLoad; + + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { + this.chunkLoadReason = chunkLoadReason; + this.isWaitForChunkLoad = isWaitForChunkLoad; + } + + public abstract void onLoadedChunk(Chunk chunk); - void onLoadedChunk(Chunk chunk); + public abstract void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloadedChunk); - void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloadedChunk); + public abstract void onFinish(); - void onFinish(); + public final void onChunkNotExist(ChunkPosition chunkPosition) { + if (!plugin.getProviders().hasCustomWorldsSupport()) + return; + + CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + onLoadedChunk(chunk); + }); + + if (this.isWaitForChunkLoad) { + futureChunk.join(); + } + } } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java index 6b84f980fc..955c0d9331 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java @@ -13,8 +13,8 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_17.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_17.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; @@ -97,7 +98,8 @@ public void setBiome(List chunkPositions, org.bukkit.block.Biome if (chunkPositions.isEmpty()) return; - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); @@ -152,7 +154,8 @@ public void deleteChunks(Island island, List chunkPositions, @Nul chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Arrays.fill(levelChunk.getSections(), LevelChunk.EMPTY_SECTION); @@ -242,7 +245,8 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); - NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback( + ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -287,7 +291,8 @@ public CompletableFuture> calculateChunkEntities(Collection chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); List> unloadedEntityTags = new LinkedList<>(); - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( + ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java index b9cdadd88a..166fae0a50 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java @@ -16,6 +16,8 @@ import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Suppliers; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; @@ -39,8 +41,10 @@ import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import java.lang.reflect.Modifier; @@ -178,8 +182,10 @@ private static void runActionOnUnloadedChunks(Collection chunks, try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos); - if (chunkCompound == null) + if (chunkCompound == null) { + chunkCallback.onChunkNotExist(chunkPosition); return; + } net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.getChunkData(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, chunkPos, serverLevel); @@ -218,8 +224,11 @@ private static void runActionOnUnloadedEntityChunks(Collection ch if (error != null) { completableFuture.completeExceptionally(error); } else { - if (entityData != null) + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { chunkCallback.onUnloadedChunk(chunkPosition, entityData); + } completableFuture.complete(null); } }); @@ -352,13 +361,35 @@ private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPo blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); } - public interface ChunkCallback { + public static abstract class ChunkCallback { + + private final ChunkLoadReason chunkLoadReason; + private final boolean isWaitForChunkLoad; + + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { + this.chunkLoadReason = chunkLoadReason; + this.isWaitForChunkLoad = isWaitForChunkLoad; + } + + public abstract void onLoadedChunk(LevelChunk levelChunk); - void onLoadedChunk(LevelChunk levelChunk); + public abstract void onUnloadedChunk(ChunkPosition chunkPosition, net.minecraft.nbt.CompoundTag unloadedChunk); - void onUnloadedChunk(ChunkPosition chunkPosition, net.minecraft.nbt.CompoundTag unloadedChunk); + public abstract void onFinish(); - void onFinish(); + public final void onChunkNotExist(ChunkPosition chunkPosition) { + if (!plugin.getProviders().hasCustomWorldsSupport()) + return; + + CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); + onLoadedChunk(levelChunk); + }); + + if (this.isWaitForChunkLoad) { + futureChunk.join(); + } + } } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java index 14d0acb848..9477fced6f 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java @@ -10,8 +10,8 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; @@ -20,6 +20,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_18.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_18.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; @@ -93,7 +94,8 @@ public void setBiome(List chunkPositions, org.bukkit.block.Biome if (chunkPositions.isEmpty()) return; - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); @@ -164,7 +166,8 @@ public void deleteChunks(Island island, List chunkPositions, Runn chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); @@ -301,7 +304,8 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); - NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback( + ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -387,7 +391,8 @@ public CompletableFuture> calculateChunkEntities(Collection chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); List unloadedChunkCompounds = new LinkedList<>(); - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( + ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java index 0389237f75..6248db328c 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java @@ -16,6 +16,8 @@ import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Suppliers; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; @@ -41,8 +43,10 @@ import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import java.io.IOException; @@ -184,8 +188,10 @@ private static void runActionOnUnloadedChunks(Collection chunks, try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos); - if (chunkCompound == null) + if (chunkCompound == null) { + chunkCallback.onChunkNotExist(chunkPosition); return; + } net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, @@ -237,7 +243,9 @@ private static void runActionOnUnloadedEntityChunks(Collection ch if (error != null) { completableFuture.completeExceptionally(error); } else { - if (entityData != null) { + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } @@ -399,13 +407,35 @@ private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPo blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); } - public interface ChunkCallback { + public static abstract class ChunkCallback { + + private final ChunkLoadReason chunkLoadReason; + private final boolean isWaitForChunkLoad; + + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { + this.chunkLoadReason = chunkLoadReason; + this.isWaitForChunkLoad = isWaitForChunkLoad; + } + + public abstract void onLoadedChunk(LevelChunk levelChunk); - void onLoadedChunk(LevelChunk levelChunk); + public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + public abstract void onFinish(); - void onFinish(); + public final void onChunkNotExist(ChunkPosition chunkPosition) { + if (!plugin.getProviders().hasCustomWorldsSupport()) + return; + + CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); + onLoadedChunk(levelChunk); + }); + + if (this.isWaitForChunkLoad) { + futureChunk.join(); + } + } } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java index 928d34b1f9..fc3167e938 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java @@ -11,8 +11,8 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; @@ -21,6 +21,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_19.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_19.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; @@ -97,7 +98,8 @@ public void setBiome(List chunkPositions, org.bukkit.block.Biome if (chunkPositions.isEmpty()) return; - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -168,7 +170,8 @@ public void deleteChunks(Island island, List chunkPositions, @Nul chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -307,7 +310,8 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( + ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -393,7 +397,8 @@ public CompletableFuture> calculateChunkEntities(Collection chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); List unloadedChunkCompounds = new LinkedList<>(); - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( + ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java index 4ab18cb078..f2d1ef0ffd 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java @@ -16,6 +16,8 @@ import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Suppliers; import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; @@ -44,6 +46,7 @@ import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; @@ -189,8 +192,10 @@ private static void runActionOnUnloadedChunks(Collection chunks, try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); - if (chunkCompound == null) + if (chunkCompound == null) { + chunkCallback.onChunkNotExist(chunkPosition); return; + } net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, @@ -273,10 +278,14 @@ private static void runActionOnUnloadedEntityChunks(Collection ch try { net.minecraft.nbt.CompoundTag entityData = serverLevel.entityDataControllerNew.readData( chunkPosition.getX(), chunkPosition.getZ()); - if (entityData != null) { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); + + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + return; } + + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); } catch (IOException error) { Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } @@ -438,13 +447,35 @@ private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPo blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); } - public interface ChunkCallback { + public static abstract class ChunkCallback { + + private final ChunkLoadReason chunkLoadReason; + private final boolean isWaitForChunkLoad; + + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { + this.chunkLoadReason = chunkLoadReason; + this.isWaitForChunkLoad = isWaitForChunkLoad; + } + + public abstract void onLoadedChunk(LevelChunk levelChunk); + + public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + + public abstract void onFinish(); - void onLoadedChunk(LevelChunk levelChunk); + public final void onChunkNotExist(ChunkPosition chunkPosition) { + if (!plugin.getProviders().hasCustomWorldsSupport()) + return; - void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); + onLoadedChunk(levelChunk); + }); - void onFinish(); + if (this.isWaitForChunkLoad) { + futureChunk.join(); + } + } } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java index db2ac8ddaa..9320df0df4 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java @@ -12,8 +12,8 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; @@ -22,6 +22,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; @@ -109,7 +110,8 @@ public void setBiome(List chunkPositions, org.bukkit.block.Biome Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -176,7 +178,8 @@ public void deleteChunks(Island island, List chunkPositions, @Nul chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -315,7 +318,8 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( + ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -401,7 +405,8 @@ public CompletableFuture> calculateChunkEntities(Collection chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); List unloadedChunkCompounds = new LinkedList<>(); - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( + ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java index 02be14144c..60b8b098fb 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java @@ -16,6 +16,8 @@ import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Suppliers; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; @@ -43,6 +45,7 @@ import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; @@ -187,8 +190,10 @@ private static void runActionOnUnloadedChunks(Collection chunks, try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); - if (chunkCompound == null) + if (chunkCompound == null) { + chunkCallback.onChunkNotExist(chunkPosition); return; + } net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, @@ -270,10 +275,14 @@ private static void runActionOnUnloadedEntityChunks(Collection ch try { net.minecraft.nbt.CompoundTag entityData = serverLevel.entityDataControllerNew.readData( chunkPosition.getX(), chunkPosition.getZ()); - if (entityData != null) { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); + + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + return; } + + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); } catch (IOException error) { Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } @@ -430,13 +439,35 @@ private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPo blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); } - public interface ChunkCallback { + public static abstract class ChunkCallback { + + private final ChunkLoadReason chunkLoadReason; + private final boolean isWaitForChunkLoad; + + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { + this.chunkLoadReason = chunkLoadReason; + this.isWaitForChunkLoad = isWaitForChunkLoad; + } - void onLoadedChunk(LevelChunk levelChunk); + public abstract void onLoadedChunk(LevelChunk levelChunk); - void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - void onFinish(); + public abstract void onFinish(); + + public final void onChunkNotExist(ChunkPosition chunkPosition) { + if (!plugin.getProviders().hasCustomWorldsSupport()) + return; + + CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); + onLoadedChunk(levelChunk); + }); + + if (this.isWaitForChunkLoad) { + futureChunk.join(); + } + } } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java index 942e6d259a..a57ec02279 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java @@ -21,6 +21,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_4.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; @@ -101,7 +102,8 @@ public void setBiome(List chunkPositions, org.bukkit.block.Biome Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -167,7 +169,8 @@ public void deleteChunks(Island island, List chunkPositions, @Nul chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -304,7 +307,8 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( + ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -388,7 +392,8 @@ public CompletableFuture> calculateChunkEntities(Collection chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); List unloadedChunkCompounds = new LinkedList<>(); - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( + ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java index 5c36d5caf1..182b022188 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java @@ -16,6 +16,8 @@ import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Suppliers; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; @@ -44,6 +46,7 @@ import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; @@ -272,10 +275,14 @@ private static void runActionOnUnloadedEntityChunks(Collection ch try { net.minecraft.nbt.CompoundTag entityData = serverLevel.entityDataControllerNew.readData( chunkPosition.getX(), chunkPosition.getZ()); - if (entityData != null) { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); + + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + return; } + + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); } catch (IOException error) { Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } @@ -432,13 +439,35 @@ private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPo blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); } - public interface ChunkCallback { + public static abstract class ChunkCallback { + + private final ChunkLoadReason chunkLoadReason; + private final boolean isWaitForChunkLoad; + + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { + this.chunkLoadReason = chunkLoadReason; + this.isWaitForChunkLoad = isWaitForChunkLoad; + } + + public abstract void onLoadedChunk(LevelChunk levelChunk); + + public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - void onLoadedChunk(LevelChunk levelChunk); + public abstract void onFinish(); - void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + public final void onChunkNotExist(ChunkPosition chunkPosition) { + if (!plugin.getProviders().hasCustomWorldsSupport()) + return; - void onFinish(); + CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); + onLoadedChunk(levelChunk); + }); + + if (this.isWaitForChunkLoad) { + futureChunk.join(); + } + } } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java index b8694e5c2e..cf6dc7454c 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java @@ -11,8 +11,8 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; @@ -21,6 +21,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_21.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; @@ -95,7 +96,8 @@ public void setBiome(List chunkPositions, org.bukkit.block.Biome Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -163,7 +165,8 @@ public void deleteChunks(Island island, List chunkPositions, @Nul chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -291,7 +294,8 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( + ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -375,7 +379,8 @@ public CompletableFuture> calculateChunkEntities(Collection chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); List unloadedChunkCompounds = new LinkedList<>(); - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( + ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java index 257ef5c0a3..0cb53fe097 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java @@ -16,13 +16,13 @@ import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Suppliers; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.ListTag; -import net.minecraft.network.protocol.Packet; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkHolder; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; @@ -49,6 +49,7 @@ import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; @@ -71,10 +72,6 @@ public class NMSUtils { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final ReflectMethod SEND_PACKETS_TO_RELEVANT_PLAYERS = new ReflectMethod<>( - ChunkHolder.class, 1, Packet.class, boolean.class); - private static final ReflectField> VISIBLE_CHUNKS = new ReflectField<>( - ChunkMap.class, Map.class, Modifier.PUBLIC | Modifier.VOLATILE, 1); private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( @@ -286,10 +283,14 @@ private static void runActionOnUnloadedEntityChunks(Collection ch try { net.minecraft.nbt.CompoundTag entityData = serverLevel.moonrise$getEntityChunkDataController() .readData(chunkPosition.getX(), chunkPosition.getZ()); - if (entityData != null) { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); + + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + return; } + + UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); } catch (IOException error) { Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } @@ -464,17 +465,35 @@ private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPo blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); } - public interface ChunkCallback { + public static abstract class ChunkCallback { - void onLoadedChunk(LevelChunk levelChunk); + private final ChunkLoadReason chunkLoadReason; + private final boolean isWaitForChunkLoad; - void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { + this.chunkLoadReason = chunkLoadReason; + this.isWaitForChunkLoad = isWaitForChunkLoad; + } - default void onChunkNotExist(ChunkPosition chunkPosition) { + public abstract void onLoadedChunk(LevelChunk levelChunk); - } + public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + + public abstract void onFinish(); - void onFinish(); + public final void onChunkNotExist(ChunkPosition chunkPosition) { + if (!plugin.getProviders().hasCustomWorldsSupport()) + return; + + CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); + onLoadedChunk(levelChunk); + }); + + if (this.isWaitForChunkLoad) { + futureChunk.join(); + } + } } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java index 419b8164b1..1230017103 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java @@ -21,6 +21,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_3.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; @@ -96,7 +97,8 @@ public void setBiome(List chunkPositions, org.bukkit.block.Biome Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); @@ -164,7 +166,8 @@ public void deleteChunks(Island island, List chunkPositions, @Nul chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); @@ -292,7 +295,8 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( + ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -376,7 +380,8 @@ public CompletableFuture> calculateChunkEntities(Collection chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); List unloadedChunkCompounds = new LinkedList<>(); - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( + ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java index 142419a8d5..4ee0e1d55f 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java @@ -17,6 +17,8 @@ import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Suppliers; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; @@ -48,6 +50,7 @@ import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; @@ -291,8 +294,11 @@ private static void runActionOnUnloadedEntityChunks(Collection ch if (entityData != null) { UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); + return; } } + + chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } @@ -467,17 +473,35 @@ private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPo blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); } - public interface ChunkCallback { + public static abstract class ChunkCallback { + + private final ChunkLoadReason chunkLoadReason; + private final boolean isWaitForChunkLoad; - void onLoadedChunk(LevelChunk levelChunk); + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { + this.chunkLoadReason = chunkLoadReason; + this.isWaitForChunkLoad = isWaitForChunkLoad; + } - void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + public abstract void onLoadedChunk(LevelChunk levelChunk); - default void onChunkNotExist(ChunkPosition chunkPosition) { + public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - } + public abstract void onFinish(); - void onFinish(); + public final void onChunkNotExist(ChunkPosition chunkPosition) { + if (!plugin.getProviders().hasCustomWorldsSupport()) + return; + + CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); + onLoadedChunk(levelChunk); + }); + + if (this.isWaitForChunkLoad) { + futureChunk.join(); + } + } } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java index 4b358d4ae6..13358330a9 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -11,8 +11,8 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; @@ -21,6 +21,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_4.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; @@ -96,7 +97,8 @@ public void setBiome(List chunkPositions, org.bukkit.block.Biome Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); @@ -164,7 +166,8 @@ public void deleteChunks(Island island, List chunkPositions, @Nul chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); @@ -292,7 +295,8 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( + ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -376,7 +380,8 @@ public CompletableFuture> calculateChunkEntities(Collection chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); List unloadedChunkCompounds = new LinkedList<>(); - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( + ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java index c4b5bad6a7..00a63198cd 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java @@ -17,6 +17,8 @@ import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Suppliers; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; @@ -48,6 +50,7 @@ import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; @@ -467,17 +470,35 @@ private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPo blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); } - public interface ChunkCallback { + public static abstract class ChunkCallback { - void onLoadedChunk(LevelChunk levelChunk); + private final ChunkLoadReason chunkLoadReason; + private final boolean isWaitForChunkLoad; - void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { + this.chunkLoadReason = chunkLoadReason; + this.isWaitForChunkLoad = isWaitForChunkLoad; + } - default void onChunkNotExist(ChunkPosition chunkPosition) { + public abstract void onLoadedChunk(LevelChunk levelChunk); - } + public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + + public abstract void onFinish(); + + public final void onChunkNotExist(ChunkPosition chunkPosition) { + if (!plugin.getProviders().hasCustomWorldsSupport()) + return; - void onFinish(); + CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); + onLoadedChunk(levelChunk); + }); + + if (this.isWaitForChunkLoad) { + futureChunk.join(); + } + } } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java index 2115f8785c..6187b4a3c4 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java @@ -21,6 +21,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_5.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; @@ -97,7 +98,8 @@ public void setBiome(List chunkPositions, org.bukkit.block.Biome Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); @@ -165,7 +167,8 @@ public void deleteChunks(Island island, List chunkPositions, @Nul chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); @@ -293,7 +296,8 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( + ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -379,7 +383,8 @@ public CompletableFuture> calculateChunkEntities(Collection chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); List unloadedChunkCompounds = new LinkedList<>(); - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( + ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java index e5cbc58f53..47c6fc7121 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java @@ -17,6 +17,8 @@ import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Suppliers; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; @@ -48,6 +50,7 @@ import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; @@ -467,17 +470,35 @@ private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPo blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); } - public interface ChunkCallback { + public static abstract class ChunkCallback { - void onLoadedChunk(LevelChunk levelChunk); + private final ChunkLoadReason chunkLoadReason; + private final boolean isWaitForChunkLoad; - void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { + this.chunkLoadReason = chunkLoadReason; + this.isWaitForChunkLoad = isWaitForChunkLoad; + } - default void onChunkNotExist(ChunkPosition chunkPosition) { + public abstract void onLoadedChunk(LevelChunk levelChunk); - } + public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + + public abstract void onFinish(); + + public final void onChunkNotExist(ChunkPosition chunkPosition) { + if (!plugin.getProviders().hasCustomWorldsSupport()) + return; - void onFinish(); + CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); + onLoadedChunk(levelChunk); + }); + + if (this.isWaitForChunkLoad) { + futureChunk.join(); + } + } } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java index 1eda55a2f8..5d512de26c 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java @@ -21,6 +21,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_7.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; @@ -104,7 +105,8 @@ public void setBiome(List chunkPositions, org.bukkit.block.Biome Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); @@ -172,7 +174,8 @@ public void deleteChunks(Island island, List chunkPositions, @Nul chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), chunkPosition.getX(), chunkPosition.getZ(), false)); - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( + ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); @@ -300,7 +303,8 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( + ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -386,7 +390,8 @@ public CompletableFuture> calculateChunkEntities(Collection chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); List unloadedChunkCompounds = new LinkedList<>(); - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback() { + NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( + ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java index 073411ca3f..e88f93cc6b 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java @@ -17,6 +17,8 @@ import com.bgsoftware.superiorskyblock.tag.IntArrayTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.google.common.base.Suppliers; import com.mojang.logging.LogUtils; import net.minecraft.core.BlockPos; @@ -51,6 +53,7 @@ import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.ValueInput; +import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; @@ -297,8 +300,11 @@ private static void runActionOnUnloadedEntityChunks(Collection ch if (entityData != null) { UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); + return; } } + + chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } @@ -478,17 +484,35 @@ private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPo blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); } - public interface ChunkCallback { + public static abstract class ChunkCallback { + + private final ChunkLoadReason chunkLoadReason; + private final boolean isWaitForChunkLoad; - void onLoadedChunk(LevelChunk levelChunk); + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { + this.chunkLoadReason = chunkLoadReason; + this.isWaitForChunkLoad = isWaitForChunkLoad; + } - void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); + public abstract void onLoadedChunk(LevelChunk levelChunk); - default void onChunkNotExist(ChunkPosition chunkPosition) { + public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - } + public abstract void onFinish(); - void onFinish(); + public final void onChunkNotExist(ChunkPosition chunkPosition) { + if (!plugin.getProviders().hasCustomWorldsSupport()) + return; + + CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); + onLoadedChunk(levelChunk); + }); + + if (this.isWaitForChunkLoad) { + futureChunk.join(); + } + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunkLoadReason.java b/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunkLoadReason.java index 7908c1fea7..2dc14cf9fb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunkLoadReason.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/chunk/ChunkLoadReason.java @@ -10,6 +10,8 @@ public enum ChunkLoadReason { FIND_SAFE_SPOT, API_REQUEST, BIOME_REQUEST, - WARP_SIGN_BREAK + WARP_SIGN_BREAK, + SET_BIOME, + DELETE_CHUNK } From 1796e4c04bc5120770862d53908f20832f85a4aa Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Wed, 1 Oct 2025 11:40:08 +0200 Subject: [PATCH 348/600] Added tab completes to the /is value command (#2679) --- .../bgsoftware/superiorskyblock/commands/player/CmdValue.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdValue.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdValue.java index 0068ef7e75..5c128dfdfa 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdValue.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdValue.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.Text; @@ -131,7 +132,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { - return Collections.emptyList(); + return args.length == 2 ? CommandTabCompletes.getMaterials(args[1]) : Collections.emptyList(); } } From 583e7fe764bc9e5173c4276c106ae305673c6415 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Wed, 1 Oct 2025 11:40:54 +0200 Subject: [PATCH 349/600] Fixed tab completes in /is ban command (#2685) --- .../bgsoftware/superiorskyblock/commands/player/CmdBan.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBan.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBan.java index 6f686c61f1..db0e92bbc4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBan.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdBan.java @@ -80,9 +80,9 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer @Override public List tabComplete(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { - return args.length != 2 ? Collections.emptyList() : CommandTabCompletes.getOnlinePlayers(plugin, args[1], true, + return args.length == 2 ? CommandTabCompletes.getOnlinePlayers(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), onlinePlayer -> !island.isBanned(onlinePlayer) && (!island.isMember(onlinePlayer) || - onlinePlayer.getPlayerRole().isLessThan(superiorPlayer.getPlayerRole()))); + onlinePlayer.getPlayerRole().isLessThan(superiorPlayer.getPlayerRole()))) : Collections.emptyList(); } } From 3b49c6ffdd00b1db6ec2dab4b1ec98282aaf964d Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Wed, 1 Oct 2025 11:42:43 +0200 Subject: [PATCH 350/600] Fixed tab completes in team admin commands (#2684) --- .../superiorskyblock/commands/CommandTabCompletes.java | 6 ++++++ .../commands/admin/CmdAdminDemote.java | 8 ++++++++ .../superiorskyblock/commands/admin/CmdAdminKick.java | 10 +++++++++- .../commands/admin/CmdAdminPromote.java | 8 ++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index 960bba6a57..2185944778 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -72,6 +72,12 @@ public static List getIslandMembers(Island island, String argument) { return getPlayers(island.getIslandMembers(false), argument); } + public static List getOnlinePlayersWithIsland(SuperiorSkyblockPlugin plugin, String argument, boolean hideVanished, + Predicate predicate) { + return getOnlinePlayers(plugin, argument, hideVanished, (onlinePlayer) -> + onlinePlayer != null && onlinePlayer.hasIsland() && predicate.test(onlinePlayer)); + } + public static List getOnlinePlayers(SuperiorSkyblockPlugin plugin, String argument, boolean hideVanish) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDemote.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDemote.java index c80bffc6b6..e0ff540b56 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDemote.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDemote.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -92,4 +93,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, Superio Message.GOT_DEMOTED.send(targetPlayer, targetPlayer.getPlayerRole()); } + @Override + public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + return args.length == 3 ? CommandTabCompletes.getOnlinePlayersWithIsland(plugin, args[2], false, + superiorPlayer -> !superiorPlayer.getIslandLeader().equals(superiorPlayer) && + !superiorPlayer.getPlayerRole().isFirstRole()) : Collections.emptyList(); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminKick.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminKick.java index f342f5db04..92d1858cd8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminKick.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminKick.java @@ -1,10 +1,11 @@ package com.bgsoftware.superiorskyblock.commands.admin; -import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; +import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -72,4 +73,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, Superio sender.getName(), targetIsland, targetPlayer); } + @Override + public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + return args.length == 3 ? CommandTabCompletes.getOnlinePlayersWithIsland(plugin, args[2], false, + superiorPlayer -> !superiorPlayer.getIslandLeader().equals(superiorPlayer)) : + Collections.emptyList(); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminPromote.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminPromote.java index 966a7b35e1..e20144ecd8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminPromote.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminPromote.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminPlayerCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -99,4 +100,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, Superio Message.GOT_PROMOTED.send(targetPlayer, targetPlayer.getPlayerRole()); } + @Override + public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + return args.length == 3 ? CommandTabCompletes.getOnlinePlayersWithIsland(plugin, args[2], false, + superiorPlayer -> !superiorPlayer.getIslandLeader().equals(superiorPlayer) && + !superiorPlayer.getPlayerRole().getNextRole().isLastRole()) : Collections.emptyList(); + } + } From 1a671aac138012a6e2eb5ad33cb378936db86a30 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Wed, 1 Oct 2025 11:44:56 +0200 Subject: [PATCH 351/600] Added `*` to the usage of the /is admin adddisbands and /is admin addsize commands (#2682) --- .../superiorskyblock/commands/admin/CmdAdminAddDisbands.java | 3 ++- .../superiorskyblock/commands/admin/CmdAdminAddSize.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddDisbands.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddDisbands.java index 7be87f2d53..eb050afb1a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddDisbands.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddDisbands.java @@ -25,7 +25,8 @@ public String getPermission() { @Override public String getUsage(java.util.Locale locale) { return "admin adddisbands <" + - Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "> <" + + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ALL_PLAYERS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_AMOUNT.getMessage(locale) + ">"; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddSize.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddSize.java index 3540c46d80..0463d966a4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddSize.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddSize.java @@ -32,7 +32,8 @@ public String getPermission() { public String getUsage(java.util.Locale locale) { return "admin addsize <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + - Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "> <" + + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_SIZE.getMessage(locale) + ">"; } From aaf1afb003241555f67d44e43a6733d83951b77b Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Wed, 1 Oct 2025 11:46:23 +0200 Subject: [PATCH 352/600] Added tab completes to the /is admin schematic command (#2681) --- .../superiorskyblock/commands/admin/CmdAdminSchematic.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java index 07067b0101..b60d85d02b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSchematic.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -24,7 +25,8 @@ public String getPermission() { @Override public String getUsage(java.util.Locale locale) { - return "admin schematic [" + Message.COMMAND_ARGUMENT_SCHEMATIC_NAME.getMessage(locale) + "] [" + + return "admin schematic [" + + Message.COMMAND_ARGUMENT_SCHEMATIC_NAME.getMessage(locale) + "] [" + Message.COMMAND_ARGUMENT_SCHEMATIC_SAVE_AIR.getMessage(locale) + "[true/false]]"; } @@ -76,7 +78,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { - return Collections.emptyList(); + return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], "true", "false") : + Collections.emptyList(); } } From a35703e619cf3da98e836f08f87a14e081a0b014 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 1 Oct 2025 14:47:12 +0300 Subject: [PATCH 353/600] Fix async errors due to recent commit --- .../com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java | 2 +- .../com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java index 8878089821..21a5984f9b 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java @@ -317,7 +317,7 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); - onLoadedChunk(chunk); + BukkitExecutor.ensureMain(() -> onLoadedChunk(chunk)); }); if (this.isWaitForChunkLoad) { diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java index 166fae0a50..dd17c1ebcb 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java @@ -383,7 +383,7 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); - onLoadedChunk(levelChunk); + BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); if (this.isWaitForChunkLoad) { diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java index 6248db328c..00ac5f16fe 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java @@ -429,7 +429,7 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); - onLoadedChunk(levelChunk); + BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); if (this.isWaitForChunkLoad) { diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java index f2d1ef0ffd..0dd4e390bb 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java @@ -469,7 +469,7 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - onLoadedChunk(levelChunk); + BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); if (this.isWaitForChunkLoad) { diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java index 60b8b098fb..424c049efd 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java @@ -461,7 +461,7 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - onLoadedChunk(levelChunk); + BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); if (this.isWaitForChunkLoad) { diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java index 182b022188..8f075fcd98 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java @@ -461,7 +461,7 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - onLoadedChunk(levelChunk); + BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); if (this.isWaitForChunkLoad) { diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java index 0cb53fe097..cec848eeb0 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java @@ -487,7 +487,7 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - onLoadedChunk(levelChunk); + BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); if (this.isWaitForChunkLoad) { diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java index 4ee0e1d55f..051dd9e79d 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java @@ -495,7 +495,7 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - onLoadedChunk(levelChunk); + BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); if (this.isWaitForChunkLoad) { diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java index 00a63198cd..2d65187d86 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java @@ -492,7 +492,7 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - onLoadedChunk(levelChunk); + BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); if (this.isWaitForChunkLoad) { diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java index 47c6fc7121..2d5e6c2482 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java @@ -492,7 +492,7 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - onLoadedChunk(levelChunk); + BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); if (this.isWaitForChunkLoad) { diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java index e88f93cc6b..f2f504e8b2 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java @@ -506,7 +506,7 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - onLoadedChunk(levelChunk); + BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); if (this.isWaitForChunkLoad) { From 08d9661f8ae8fa9ed35302f588927fb17b0b17a0 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 1 Oct 2025 16:11:08 +0300 Subject: [PATCH 354/600] Better synchronization of multiple tasks running together --- .../nms/v1_16_R3/NMSChunksImpl.java | 8 ++ .../nms/v1_16_R3/NMSUtils.java | 31 ++++++-- .../nms/v1_17/NMSChunksImpl.java | 8 ++ .../superiorskyblock/nms/v1_17/NMSUtils.java | 52 ++++++++----- .../nms/v1_18/NMSChunksImpl.java | 8 ++ .../superiorskyblock/nms/v1_18/NMSUtils.java | 58 +++++++++----- .../nms/v1_19/NMSChunksImpl.java | 8 ++ .../superiorskyblock/nms/v1_19/NMSUtils.java | 64 +++++++++------ .../nms/v1_20_3/NMSChunksImpl.java | 8 ++ .../nms/v1_20_3/NMSUtils.java | 66 ++++++++++------ .../nms/v1_20_4/NMSChunksImpl.java | 8 ++ .../nms/v1_20_4/NMSUtils.java | 70 +++++++++++------ .../nms/v1_21/NMSChunksImpl.java | 8 ++ .../superiorskyblock/nms/v1_21/NMSUtils.java | 74 +++++++++++------- .../nms/v1_21_3/NMSChunksImpl.java | 8 ++ .../nms/v1_21_3/NMSUtils.java | 75 +++++++++++------- .../nms/v1_21_4/NMSChunksImpl.java | 8 ++ .../nms/v1_21_4/NMSUtils.java | 78 ++++++++++++------- .../nms/v1_21_5/NMSChunksImpl.java | 8 ++ .../nms/v1_21_5/NMSUtils.java | 77 +++++++++++------- .../nms/v1_21_7/NMSChunksImpl.java | 8 ++ .../nms/v1_21_7/NMSUtils.java | 75 +++++++++++------- .../core/threads/SynchronizedTasks.java | 43 ++++++++++ .../island/GridManagerImpl.java | 2 +- .../superiorskyblock/island/IslandUtils.java | 5 +- .../superiorskyblock/island/SIsland.java | 76 ++++++++++-------- .../container/DefaultIslandsContainer.java | 4 +- 27 files changed, 657 insertions(+), 281 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/threads/SynchronizedTasks.java diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java index 3e6d8ea411..411b2c1bff 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java @@ -246,6 +246,8 @@ public void onLoadedChunk(Chunk chunk) { ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(), chunk.getPos().x, chunk.getPos().z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, chunk.getSections())); + + this.chunkLoadLatch.countDown(); } @Override @@ -266,6 +268,8 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloaded CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + this.chunkLoadLatch.countDown(); } @Override @@ -292,12 +296,16 @@ public void onLoadedChunk(Chunk chunk) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + this.chunkLoadLatch.countDown(); } @Override public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound entityData) { WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); unloadedEntityTags.add(new Pair<>(worldServer, entityData.getList("Entities", 10))); + + this.chunkLoadLatch.countDown(); } @Override diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java index 21a5984f9b..080d79eca1 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java @@ -46,6 +46,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; public class NMSUtils { @@ -151,12 +152,20 @@ private static void runActionOnUnloadedChunks(Collection chunks, PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { + CountDownLatch countDownLatch; + if (chunkCallback.isWaitForChunkLoad) { + countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + } else { + countDownLatch = null; + } + chunks.forEach(chunkPosition -> { WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PlayerChunkMap playerChunkMap = worldServer.getChunkProvider().playerChunkMap; ChunkCoordIntPair chunkCoords = new ChunkCoordIntPair(chunkPosition.getX(), chunkPosition.getZ()); + boolean calledCountdown = false; try { NBTTagCompound chunkCompound = playerChunkMap.read(chunkCoords); @@ -170,13 +179,27 @@ private static void runActionOnUnloadedChunks(Collection chunks, if (chunkDataCompound.hasKeyOfType("Level", 10)) { chunkCallback.onUnloadedChunk(chunkPosition, chunkDataCompound.getCompound("Level")); + calledCountdown = true; if (saveChunks) playerChunkMap.a(chunkCoords, chunkDataCompound); + } else { + if (countDownLatch != null) + countDownLatch.countDown(); } } catch (Exception error) { + if (!calledCountdown && countDownLatch != null) + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + + if (countDownLatch != null) { + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } + } }).runSync(v -> { chunkCallback.onFinish(); @@ -300,6 +323,8 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + protected CountDownLatch chunkLoadLatch; + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; @@ -315,14 +340,10 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; - CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); BukkitExecutor.ensureMain(() -> onLoadedChunk(chunk)); }); - - if (this.isWaitForChunkLoad) { - futureChunk.join(); - } } } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java index 955c0d9331..c93a1047b0 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java @@ -252,6 +252,8 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.getSections())); + + this.chunkLoadLatch.countDown(); } @Override @@ -273,6 +275,8 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag unloadedChu CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, levelChunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + this.chunkLoadLatch.countDown(); } @Override @@ -299,12 +303,16 @@ public void onLoadedChunk(LevelChunk levelChunk) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + this.chunkLoadLatch.countDown(); } @Override public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag entityData) { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); unloadedEntityTags.add(new Pair<>(serverLevel, entityData.getList("Entities", 10))); + + this.chunkLoadLatch.countDown(); } @Override diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java index dd17c1ebcb..f017267d9c 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_17.world.PropertiesMapper; @@ -41,7 +40,6 @@ import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; @@ -55,6 +53,7 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; public class NMSUtils { @@ -173,12 +172,20 @@ private static void runActionOnUnloadedChunks(Collection chunks, PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { + CountDownLatch countDownLatch; + if (chunkCallback.isWaitForChunkLoad) { + countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + } else { + countDownLatch = null; + } + chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + boolean calledCountdown = false; try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos); @@ -192,13 +199,27 @@ private static void runActionOnUnloadedChunks(Collection chunks, if (chunkDataCompound.contains("Level", 10)) { chunkCallback.onUnloadedChunk(chunkPosition, chunkDataCompound.getCompound("Level")); + calledCountdown = true; if (saveChunks) chunkMap.write(chunkPos, chunkDataCompound); + } else { + if (countDownLatch != null) + countDownLatch.countDown(); } } catch (Exception error) { + if (!calledCountdown && countDownLatch != null) + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + + if (countDownLatch != null) { + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } + } }).runSync(v -> { chunkCallback.onFinish(); @@ -209,37 +230,34 @@ private static void runActionOnUnloadedChunks(Collection chunks, private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - CompletableFutureList workerChunks = new CompletableFutureList<>(-1); + CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); IOWorker worker = ENTITY_STORAGE_WORKER.get(serverLevel.entityManager.permanentStorage); - CompletableFuture completableFuture = new CompletableFuture<>(); - workerChunks.add(completableFuture); - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); WORKER_LOAD_ASYNC.invoke(worker, chunkPos).whenComplete((entityData, error) -> { if (error != null) { - completableFuture.completeExceptionally(error); + countDownLatch.countDown(); + throw new RuntimeException(error); } else { if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); } else { chunkCallback.onUnloadedChunk(chunkPosition, entityData); } - completableFuture.complete(null); } }); }); BukkitExecutor.createTask().runAsync(v -> { - workerChunks.forEachCompleted(pair -> { - // Wait for all chunks to load. - }, error -> { - Log.error(error, "An unexpected error occurred while interacting with an unloaded chunk:"); - }); + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -366,6 +384,8 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + protected CountDownLatch chunkLoadLatch; + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; @@ -381,14 +401,10 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; - CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); - - if (this.isWaitForChunkLoad) { - futureChunk.join(); - } } } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java index 9477fced6f..c178830217 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java @@ -311,6 +311,8 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.getSections())); + + this.chunkLoadLatch.countDown(); } @Override @@ -373,6 +375,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + this.chunkLoadLatch.countDown(); } @Override @@ -399,11 +403,15 @@ public void onLoadedChunk(LevelChunk levelChunk) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + this.chunkLoadLatch.countDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); + + this.chunkLoadLatch.countDown(); } @Override diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java index 00ac5f16fe..86f326c317 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_18.world.PropertiesMapper; @@ -43,7 +42,6 @@ import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; @@ -59,6 +57,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; public class NMSUtils { @@ -177,6 +176,13 @@ private static void runActionOnUnloadedChunks(Collection chunks, PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { + CountDownLatch countDownLatch; + if (chunkCallback.isWaitForChunkLoad) { + countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + } else { + countDownLatch = null; + } + List chunkCompounds = new LinkedList<>(); chunks.forEach(chunkPosition -> { @@ -185,6 +191,7 @@ private static void runActionOnUnloadedChunks(Collection chunks, ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + boolean calledCountdown = false; try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos); @@ -199,14 +206,25 @@ private static void runActionOnUnloadedChunks(Collection chunks, UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); chunkCallback.onUnloadedChunk(unloadedChunkCompound); + calledCountdown = true; if (saveChunks) chunkCompounds.add(unloadedChunkCompound); } catch (Exception error) { + if (!calledCountdown && countDownLatch != null) + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + if (countDownLatch != null) { + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } + } + return chunkCompounds; }).runSync(chunkCompounds -> { chunkCompounds.forEach(unloadedChunkCompound -> { @@ -228,20 +246,18 @@ private static void runActionOnUnloadedChunks(Collection chunks, private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - CompletableFutureList workerChunks = new CompletableFutureList<>(-1); + CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); IOWorker worker = ENTITY_STORAGE_WORKER.get(serverLevel.entityManager.permanentStorage); - CompletableFuture completableFuture = new CompletableFuture<>(); - workerChunks.add(completableFuture); - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); WORKER_LOAD_ASYNC.invoke(worker, chunkPos).whenComplete((entityData, error) -> { if (error != null) { - completableFuture.completeExceptionally(error); + countDownLatch.countDown(); + throw new RuntimeException(error); } else { if (entityData == null) { chunkCallback.onChunkNotExist(chunkPosition); @@ -249,18 +265,16 @@ private static void runActionOnUnloadedEntityChunks(Collection ch UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } - - completableFuture.complete(null); } }); }); BukkitExecutor.createTask().runAsync(v -> { - workerChunks.forEachCompleted(pair -> { - // Wait for chunks to load. - }, error -> { - Log.error(error, "An unexpected error occurred while interacting with an unloaded chunk:"); - }); + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -412,11 +426,21 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + protected CountDownLatch chunkLoadLatch; + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; } + public final boolean isWaitForChunkLoad() { + return isWaitForChunkLoad; + } + + public final void setChunkLoadLatch(CountDownLatch chunkLoadLatch) { + this.chunkLoadLatch = chunkLoadLatch; + } + public abstract void onLoadedChunk(LevelChunk levelChunk); public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); @@ -427,14 +451,10 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; - CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); - - if (this.isWaitForChunkLoad) { - futureChunk.join(); - } } } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java index fc3167e938..4b1195b870 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java @@ -317,6 +317,8 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.getSections())); + + this.chunkLoadLatch.countDown(); } @Override @@ -379,6 +381,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + this.chunkLoadLatch.countDown(); } @Override @@ -405,11 +409,15 @@ public void onLoadedChunk(LevelChunk levelChunk) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + this.chunkLoadLatch.countDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); + + this.chunkLoadLatch.countDown(); } @Override diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java index 0dd4e390bb..d3eb991c15 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_19.world.PropertiesMapper; @@ -46,7 +45,6 @@ import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; @@ -62,6 +60,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; public class NMSUtils { @@ -181,6 +180,13 @@ private static void runActionOnUnloadedChunks(Collection chunks, PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { + CountDownLatch countDownLatch; + if (chunkCallback.isWaitForChunkLoad) { + countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + } else { + countDownLatch = null; + } + List chunkCompounds = new LinkedList<>(); chunks.forEach(chunkPosition -> { @@ -189,6 +195,7 @@ private static void runActionOnUnloadedChunks(Collection chunks, ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + boolean calledCountdown = false; try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); @@ -203,14 +210,25 @@ private static void runActionOnUnloadedChunks(Collection chunks, UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); chunkCallback.onUnloadedChunk(unloadedChunkCompound); + calledCountdown = true; if (saveChunks) chunkCompounds.add(unloadedChunkCompound); } catch (Exception error) { + if (!calledCountdown && countDownLatch != null) + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPos, ":"); } }); + if (countDownLatch != null) { + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } + } + return chunkCompounds; }).runSync(chunkCompounds -> { chunkCompounds.forEach(unloadedChunkCompound -> { @@ -232,9 +250,9 @@ private static void runActionOnUnloadedChunks(Collection chunks, private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - CompletableFutureList workerChunks = new CompletableFutureList<>(-1); + CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); @@ -242,31 +260,28 @@ private static void runActionOnUnloadedEntityChunks(Collection ch ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - CompletableFuture completableFuture = new CompletableFuture<>(); - workerChunks.add(completableFuture); - worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { - completableFuture.completeExceptionally(error); + countDownLatch.countDown(); + throw new RuntimeException(error); } else { net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); - - if (entityData != null) { + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } - - completableFuture.complete(null); } }); }); BukkitExecutor.createTask().runAsync(v -> { - workerChunks.forEachCompleted(pair -> { - // Wait for all chunks to load. - }, error -> { - Log.error(error, "An unexpected error occurred while interacting with an unloaded chunk:"); - }); + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -287,9 +302,16 @@ private static void runActionOnUnloadedEntityChunks(Collection ch UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } catch (IOException error) { + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -452,6 +474,8 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + protected CountDownLatch chunkLoadLatch; + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; @@ -467,14 +491,10 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; - CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); - - if (this.isWaitForChunkLoad) { - futureChunk.join(); - } } } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java index 9320df0df4..83c1a2729b 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java @@ -325,6 +325,8 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + + this.chunkLoadLatch.countDown(); } @Override @@ -387,6 +389,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + this.chunkLoadLatch.countDown(); } @Override @@ -413,11 +417,15 @@ public void onLoadedChunk(LevelChunk levelChunk) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + this.chunkLoadLatch.countDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); + + this.chunkLoadLatch.countDown(); } @Override diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java index 424c049efd..706d05e8d3 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.PropertiesMapper; @@ -45,7 +44,6 @@ import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; @@ -61,6 +59,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; public class NMSUtils { @@ -179,6 +178,13 @@ private static void runActionOnUnloadedChunks(Collection chunks, PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { + CountDownLatch countDownLatch; + if (chunkCallback.isWaitForChunkLoad) { + countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + } else { + countDownLatch = null; + } + List chunkCompounds = new LinkedList<>(); chunks.forEach(chunkPosition -> { @@ -187,6 +193,7 @@ private static void runActionOnUnloadedChunks(Collection chunks, ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + boolean calledCountdown = false; try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); @@ -201,14 +208,25 @@ private static void runActionOnUnloadedChunks(Collection chunks, UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); chunkCallback.onUnloadedChunk(unloadedChunkCompound); + calledCountdown = true; if (saveChunks) chunkCompounds.add(unloadedChunkCompound); } catch (Exception error) { + if (!calledCountdown && countDownLatch != null) + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + if (countDownLatch != null) { + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } + } + return chunkCompounds; }).runSync(chunkCompounds -> { chunkCompounds.forEach(unloadedChunkCompound -> { @@ -230,9 +248,9 @@ private static void runActionOnUnloadedChunks(Collection chunks, private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - CompletableFutureList readChunksTasksList = new CompletableFutureList<>(-1); + CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); @@ -241,29 +259,28 @@ private static void runActionOnUnloadedEntityChunks(Collection ch ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - CompletableFuture readTask = new CompletableFuture<>(); - readChunksTasksList.add(readTask); - worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { - readTask.completeExceptionally(error); + countDownLatch.countDown(); + throw new RuntimeException(error); } else { - entityDataOptional.ifPresent(entityData -> { + net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); - }); - - readTask.complete(null); + } } }); }); BukkitExecutor.createTask().runAsync(v -> { - readChunksTasksList.forEachCompleted(p -> { - // Wait for all chunks to load. - }, error -> { - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk:"); - }); + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -284,9 +301,16 @@ private static void runActionOnUnloadedEntityChunks(Collection ch UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } catch (IOException error) { + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -444,6 +468,8 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + protected CountDownLatch chunkLoadLatch; + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; @@ -459,14 +485,10 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; - CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); - - if (this.isWaitForChunkLoad) { - futureChunk.join(); - } } } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java index a57ec02279..2811707dff 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java @@ -314,6 +314,8 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + + this.chunkLoadLatch.countDown(); } @Override @@ -374,6 +376,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + this.chunkLoadLatch.countDown(); } @Override @@ -400,11 +404,15 @@ public void onLoadedChunk(LevelChunk levelChunk) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + this.chunkLoadLatch.countDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); + + this.chunkLoadLatch.countDown(); } @Override diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java index 8f075fcd98..fa49f8527a 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.PropertiesMapper; @@ -46,7 +45,6 @@ import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; @@ -62,6 +60,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; public class NMSUtils { @@ -181,6 +180,13 @@ private static void runActionOnUnloadedChunks(Collection chunks, PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { + CountDownLatch countDownLatch; + if (chunkCallback.isWaitForChunkLoad) { + countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + } else { + countDownLatch = null; + } + List chunkCompounds = new LinkedList<>(); chunks.forEach(chunkPosition -> { @@ -189,11 +195,14 @@ private static void runActionOnUnloadedChunks(Collection chunks, ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + boolean calledCountdown = false; try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); - if (chunkCompound == null) + if (chunkCompound == null) { + chunkCallback.onChunkNotExist(chunkPosition); return; + } net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, @@ -201,14 +210,25 @@ private static void runActionOnUnloadedChunks(Collection chunks, UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); chunkCallback.onUnloadedChunk(unloadedChunkCompound); + calledCountdown = true; if (saveChunks) chunkCompounds.add(unloadedChunkCompound); } catch (Exception error) { + if (!calledCountdown && countDownLatch != null) + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + if (countDownLatch != null) { + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } + } + return chunkCompounds; }).runSync(chunkCompounds -> { chunkCompounds.forEach(unloadedChunkCompound -> { @@ -230,9 +250,9 @@ private static void runActionOnUnloadedChunks(Collection chunks, private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - CompletableFutureList readChunksTasksList = new CompletableFutureList<>(-1); + CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); @@ -241,29 +261,28 @@ private static void runActionOnUnloadedEntityChunks(Collection ch ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - CompletableFuture readTask = new CompletableFuture<>(); - readChunksTasksList.add(readTask); - regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { - readTask.completeExceptionally(error); + countDownLatch.countDown(); + throw new RuntimeException(error); } else { - entityDataOptional.ifPresent(entityData -> { + net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); - }); - - readTask.complete(null); + } } }); }); BukkitExecutor.createTask().runAsync(v -> { - readChunksTasksList.forEachCompleted(p -> { - // Wait for all chunks to load. - }, error -> { - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk:"); - }); + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -284,9 +303,16 @@ private static void runActionOnUnloadedEntityChunks(Collection ch UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } catch (IOException error) { + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -444,6 +470,8 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + protected CountDownLatch chunkLoadLatch; + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; @@ -459,14 +487,10 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; - CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); - - if (this.isWaitForChunkLoad) { - futureChunk.join(); - } } } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java index cf6dc7454c..7e30c7dea9 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java @@ -301,6 +301,8 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + + this.chunkLoadLatch.countDown(); } @Override @@ -361,6 +363,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + this.chunkLoadLatch.countDown(); } @Override @@ -387,11 +391,15 @@ public void onLoadedChunk(LevelChunk levelChunk) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + this.chunkLoadLatch.countDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); + + this.chunkLoadLatch.countDown(); } @Override diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java index cec848eeb0..a8edbc4a34 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_21.world.PropertiesMapper; @@ -49,7 +48,6 @@ import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; @@ -66,6 +64,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; public class NMSUtils { @@ -185,15 +184,23 @@ private static void runActionOnUnloadedChunks(Collection chunks, PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { + CountDownLatch countDownLatch; + if (chunkCallback.isWaitForChunkLoad) { + countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + } else { + countDownLatch = null; + } + List chunkCompounds = new LinkedList<>(); chunks.forEach(chunkPosition -> { - try { - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + boolean calledCountdown = false; + try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); if (chunkCompound == null) { @@ -207,14 +214,25 @@ private static void runActionOnUnloadedChunks(Collection chunks, UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); chunkCallback.onUnloadedChunk(unloadedChunkCompound); + calledCountdown = true; if (saveChunks) chunkCompounds.add(unloadedChunkCompound); } catch (Exception error) { + if (!calledCountdown && countDownLatch != null) + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + if (countDownLatch != null) { + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } + } + return chunkCompounds; }).runSync(chunkCompounds -> { chunkCompounds.forEach(unloadedChunkCompound -> { @@ -238,9 +256,9 @@ private static void runActionOnUnloadedChunks(Collection chunks, } private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - CompletableFutureList readChunksTasksList = new CompletableFutureList<>(-1); + CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); @@ -249,29 +267,28 @@ private static void runActionOnUnloadedEntityChunks(Collection ch ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - CompletableFuture readTask = new CompletableFuture<>(); - readChunksTasksList.add(readTask); - regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { - readTask.completeExceptionally(error); + countDownLatch.countDown(); + throw new RuntimeException(error); } else { - entityDataOptional.ifPresent(entityData -> { + net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); - }); - - readTask.complete(null); + } } }); }); BukkitExecutor.createTask().runAsync(v -> { - readChunksTasksList.forEachCompleted(p -> { - // Wait for all chunks to load. - }, error -> { - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk:"); - }); + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -292,9 +309,16 @@ private static void runActionOnUnloadedEntityChunks(Collection ch UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); } catch (IOException error) { + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -470,6 +494,8 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + protected CountDownLatch chunkLoadLatch; + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; @@ -485,14 +511,10 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; - CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); - - if (this.isWaitForChunkLoad) { - futureChunk.join(); - } } } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java index 1230017103..10b43dcf5d 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java @@ -302,6 +302,8 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + + this.chunkLoadLatch.countDown(); } @Override @@ -362,6 +364,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + this.chunkLoadLatch.countDown(); } @Override @@ -388,11 +392,15 @@ public void onLoadedChunk(LevelChunk levelChunk) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + this.chunkLoadLatch.countDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); + + this.chunkLoadLatch.countDown(); } @Override diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java index 051dd9e79d..fba7d1bd35 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java @@ -8,7 +8,6 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.PropertiesMapper; @@ -50,7 +49,6 @@ import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; @@ -67,6 +65,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; public class NMSUtils { @@ -186,15 +185,23 @@ private static void runActionOnUnloadedChunks(Collection chunks, PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { + CountDownLatch countDownLatch; + if (chunkCallback.isWaitForChunkLoad) { + countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + } else { + countDownLatch = null; + } + List chunkCompounds = new LinkedList<>(); chunks.forEach(chunkPosition -> { - try { - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + boolean calledCountdown = false; + try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); if (chunkCompound == null) { @@ -208,18 +215,28 @@ private static void runActionOnUnloadedChunks(Collection chunks, UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); chunkCallback.onUnloadedChunk(unloadedChunkCompound); + calledCountdown = true; if (saveChunks) chunkCompounds.add(unloadedChunkCompound); } catch (Exception error) { + if (!calledCountdown && countDownLatch != null) + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + if (countDownLatch != null) { + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } + } + return chunkCompounds; }).runSync(chunkCompounds -> { chunkCompounds.forEach(unloadedChunkCompound -> { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; @@ -240,9 +257,9 @@ private static void runActionOnUnloadedChunks(Collection chunks, } private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - CompletableFutureList readChunksTasksList = new CompletableFutureList<>(-1); + CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); @@ -251,29 +268,28 @@ private static void runActionOnUnloadedEntityChunks(Collection ch ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - CompletableFuture readTask = new CompletableFuture<>(); - readChunksTasksList.add(readTask); - regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { - readTask.completeExceptionally(error); + countDownLatch.countDown(); + throw new RuntimeException(error); } else { - entityDataOptional.ifPresent(entityData -> { + net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); - }); - - readTask.complete(null); + } } }); }); BukkitExecutor.createTask().runAsync(v -> { - readChunksTasksList.forEachCompleted(p -> { - // Wait for all chunks to load. - }, error -> { - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk:"); - }); + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -300,9 +316,16 @@ private static void runActionOnUnloadedEntityChunks(Collection ch chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -478,6 +501,8 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + protected CountDownLatch chunkLoadLatch; + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; @@ -493,14 +518,10 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; - CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); - - if (this.isWaitForChunkLoad) { - futureChunk.join(); - } } } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java index 13358330a9..e1a25f6fc0 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -302,6 +302,8 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + + this.chunkLoadLatch.countDown(); } @Override @@ -362,6 +364,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + this.chunkLoadLatch.countDown(); } @Override @@ -388,11 +392,15 @@ public void onLoadedChunk(LevelChunk levelChunk) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + this.chunkLoadLatch.countDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); + + this.chunkLoadLatch.countDown(); } @Override diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java index 2d65187d86..932289e21e 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java @@ -8,7 +8,6 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.PropertiesMapper; @@ -50,7 +49,6 @@ import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; @@ -67,6 +65,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; public class NMSUtils { @@ -186,15 +185,23 @@ private static void runActionOnUnloadedChunks(Collection chunks, PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { + CountDownLatch countDownLatch; + if (chunkCallback.isWaitForChunkLoad) { + countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + } else { + countDownLatch = null; + } + List chunkCompounds = new LinkedList<>(); chunks.forEach(chunkPosition -> { - try { - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + boolean calledCountdown = false; + try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); if (chunkCompound == null) { @@ -208,18 +215,28 @@ private static void runActionOnUnloadedChunks(Collection chunks, UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); chunkCallback.onUnloadedChunk(unloadedChunkCompound); + calledCountdown = true; if (saveChunks) chunkCompounds.add(unloadedChunkCompound); } catch (Exception error) { + if (!calledCountdown && countDownLatch != null) + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + if (countDownLatch != null) { + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } + } + return chunkCompounds; }).runSync(chunkCompounds -> { chunkCompounds.forEach(unloadedChunkCompound -> { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; @@ -240,9 +257,9 @@ private static void runActionOnUnloadedChunks(Collection chunks, } private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - CompletableFutureList readChunksTasksList = new CompletableFutureList<>(-1); + CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); @@ -251,29 +268,28 @@ private static void runActionOnUnloadedEntityChunks(Collection ch ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - CompletableFuture readTask = new CompletableFuture<>(); - readChunksTasksList.add(readTask); - regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { - readTask.completeExceptionally(error); + countDownLatch.countDown(); + throw new RuntimeException(error); } else { - entityDataOptional.ifPresent(entityData -> { + net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); - }); - - readTask.complete(null); + } } }); }); BukkitExecutor.createTask().runAsync(v -> { - readChunksTasksList.forEachCompleted(p -> { - // Wait for all chunks to load. - }, error -> { - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk:"); - }); + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -294,12 +310,22 @@ private static void runActionOnUnloadedEntityChunks(Collection ch if (entityData != null) { UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); + return; } } + + chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -475,6 +501,8 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + protected CountDownLatch chunkLoadLatch; + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; @@ -490,14 +518,10 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; - CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); - - if (this.isWaitForChunkLoad) { - futureChunk.join(); - } } } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java index 6187b4a3c4..dc53e4ef7d 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java @@ -303,6 +303,8 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + + this.chunkLoadLatch.countDown(); } @Override @@ -365,6 +367,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + this.chunkLoadLatch.countDown(); } @Override @@ -391,11 +395,15 @@ public void onLoadedChunk(LevelChunk levelChunk) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + this.chunkLoadLatch.countDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); + + this.chunkLoadLatch.countDown(); } @Override diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java index 2d5e6c2482..b2bb0df6d2 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java @@ -8,7 +8,6 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.PropertiesMapper; @@ -50,7 +49,6 @@ import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; @@ -67,6 +65,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; public class NMSUtils { @@ -186,15 +185,23 @@ private static void runActionOnUnloadedChunks(Collection chunks, PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { + CountDownLatch countDownLatch; + if (chunkCallback.isWaitForChunkLoad) { + countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + } else { + countDownLatch = null; + } + List chunkCompounds = new LinkedList<>(); chunks.forEach(chunkPosition -> { - try { - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + boolean calledCountdown = false; + try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); if (chunkCompound == null) { @@ -208,18 +215,28 @@ private static void runActionOnUnloadedChunks(Collection chunks, UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); chunkCallback.onUnloadedChunk(unloadedChunkCompound); + calledCountdown = true; if (saveChunks) chunkCompounds.add(unloadedChunkCompound); } catch (Exception error) { + if (!calledCountdown && countDownLatch != null) + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + if (countDownLatch != null) { + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } + } + return chunkCompounds; }).runSync(chunkCompounds -> { chunkCompounds.forEach(unloadedChunkCompound -> { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; @@ -240,9 +257,9 @@ private static void runActionOnUnloadedChunks(Collection chunks, } private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - CompletableFutureList readChunksTasksList = new CompletableFutureList<>(-1); + CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); @@ -251,29 +268,28 @@ private static void runActionOnUnloadedEntityChunks(Collection ch ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - CompletableFuture readTask = new CompletableFuture<>(); - readChunksTasksList.add(readTask); - regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { - readTask.completeExceptionally(error); + countDownLatch.countDown(); + throw new RuntimeException(error); } else { - entityDataOptional.ifPresent(entityData -> { + net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); - }); - - readTask.complete(null); + } } }); }); BukkitExecutor.createTask().runAsync(v -> { - readChunksTasksList.forEachCompleted(p -> { - // Wait for all chunks to load. - }, error -> { - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk:"); - }); + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -296,10 +312,19 @@ private static void runActionOnUnloadedEntityChunks(Collection ch chunkCallback.onUnloadedChunk(unloadedChunkCompound); } } + + chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -475,6 +500,8 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + protected CountDownLatch chunkLoadLatch; + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; @@ -490,14 +517,10 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; - CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); - - if (this.isWaitForChunkLoad) { - futureChunk.join(); - } } } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java index 5d512de26c..ae8749640a 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java @@ -310,6 +310,8 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + + this.chunkLoadLatch.countDown(); } @Override @@ -372,6 +374,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + this.chunkLoadLatch.countDown(); } @Override @@ -398,11 +402,15 @@ public void onLoadedChunk(LevelChunk levelChunk) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + this.chunkLoadLatch.countDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); + + this.chunkLoadLatch.countDown(); } @Override diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java index f2f504e8b2..52ac55280e 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java @@ -8,7 +8,6 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.PropertiesMapper; @@ -53,7 +52,6 @@ import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.ValueInput; -import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; @@ -71,6 +69,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; public class NMSUtils { @@ -192,15 +191,23 @@ private static void runActionOnUnloadedChunks(Collection chunks, PENDING_CHUNK_ACTIONS.add(pendingTask); BukkitExecutor.createTask().runAsync(v -> { + CountDownLatch countDownLatch; + if (chunkCallback.isWaitForChunkLoad) { + countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + } else { + countDownLatch = null; + } + List chunkCompounds = new LinkedList<>(); chunks.forEach(chunkPosition -> { - try { - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + boolean calledCountdown = false; + try { net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); if (chunkCompound == null) { @@ -214,18 +221,28 @@ private static void runActionOnUnloadedChunks(Collection chunks, UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); chunkCallback.onUnloadedChunk(unloadedChunkCompound); + calledCountdown = true; if (saveChunks) chunkCompounds.add(unloadedChunkCompound); } catch (Exception error) { + if (!calledCountdown && countDownLatch != null) + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + if (countDownLatch != null) { + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } + } + return chunkCompounds; }).runSync(chunkCompounds -> { chunkCompounds.forEach(unloadedChunkCompound -> { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; @@ -246,9 +263,9 @@ private static void runActionOnUnloadedChunks(Collection chunks, } private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - CompletableFutureList readChunksTasksList = new CompletableFutureList<>(-1); + CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { chunks.forEach(chunkPosition -> { ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); @@ -257,29 +274,28 @@ private static void runActionOnUnloadedEntityChunks(Collection ch ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - CompletableFuture readTask = new CompletableFuture<>(); - readChunksTasksList.add(readTask); - regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { if (error != null) { - readTask.completeExceptionally(error); + countDownLatch.countDown(); + throw new RuntimeException(error); } else { - entityDataOptional.ifPresent(entityData -> { + net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); - }); - - readTask.complete(null); + } } }); }); BukkitExecutor.createTask().runAsync(v -> { - readChunksTasksList.forEachCompleted(p -> { - // Wait for all chunks to load. - }, error -> { - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk:"); - }); + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -306,9 +322,16 @@ private static void runActionOnUnloadedEntityChunks(Collection ch chunkCallback.onChunkNotExist(chunkPosition); } catch (IOException error) { + countDownLatch.countDown(); Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); } }); + + try { + countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } }).runSync(v -> { chunkCallback.onFinish(); }); @@ -489,6 +512,8 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + protected CountDownLatch chunkLoadLatch; + public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { this.chunkLoadReason = chunkLoadReason; this.isWaitForChunkLoad = isWaitForChunkLoad; @@ -504,14 +529,10 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; - CompletableFuture futureChunk = ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); }); - - if (this.isWaitForChunkLoad) { - futureChunk.join(); - } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/SynchronizedTasks.java b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/SynchronizedTasks.java new file mode 100644 index 0000000000..0674794bf1 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/SynchronizedTasks.java @@ -0,0 +1,43 @@ +package com.bgsoftware.superiorskyblock.core.threads; + +import org.bukkit.Bukkit; + +import javax.annotation.Nullable; +import java.util.concurrent.CountDownLatch; + +public class SynchronizedTasks { + + @Nullable + private final CountDownLatch countDownLatch; + @Nullable + private final Runnable onFinishCallback; + + public SynchronizedTasks(int count, @Nullable Runnable onFinishCallback) { + this.countDownLatch = count <= 0 ? null : new CountDownLatch(count); + this.onFinishCallback = onFinishCallback; + } + + public void notifyTaskComplete() { + if (this.countDownLatch != null) + this.countDownLatch.countDown(); + } + + public void waitAllAsync() { + if (Bukkit.isPrimaryThread()) { + BukkitExecutor.async(this::waitAllAsync); + return; + } + + if (this.countDownLatch != null) { + try { + this.countDownLatch.await(); + } catch (InterruptedException error) { + throw new RuntimeException(error); + } + } + + if (this.onFinishCallback != null) + this.onFinishCallback.run(); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index bea2567426..5bc1110bdb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -665,7 +665,7 @@ public void forceSortIslands(SortingType sortingType) { } @Override - public void sortIslands(SortingType sortingType, Runnable onFinish) { + public void sortIslands(SortingType sortingType, @Nullable Runnable onFinish) { Preconditions.checkNotNull(sortingType, "sortingType parameter cannot be null."); Log.debug(Debug.SORT_ISLANDS, sortingType.getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java index 76f50f001b..51925f78f1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java @@ -20,6 +20,7 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.core.threads.SynchronizedTasks; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; @@ -283,11 +284,13 @@ public static void handleBanPlayer(SuperiorPlayer caller, Island island, Superio } public static void deleteChunks(Island island, List chunkPositions, Runnable onFinish) { - plugin.getNMSChunks().deleteChunks(island, chunkPositions, onFinish); + SynchronizedTasks synchronizedTasks = new SynchronizedTasks(1, onFinish); chunkPositions.forEach(chunkPosition -> { plugin.getStackedBlocks().removeStackedBlocks(chunkPosition); PluginEventsFactory.callIslandChunkResetEvent(island, chunkPosition); }); + plugin.getNMSChunks().deleteChunks(island, chunkPositions, synchronizedTasks::notifyTaskComplete); + synchronizedTasks.waitAllAsync(); } public static boolean isValidRoleForLimit(PlayerRole playerRole) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 5dce6bf8fd..72aff47c37 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -76,6 +76,7 @@ import com.bgsoftware.superiorskyblock.core.profiler.Profiler; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.bgsoftware.superiorskyblock.core.threads.SynchronizedTasks; import com.bgsoftware.superiorskyblock.core.value.DoubleValue; import com.bgsoftware.superiorskyblock.core.value.IntValue; import com.bgsoftware.superiorskyblock.core.value.Value; @@ -1311,38 +1312,46 @@ public void resetChunks(@IslandChunkFlags int flags) { public void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish) { final int realFlags = flags | IslandChunkFlags.NO_EMPTY_CHUNKS; - for (World registeredWorld : plugin.getGrid().getRegisteredWorlds()) { - WorldInfo worldInfo = WorldInfo.of(registeredWorld); - List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, realFlags); - if (!chunkPositions.isEmpty()) - IslandUtils.deleteChunks(this, chunkPositions, null); - } - - MutableObject lastDimension = new MutableObject<>(null); - boolean hasDimension = false; + List dimensionList = new LinkedList<>(); for (Dimension dimension : Dimension.values()) { if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && wasSchematicGenerated(dimension)) { - hasDimension = true; - lastDimension.setValue(dimension); - IslandWorlds.accessIslandWorldAsync(this, dimension, true, result -> { - result.ifLeft(world -> { - WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); - List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, realFlags); - if (!chunkPositions.isEmpty()) { - IslandUtils.deleteChunks(this, chunkPositions, - dimension == lastDimension.getValue() ? onFinish : null); - } - }).ifRight(err -> { - if (onFinish != null && dimension == lastDimension.getValue()) - onFinish.run(); - }); - }); + dimensionList.add(dimension); } } - if (!hasDimension && onFinish != null) - onFinish.run(); + List customWorlds = plugin.getGrid().getRegisteredWorlds(); + + SynchronizedTasks synchronizedTasks = new SynchronizedTasks(dimensionList.size() + customWorlds.size(), onFinish); + + customWorlds.forEach(registeredWorld -> { + WorldInfo worldInfo = WorldInfo.of(registeredWorld); + List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, realFlags); + if (!chunkPositions.isEmpty()) { + IslandUtils.deleteChunks(this, chunkPositions, synchronizedTasks::notifyTaskComplete); + } else { + synchronizedTasks.notifyTaskComplete(); + } + }); + + dimensionList.forEach(dimension -> { + IslandWorlds.accessIslandWorldAsync(this, dimension, true, result -> { + result.ifLeft(world -> { + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); + List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, realFlags); + if (!chunkPositions.isEmpty()) { + IslandUtils.deleteChunks(this, chunkPositions, synchronizedTasks::notifyTaskComplete); + } else { + synchronizedTasks.notifyTaskComplete(); + } + }).ifRight(error -> { + synchronizedTasks.notifyTaskComplete(); + throw new RuntimeException(error); + }); + }); + }); + + synchronizedTasks.waitAllAsync(); } @Override @@ -1355,18 +1364,17 @@ public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, @Nulla Preconditions.checkNotNull(dimension, "dimension parameter cannot be null"); IslandWorlds.accessIslandWorldAsync(this, dimension, true, result -> { - if (result.getRight() == null) { + result.ifRight(error -> { + throw new RuntimeException(error); + }).ifLeft(world -> { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, dimension); - List chunkPositions = IslandUtils.getChunkCoords(this, - worldInfo, flags | IslandChunkFlags.NO_EMPTY_CHUNKS); + List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, flags | IslandChunkFlags.NO_EMPTY_CHUNKS); if (!chunkPositions.isEmpty()) { IslandUtils.deleteChunks(this, chunkPositions, onFinish); - return; + } else if (onFinish != null) { + onFinish.run(); } - } - - if (onFinish != null) - onFinish.run(); + }); }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index 9323169aa1..5b4a7cbbf4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -173,7 +173,7 @@ public void sortIslands(SortingType sortingType, Runnable onFinish) { } @Override - public void sortIslands(SortingType sortingType, boolean forceSort, Runnable onFinish) { + public void sortIslands(SortingType sortingType, boolean forceSort, @Nullable Runnable onFinish) { ensureSortingType(sortingType); Synchronized> sortedIslands = this.sortedIslands.get(sortingType); @@ -218,7 +218,7 @@ private void ensureSortingType(SortingType sortingType) { Preconditions.checkState(sortedIslands.containsKey(sortingType), "The sorting-type " + sortingType + " doesn't exist in the database. Please contact author!"); } - private void sortIslandsInternal(SortingType sortingType, Runnable onFinish) { + private void sortIslandsInternal(SortingType sortingType, @Nullable Runnable onFinish) { List existingIslands = new LinkedList<>(islandsByUUID.values()); existingIslands.removeIf(Island::isIgnored); From 79b5a05ab1254eacabc408d61b78c8f5c34cce9a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 2 Oct 2025 14:48:14 +0300 Subject: [PATCH 355/600] Fix NPE when accessing chunkLoadLatch (#2688) --- .../superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java | 8 ++++---- .../superiorskyblock/nms/v1_16_R3/NMSUtils.java | 6 ++++++ .../superiorskyblock/nms/v1_17/NMSChunksImpl.java | 8 ++++---- .../bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java | 6 ++++++ .../superiorskyblock/nms/v1_18/NMSChunksImpl.java | 8 ++++---- .../bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java | 6 ++++++ .../superiorskyblock/nms/v1_19/NMSChunksImpl.java | 8 ++++---- .../bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java | 6 ++++++ .../superiorskyblock/nms/v1_20_3/NMSChunksImpl.java | 8 ++++---- .../bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java | 6 ++++++ .../superiorskyblock/nms/v1_20_4/NMSChunksImpl.java | 8 ++++---- .../bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java | 6 ++++++ .../superiorskyblock/nms/v1_21/NMSChunksImpl.java | 8 ++++---- .../bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java | 6 ++++++ .../superiorskyblock/nms/v1_21_3/NMSChunksImpl.java | 8 ++++---- .../bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java | 6 ++++++ .../superiorskyblock/nms/v1_21_4/NMSChunksImpl.java | 8 ++++---- .../bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java | 6 ++++++ .../superiorskyblock/nms/v1_21_5/NMSChunksImpl.java | 8 ++++---- .../bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java | 6 ++++++ .../superiorskyblock/nms/v1_21_7/NMSChunksImpl.java | 8 ++++---- .../bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java | 6 ++++++ 22 files changed, 110 insertions(+), 44 deletions(-) diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java index 411b2c1bff..48cb45397f 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java @@ -247,7 +247,7 @@ public void onLoadedChunk(Chunk chunk) { chunk.getPos().x, chunk.getPos().z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, chunk.getSections())); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -269,7 +269,7 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloaded allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -297,7 +297,7 @@ public void onLoadedChunk(Chunk chunk) { chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -305,7 +305,7 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound entityDa WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); unloadedEntityTags.add(new Pair<>(worldServer, entityData.getList("Entities", 10))); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java index 080d79eca1..d14024458a 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java @@ -323,6 +323,7 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { @@ -336,6 +337,11 @@ public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad public abstract void onFinish(); + protected final void latchCountDown() { + if (this.chunkLoadLatch != null) + this.chunkLoadLatch.countDown(); + } + public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java index c93a1047b0..74ab59f8fa 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java @@ -253,7 +253,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.getSections())); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -276,7 +276,7 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag unloadedChu allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -304,7 +304,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -312,7 +312,7 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag entityData) ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); unloadedEntityTags.add(new Pair<>(serverLevel, entityData.getList("Entities", 10))); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java index f017267d9c..acc2479106 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java @@ -384,6 +384,7 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { @@ -397,6 +398,11 @@ public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad public abstract void onFinish(); + protected final void latchCountDown() { + if (this.chunkLoadLatch != null) + this.chunkLoadLatch.countDown(); + } + public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java index c178830217..f996bd3de4 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java @@ -312,7 +312,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.getSections())); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -376,7 +376,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -404,14 +404,14 @@ public void onLoadedChunk(LevelChunk levelChunk) { chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java index 86f326c317..eb3162804f 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java @@ -426,6 +426,7 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { @@ -447,6 +448,11 @@ public final void setChunkLoadLatch(CountDownLatch chunkLoadLatch) { public abstract void onFinish(); + protected final void latchCountDown() { + if (this.chunkLoadLatch != null) + this.chunkLoadLatch.countDown(); + } + public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java index 4b1195b870..dbe60e9a1c 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java @@ -318,7 +318,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.getSections())); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -382,7 +382,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -410,14 +410,14 @@ public void onLoadedChunk(LevelChunk levelChunk) { chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java index d3eb991c15..30b2627e2a 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java @@ -474,6 +474,7 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { @@ -487,6 +488,11 @@ public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad public abstract void onFinish(); + protected final void latchCountDown() { + if (this.chunkLoadLatch != null) + this.chunkLoadLatch.countDown(); + } + public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java index 83c1a2729b..1569ba10a7 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java @@ -326,7 +326,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -390,7 +390,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -418,14 +418,14 @@ public void onLoadedChunk(LevelChunk levelChunk) { chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java index 706d05e8d3..81a35ff74e 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java @@ -468,6 +468,7 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { @@ -481,6 +482,11 @@ public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad public abstract void onFinish(); + protected final void latchCountDown() { + if (this.chunkLoadLatch != null) + this.chunkLoadLatch.countDown(); + } + public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java index 2811707dff..f6aa57651a 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java @@ -315,7 +315,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -377,7 +377,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -405,14 +405,14 @@ public void onLoadedChunk(LevelChunk levelChunk) { chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java index fa49f8527a..5bde897d71 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java @@ -470,6 +470,7 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { @@ -483,6 +484,11 @@ public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad public abstract void onFinish(); + protected final void latchCountDown() { + if (this.chunkLoadLatch != null) + this.chunkLoadLatch.countDown(); + } + public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java index 7e30c7dea9..d64e69653d 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java @@ -302,7 +302,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -364,7 +364,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -392,14 +392,14 @@ public void onLoadedChunk(LevelChunk levelChunk) { chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java index a8edbc4a34..10a7713b6f 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java @@ -494,6 +494,7 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { @@ -507,6 +508,11 @@ public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad public abstract void onFinish(); + protected final void latchCountDown() { + if (this.chunkLoadLatch != null) + this.chunkLoadLatch.countDown(); + } + public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java index 10b43dcf5d..127b4dd613 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java @@ -303,7 +303,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -365,7 +365,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -393,14 +393,14 @@ public void onLoadedChunk(LevelChunk levelChunk) { chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java index fba7d1bd35..7d4133d4fc 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java @@ -501,6 +501,7 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { @@ -514,6 +515,11 @@ public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad public abstract void onFinish(); + protected final void latchCountDown() { + if (this.chunkLoadLatch != null) + this.chunkLoadLatch.countDown(); + } + public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java index e1a25f6fc0..b7df630172 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -303,7 +303,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -365,7 +365,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -393,14 +393,14 @@ public void onLoadedChunk(LevelChunk levelChunk) { chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java index 932289e21e..b2a65d2fbb 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java @@ -501,6 +501,7 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { @@ -514,6 +515,11 @@ public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad public abstract void onFinish(); + protected final void latchCountDown() { + if (this.chunkLoadLatch != null) + this.chunkLoadLatch.countDown(); + } + public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java index dc53e4ef7d..eff5fa3cd2 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java @@ -304,7 +304,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -368,7 +368,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -396,14 +396,14 @@ public void onLoadedChunk(LevelChunk levelChunk) { chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java index b2bb0df6d2..607a6a293c 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java @@ -500,6 +500,7 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { @@ -513,6 +514,11 @@ public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad public abstract void onFinish(); + protected final void latchCountDown() { + if (this.chunkLoadLatch != null) + this.chunkLoadLatch.countDown(); + } + public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java index ae8749640a..3c1739e6c4 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java @@ -311,7 +311,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -375,7 +375,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override @@ -403,14 +403,14 @@ public void onLoadedChunk(LevelChunk levelChunk) { chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { unloadedChunkCompounds.add(unloadedChunkCompound); - this.chunkLoadLatch.countDown(); + latchCountDown(); } @Override diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java index 52ac55280e..ee2dcf8a71 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java @@ -512,6 +512,7 @@ public static abstract class ChunkCallback { private final ChunkLoadReason chunkLoadReason; private final boolean isWaitForChunkLoad; + @Nullable protected CountDownLatch chunkLoadLatch; public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { @@ -525,6 +526,11 @@ public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad public abstract void onFinish(); + protected final void latchCountDown() { + if (this.chunkLoadLatch != null) + this.chunkLoadLatch.countDown(); + } + public final void onChunkNotExist(ChunkPosition chunkPosition) { if (!plugin.getProviders().hasCustomWorldsSupport()) return; From a99c04b9cd61a49ca6b0625248a15cbec51353b9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 4 Oct 2025 16:08:41 +0300 Subject: [PATCH 356/600] Generate NMS code for each version --- NMS/build.gradle | 53 +- .../AbstractNMSAlgorithms.java.template | 312 ++++++++++ .../templates/AbstractNMSChunks.java.template | 278 +++++++++ .../AbstractNMSEntities.java.template | 51 ++ .../templates/AbstractNMSTags.java.template | 116 ++++ .../templates/AbstractNMSWorld.java.template | 364 ++++++++++++ .../NMSDragonFightImpl.java.template} | 19 +- .../templates/NMSHologramsImpl.java.template | 29 + .../templates/NMSPlayersImpl.java.template} | 9 +- .../main/templates/NMSUtils.java.template} | 222 ++++--- .../crops/CropsBlockEntity.java.template} | 5 +- .../CropsTickingBlockEntity.java.template} | 2 +- .../crops/CropsTickingMethod.java.template} | 19 +- ...tractIslandEntityEnderDragon.java.template | 84 +++ .../dragon/DragonUtils.java.template} | 2 +- ...dWorldEndDragonFightHandler.java.template} | 2 +- .../IslandEndDragonFight.java.template} | 20 +- .../dragon/SpikesCache.java.template} | 2 +- .../IslandsGeneratorImpl.java.template} | 2 +- .../AbstractEntityHologram.java.template | 140 +++++ ...MenuBrewingStandBlockEntity.java.template} | 2 +- .../MenuDispenserBlockEntity.java.template} | 2 +- .../MenuFurnaceBlockEntity.java.template} | 2 +- .../menu/MenuHopperBlockEntity.java.template} | 2 +- .../OfflinePlayerDataImpl.java.template} | 15 +- ...gSpawnerBlockEntityNotifier.java.template} | 2 +- .../utils/SetBlockContext.java.template | 31 + .../utils/TickingBlockList.java.template | 9 + .../world/BlockEntityCache.java.template} | 5 +- .../world/ChunkReaderImpl.java.template} | 55 +- .../world/KeyBlocksCache.java.template} | 7 +- .../world/PropertiesMapper.java.template} | 5 +- .../WorldEditSessionDataImpl.java.template} | 3 +- .../world/WorldEditSessionImpl.java.template} | 234 +++----- NMS/v1_17/properties | 7 + .../nms/v1_17/NMSAlgorithmsImpl.java | 274 +-------- .../nms/v1_17/NMSChunksImpl.java | 329 +++-------- .../nms/v1_17/NMSDragonFightImpl.java | 119 ---- .../nms/v1_17/NMSEntitiesImpl.java | 36 +- .../nms/v1_17/NMSHologramsImpl.java | 193 ------- .../nms/v1_17/NMSPlayersImpl.java | 123 ---- .../nms/v1_17/NMSTagsImpl.java | 96 +-- .../superiorskyblock/nms/v1_17/NMSUtils.java | 418 -------------- .../nms/v1_17/NMSWorldImpl.java | 336 +---------- .../nms/v1_17/crops/CropsBlockEntity.java | 96 --- .../v1_17/crops/CropsTickingBlockEntity.java | 31 - .../nms/v1_17/crops/CropsTickingMethod.java | 157 ----- .../nms/v1_17/dragon/DragonUtils.java | 37 -- .../dragon/EndWorldEndDragonFightHandler.java | 49 -- .../v1_17/dragon/IslandEndDragonFight.java | 209 ------- .../v1_17/dragon/IslandEntityEnderDragon.java | 68 +-- .../nms/v1_17/dragon/SpikesCache.java | 179 ------ .../v1_17/generator/IslandsGeneratorImpl.java | 73 --- .../nms/v1_17/hologram/EntityHologram.java | 39 ++ .../menu/MenuBrewingStandBlockEntity.java | 24 - .../v1_17/menu/MenuDispenserBlockEntity.java | 24 - .../v1_17/menu/MenuFurnaceBlockEntity.java | 24 - .../nms/v1_17/menu/MenuHopperBlockEntity.java | 24 - .../v1_17/player/OfflinePlayerDataImpl.java | 74 --- .../TickingSpawnerBlockEntityNotifier.java | 57 -- .../nms/v1_17/utils/NMSUtilsVersioned.java | 288 +++++++++ .../nms/v1_17/world/BlockEntityCache.java | 34 -- .../nms/v1_17/world/ChunkReaderImpl.java | 248 -------- .../nms/v1_17/world/KeyBlocksCache.java | 32 - .../nms/v1_17/world/PropertiesMapper.java | 84 --- .../world/PropertiesMapperVersioned.java | 15 + .../nms/v1_17/world/WorldEditSessionImpl.java | 464 --------------- NMS/v1_18/properties | 7 + .../nms/v1_18/NMSAlgorithmsImpl.java | 275 +-------- .../nms/v1_18/NMSChunksImpl.java | 314 ++-------- .../nms/v1_18/NMSDragonFightImpl.java | 119 ---- .../nms/v1_18/NMSEntitiesImpl.java | 35 +- .../nms/v1_18/NMSHologramsImpl.java | 193 ------- .../nms/v1_18/NMSPlayersImpl.java | 123 ---- .../nms/v1_18/NMSTagsImpl.java | 96 +-- .../nms/v1_18/NMSWorldImpl.java | 339 +---------- .../nms/v1_18/crops/CropsBlockEntity.java | 96 --- .../v1_18/crops/CropsTickingBlockEntity.java | 31 - .../nms/v1_18/crops/CropsTickingMethod.java | 157 ----- .../dragon/EndWorldEndDragonFightHandler.java | 49 -- .../v1_18/dragon/IslandEndDragonFight.java | 206 ------- .../v1_18/dragon/IslandEntityEnderDragon.java | 69 +-- .../nms/v1_18/dragon/SpikesCache.java | 189 ------ .../v1_18/generator/IslandsGeneratorImpl.java | 66 --- .../nms/v1_18/hologram/EntityHologram.java | 39 ++ .../menu/MenuBrewingStandBlockEntity.java | 24 - .../v1_18/menu/MenuDispenserBlockEntity.java | 24 - .../v1_18/menu/MenuFurnaceBlockEntity.java | 24 - .../nms/v1_18/menu/MenuHopperBlockEntity.java | 24 - .../v1_18/player/OfflinePlayerDataImpl.java | 74 --- .../TickingSpawnerBlockEntityNotifier.java | 57 -- .../nms/v1_18/utils/NMSUtilsVersioned.java | 279 +++++++++ .../nms/v1_18/world/PropertiesMapper.java | 84 --- .../world/PropertiesMapperVersioned.java | 15 + .../v1_18/world/WorldEditSessionDataImpl.java | 167 ------ NMS/v1_19/properties | 7 + .../nms/v1_19/NMSAlgorithmsImpl.java | 291 +--------- .../nms/v1_19/NMSChunksImpl.java | 316 ++-------- .../nms/v1_19/NMSDragonFightImpl.java | 119 ---- .../nms/v1_19/NMSEntitiesImpl.java | 35 +- .../nms/v1_19/NMSHologramsImpl.java | 193 ------- .../nms/v1_19/NMSPlayersImpl.java | 123 ---- .../nms/v1_19/NMSTagsImpl.java | 96 +-- .../superiorskyblock/nms/v1_19/NMSUtils.java | 508 ---------------- .../nms/v1_19/NMSWorldImpl.java | 335 +---------- .../nms/v1_19/crops/CropsBlockEntity.java | 96 --- .../v1_19/crops/CropsTickingBlockEntity.java | 30 - .../nms/v1_19/crops/CropsTickingMethod.java | 157 ----- .../nms/v1_19/dragon/DragonUtils.java | 37 -- .../dragon/EndWorldEndDragonFightHandler.java | 49 -- .../v1_19/dragon/IslandEndDragonFight.java | 206 ------- .../v1_19/dragon/IslandEntityEnderDragon.java | 69 +-- .../nms/v1_19/hologram/EntityHologram.java | 39 ++ .../menu/MenuBrewingStandBlockEntity.java | 24 - .../v1_19/menu/MenuDispenserBlockEntity.java | 24 - .../v1_19/menu/MenuFurnaceBlockEntity.java | 24 - .../nms/v1_19/menu/MenuHopperBlockEntity.java | 24 - .../v1_19/player/OfflinePlayerDataImpl.java | 74 --- .../nms/v1_19/utils/NMSUtilsVersioned.java | 310 ++++++++++ .../nms/v1_19/world/BlockEntityCache.java | 34 -- .../nms/v1_19/world/ChunkReaderImpl.java | 231 -------- .../nms/v1_19/world/KeyBlocksCache.java | 32 - .../world/PropertiesMapperVersioned.java | 17 + .../v1_19/world/WorldEditSessionDataImpl.java | 167 ------ .../nms/v1_19/world/WorldEditSessionImpl.java | 440 -------------- NMS/v1_20_3/properties | 7 + .../nms/v1_20_3/NMSAlgorithmsImpl.java | 294 +--------- .../nms/v1_20_3/NMSChunksImpl.java | 344 ++--------- .../nms/v1_20_3/NMSDragonFightImpl.java | 118 ---- .../nms/v1_20_3/NMSEntitiesImpl.java | 35 +- .../nms/v1_20_3/NMSHologramsImpl.java | 193 ------- .../nms/v1_20_3/NMSPlayersImpl.java | 123 ---- .../nms/v1_20_3/NMSTagsImpl.java | 96 +-- .../nms/v1_20_3/NMSUtils.java | 502 ---------------- .../nms/v1_20_3/NMSWorldImpl.java | 347 +---------- .../nms/v1_20_3/crops/CropsBlockEntity.java | 96 --- .../crops/CropsTickingBlockEntity.java | 30 - .../nms/v1_20_3/crops/CropsTickingMethod.java | 157 ----- .../nms/v1_20_3/dragon/DragonUtils.java | 37 -- .../dragon/EndWorldEndDragonFightHandler.java | 48 -- .../v1_20_3/dragon/IslandEndDragonFight.java | 211 ------- .../dragon/IslandEntityEnderDragon.java | 69 +-- .../nms/v1_20_3/dragon/SpikesCache.java | 189 ------ .../generator/IslandsGeneratorImpl.java | 67 --- .../nms/v1_20_3/hologram/EntityHologram.java | 39 ++ .../menu/MenuBrewingStandBlockEntity.java | 24 - .../menu/MenuDispenserBlockEntity.java | 24 - .../v1_20_3/menu/MenuFurnaceBlockEntity.java | 24 - .../v1_20_3/menu/MenuHopperBlockEntity.java | 24 - .../v1_20_3/player/OfflinePlayerDataImpl.java | 76 --- .../TickingSpawnerBlockEntityNotifier.java | 57 -- .../nms/v1_20_3/utils/NMSUtilsVersioned.java | 307 ++++++++++ .../nms/v1_20_3/world/BlockEntityCache.java | 34 -- .../nms/v1_20_3/world/ChunkReaderImpl.java | 242 -------- .../nms/v1_20_3/world/KeyBlocksCache.java | 32 - .../nms/v1_20_3/world/PropertiesMapper.java | 85 --- .../world/PropertiesMapperVersioned.java | 17 + .../world/WorldEditSessionDataImpl.java | 167 ------ .../v1_20_3/world/WorldEditSessionImpl.java | 492 ---------------- NMS/v1_20_4/properties | 7 + .../nms/v1_20_4/NMSAlgorithmsImpl.java | 308 +--------- .../nms/v1_20_4/NMSChunksImpl.java | 334 ++--------- .../nms/v1_20_4/NMSEntitiesImpl.java | 35 +- .../nms/v1_20_4/NMSHologramsImpl.java | 193 ------- .../nms/v1_20_4/NMSTagsImpl.java | 115 +--- .../nms/v1_20_4/NMSUtils.java | 504 ---------------- .../nms/v1_20_4/NMSWorldImpl.java | 347 +---------- .../nms/v1_20_4/crops/CropsBlockEntity.java | 96 --- .../nms/v1_20_4/crops/CropsTickingMethod.java | 156 ----- .../nms/v1_20_4/dragon/DragonUtils.java | 37 -- .../v1_20_4/dragon/IslandEndDragonFight.java | 211 ------- .../dragon/IslandEntityEnderDragon.java | 71 +-- .../nms/v1_20_4/dragon/SpikesCache.java | 189 ------ .../generator/IslandsGeneratorImpl.java | 67 --- .../nms/v1_20_4/hologram/EntityHologram.java | 39 ++ .../menu/MenuBrewingStandBlockEntity.java | 24 - .../menu/MenuDispenserBlockEntity.java | 24 - .../v1_20_4/menu/MenuFurnaceBlockEntity.java | 24 - .../v1_20_4/player/OfflinePlayerDataImpl.java | 75 --- .../TickingSpawnerBlockEntityNotifier.java | 57 -- .../nms/v1_20_4/utils/NMSUtilsVersioned.java | 361 ++++++++++++ .../nms/v1_20_4/world/BlockEntityCache.java | 34 -- .../nms/v1_20_4/world/ChunkReaderImpl.java | 243 -------- .../nms/v1_20_4/world/KeyBlocksCache.java | 32 - .../nms/v1_20_4/world/PropertiesMapper.java | 85 --- .../world/PropertiesMapperVersioned.java | 17 + .../world/WorldEditSessionDataImpl.java | 167 ------ .../v1_20_4/world/WorldEditSessionImpl.java | 486 ---------------- NMS/v1_21/properties | 7 + .../nms/v1_21/NMSAlgorithmsImpl.java | 288 +-------- .../nms/v1_21/NMSChunksImpl.java | 307 ++-------- .../nms/v1_21/NMSDragonFightImpl.java | 118 ---- .../nms/v1_21/NMSEntitiesImpl.java | 34 +- .../nms/v1_21/NMSHologramsImpl.java | 193 ------- .../nms/v1_21/NMSPlayersImpl.java | 123 ---- .../nms/v1_21/NMSTagsImpl.java | 117 +--- .../superiorskyblock/nms/v1_21/NMSUtils.java | 528 ----------------- .../nms/v1_21/NMSWorldImpl.java | 369 +----------- .../v1_21/crops/CropsTickingBlockEntity.java | 30 - .../nms/v1_21/crops/CropsTickingMethod.java | 164 ------ .../nms/v1_21/dragon/DragonUtils.java | 37 -- .../dragon/EndWorldEndDragonFightHandler.java | 48 -- .../v1_21/dragon/IslandEntityEnderDragon.java | 71 +-- .../nms/v1_21/dragon/SpikesCache.java | 189 ------ .../v1_21/generator/IslandsGeneratorImpl.java | 67 --- .../nms/v1_21/hologram/EntityHologram.java | 39 ++ .../nms/v1_21/menu/MenuHopperBlockEntity.java | 26 - .../v1_21/player/OfflinePlayerDataImpl.java | 75 --- .../TickingSpawnerBlockEntityNotifier.java | 57 -- .../nms/v1_21/utils/NMSUtilsVersioned.java | 370 ++++++++++++ .../nms/v1_21/world/BlockEntityCache.java | 34 -- .../nms/v1_21/world/ChunkReaderImpl.java | 243 -------- .../nms/v1_21/world/KeyBlocksCache.java | 32 - .../nms/v1_21/world/PropertiesMapper.java | 85 --- .../world/PropertiesMapperVersioned.java | 17 + .../v1_21/world/WorldEditSessionDataImpl.java | 167 ------ .../nms/v1_21/world/WorldEditSessionImpl.java | 480 --------------- NMS/v1_21_3/properties | 7 + .../nms/v1_21_3/NMSAlgorithmsImpl.java | 271 +-------- .../nms/v1_21_3/NMSChunksImpl.java | 307 ++-------- .../nms/v1_21_3/NMSDragonFightImpl.java | 118 ---- .../nms/v1_21_3/NMSEntitiesImpl.java | 34 +- .../nms/v1_21_3/NMSHologramsImpl.java | 188 ------ .../nms/v1_21_3/NMSPlayersImpl.java | 123 ---- .../nms/v1_21_3/NMSTagsImpl.java | 117 +--- .../nms/v1_21_3/NMSUtils.java | 535 ----------------- .../nms/v1_21_3/NMSWorldImpl.java | 369 +----------- .../nms/v1_21_3/crops/CropsBlockEntity.java | 102 ---- .../crops/CropsTickingBlockEntity.java | 30 - .../nms/v1_21_3/crops/CropsTickingMethod.java | 159 ----- .../nms/v1_21_3/dragon/DragonUtils.java | 37 -- .../dragon/EndWorldEndDragonFightHandler.java | 48 -- .../v1_21_3/dragon/IslandEndDragonFight.java | 211 ------- .../dragon/IslandEntityEnderDragon.java | 75 +-- .../nms/v1_21_3/dragon/SpikesCache.java | 189 ------ .../generator/IslandsGeneratorImpl.java | 67 --- .../nms/v1_21_3/hologram/EntityHologram.java | 39 ++ .../menu/MenuBrewingStandBlockEntity.java | 24 - .../menu/MenuDispenserBlockEntity.java | 24 - .../v1_21_3/menu/MenuFurnaceBlockEntity.java | 24 - .../v1_21_3/menu/MenuHopperBlockEntity.java | 26 - .../v1_21_3/player/OfflinePlayerDataImpl.java | 75 --- .../TickingSpawnerBlockEntityNotifier.java | 57 -- .../nms/v1_21_3/utils/NMSUtilsVersioned.java | 375 ++++++++++++ .../nms/v1_21_3/world/BlockEntityCache.java | 34 -- .../nms/v1_21_3/world/ChunkReaderImpl.java | 243 -------- .../nms/v1_21_3/world/KeyBlocksCache.java | 32 - .../nms/v1_21_3/world/PropertiesMapper.java | 85 --- .../world/PropertiesMapperVersioned.java | 17 + .../world/WorldEditSessionDataImpl.java | 167 ------ .../v1_21_3/world/WorldEditSessionImpl.java | 479 --------------- NMS/v1_21_4/properties | 7 + .../nms/v1_21_4/NMSAlgorithmsImpl.java | 289 +-------- .../nms/v1_21_4/NMSChunksImpl.java | 307 ++-------- .../nms/v1_21_4/NMSDragonFightImpl.java | 118 ---- .../nms/v1_21_4/NMSEntitiesImpl.java | 34 +- .../nms/v1_21_4/NMSHologramsImpl.java | 188 ------ .../nms/v1_21_4/NMSPlayersImpl.java | 123 ---- .../nms/v1_21_4/NMSTagsImpl.java | 117 +--- .../nms/v1_21_4/NMSUtils.java | 535 ----------------- .../nms/v1_21_4/NMSWorldImpl.java | 369 +----------- .../nms/v1_21_4/crops/CropsBlockEntity.java | 102 ---- .../crops/CropsTickingBlockEntity.java | 30 - .../nms/v1_21_4/dragon/DragonUtils.java | 37 -- .../dragon/EndWorldEndDragonFightHandler.java | 48 -- .../v1_21_4/dragon/IslandEndDragonFight.java | 211 ------- .../dragon/IslandEntityEnderDragon.java | 75 +-- .../nms/v1_21_4/dragon/SpikesCache.java | 189 ------ .../generator/IslandsGeneratorImpl.java | 67 --- .../nms/v1_21_4/hologram/EntityHologram.java | 39 ++ .../menu/MenuBrewingStandBlockEntity.java | 24 - .../menu/MenuDispenserBlockEntity.java | 24 - .../v1_21_4/menu/MenuFurnaceBlockEntity.java | 24 - .../v1_21_4/menu/MenuHopperBlockEntity.java | 26 - .../TickingSpawnerBlockEntityNotifier.java | 57 -- .../nms/v1_21_4/utils/NMSUtilsVersioned.java | 375 ++++++++++++ .../nms/v1_21_4/world/BlockEntityCache.java | 34 -- .../nms/v1_21_4/world/ChunkReaderImpl.java | 243 -------- .../nms/v1_21_4/world/KeyBlocksCache.java | 32 - .../nms/v1_21_4/world/PropertiesMapper.java | 85 --- .../world/PropertiesMapperVersioned.java | 17 + .../world/WorldEditSessionDataImpl.java | 167 ------ .../v1_21_4/world/WorldEditSessionImpl.java | 478 --------------- NMS/v1_21_5/properties | 7 + .../nms/v1_21_5/NMSAlgorithmsImpl.java | 289 +-------- .../nms/v1_21_5/NMSChunksImpl.java | 307 ++-------- .../nms/v1_21_5/NMSDragonFightImpl.java | 118 ---- .../nms/v1_21_5/NMSEntitiesImpl.java | 34 +- .../nms/v1_21_5/NMSHologramsImpl.java | 188 ------ .../nms/v1_21_5/NMSPlayersImpl.java | 123 ---- .../nms/v1_21_5/NMSTagsImpl.java | 117 +--- .../nms/v1_21_5/NMSUtils.java | 534 ----------------- .../nms/v1_21_5/NMSWorldImpl.java | 369 +----------- .../nms/v1_21_5/crops/CropsBlockEntity.java | 102 ---- .../crops/CropsTickingBlockEntity.java | 31 - .../nms/v1_21_5/crops/CropsTickingMethod.java | 159 ----- .../nms/v1_21_5/dragon/DragonUtils.java | 37 -- .../dragon/EndWorldEndDragonFightHandler.java | 48 -- .../v1_21_5/dragon/IslandEndDragonFight.java | 212 ------- .../dragon/IslandEntityEnderDragon.java | 75 +-- .../nms/v1_21_5/dragon/SpikesCache.java | 190 ------ .../generator/IslandsGeneratorImpl.java | 67 --- .../nms/v1_21_5/hologram/EntityHologram.java | 39 ++ .../menu/MenuBrewingStandBlockEntity.java | 24 - .../menu/MenuDispenserBlockEntity.java | 24 - .../v1_21_5/menu/MenuFurnaceBlockEntity.java | 24 - .../v1_21_5/menu/MenuHopperBlockEntity.java | 26 - .../v1_21_5/player/OfflinePlayerDataImpl.java | 79 --- .../TickingSpawnerBlockEntityNotifier.java | 57 -- .../nms/v1_21_5/utils/NMSUtilsVersioned.java | 374 ++++++++++++ .../nms/v1_21_5/world/BlockEntityCache.java | 34 -- .../nms/v1_21_5/world/ChunkReaderImpl.java | 243 -------- .../nms/v1_21_5/world/KeyBlocksCache.java | 32 - .../nms/v1_21_5/world/PropertiesMapper.java | 86 --- .../world/PropertiesMapperVersioned.java | 18 + .../world/WorldEditSessionDataImpl.java | 167 ------ .../v1_21_5/world/WorldEditSessionImpl.java | 477 --------------- NMS/v1_21_7/properties | 7 + .../nms/v1_21_7/NMSAlgorithmsImpl.java | 290 +--------- .../nms/v1_21_7/NMSChunksImpl.java | 302 ++-------- .../nms/v1_21_7/NMSDragonFightImpl.java | 118 ---- .../nms/v1_21_7/NMSEntitiesImpl.java | 39 +- .../nms/v1_21_7/NMSHologramsImpl.java | 204 ------- .../nms/v1_21_7/NMSPlayersImpl.java | 123 ---- .../nms/v1_21_7/NMSTagsImpl.java | 123 +--- .../nms/v1_21_7/NMSUtils.java | 546 ------------------ .../nms/v1_21_7/NMSWorldImpl.java | 350 +---------- .../nms/v1_21_7/crops/CropsBlockEntity.java | 102 ---- .../crops/CropsTickingBlockEntity.java | 30 - .../nms/v1_21_7/crops/CropsTickingMethod.java | 159 ----- .../nms/v1_21_7/dragon/DragonUtils.java | 37 -- .../dragon/EndWorldEndDragonFightHandler.java | 48 -- .../v1_21_7/dragon/IslandEndDragonFight.java | 211 ------- .../dragon/IslandEntityEnderDragon.java | 77 +-- .../nms/v1_21_7/dragon/SpikesCache.java | 190 ------ .../generator/IslandsGeneratorImpl.java | 67 --- .../nms/v1_21_7/hologram/EntityHologram.java | 56 ++ .../menu/MenuBrewingStandBlockEntity.java | 24 - .../menu/MenuDispenserBlockEntity.java | 24 - .../v1_21_7/menu/MenuFurnaceBlockEntity.java | 24 - .../v1_21_7/menu/MenuHopperBlockEntity.java | 26 - .../v1_21_7/player/OfflinePlayerDataImpl.java | 79 --- .../TickingSpawnerBlockEntityNotifier.java | 57 -- .../nms/v1_21_7/utils/NMSUtilsVersioned.java | 389 +++++++++++++ .../nms/v1_21_7/world/BlockEntityCache.java | 34 -- .../nms/v1_21_7/world/ChunkReaderImpl.java | 255 -------- .../nms/v1_21_7/world/KeyBlocksCache.java | 32 - .../nms/v1_21_7/world/PropertiesMapper.java | 86 --- .../world/PropertiesMapperVersioned.java | 18 + .../world/WorldEditSessionDataImpl.java | 167 ------ .../v1_21_7/world/WorldEditSessionImpl.java | 492 ---------------- 351 files changed, 6787 insertions(+), 38777 deletions(-) create mode 100644 NMS/src/main/templates/AbstractNMSAlgorithms.java.template create mode 100644 NMS/src/main/templates/AbstractNMSChunks.java.template create mode 100644 NMS/src/main/templates/AbstractNMSEntities.java.template create mode 100644 NMS/src/main/templates/AbstractNMSTags.java.template create mode 100644 NMS/src/main/templates/AbstractNMSWorld.java.template rename NMS/{v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSDragonFightImpl.java => src/main/templates/NMSDragonFightImpl.java.template} (82%) create mode 100644 NMS/src/main/templates/NMSHologramsImpl.java.template rename NMS/{v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSPlayersImpl.java => src/main/templates/NMSPlayersImpl.java.template} (91%) rename NMS/{v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java => src/main/templates/NMSUtils.java.template} (68%) rename NMS/{v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsBlockEntity.java => src/main/templates/crops/CropsBlockEntity.java.template} (94%) rename NMS/{v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingBlockEntity.java => src/main/templates/crops/CropsTickingBlockEntity.java.template} (91%) rename NMS/{v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingMethod.java => src/main/templates/crops/CropsTickingMethod.java.template} (88%) create mode 100644 NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template rename NMS/{v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/DragonUtils.java => src/main/templates/dragon/DragonUtils.java.template} (94%) rename NMS/{v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndWorldEndDragonFightHandler.java => src/main/templates/dragon/EndWorldEndDragonFightHandler.java.template} (96%) rename NMS/{v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEndDragonFight.java => src/main/templates/dragon/IslandEndDragonFight.java.template} (90%) rename NMS/{v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/SpikesCache.java => src/main/templates/dragon/SpikesCache.java.template} (98%) rename NMS/{v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/generator/IslandsGeneratorImpl.java => src/main/templates/generator/IslandsGeneratorImpl.java.template} (96%) create mode 100644 NMS/src/main/templates/hologram/AbstractEntityHologram.java.template rename NMS/{v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuBrewingStandBlockEntity.java => src/main/templates/menu/MenuBrewingStandBlockEntity.java.template} (91%) rename NMS/{v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuDispenserBlockEntity.java => src/main/templates/menu/MenuDispenserBlockEntity.java.template} (91%) rename NMS/{v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuFurnaceBlockEntity.java => src/main/templates/menu/MenuFurnaceBlockEntity.java.template} (91%) rename NMS/{v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuHopperBlockEntity.java => src/main/templates/menu/MenuHopperBlockEntity.java.template} (92%) rename NMS/{v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/player/OfflinePlayerDataImpl.java => src/main/templates/player/OfflinePlayerDataImpl.java.template} (80%) rename NMS/{v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/spawners/TickingSpawnerBlockEntityNotifier.java => src/main/templates/spawners/TickingSpawnerBlockEntityNotifier.java.template} (96%) create mode 100644 NMS/src/main/templates/utils/SetBlockContext.java.template create mode 100644 NMS/src/main/templates/utils/TickingBlockList.java.template rename NMS/{v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockEntityCache.java => src/main/templates/world/BlockEntityCache.java.template} (83%) rename NMS/{v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java => src/main/templates/world/ChunkReaderImpl.java.template} (78%) rename NMS/{v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/KeyBlocksCache.java => src/main/templates/world/KeyBlocksCache.java.template} (77%) rename NMS/{v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/PropertiesMapper.java => src/main/templates/world/PropertiesMapper.java.template} (96%) rename NMS/{v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionDataImpl.java => src/main/templates/world/WorldEditSessionDataImpl.java.template} (98%) rename NMS/{v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java => src/main/templates/world/WorldEditSessionImpl.java.template} (59%) create mode 100644 NMS/v1_17/properties delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSDragonFightImpl.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSHologramsImpl.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSPlayersImpl.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsBlockEntity.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingBlockEntity.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/DragonUtils.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndWorldEndDragonFightHandler.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEndDragonFight.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/SpikesCache.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/generator/IslandsGeneratorImpl.java create mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/hologram/EntityHologram.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuBrewingStandBlockEntity.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuDispenserBlockEntity.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuFurnaceBlockEntity.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuHopperBlockEntity.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/player/OfflinePlayerDataImpl.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/spawners/TickingSpawnerBlockEntityNotifier.java create mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockEntityCache.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/KeyBlocksCache.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/PropertiesMapper.java create mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/PropertiesMapperVersioned.java delete mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java create mode 100644 NMS/v1_18/properties delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSDragonFightImpl.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSHologramsImpl.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSPlayersImpl.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsBlockEntity.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingBlockEntity.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndWorldEndDragonFightHandler.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEndDragonFight.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/SpikesCache.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/generator/IslandsGeneratorImpl.java create mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/hologram/EntityHologram.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuBrewingStandBlockEntity.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuDispenserBlockEntity.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuFurnaceBlockEntity.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuHopperBlockEntity.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/player/OfflinePlayerDataImpl.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/spawners/TickingSpawnerBlockEntityNotifier.java create mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/PropertiesMapper.java create mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/PropertiesMapperVersioned.java delete mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionDataImpl.java create mode 100644 NMS/v1_19/properties delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSDragonFightImpl.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSHologramsImpl.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSPlayersImpl.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsBlockEntity.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingBlockEntity.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/DragonUtils.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndWorldEndDragonFightHandler.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEndDragonFight.java create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/hologram/EntityHologram.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuBrewingStandBlockEntity.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuDispenserBlockEntity.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuFurnaceBlockEntity.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuHopperBlockEntity.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/player/OfflinePlayerDataImpl.java create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockEntityCache.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/KeyBlocksCache.java create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/PropertiesMapperVersioned.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionDataImpl.java delete mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java create mode 100644 NMS/v1_20_3/properties delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSDragonFightImpl.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSHologramsImpl.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSPlayersImpl.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsBlockEntity.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingBlockEntity.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/DragonUtils.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndWorldEndDragonFightHandler.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEndDragonFight.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/SpikesCache.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/generator/IslandsGeneratorImpl.java create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/hologram/EntityHologram.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuBrewingStandBlockEntity.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuDispenserBlockEntity.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuFurnaceBlockEntity.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuHopperBlockEntity.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/player/OfflinePlayerDataImpl.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/spawners/TickingSpawnerBlockEntityNotifier.java create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockEntityCache.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/KeyBlocksCache.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/PropertiesMapper.java create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/PropertiesMapperVersioned.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionDataImpl.java delete mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java create mode 100644 NMS/v1_20_4/properties delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSHologramsImpl.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsBlockEntity.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/DragonUtils.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEndDragonFight.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/SpikesCache.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/generator/IslandsGeneratorImpl.java create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/hologram/EntityHologram.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuBrewingStandBlockEntity.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuDispenserBlockEntity.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuFurnaceBlockEntity.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/player/OfflinePlayerDataImpl.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/spawners/TickingSpawnerBlockEntityNotifier.java create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockEntityCache.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/KeyBlocksCache.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/PropertiesMapper.java create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/PropertiesMapperVersioned.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionDataImpl.java delete mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java create mode 100644 NMS/v1_21/properties delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSDragonFightImpl.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSHologramsImpl.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSPlayersImpl.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingBlockEntity.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/DragonUtils.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndWorldEndDragonFightHandler.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/SpikesCache.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/generator/IslandsGeneratorImpl.java create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/hologram/EntityHologram.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuHopperBlockEntity.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/player/OfflinePlayerDataImpl.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/spawners/TickingSpawnerBlockEntityNotifier.java create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockEntityCache.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/KeyBlocksCache.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/PropertiesMapper.java create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/PropertiesMapperVersioned.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionDataImpl.java delete mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java create mode 100644 NMS/v1_21_3/properties delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSDragonFightImpl.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSHologramsImpl.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSPlayersImpl.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsBlockEntity.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingBlockEntity.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/DragonUtils.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndWorldEndDragonFightHandler.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEndDragonFight.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/SpikesCache.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/generator/IslandsGeneratorImpl.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/hologram/EntityHologram.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuBrewingStandBlockEntity.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuDispenserBlockEntity.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuFurnaceBlockEntity.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuHopperBlockEntity.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/player/OfflinePlayerDataImpl.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/spawners/TickingSpawnerBlockEntityNotifier.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockEntityCache.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/KeyBlocksCache.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/PropertiesMapper.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/PropertiesMapperVersioned.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionDataImpl.java delete mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java create mode 100644 NMS/v1_21_4/properties delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSDragonFightImpl.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSHologramsImpl.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsBlockEntity.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingBlockEntity.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/DragonUtils.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndWorldEndDragonFightHandler.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEndDragonFight.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/SpikesCache.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/generator/IslandsGeneratorImpl.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/hologram/EntityHologram.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuBrewingStandBlockEntity.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuDispenserBlockEntity.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuFurnaceBlockEntity.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuHopperBlockEntity.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/spawners/TickingSpawnerBlockEntityNotifier.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockEntityCache.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapper.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapperVersioned.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionDataImpl.java delete mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java create mode 100644 NMS/v1_21_5/properties delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSDragonFightImpl.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSHologramsImpl.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSPlayersImpl.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsBlockEntity.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingBlockEntity.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingMethod.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/DragonUtils.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndWorldEndDragonFightHandler.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEndDragonFight.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/SpikesCache.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/generator/IslandsGeneratorImpl.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/hologram/EntityHologram.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuBrewingStandBlockEntity.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuDispenserBlockEntity.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuFurnaceBlockEntity.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuHopperBlockEntity.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/player/OfflinePlayerDataImpl.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/spawners/TickingSpawnerBlockEntityNotifier.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockEntityCache.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapperVersioned.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionDataImpl.java delete mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java create mode 100644 NMS/v1_21_7/properties delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSDragonFightImpl.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSHologramsImpl.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSPlayersImpl.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsBlockEntity.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingBlockEntity.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingMethod.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/DragonUtils.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndWorldEndDragonFightHandler.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEndDragonFight.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/SpikesCache.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/generator/IslandsGeneratorImpl.java create mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/hologram/EntityHologram.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuBrewingStandBlockEntity.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuDispenserBlockEntity.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuFurnaceBlockEntity.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuHopperBlockEntity.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/player/OfflinePlayerDataImpl.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/spawners/TickingSpawnerBlockEntityNotifier.java create mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockEntityCache.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/ChunkReaderImpl.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/KeyBlocksCache.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapper.java create mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapperVersioned.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionDataImpl.java delete mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java diff --git a/NMS/build.gradle b/NMS/build.gradle index fce298d145..e3a33c516d 100644 --- a/NMS/build.gradle +++ b/NMS/build.gradle @@ -1 +1,52 @@ -group 'NMS' \ No newline at end of file +group 'NMS' + +subprojects { + def generatedSrcDir = file("$buildDir/generated/sources/nms") + + task generateNmsSources { + doLast { + delete generatedSrcDir + + generatedSrcDir.mkdirs() + + def props = new Properties() + def propertiesFile = file("$projectDir/properties") + if (!propertiesFile.exists()) { + return + } + + propertiesFile.withInputStream { stream -> + props.load(stream) + } + + def templatesDir = file("${rootDir}/NMS/src/main/templates/") + def templates = fileTree(templatesDir) { + include '**/*.template' + } + + templates.each { File templateFile -> + def relativePath = templatesDir.toPath().relativize(templateFile.toPath()).toString() + def outputFile = new File(generatedSrcDir, relativePath.replace('.template', '')) + outputFile.parentFile.mkdirs() + + def templateText = templateFile.text + props.each { k, v -> + templateText = templateText.replace("\${${k}}", v) + } + outputFile.text = templateText + println "Generated ${outputFile}" + } + + } + } + + sourceSets { + main { + java { + srcDirs = ['src/main/java', generatedSrcDir] + } + } + } + + compileJava.dependsOn(generateNmsSources) +} \ No newline at end of file diff --git a/NMS/src/main/templates/AbstractNMSAlgorithms.java.template b/NMS/src/main/templates/AbstractNMSAlgorithms.java.template new file mode 100644 index 0000000000..f2ccb552fc --- /dev/null +++ b/NMS/src/main/templates/AbstractNMSAlgorithms.java.template @@ -0,0 +1,312 @@ +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; +import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; +import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuBrewingStandBlockEntity; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuDispenserBlockEntity; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuFurnaceBlockEntity; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuHopperBlockEntity; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.BlockEntityCache; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.KeyBlocksCache; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; +import io.papermc.paper.chat.ChatRenderer; +import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.text.TextReplacementConfig; +import net.minecraft.core.BlockPos; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.Container; +import net.minecraft.world.entity.item.FallingBlockEntity; +import net.minecraft.world.entity.vehicle.AbstractMinecart; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.block.Biome; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; +import org.bukkit.command.defaults.BukkitCommand; +import ${CRAFTBUKKIT_PACKAGE}.CraftServer; +import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftFallingBlock; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftMinecart; +import ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionEffect; +import org.jetbrains.annotations.NotNull; + +import java.util.EnumMap; +import java.util.Optional; +import java.util.function.BiFunction; + +public abstract class AbstractNMSAlgorithms implements NMSAlgorithms { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final Multimap EMPTY_ATTRIBUTES_MAP = + MultimapBuilder.hashKeys().hashSetValues().build(); + + private static final EnumBridge BIOME_ENUM_BRIDGE = new EnumBridge<>() { + @Override + public Biome[] getValues() { + return Biome.values(); + } + + @Override + public String getName(Biome enumValue) { + return enumValue.name(); + } + }; + + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); + + static { + MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); + MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); + } + + private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { + @Override + public byte[] processClass(byte[] classBytes, String path) { + return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); + } + }; + + @Override + public void registerCommand(BukkitCommand command) { + ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); + } + + @Override + public int getCombinedId(Location location) { + org.bukkit.World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return 0; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + blockState = serverLevel.getBlockState(wrapper.getHandle()); + } + return Block.getId(blockState); + } + + @Override + public int getCombinedId(Material material, byte data) { + BlockState blockState; + + if (data == 0) { + Block block = CraftMagicNumbers.getBlock(material); + if (block == null) + return -1; + blockState = block.defaultBlockState(); + } else { + blockState = CraftMagicNumbers.getBlock(material, data); + } + + return blockState == null ? -1 : Block.getId(blockState); + } + + @Override + public Optional getTileEntityIdFromCombinedId(int combinedId) { + BlockState blockState = Block.stateById(combinedId); + + if (!blockState.hasBlockEntity()) + return Optional.empty(); + + String id = BlockEntityCache.getBlockEntityId(blockState); + + return Text.isBlank(id) ? Optional.empty() : Optional.of(id); + } + + @Override + public int compareMaterials(Material o1, Material o2) { + int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); + int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); + return Integer.compare(firstMaterial, secondMaterial); + } + + @Override + public short getBlockDataValue(org.bukkit.block.BlockState blockState) { + BlockData blockData = blockState.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getBlockDataValue(org.bukkit.block.Block block) { + BlockData blockData = block.getBlockData(); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); + } + + @Override + public short getMaxBlockDataValue(Material material) { + if (!material.isBlock()) + return 0; + + BlockData blockData = Bukkit.createBlockData(material); + return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); + } + + @Override + public Key getBlockKey(int combinedId) { + Block block = Block.stateById(combinedId).getBlock(); + return KeyBlocksCache.getBlockKey(block); + } + + @Override + public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { + AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); + Block block = minecart.getDisplayBlockState().getBlock(); + return KeyBlocksCache.getBlockKey(block); + } + + @Override + public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { + FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); + Block block = fallingBlock.getBlockState().getBlock(); + return KeyBlocksCache.getBlockKey(block); + } + + @Override + public void setCustomModel(ItemMeta itemMeta, int customModel) { + itemMeta.setCustomModelData(customModel); + } + + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + // Doesn't exist + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + // Doesn't exist + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + // Doesn't exist + } + + @Override + public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { + if (!potionMeta.hasCustomEffects()) + potionMeta.setColor(potionEffect.getType().getColor()); + potionMeta.addCustomEffect(potionEffect, true); + } + + @Nullable + @Override + public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { + MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); + return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); + } + + @Override + public int getMaxWorldSize() { + return Bukkit.getMaxWorldSize(); + } + + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + + @Override + public int getDataVersion() { + return CraftMagicNumbers.INSTANCE.getDataVersion(); + } + + @Override + public ClassProcessor getClassProcessor() { + return CLASS_PROCESSOR; + } + + @Override + public void handlePaperChatRenderer(Object event) { + if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) + return; + + ChatRenderer originalRenderer = asyncChatEvent.renderer(); + asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); + } + + @Override + public void hideAttributes(ItemMeta itemMeta) { + itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); + } + + @Override + public EnumBridge getBiomeBridge() { + return BIOME_ENUM_BRIDGE; + } + + private interface MenuCreator extends BiFunction { + } + + private static class ChatRendererWrapper { + + private static final String MESSAGE_PLACEHOLDER = "{message}"; + private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = + net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); + + private final ChatRenderer renderer = new ChatRenderer() { + @Override + public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, + net.kyori.adventure.text.@NotNull Component sourceDisplayName, + net.kyori.adventure.text.@NotNull Component message, + @NotNull Audience viewer) { + String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer + .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); + Island island = superiorPlayer.getIsland(); + + return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( + Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) + .replaceText(TextReplacementConfig.builder() + .matchLiteral(MESSAGE_PLACEHOLDER) + .replacement(message) + .build()); + } + }; + + private final ChatRenderer originalRenderer; + + public ChatRendererWrapper(ChatRenderer originalRenderer) { + this.originalRenderer = originalRenderer; + } + + } + +} diff --git a/NMS/src/main/templates/AbstractNMSChunks.java.template b/NMS/src/main/templates/AbstractNMSChunks.java.template new file mode 100644 index 0000000000..8e7cdd8363 --- /dev/null +++ b/NMS/src/main/templates/AbstractNMSChunks.java.template @@ -0,0 +1,278 @@ +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.core.CalculatedChunk; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Counter; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.bgsoftware.superiorskyblock.nms.NMSChunks; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsBlockEntity; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsTickingMethod; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.KeyBlocksCache; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SlabBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.SlabType; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.phys.AABB; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import ${CRAFTBUKKIT_PACKAGE}.CraftChunk; +import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.CompletableFuture; + +public abstract class AbstractNMSChunks implements NMSChunks { + + protected final SuperiorSkyblockPlugin plugin; + + protected AbstractNMSChunks(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + KeyBlocksCache.cacheAllBlocks(); + CropsTickingMethod.register(); + } + + @Override + public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, + Collection playersToUpdate) { + if (chunkPositions.isEmpty()) + return; + + NMSUtils.runActionOnChunks(chunkPositions, true, getBiomesChunkCallback(bukkitBiome, playersToUpdate)); + } + + protected abstract NMSUtils.ChunkCallback getBiomesChunkCallback( + org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate); + + @Override + public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { + if (chunkPositions.isEmpty()) + return; + + chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), + chunkPosition.getX(), chunkPosition.getZ(), false)); + + NMSUtils.runActionOnChunks(chunkPositions, true, getDeleteChunkCallback(onFinish)); + } + + protected abstract NMSUtils.ChunkCallback getDeleteChunkCallback(@Nullable Runnable onFinish); + + @Override + public CompletableFuture> calculateChunks(List chunkPositions, + Synchronized> unloadedChunksCache) { + List allCalculatedChunks = new LinkedList<>(); + List chunkPositionsToCalculate = new LinkedList<>(); + + Iterator chunkPositionsIterator = chunkPositions.iterator(); + while (chunkPositionsIterator.hasNext()) { + ChunkPosition chunkPosition = chunkPositionsIterator.next(); + CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); + if (cachedCalculatedChunk != null) { + allCalculatedChunks.add(cachedCalculatedChunk); + chunkPositionsIterator.remove(); + } else { + chunkPositionsToCalculate.add(chunkPosition); + } + } + + if (chunkPositions.isEmpty()) + return CompletableFuture.completedFuture(allCalculatedChunks); + + CompletableFuture> completableFuture = new CompletableFuture<>(); + + NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, + getCalculateChunkCallback(completableFuture, unloadedChunksCache, allCalculatedChunks)); + + return completableFuture; + } + + protected abstract NMSUtils.ChunkCallback getCalculateChunkCallback( + CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks); + + @Override + public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { + CompletableFuture> completableFuture = new CompletableFuture<>(); + + KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + List unloadedChunkCompounds = new LinkedList<>(); + + NMSUtils.runActionOnEntityChunks(chunkPositions, + getEntitiesChunkCallback(chunkEntities, unloadedChunkCompounds, completableFuture)); + + return completableFuture; + } + + protected abstract NMSUtils.ChunkCallback getEntitiesChunkCallback( + KeyMap chunkEntities, List unloadedChunkCompounds, + CompletableFuture> completableFuture); + + @Override + public void injectChunkSections(Chunk chunk) { + // No implementation + } + + @Override + public boolean isChunkEmpty(Chunk bukkitChunk) { + ServerLevel serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle(); + LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); + return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> + chunkSection == null || NMSUtilsVersioned.isLevelChunkSectionEmpty(chunkSection)); + } + + @Override + public Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); + return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; + } + + @Override + public void startTickingChunk(Island island, Chunk chunk, boolean stop) { + if (plugin.getSettings().getCropsInterval() <= 0) + return; + + if (stop) { + CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); + if (cropsBlockEntity != null) + cropsBlockEntity.remove(); + } else { + ServerLevel serverLevel = ((CraftWorld) chunk.getWorld()).getHandle(); + LevelChunk levelChunk = serverLevel.getChunk(chunk.getX(), chunk.getZ()); + CropsBlockEntity.create(island, levelChunk); + } + } + + @Override + public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { + if (chunkPositions.isEmpty()) return; + CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> + cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); + } + + @Override + public void shutdown() { + List> pendingTasks = NMSUtils.getPendingChunkActions(); + + if (pendingTasks.isEmpty()) + return; + + Log.info("Waiting for chunk tasks to complete."); + + CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); + } + + @Override + public List getBlockEntities(Chunk chunk) { + ServerLevel serverLevel = ((CraftWorld) chunk.getWorld()).getHandle(); + LevelChunk levelChunk = serverLevel.getChunk(chunk.getX(), chunk.getZ()); + + List blockEntities = new LinkedList<>(); + + World bukkitWorld = chunk.getWorld(); + + levelChunk.getBlockEntities().keySet().forEach(blockPos -> + blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); + + return blockEntities; + } + + protected CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { + KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); + List spawnersLocations = new LinkedList<>(); + + for (int i = 0; i < chunkSections.length; ++i) { + LevelChunkSection levelChunkSection = chunkSections[i]; + if (levelChunkSection != null && !NMSUtilsVersioned.isLevelChunkSectionEmpty(levelChunkSection)) { + int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4; + for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { + BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); + calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, + sectionBottomY, blockCounts, spawnersLocations); + } + } + } + + return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); + } + + protected void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, + int sectionBottomY, KeyMap blockCounts, + List spawnersLocations) { + Block block = blockState.getBlock(); + + if (block == Blocks.AIR) + return; + + Location location = new Location(chunkPosition.getWorld(), + (chunkPosition.getX() << 4) + x, + sectionBottomY + y, + (chunkPosition.getZ() << 4) + z); + + int blockAmount = 1; + + if (NMSUtils.isDoubleBlock(block, blockState)) { + blockAmount = 2; + blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); + } + + Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); + blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); + if (block == Blocks.SPAWNER) { + spawnersLocations.add(location); + } + } + + protected void removeEntities(LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + ServerLevel serverLevel = levelChunk.level; + + int chunkWorldCoordX = chunkPos.x << 4; + int chunkWorldCoordZ = chunkPos.z << 4; + + + AABB chunkBounds = new AABB(chunkWorldCoordX, NMSUtilsVersioned.getMinBuildHeight(serverLevel), chunkWorldCoordZ, + chunkWorldCoordX + 15, NMSUtilsVersioned.getMaxBuildHeight(serverLevel), chunkWorldCoordZ + 15); + + List worldEntities = new LinkedList<>(); + serverLevel.getEntities().get(chunkBounds, worldEntities::add); + + worldEntities.forEach(nmsEntity -> { + if (!(nmsEntity instanceof net.minecraft.world.entity.player.Player)) + nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); + }); + } + + protected void removeBlockEntities(LevelChunk levelChunk) { + levelChunk.blockEntities.values().forEach(BlockEntity::setRemoved); + levelChunk.blockEntities.clear(); + } + +} diff --git a/NMS/src/main/templates/AbstractNMSEntities.java.template b/NMS/src/main/templates/AbstractNMSEntities.java.template new file mode 100644 index 0000000000..81d3d2cf53 --- /dev/null +++ b/NMS/src/main/templates/AbstractNMSEntities.java.template @@ -0,0 +1,51 @@ +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; + +import com.bgsoftware.superiorskyblock.nms.NMSEntities; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.entity.Entity; +import org.bukkit.Material; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftAnimals; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftEntity; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftMinecartFurnace; +import ${CRAFTBUKKIT_PACKAGE}.inventory.CraftItemStack; +import org.bukkit.entity.Animals; +import org.bukkit.entity.Steerable; +import org.bukkit.entity.minecart.PoweredMinecart; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.ItemStack; + +public abstract class AbstractNMSEntities implements NMSEntities { + + @Override + public ItemStack[] getEquipment(EntityEquipment entityEquipment) { + ItemStack[] itemStacks = new ItemStack[7]; + + itemStacks[0] = new ItemStack(Material.ARMOR_STAND); + itemStacks[1] = entityEquipment.getItemInMainHand(); + itemStacks[2] = entityEquipment.getItemInOffHand(); + itemStacks[3] = entityEquipment.getHelmet(); + itemStacks[4] = entityEquipment.getChestplate(); + itemStacks[5] = entityEquipment.getLeggings(); + itemStacks[6] = entityEquipment.getBoots(); + + return itemStacks; + } + + @Override + public boolean isAnimalFood(ItemStack itemStack, Animals animals) { + return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); + } + + @Override + public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { + Entity entity = ((CraftEntity) bukkitEntity).getHandle(); + return getPortalTicks(entity); + } + + protected abstract int getPortalTicks(Entity entity); + + @Override + public boolean canShearSaddleFromEntity(org.bukkit.entity.Entity entity) { + return entity instanceof Steerable steerable && steerable.hasSaddle(); + } +} diff --git a/NMS/src/main/templates/AbstractNMSTags.java.template b/NMS/src/main/templates/AbstractNMSTags.java.template new file mode 100644 index 0000000000..be7735fc6a --- /dev/null +++ b/NMS/src/main/templates/AbstractNMSTags.java.template @@ -0,0 +1,116 @@ +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; + +import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.nms.NMSTags; +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.bgsoftware.superiorskyblock.tag.ListTag; +import com.bgsoftware.superiorskyblock.tag.Tag; +import com.mojang.serialization.Dynamic; +import net.minecraft.nbt.NbtOps; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.item.ItemStack; +import org.bukkit.Location; +import org.bukkit.Material; +import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; +import ${CRAFTBUKKIT_PACKAGE}.inventory.CraftItemStack; +import ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers; + +public abstract class AbstractNMSTags implements NMSTags { + + @Override + public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + return setTagAndGetCompoundTag(itemStack, "DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + } + + protected abstract CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value); + + @Override + public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { + if (compoundTag.containsKey("NBT")) { + // Old compound version, deserialize it accordingly + return deserializeItemOld(compoundTag); + } + + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); + + int currentVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); + int itemVersion = getCompoundTagInt(tagCompound, "DataVersion", 0); + if (itemVersion < currentVersion) { + tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, + new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); + } + + ItemStack itemStack = parseItemStack(tagCompound); + + return CraftItemStack.asCraftMirror(itemStack); + } + + protected abstract int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def); + + protected abstract ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag); + + private org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { + String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); + Material type = Material.valueOf(typeName); + int amount = compoundTag.getInt("amount").orElse(0); + short data = (short) compoundTag.getShort("data").orElse(0); + CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); + + org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + if (nbtData != null) { + setItemStackCompoundTag(itemStack, (net.minecraft.nbt.CompoundTag) nbtData.toNBT()); + } + + return CraftItemStack.asCraftMirror(itemStack); + } + + protected abstract void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag); + + @Override + public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { + net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); + + if (compoundTag == null) + compoundTag = new net.minecraft.nbt.CompoundTag(); + + if (!compoundTag.contains("id")) + //noinspection deprecation + compoundTag.putString("id", entityType.getName()); + + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + + loadEntity(compoundTag, serverLevel, location); + } + + protected abstract void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location); + + @Override + public Object parseList(ListTag listTag) { + net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); + + for (Tag tag : listTag) + nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); + + return nbtTagList; + } + + @Override + public Object getNBTCompoundTag(Object object, String key) { + return ((net.minecraft.nbt.CompoundTag) object).get(key); + } + + @Override + public void setNBTCompoundTagValue(Object object, String key, Object value) { + ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); + } + + @Override + public int getNBTTagListSize(Object object) { + return ((net.minecraft.nbt.ListTag) object).size(); + } + +} diff --git a/NMS/src/main/templates/AbstractNMSWorld.java.template b/NMS/src/main/templates/AbstractNMSWorld.java.template new file mode 100644 index 0000000000..df703217cd --- /dev/null +++ b/NMS/src/main/templates/AbstractNMSWorld.java.template @@ -0,0 +1,364 @@ +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; +import com.bgsoftware.superiorskyblock.nms.ICachedBlock; +import com.bgsoftware.superiorskyblock.nms.NMSWorld; +import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; +import ${COMMON_NMS_PACKAGE}.algorithms.NMSCachedBlock; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.generator.IslandsGeneratorImpl; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.ChunkReaderImpl; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.WorldEditSessionImpl; +import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; +import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.world.SignType; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.block.entity.SpawnerBlockEntity; +import net.minecraft.world.level.block.entity.TickingBlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.border.WorldBorder; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.ChunkSnapshot; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.Sign; +import org.bukkit.block.data.type.WallSign; +import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; +import ${CRAFTBUKKIT_PACKAGE}.block.CraftBlock; +import ${CRAFTBUKKIT_PACKAGE}.block.CraftBlockState; +import ${CRAFTBUKKIT_PACKAGE}.block.CraftSign; +import ${CRAFTBUKKIT_PACKAGE}.block.data.CraftBlockData; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer; +import org.bukkit.entity.Player; + +import java.lang.reflect.Modifier; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.function.IntFunction; + +public abstract class AbstractNMSWorld implements NMSWorld { + + private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); + private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, + Object.class, "chunkPacketBlockController") + .removeFinal(); + + protected final SuperiorSkyblockPlugin plugin; + + protected AbstractNMSWorld(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + } + + @Override + public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); + Location location = new Location( + Bukkit.getWorld(chunkSnapshot.getWorldName()), + (chunkSnapshot.getX() << 4) + x, + y, + (chunkSnapshot.getZ() << 4) + z + ); + + return Keys.of(KeyBlocksCache.getBlockKey(block), location); + } + + @Override + public void listenSpawner(Location location, IntFunction delayChangeCallback) { + SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); + if (spawnerBlockEntity == null) + return; + + ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); + + List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel); + Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); + List tickersToAdd = new LinkedList<>(); + + while (blockEntityTickersIterator.hasNext()) { + TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); + if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && + !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { + blockEntityTickersIterator.remove(); + tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); + } + } + + if (!tickersToAdd.isEmpty()) + blockEntityTickers.addAll(tickersToAdd); + } + + @Override + public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { + if (!plugin.getSettings().isWorldBorders()) + return; + + Player player = superiorPlayer.asPlayer(); + World world = superiorPlayer.getWorld(); + + if (world == null || player == null) + return; + + int islandSize = island == null ? 0 : island.getIslandSize(); + + boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; + + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + + WorldBorder worldBorder; + + if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { + worldBorder = serverLevel.getWorldBorder(); + } else { + Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); + if (dimension == null) + return; + + Location center = island.getCenter(dimension); + + worldBorder = new WorldBorder(); + worldBorder.world = serverLevel; + worldBorder.setWarningBlocks(0); + worldBorder.setCenter(center.getX(), center.getZ()); + + switch (superiorPlayer.getBorderColor()) { + case BLUE: + worldBorder.setSize((islandSize * 2) + 1D); + break; + case GREEN: + worldBorder.setSize((islandSize * 2) + 1.001D); + worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); + break; + case RED: + worldBorder.setSize((islandSize * 2) + 1D); + worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); + break; + } + } + + ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); + ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); + } + + @Override + public Object getBlockData(org.bukkit.block.Block block) { + return block.getBlockData(); + } + + @Override + public void setBlock(Location location, int combinedId) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + + BlockState blockState = + NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); + + if (blockState != null) { + serverLevel.getChunkSource().blockChanged(blockPos); + if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { + serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); + } + } + } + } + + @Override + public ICachedBlock cacheBlock(org.bukkit.block.Block block) { + return NMSCachedBlock.obtain(block); + } + + @Override + public boolean isWaterLogged(org.bukkit.block.Block block) { + if (Materials.isWater(block.getType())) + return true; + + BlockData blockData = block.getBlockData(); + + return blockData instanceof BubbleColumn || + (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); + } + + @Override + public SignType getSignType(Object sign) { + if (sign instanceof WallSign) + return SignType.WALL_SIGN; + else if (sign instanceof Sign) + return SignType.STANDING_SIGN; + else + return SignType.UNKNOWN; + } + + @Override + public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { + BlockState blockState = ((CraftBlock) block).getNMS(); + return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; + } + + @Override + public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { + return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); + } + + @Override + public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { + return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); + } + + private int getDefaultAmount(BlockState blockState) { + Block block = blockState.getBlock(); + return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; + } + + @Override + public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { + return !bukkitBlock.isPassable(); + } + + @Override + public void placeSign(Island island, Location location) { + SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); + if (signBlockEntity == null) + return; + + String[] lines = new String[4]; + Component[] messages = getSignBlockEntityText(signBlockEntity); + System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length); + String[] strippedLines = new String[4]; + for (int i = 0; i < 4; i++) + strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); + + Component[] newLines; + + IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); + if (result.isCancelEvent()) { + newLines = CraftSign.sanitizeLines(strippedLines); + } else { + newLines = CraftSign.sanitizeLines(lines); + } + + System.arraycopy(newLines, 0, messages, 0, 4); + } + + protected abstract Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity); + + @Override + public void playGeneratorSound(Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + serverLevel.levelEvent(1501, blockPos, 0); + } + } + + @Override + public void playBreakAnimation(org.bukkit.block.Block block) { + ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(block.getX(), block.getY(), block.getZ()); + serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); + } + } + + @Override + public void playPlaceSound(Location location) { + World bukkitWorld = location.getWorld(); + + if (bukkitWorld == null) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); + + serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, + (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); + } + } + + @Override + public int getMinHeight(World world) { + return world.getMinHeight(); + } + + @Override + public void removeAntiXray(org.bukkit.World bukkitWorld) { + if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) + return; + + ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); + CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ${PAPER_CHUNK_BLOCK_CONTROLLER_CLASS}.NO_OPERATION_INSTANCE); + } + + @Override + public IslandsGenerator createGenerator(Dimension dimension) { + return new IslandsGeneratorImpl(dimension); + } + + @Override + public WorldEditSession createEditSession(World world) { + return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); + } + + @Override + public WorldEditSession createPartialEditSession(Dimension dimension) { + return WorldEditSessionImpl.obtain(dimension); + } + + @Override + public ChunkReader createChunkReader(Chunk chunk) { + return new ChunkReaderImpl(chunk); + } + + private static ReflectField> initializeLevelBlockEntityTickersField() { + ReflectField> field = new ReflectField<>( + Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); + + if (!field.isValid()) + field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); + + return field; + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSDragonFightImpl.java b/NMS/src/main/templates/NMSDragonFightImpl.java.template similarity index 82% rename from NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSDragonFightImpl.java rename to NMS/src/main/templates/NMSDragonFightImpl.java.template index 8c8843efa1..854ceb2241 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSDragonFightImpl.java +++ b/NMS/src/main/templates/NMSDragonFightImpl.java.template @@ -1,14 +1,15 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon.EndWorldEndDragonFightHandler; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon.IslandEndDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon.IslandEntityEnderDragon; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon.SpikesCache; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.EndWorldEndDragonFightHandler; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEndDragonFight; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEntityEnderDragon; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.SpikesCache; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.google.common.cache.LoadingCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; @@ -20,7 +21,7 @@ import org.bukkit.NamespacedKey; import org.bukkit.World; import org.bukkit.advancement.Advancement; -import org.bukkit.craftbukkit.CraftWorld; +import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import org.bukkit.entity.Player; import java.lang.reflect.Modifier; @@ -66,7 +67,7 @@ public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dim ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return null; IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); @@ -82,7 +83,7 @@ public void startDragonBattle(Island island, Location location) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); @@ -97,7 +98,7 @@ public void removeDragonBattle(Island island, Dimension dimension) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndWorldEndDragonFightHandler dragonFightHandler)) return; EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); diff --git a/NMS/src/main/templates/NMSHologramsImpl.java.template b/NMS/src/main/templates/NMSHologramsImpl.java.template new file mode 100644 index 0000000000..869bfc61ff --- /dev/null +++ b/NMS/src/main/templates/NMSHologramsImpl.java.template @@ -0,0 +1,29 @@ +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; + +import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; +import com.bgsoftware.superiorskyblock.nms.NMSHolograms; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.hologram.EntityHologram; +import com.google.common.base.Preconditions; +import net.minecraft.server.level.ServerLevel; +import org.bukkit.Location; +import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftEntity; +import org.bukkit.entity.Entity; + +public class NMSHologramsImpl implements NMSHolograms { + + @Override + public Hologram createHologram(Location location) { + Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); + ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); + serverLevel.addFreshEntity(entityHologram); + return entityHologram; + } + + @Override + public boolean isHologram(Entity entity) { + return ((CraftEntity) entity).getHandle() instanceof Hologram; + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSPlayersImpl.java b/NMS/src/main/templates/NMSPlayersImpl.java.template similarity index 91% rename from NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSPlayersImpl.java rename to NMS/src/main/templates/NMSPlayersImpl.java.template index 581e3c458e..e6920c7918 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSPlayersImpl.java +++ b/NMS/src/main/templates/NMSPlayersImpl.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectMethod; @@ -6,7 +6,8 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.NMSPlayers; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.player.OfflinePlayerDataImpl; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.player.OfflinePlayerDataImpl; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; import com.mojang.authlib.properties.Property; @@ -17,7 +18,7 @@ import org.bukkit.OfflinePlayer; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.entity.CraftPlayer; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer; import org.bukkit.entity.Item; import org.bukkit.entity.Player; @@ -46,7 +47,7 @@ public void setSkinTexture(SuperiorPlayer superiorPlayer) { @Override public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { - superiorPlayer.setTextureValue(property.value()); + superiorPlayer.setTextureValue(NMSUtilsVersioned.getPropertyValue(property)); } @SuppressWarnings("deprecation") diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java b/NMS/src/main/templates/NMSUtils.java.template similarity index 68% rename from NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java rename to NMS/src/main/templates/NMSUtils.java.template index eb3162804f..a123030798 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSUtils.java +++ b/NMS/src/main/templates/NMSUtils.java.template @@ -1,7 +1,6 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.ChunkPosition; @@ -9,7 +8,9 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.nms.v1_18.world.PropertiesMapper; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.SetBlockContext; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.tag.ByteTag; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.IntArrayTag; @@ -17,16 +18,13 @@ import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; -import com.google.common.base.Suppliers; import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.core.SectionPos; -import net.minecraft.nbt.ListTag; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.BlockTags; import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.block.BedBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SlabBlock; @@ -38,24 +36,17 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.storage.EntityStorage; -import net.minecraft.world.level.chunk.storage.IOWorker; import net.minecraft.world.level.levelgen.Heightmap; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; +import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; -import java.io.IOException; -import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; @@ -66,10 +57,6 @@ public class NMSUtils { private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); - private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( - EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); - private static final ReflectMethod> WORKER_LOAD_ASYNC = new ReflectMethod<>( - IOWorker.class, CompletableFuture.class, 1, ChunkPos.class); private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); @@ -160,6 +147,7 @@ private static void runActionOnUnloadedChunks(Collection chunks, LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( chunkPosition.getX(), chunkPosition.getZ()); + if (cachedUnloadedChunk != null) { chunkCallback.onLoadedChunk(cachedUnloadedChunk); chunksIterator.remove(); @@ -193,16 +181,15 @@ private static void runActionOnUnloadedChunks(Collection chunks, boolean calledCountdown = false; try { - net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos); + net.minecraft.nbt.CompoundTag chunkCompound = NMSUtilsVersioned.readChunk(chunkMap, chunkPos); if (chunkCompound == null) { chunkCallback.onChunkNotExist(chunkPosition); return; } - net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), - Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, - Optional.empty(), chunkPos, serverLevel); + net.minecraft.nbt.CompoundTag chunkDataCompound = NMSUtilsVersioned.getChunkData( + chunkMap, chunkCompound, serverLevel, chunkPos); UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); chunkCallback.onUnloadedChunk(unloadedChunkCompound); @@ -228,11 +215,14 @@ private static void runActionOnUnloadedChunks(Collection chunks, return chunkCompounds; }).runSync(chunkCompounds -> { chunkCompounds.forEach(unloadedChunkCompound -> { - ChunkMap chunkMap = unloadedChunkCompound.serverLevel().getChunkSource().chunkMap; + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; + + ChunkPos chunkPos = unloadedChunkCompound.chunkPos(); try { - chunkMap.write(unloadedChunkCompound.chunkPos(), unloadedChunkCompound.chunkCompound); - } catch (IOException error) { + NMSUtilsVersioned.saveChunkData(chunkMap, unloadedChunkCompound.chunkCompound, chunkPos); + } catch (Exception error) { Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); } }); @@ -244,32 +234,10 @@ private static void runActionOnUnloadedChunks(Collection chunks, }); } - private static void runActionOnUnloadedEntityChunks(Collection chunks, - ChunkCallback chunkCallback) { + private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - IOWorker worker = ENTITY_STORAGE_WORKER.get(serverLevel.entityManager.permanentStorage); - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - WORKER_LOAD_ASYNC.invoke(worker, chunkPos).whenComplete((entityData, error) -> { - if (error != null) { - countDownLatch.countDown(); - throw new RuntimeException(error); - } else { - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - } else { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } - } - }); - }); - - BukkitExecutor.createTask().runAsync(v -> { + NMSUtilsVersioned.runActionOnUnloadedEntityChunks(chunks, chunkCallback, countDownLatch).runAsync(v -> { try { countDownLatch.await(); } catch (InterruptedException error) { @@ -285,18 +253,72 @@ public static List> getPendingChunkActions() { } public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { - return new ProtoChunk(chunkPos, - UpgradeData.EMPTY, - serverLevel, - serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), - null); + return NMSUtilsVersioned.createProtoChunk(chunkPos, serverLevel); } public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { + @Nullable CompoundTag statesTag, @Nullable CompoundTag tileEntity) { ServerLevel serverLevel = levelChunk.level; + SetBlockContext setBlockContext = new SetBlockContext() { + + @Override + public LevelHeightAccessor levelHeightAccessor() { + return serverLevel; + } + + @Override + public void prepareChunkAccess(ChunkPos chunkPos) { + // Do nothing + } + + @Override + public LevelChunkSection getChunkSection(int i) { + return levelChunk.getSections()[i]; + } + + @Override + public Map getHeightmaps() { + return levelChunk.heightmaps; + } + + @Override + public void onSetBlockWithUpdate(BlockPos blockPos, BlockState blockState) { + serverLevel.setBlock(blockPos, blockState, 3); + } + + @Override + public void onPostSetBlock(BlockPos blockPos, BlockState blockState) { + NMSUtilsVersioned.markUnsaved(levelChunk); + } + + @Override + public void onLightUpdate(BlockPos blockPos, BlockState blockState, boolean isOriginallyChunkSectionEmpty, boolean isChunkSectionEmpty) { + if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) + serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); + + serverLevel.getLightEngine().checkBlock(blockPos); + } - if (!isValidPosition(serverLevel, blockPos)) + @Override + public void onBlockEntityUpdate(BlockPos blockPos, CompoundTag blockEntityTag) { + net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); + if (tileEntityCompound != null) { + tileEntityCompound.putInt("x", blockPos.getX()); + tileEntityCompound.putInt("y", blockPos.getY()); + tileEntityCompound.putInt("z", blockPos.getZ()); + BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); + if (worldBlockEntity != null) { + NMSUtilsVersioned.loadBlockEntity(worldBlockEntity, tileEntityCompound); + } + } + } + }; + return setBlock(setBlockContext, blockPos, combinedId, statesTag, tileEntity); + } + + public static BlockState setBlock(SetBlockContext setBlockContext, BlockPos blockPos, int combinedId, + @Nullable CompoundTag statesTag, @Nullable CompoundTag tileEntity) { + if (!isValidPosition(setBlockContext, blockPos)) return null; BlockState blockState = Block.stateById(combinedId); @@ -325,54 +347,40 @@ public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int } } - if ((blockState.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || + if ((NMSUtilsVersioned.isBlockStateLiquid(blockState) && plugin.getSettings().isLiquidUpdate()) || blockState.getBlock() instanceof BedBlock) { - serverLevel.setBlock(blockPos, blockState, 3); + setBlockContext.onSetBlockWithUpdate(blockPos, blockState); return blockState; } - int indexY = serverLevel.getSectionIndex(blockPos.getY()); + setBlockContext.prepareChunkAccess(new ChunkPos(blockPos)); - LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; + int indexY = setBlockContext.levelHeightAccessor().getSectionIndex(blockPos.getY()); - if (levelChunkSection == null) { - int yOffset = SectionPos.blockToSectionCoord(blockPos.getY()); - //noinspection deprecation - levelChunkSection = levelChunk.getSections()[indexY] = new LevelChunkSection(yOffset, levelChunk.biomeRegistry); - } + LevelChunkSection levelChunkSection = setBlockContext.getChunkSection(indexY); int blockX = blockPos.getX() & 15; int blockY = blockPos.getY(); int blockZ = blockPos.getZ() & 15; - boolean isOriginallyChunkSectionEmpty = levelChunkSection.hasOnlyAir(); + boolean isOriginallyChunkSectionEmpty = NMSUtilsVersioned.isLevelChunkSectionEmpty(levelChunkSection); levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); + Map heightmaps = setBlockContext.getHeightmaps(); + heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); + heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); + heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); + heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - levelChunk.setUnsaved(true); + setBlockContext.onPostSetBlock(blockPos, blockState); - boolean isChunkSectionEmpty = levelChunkSection.hasOnlyAir(); + boolean isChunkSectionEmpty = NMSUtilsVersioned.isLevelChunkSectionEmpty(levelChunkSection); - if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) - serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); - - serverLevel.getLightEngine().checkBlock(blockPos); + setBlockContext.onLightUpdate(blockPos, blockState, isOriginallyChunkSectionEmpty, isChunkSectionEmpty); if (tileEntity != null) { - net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); - if (tileEntityCompound != null) { - tileEntityCompound.putInt("x", blockPos.getX()); - tileEntityCompound.putInt("y", blockPos.getY()); - tileEntityCompound.putInt("z", blockPos.getZ()); - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.load(tileEntityCompound); - } + setBlockContext.onBlockEntityUpdate(blockPos, tileEntity); } return blockState; @@ -383,27 +391,8 @@ public static boolean isDoubleBlock(Block block, BlockState blockState) { blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; } - public record UnloadedChunkCompound(ChunkPosition chunkPosition, net.minecraft.nbt.CompoundTag chunkCompound) { - - public ListTag getSections() { - return chunkCompound.getList("sections", 10); - } - - public ListTag getEntities() { - return chunkCompound.getList("Entities", 10); - } - - public void setSections(ListTag sectionsList) { - chunkCompound.put("sections", sectionsList); - } - - public void setEntities(ListTag entitiesList) { - chunkCompound.put("entities", entitiesList); - } - - public void setBlockEntities(ListTag blockEntitiesList) { - chunkCompound.put("block_entities", blockEntitiesList); - } + public record UnloadedChunkCompound(ChunkPosition chunkPosition, + net.minecraft.nbt.CompoundTag chunkCompound) { public ServerLevel serverLevel() { return ((CraftWorld) chunkPosition.getWorld()).getHandle(); @@ -415,10 +404,10 @@ public ChunkPos chunkPos() { } - private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { + private static boolean isValidPosition(SetBlockContext setBlockContext, BlockPos blockPos) { return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); + !setBlockContext.levelHeightAccessor().isOutsideBuildHeight(blockPos.getY()); } public static abstract class ChunkCallback { @@ -434,14 +423,6 @@ public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad this.isWaitForChunkLoad = isWaitForChunkLoad; } - public final boolean isWaitForChunkLoad() { - return isWaitForChunkLoad; - } - - public final void setChunkLoadLatch(CountDownLatch chunkLoadLatch) { - this.chunkLoadLatch = chunkLoadLatch; - } - public abstract void onLoadedChunk(LevelChunk levelChunk); public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); @@ -458,8 +439,11 @@ public final void onChunkNotExist(ChunkPosition chunkPosition) { return; ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { - LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); - BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); + BukkitExecutor.ensureMain(() -> { + ServerLevel serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle(); + LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); + onLoadedChunk(levelChunk); + }); }); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsBlockEntity.java b/NMS/src/main/templates/crops/CropsBlockEntity.java.template similarity index 94% rename from NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsBlockEntity.java rename to NMS/src/main/templates/crops/CropsBlockEntity.java.template index eb7f0db6de..cbe4fb3831 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsBlockEntity.java +++ b/NMS/src/main/templates/crops/CropsBlockEntity.java.template @@ -1,10 +1,12 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.crops; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsTickingBlockEntity; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsTickingMethod; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; @@ -65,7 +67,6 @@ public static void forEachChunk(List chunkPositions, Consumer SERVER_LEVEL_SIMPLE_RANDOM = new ReflectField<>( - ServerLevel.class, RandomSource.class, "simpleRandom"); + private static final ReflectField<${SERVER_LEVEL_RANDOM_TYPE}> SERVER_LEVEL_SIMPLE_RANDOM = new ReflectField<>( + ServerLevel.class, ${SERVER_LEVEL_RANDOM_TYPE}.class, "simpleRandom"); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @@ -70,12 +71,12 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { ServerLevel serverLevel = levelChunk.level; LevelChunkSection[] sections = levelChunk.getSections(); - int minSection = serverLevel.getMinSectionY(); + int minSection = NMSUtilsVersioned.getMinSection(serverLevel); ChunkPos chunkPos = levelChunk.getPos(); int chunkOffsetX = chunkPos.x << 4; int chunkOffsetZ = chunkPos.z << 4; - RandomSource simpleRandom = SERVER_LEVEL_SIMPLE_RANDOM.get(serverLevel); + ${SERVER_LEVEL_RANDOM_TYPE} simpleRandom = SERVER_LEVEL_SIMPLE_RANDOM.get(serverLevel); for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { LevelChunkSection levelChunkSection = sections[sectionIndex]; @@ -83,8 +84,8 @@ protected void doTick(LevelChunk levelChunk, int tickSpeed) { continue; } - ca.spottedleaf.moonrise.common.list.ShortList tickList = - levelChunkSection.moonrise$getTickingBlockList(); + TickingBlockList tickList = NMSUtilsVersioned.getTickingBlockList(levelChunkSection); + int tickingBlocks = tickList.size(); if (tickingBlocks <= 0) { continue; diff --git a/NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template b/NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template new file mode 100644 index 0000000000..2253858535 --- /dev/null +++ b/NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template @@ -0,0 +1,84 @@ +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon; + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.config.SettingsManager; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEntityEnderDragon; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.DragonUtils; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.EndWorldEndDragonFightHandler; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEndDragonFight; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.level.Level; +import org.bukkit.Location; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftEnderDragon; + +public class AbstractIslandEntityEnderDragon extends EnderDragon { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + @NotNull + public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { + return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : + new EnderDragon(entityTypes, level); + } + + protected final ServerLevel serverLevel; + protected final Dimension dimension; + protected BlockPos islandBlockPos; + + protected AbstractIslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { + this(level); + this.islandBlockPos = islandBlockPos; + } + + protected AbstractIslandEntityEnderDragon(Level level) { + super(EntityType.ENDER_DRAGON, level); + this.serverLevel = (ServerLevel) level; + this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + } + + @Override + public void aiStep() { + DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); + } + + @Override + @NotNull + public CraftEnderDragon getBukkitEntity() { + return (CraftEnderDragon) super.getBukkitEntity(); + } + + protected void finalizeIslandEnderDragon() { + if (!(NMSUtilsVersioned.getEndDragonFight(this.serverLevel) instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) + return; + + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); + } + + if (island == null) + return; + + Location middleBlock = island.getCenter(dimension); + + SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); + if (dimensionConfig instanceof SettingsManager.Worlds.End) { + middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); + } + + this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); + + IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, + this.islandBlockPos, (IslandEntityEnderDragon) this); + dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); + } + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/DragonUtils.java b/NMS/src/main/templates/dragon/DragonUtils.java.template similarity index 94% rename from NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/DragonUtils.java rename to NMS/src/main/templates/dragon/DragonUtils.java.template index 3d912685e0..954a6e89fa 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/DragonUtils.java +++ b/NMS/src/main/templates/dragon/DragonUtils.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.dragon; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon; import com.bgsoftware.common.reflection.ReflectField; import net.minecraft.core.BlockPos; diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndWorldEndDragonFightHandler.java b/NMS/src/main/templates/dragon/EndWorldEndDragonFightHandler.java.template similarity index 96% rename from NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndWorldEndDragonFightHandler.java rename to NMS/src/main/templates/dragon/EndWorldEndDragonFightHandler.java.template index 5f7e254e7b..88cbee6092 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndWorldEndDragonFightHandler.java +++ b/NMS/src/main/templates/dragon/EndWorldEndDragonFightHandler.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEndDragonFight.java b/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template similarity index 90% rename from NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEndDragonFight.java rename to NMS/src/main/templates/dragon/IslandEndDragonFight.java.template index 9a7f3f22d3..8eb131eb63 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEndDragonFight.java +++ b/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.dragon; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; @@ -6,7 +6,9 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.DragonUtils; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -26,7 +28,8 @@ import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.phys.Vec3; import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftPlayer; +import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.event.entity.CreatureSpawnEvent; @@ -138,7 +141,7 @@ public BlockPattern.BlockPatternMatch findExitPortal() { try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); - for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { + for (int y = highestBlock; y >= NMSUtilsVersioned.getMinBuildHeight(this.serverLevel); --y) { currentPosition.setY(y); BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); @@ -177,8 +180,9 @@ private void updateBattlePlayers() { for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { Player bukkitPlayer = superiorPlayer.asPlayer(); if (bukkitPlayer != null) { - ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); - if (serverPlayer.serverLevel().equals(this.serverLevel)) { + ServerLevel serverLevel = ((CraftWorld) bukkitPlayer.getWorld()).getHandle(); + if (serverLevel.equals(this.serverLevel)) { + ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); this.dragonEvent.addPlayer(serverPlayer); nearbyPlayers.add(serverPlayer.getUUID()); } @@ -197,10 +201,10 @@ private IslandEntityEnderDragon spawnEnderDragon() { IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); - entityEnderDragon.absMoveTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), + NMSUtilsVersioned.moveEntity(entityEnderDragon, this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); - this.serverLevel.addFreshEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); + NMSUtilsVersioned.addEntity(this.serverLevel, entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); this.dragonUUID = entityEnderDragon.getUUID(); this.resetSpikeCrystals(); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/SpikesCache.java b/NMS/src/main/templates/dragon/SpikesCache.java.template similarity index 98% rename from NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/SpikesCache.java rename to NMS/src/main/templates/dragon/SpikesCache.java.template index eddeb4dfc9..034ec9fbb5 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/SpikesCache.java +++ b/NMS/src/main/templates/dragon/SpikesCache.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.dragon; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon; import com.bgsoftware.common.annotations.NotNull; diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/generator/IslandsGeneratorImpl.java b/NMS/src/main/templates/generator/IslandsGeneratorImpl.java.template similarity index 96% rename from NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/generator/IslandsGeneratorImpl.java rename to NMS/src/main/templates/generator/IslandsGeneratorImpl.java.template index 5b4e83719b..a6a26e3f9a 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/generator/IslandsGeneratorImpl.java +++ b/NMS/src/main/templates/generator/IslandsGeneratorImpl.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.generator; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.generator; import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; diff --git a/NMS/src/main/templates/hologram/AbstractEntityHologram.java.template b/NMS/src/main/templates/hologram/AbstractEntityHologram.java.template new file mode 100644 index 0000000000..09aaca29bb --- /dev/null +++ b/NMS/src/main/templates/hologram/AbstractEntityHologram.java.template @@ -0,0 +1,140 @@ +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.hologram; + +import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.decoration.ArmorStand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.bukkit.Bukkit; +import ${CRAFTBUKKIT_PACKAGE}.CraftServer; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftArmorStand; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftEntity; +import ${CRAFTBUKKIT_PACKAGE}.util.CraftChatMessage; + +public class AbstractEntityHologram extends ArmorStand implements Hologram { + + private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); + + private CraftEntity bukkitEntity; + + protected AbstractEntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + + setInvisible(true); + setSmall(true); + setShowArms(false); + setNoGravity(true); + setNoBasePlate(true); + setMarker(true); + forceSetBoundingBox(EMPTY_BOUND); + + super.collides = false; + super.setCustomNameVisible(true); + } + + @Override + public void setHologramName(String name) { + super.setCustomName(CraftChatMessage.fromStringOrNull(name)); + } + + @Override + public void removeHologram() { + super.remove(RemovalReason.DISCARDED); + } + + @Override + public org.bukkit.entity.ArmorStand getHandle() { + return this.getBukkitEntity(); + } + + @Override + public void inactiveTick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + @Override + public boolean repositionEntityAfterLoad() { + return false; + } + + public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { + // Prevent stand being equipped + } + public void setSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { + // Prevent stand being equipped + } + + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + + @Override + public void tick() { + // Disable normal ticking for this entity. + + // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. + if (this.onGround) { + this.onGround = false; + } + } + + public void forceSetBoundingBox(AABB boundingBox) { + super.setBoundingBox(boundingBox); + } + + @Override + public CraftArmorStand getBukkitEntity() { + if (bukkitEntity == null) { + bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); + } + return (CraftArmorStand) bukkitEntity; + } + + @Override + public void remove(RemovalReason removalReason) { + // Prevent being killed. + } + + @Override + public void playSound(SoundEvent soundEvent, float volume, float pitch) { + // Remove sounds. + } + + /* + * The field Entity.invulnerable is private. + * It's only used while saving NBTTags, but since the entity would be killed + * on chunk unload, we prefer to override isInvulnerable(). + */ + public boolean isInvulnerableTo(ServerLevel serverLevel, DamageSource damageSource) { + return true; + } + public boolean isInvulnerableTo(DamageSource damageSource) { + return true; + } + + @Override + public void setCustomName(Component component) { + // Locks the custom name. + } + + @Override + public void setCustomNameVisible(boolean isCustomNameVisible) { + // Locks the custom name. + } + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuBrewingStandBlockEntity.java b/NMS/src/main/templates/menu/MenuBrewingStandBlockEntity.java.template similarity index 91% rename from NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuBrewingStandBlockEntity.java rename to NMS/src/main/templates/menu/MenuBrewingStandBlockEntity.java.template index 8a8cd6214a..c690c79f02 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuBrewingStandBlockEntity.java +++ b/NMS/src/main/templates/menu/MenuBrewingStandBlockEntity.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.menu; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuDispenserBlockEntity.java b/NMS/src/main/templates/menu/MenuDispenserBlockEntity.java.template similarity index 91% rename from NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuDispenserBlockEntity.java rename to NMS/src/main/templates/menu/MenuDispenserBlockEntity.java.template index c676045834..4951b28d35 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuDispenserBlockEntity.java +++ b/NMS/src/main/templates/menu/MenuDispenserBlockEntity.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.menu; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuFurnaceBlockEntity.java b/NMS/src/main/templates/menu/MenuFurnaceBlockEntity.java.template similarity index 91% rename from NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuFurnaceBlockEntity.java rename to NMS/src/main/templates/menu/MenuFurnaceBlockEntity.java.template index e95f3ce628..9094ded689 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuFurnaceBlockEntity.java +++ b/NMS/src/main/templates/menu/MenuFurnaceBlockEntity.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.menu; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuHopperBlockEntity.java b/NMS/src/main/templates/menu/MenuHopperBlockEntity.java.template similarity index 92% rename from NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuHopperBlockEntity.java rename to NMS/src/main/templates/menu/MenuHopperBlockEntity.java.template index 7ec7fa8c6c..a829f2fb58 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuHopperBlockEntity.java +++ b/NMS/src/main/templates/menu/MenuHopperBlockEntity.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.menu; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/player/OfflinePlayerDataImpl.java b/NMS/src/main/templates/player/OfflinePlayerDataImpl.java.template similarity index 80% rename from NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/player/OfflinePlayerDataImpl.java rename to NMS/src/main/templates/player/OfflinePlayerDataImpl.java.template index 3370878921..6d4ff52332 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/player/OfflinePlayerDataImpl.java +++ b/NMS/src/main/templates/player/OfflinePlayerDataImpl.java.template @@ -1,11 +1,11 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.player; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.player; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.core.ObjectsPool; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.mojang.authlib.GameProfile; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; @@ -13,9 +13,9 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftPlayer; +import ${CRAFTBUKKIT_PACKAGE}.CraftServer; +import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer; import org.bukkit.entity.Player; import java.util.Optional; @@ -45,7 +45,7 @@ private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { if (serverLevel == null) return null; - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); + ServerPlayer serverPlayer = NMSUtilsVersioned.createServerPlayer(serverLevel, profile); this.fakePlayer = serverPlayer.getBukkitEntity(); this.fakePlayer.loadData(); @@ -62,7 +62,8 @@ public void setLocation(Location location) { ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); - serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + NMSUtilsVersioned.moveEntity(serverPlayer, location.getX(), location.getY(), + location.getZ(), location.getYaw(), location.getPitch()); } @Override diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/src/main/templates/spawners/TickingSpawnerBlockEntityNotifier.java.template similarity index 96% rename from NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/spawners/TickingSpawnerBlockEntityNotifier.java rename to NMS/src/main/templates/spawners/TickingSpawnerBlockEntityNotifier.java.template index d2e0ce1de9..51bde98fcc 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/spawners/TickingSpawnerBlockEntityNotifier.java +++ b/NMS/src/main/templates/spawners/TickingSpawnerBlockEntityNotifier.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.spawners; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.spawners; import net.minecraft.core.BlockPos; import net.minecraft.world.level.BaseSpawner; diff --git a/NMS/src/main/templates/utils/SetBlockContext.java.template b/NMS/src/main/templates/utils/SetBlockContext.java.template new file mode 100644 index 0000000000..e3f9205bdd --- /dev/null +++ b/NMS/src/main/templates/utils/SetBlockContext.java.template @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils; + +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.levelgen.Heightmap; + +import java.util.Map; + +public interface SetBlockContext { + + LevelHeightAccessor levelHeightAccessor(); + + void prepareChunkAccess(ChunkPos chunkPos); + + LevelChunkSection getChunkSection(int i); + + Map getHeightmaps(); + + void onSetBlockWithUpdate(BlockPos blockPos, BlockState blockState); + + void onPostSetBlock(BlockPos blockPos, BlockState blockState); + + void onLightUpdate(BlockPos blockPos, BlockState blockState, boolean isOriginallyChunkSectionEmpty, boolean isChunkSectionEmpty); + + void onBlockEntityUpdate(BlockPos blockPos, CompoundTag blockEntityTag); + +} diff --git a/NMS/src/main/templates/utils/TickingBlockList.java.template b/NMS/src/main/templates/utils/TickingBlockList.java.template new file mode 100644 index 0000000000..11ffe6391a --- /dev/null +++ b/NMS/src/main/templates/utils/TickingBlockList.java.template @@ -0,0 +1,9 @@ +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils; + +public interface TickingBlockList { + + int size(); + + int getRaw(int index); + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockEntityCache.java b/NMS/src/main/templates/world/BlockEntityCache.java.template similarity index 83% rename from NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockEntityCache.java rename to NMS/src/main/templates/world/BlockEntityCache.java.template index e61a5675ea..7cf37ad66a 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockEntityCache.java +++ b/NMS/src/main/templates/world/BlockEntityCache.java.template @@ -1,6 +1,5 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.world; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; -import net.minecraft.core.Registry; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntityType; @@ -19,7 +18,7 @@ private BlockEntityCache() { public static String getBlockEntityId(BlockState blockState) { return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { - for (BlockEntityType blockEntityType : Registry.BLOCK_ENTITY_TYPE) { + for (BlockEntityType blockEntityType : ${REGISTRY_CLASS}.BLOCK_ENTITY_TYPE) { if (blockEntityType.isValid(blockState)) { ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); if (resourceLocation != null) diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java b/NMS/src/main/templates/world/ChunkReaderImpl.java.template similarity index 78% rename from NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java rename to NMS/src/main/templates/world/ChunkReaderImpl.java.template index a4e5eeb5e3..678036b644 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/ChunkReaderImpl.java +++ b/NMS/src/main/templates/world/ChunkReaderImpl.java.template @@ -1,8 +1,10 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.world; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.PropertiesMapper; import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.core.BlockPos; @@ -11,8 +13,6 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; @@ -25,12 +25,13 @@ import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; +import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; +import ${CRAFTBUKKIT_PACKAGE}.entity.CraftEntity; +import ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers; import org.bukkit.entity.EntityType; import org.bukkit.inventory.InventoryHolder; +import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -38,10 +39,14 @@ public class ChunkReaderImpl implements ChunkReader { - private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + private static final PalettedContainer EMPTY_STATES = NMSUtilsVersioned.createEmptyPlattedContainerStates(); + private static final byte[] FULL_LIGHT = new byte[2048]; private static final byte[] EMPTY_LIGHT = new byte[2048]; + static { + Arrays.fill(FULL_LIGHT, (byte) 0xFF); + } + private final ServerLevel serverLevel; private final int x; private final int z; @@ -53,9 +58,9 @@ public class ChunkReaderImpl implements ChunkReader { private final byte[][] emitlight; public ChunkReaderImpl(Chunk bukkitChunk) { - LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); + this.serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle(); + LevelChunk levelChunk = this.serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); - this.serverLevel = levelChunk.level; ChunkPos chunkPos = levelChunk.getPos(); this.x = chunkPos.x; this.z = chunkPos.z; @@ -70,19 +75,20 @@ public ChunkReaderImpl(Chunk bukkitChunk) { for (int i = 0; i < this.blockids.length; ++i) { LevelChunkSection levelChunkSection = levelChunkSections[i]; - this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); + this.blockids[i] = NMSUtilsVersioned.isLevelChunkSectionEmpty(levelChunkSection) ? EMPTY_STATES : + NMSUtilsVersioned.copyPalettedContainer(levelChunkSection.getStates()); DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) - .getDataLayerData(SectionPos.of(this.x, i, this.z)); + .getDataLayerData(SectionPos.of(this.x, this.serverLevel.getSectionYFromSectionIndex(i), this.z)); if (skyLightArray == null) { - this.skylight[i] = EMPTY_LIGHT; + this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; } else { this.skylight[i] = new byte[2048]; System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); } DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) - .getDataLayerData(SectionPos.of(this.x, i, this.z)); + .getDataLayerData(SectionPos.of(this.x, this.serverLevel.getSectionYFromSectionIndex(i), this.z)); if (emitLightArray == null) { this.emitlight[i] = EMPTY_LIGHT; } else { @@ -92,7 +98,7 @@ public ChunkReaderImpl(Chunk bukkitChunk) { } levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(); + net.minecraft.nbt.CompoundTag compoundTag = NMSUtilsVersioned.saveBlockEntity(blockEntity); compoundTag.remove("x"); compoundTag.remove("y"); @@ -121,7 +127,7 @@ public int getZ() { @Override public Material getType(int x, int y, int z) { - return CraftMagicNumbers.getMaterial(getBlockState(x, y, z).getBlock()); + return NMSUtilsVersioned.getMaterialFromBlock(getBlockState(x, y, z).getBlock()); } @Override @@ -167,8 +173,8 @@ public CompoundTag readBlockStates(int x, int y, int z) { @Override public byte[] getLightLevels(int x, int y, int z) { int off = (y & 15) << 7 | z << 3 | x >> 1; - int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + int skyLightLevel = this.skylight[this.serverLevel.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; + int emitLightLevel = this.emitlight[this.serverLevel.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; } @@ -191,12 +197,7 @@ public void forEachEntity(EntityConsumer consumer) { } private BlockState getBlockState(int x, int y, int z) { - return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); - } - - private int getSectionIndex(int y) { - int sectionIndex = SectionPos.blockToSectionCoord(y); - return sectionIndex - this.serverLevel.getMinSection(); + return this.blockids[this.serverLevel.getSectionIndex(y)].get(x, y & 15, z); } private static class CachedEntity { @@ -217,8 +218,8 @@ private static class CachedEntity { this.pitch = entity.getXRot(); this.entityType = entity.getBukkitEntity().getType(); - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); + net.minecraft.nbt.CompoundTag compoundTag = NMSUtilsVersioned.saveEntity(entity); + compoundTag.putFloat("Yaw", entity.getYRot()); compoundTag.putFloat("Pitch", entity.getXRot()); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/KeyBlocksCache.java b/NMS/src/main/templates/world/KeyBlocksCache.java.template similarity index 77% rename from NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/KeyBlocksCache.java rename to NMS/src/main/templates/world/KeyBlocksCache.java.template index 07c8a76549..834f395baf 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/KeyBlocksCache.java +++ b/NMS/src/main/templates/world/KeyBlocksCache.java.template @@ -1,11 +1,10 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.world; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.key.Keys; -import net.minecraft.core.Registry; import net.minecraft.world.level.block.Block; import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; +import ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers; import java.util.IdentityHashMap; import java.util.Map; @@ -26,7 +25,7 @@ public static Key getBlockKey(Block block) { } public static void cacheAllBlocks() { - Registry.BLOCK.forEach(KeyBlocksCache::getBlockKey); + ${REGISTRY_CLASS}.BLOCK.forEach(KeyBlocksCache::getBlockKey); } } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/PropertiesMapper.java b/NMS/src/main/templates/world/PropertiesMapper.java.template similarity index 96% rename from NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/PropertiesMapper.java rename to NMS/src/main/templates/world/PropertiesMapper.java.template index 511d5ddeac..66aa943bdf 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/PropertiesMapper.java +++ b/NMS/src/main/templates/world/PropertiesMapper.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.world; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; import com.bgsoftware.superiorskyblock.core.logging.Log; import net.minecraft.world.level.block.state.properties.BlockStateProperties; @@ -34,7 +34,6 @@ public class PropertiesMapper { fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); - fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); @@ -50,6 +49,8 @@ public class PropertiesMapper { fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); + PropertiesMapperVersioned.initializeFields(fieldsToNames); + try { for (Field field : BlockStateProperties.class.getFields()) { field.setAccessible(true); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionDataImpl.java b/NMS/src/main/templates/world/WorldEditSessionDataImpl.java.template similarity index 98% rename from NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionDataImpl.java rename to NMS/src/main/templates/world/WorldEditSessionDataImpl.java.template index af398734af..5b74c899f4 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionDataImpl.java +++ b/NMS/src/main/templates/world/WorldEditSessionDataImpl.java.template @@ -1,8 +1,9 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.world; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.core.BlockPos; import net.minecraft.world.level.ChunkPos; diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java b/NMS/src/main/templates/world/WorldEditSessionImpl.java.template similarity index 59% rename from NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java rename to NMS/src/main/templates/world/WorldEditSessionImpl.java.template index c9c262cadf..d460e6a48b 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionImpl.java +++ b/NMS/src/main/templates/world/WorldEditSessionImpl.java.template @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.world; +package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; @@ -7,53 +7,32 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; -import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.SetBlockContext; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.ByteTag; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.google.common.base.Preconditions; import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.ticks.ProtoChunkTicks; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; -import org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator; -import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; +import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import org.bukkit.generator.ChunkGenerator; import java.util.Collections; @@ -72,7 +51,7 @@ public class WorldEditSessionImpl implements WorldEditSession { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final boolean isStarLightInterface = ((Supplier) () -> { try { - Class.forName("ca.spottedleaf.starlight.common.light.StarLightInterface"); + Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); return true; } catch (ClassNotFoundException error) { return false; @@ -90,6 +69,53 @@ public class WorldEditSessionImpl implements WorldEditSession { @Nullable private ServerLevel serverLevel; + private final SetBlockContext SET_BLOCK_CONTEXT = new SetBlockContext() { + + ChunkData chunkData; + + @Override + public LevelHeightAccessor levelHeightAccessor() { + return levelHeightAccessor; + } + + @Override + public void prepareChunkAccess(ChunkPos chunkPos) { + chunkData = chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); + } + + @Override + public LevelChunkSection getChunkSection(int i) { + return chunkData.chunkSections[i]; + } + + @Override + public Map getHeightmaps() { + return chunkData.heightmaps; + } + + @Override + public void onSetBlockWithUpdate(BlockPos blockPos, BlockState blockState) { + blocksToUpdate.add(new Pair<>(blockPos, blockState)); + } + + @Override + public void onPostSetBlock(BlockPos blockPos, BlockState blockState) { + // Do nothing + } + + @Override + public void onLightUpdate(BlockPos blockPos, BlockState blockState, boolean isOriginallyChunkSectionEmpty, boolean isChunkSectionEmpty) { + if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) + chunkData.lights.add(blockPos); + } + + @Override + public void onBlockEntityUpdate(BlockPos blockPos, CompoundTag blockEntityTag) { + blockEntities.add(new Pair<>(blockPos, blockEntityTag)); + } + + }; + public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { return POOL.obtain().initialize(serverLevel); } @@ -109,10 +135,10 @@ private WorldEditSessionImpl initialize(ServerLevel serverLevel) { } private WorldEditSessionImpl initialize(Dimension dimension) { - DimensionType dimensionType = getDimensionTypeFromDimension(dimension); + DimensionType dimensionType = NMSUtilsVersioned.getDimensionTypeFromDimension(dimension); this.serverLevel = null; this.dimension = dimension; - this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); + this.levelHeightAccessor = createLevelHeightAccessor(dimensionType.minY(), dimensionType.height()); return this; } @@ -120,64 +146,7 @@ private WorldEditSessionImpl initialize(Dimension dimension) { public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag blockEntityData) { BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - if (!isValidPosition(blockPos)) - return; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - blocksToUpdate.add(new Pair<>(blockPos, blockState)); - return; - } - - ChunkPos chunkPos = new ChunkPos(blockPos); - - if (blockEntityData != null) - blockEntities.add(new Pair<>(blockPos, blockEntityData)); - - ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); - - if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) - chunkData.lights.add(blockPos); - - LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); + NMSUtils.setBlock(SET_BLOCK_CONTEXT, blockPos, combinedId, statesTag, blockEntityData); } @Override @@ -203,10 +172,12 @@ public List getAffectedChunks() { public void applyBlocks(Chunk bukkitChunk) { Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); - LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); + ServerLevel serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle(); + LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); ChunkPos chunkPos = levelChunk.getPos(); - ChunkData chunkData = this.chunks.remove(chunkPos.toLong()); + long chunkKey = chunkPos.toLong(); + ChunkData chunkData = this.chunks.remove(chunkKey); if (chunkData == null) return; @@ -231,7 +202,7 @@ public void applyBlocks(Chunk bukkitChunk) { } } - levelChunk.setUnsaved(true); + NMSUtilsVersioned.markUnsaved(levelChunk); } @Override @@ -249,29 +220,19 @@ public void finish(Island island) { blockEntityCompound.putInt("x", blockPos.getX()); blockEntityCompound.putInt("y", blockPos.getY()); blockEntityCompound.putInt("z", blockPos.getZ()); - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (blockEntityCompound.getByte("SSB.HasSignLines") == 1) { - // We want to convert the sign lines from raw string to json - for (int i = 1; i <= 4; ++i) { - String line = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(line)) { - Component newLine = CraftChatMessage.fromString(line)[0]; - blockEntityCompound.putString("Text" + i, Component.Serializer.toJson(newLine)); - } - } - } + NMSUtilsVersioned.rewriteSignLines(blockEntityCompound); - if (worldBlockEntity != null) - worldBlockEntity.load(blockEntityCompound); + BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); + if (worldBlockEntity != null) { + NMSUtilsVersioned.loadBlockEntity(worldBlockEntity, blockEntityCompound); + } } }); if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - threadedLevelLightEngine.relight(lightenChunks, chunkCallback -> { - }, completeCallback -> { - }); + NMSUtilsVersioned.relightChunks(threadedLevelLightEngine, lightenChunks); this.lightenChunks.clear(); } @@ -324,16 +285,21 @@ private boolean isValidPosition(BlockPos blockPos) { !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); } - private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { - ResourceKey resourceKey; - switch (dimension.getEnvironment()) { - case NETHER -> resourceKey = DimensionType.NETHER_LOCATION; - case THE_END -> resourceKey = DimensionType.END_LOCATION; - default -> resourceKey = DimensionType.OVERWORLD_LOCATION; - } + private static LevelHeightAccessor createLevelHeightAccessor(int minY, int height) { + return new LevelHeightAccessor() { + @Override + public int getHeight() { + return height; + } + + public int getMinBuildHeight() { + return minY; + } - Registry registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY); - return registry.getOrThrow(resourceKey); + public int getMinY() { + return minY; + } + }; } public class ChunkData { @@ -348,12 +314,10 @@ private ChunkData(long chunkKey) { ChunkPos chunkPos = new ChunkPos(chunkKey); - Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); + NMSUtilsVersioned.createChunkSections(serverLevel, levelHeightAccessor, this.chunkSections, dimension); - createChunkSections(biomesRegistry); - - ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); + ProtoChunk tempChunk = NMSUtilsVersioned.createProtoChunk( + chunkPos, this.chunkSections, levelHeightAccessor, serverLevel); createHeightmaps(tempChunk); if (serverLevel != null) @@ -378,38 +342,13 @@ public List lights() { return this.lights; } - private void createChunkSections(Registry biomesRegistry) { - Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, - IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); - - for (int i = 0; i < this.chunkSections.length; ++i) { - int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i); - - PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), - biome, PalettedContainer.Strategy.SECTION_BIOMES); - PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - - this.chunkSections[i] = new LevelChunkSection(chunkSectionPos, statesContainer, biomesContainer); - } - } - private void runCustomWorldGenerator(ProtoChunk tempChunk) { ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) return; - CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), - bukkitGenerator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(tempChunk), - ChunkStatus.SURFACE, 0); - - chunkGenerator.buildSurface(region, - serverLevel.structureFeatureManager().forWorldGenRegion(region), - tempChunk); + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, tempChunk); // We want to copy the level chunk sections back LevelChunkSection[] tempChunkSections = tempChunk.getSections(); @@ -422,7 +361,7 @@ private void runCustomWorldGenerator(ProtoChunk tempChunk) { private void createHeightmaps(ProtoChunk tempChunk) { for (Heightmap.Types heightmapType : Heightmap.Types.values()) { - if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { + if (${CHUNK_STATUS_CLASS}.FULL.heightmapsAfter().contains(heightmapType)) { this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); } } @@ -430,4 +369,5 @@ private void createHeightmaps(ProtoChunk tempChunk) { } + } diff --git a/NMS/v1_17/properties b/NMS/v1_17/properties new file mode 100644 index 0000000000..0f646ce51e --- /dev/null +++ b/NMS/v1_17/properties @@ -0,0 +1,7 @@ +NMS_VERSION=v1_17 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit.v1_17_R1 +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.Registry +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=java.util.Random \ No newline at end of file diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java index 1d55301417..5f39410541 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java @@ -1,219 +1,26 @@ package com.bgsoftware.superiorskyblock.nms.v1_17; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; -import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; -import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.nms.algorithms.PaperGlowEnchantment; import com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment; -import com.bgsoftware.superiorskyblock.nms.v1_17.menu.MenuBrewingStandBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_17.menu.MenuDispenserBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_17.menu.MenuFurnaceBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_17.menu.MenuHopperBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_17.world.BlockEntityCache; -import com.bgsoftware.superiorskyblock.nms.v1_17.world.KeyBlocksCache; -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.TextReplacementConfig; -import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.Container; -import net.minecraft.world.entity.item.FallingBlockEntity; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.data.Ageable; -import org.bukkit.block.data.BlockData; -import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.v1_17_R1.CraftServer; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftFallingBlock; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftMinecart; import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage; -import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.potion.PotionEffect; -import org.jetbrains.annotations.NotNull; import java.lang.reflect.Field; -import java.util.EnumMap; -import java.util.Optional; -import java.util.function.BiFunction; -public class NMSAlgorithmsImpl implements NMSAlgorithms { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms { private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); - private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); - - static { - MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); - } - - private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { - @Override - public byte[] processClass(byte[] classBytes, String path) { - return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); - } - }; - - @Override - public void registerCommand(BukkitCommand command) { - ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); - } - @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]); } - @Override - public int getCombinedId(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return 0; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(wrapper.getHandle()); - } - return Block.getId(blockState); - } - - @Override - public int getCombinedId(Material material, byte data) { - BlockState blockState; - - if (data == 0) { - Block block = CraftMagicNumbers.getBlock(material); - if (block == null) - return -1; - blockState = block.defaultBlockState(); - } else { - blockState = CraftMagicNumbers.getBlock(material, data); - } - - return blockState == null ? -1 : Block.getId(blockState); - } - - @Override - public Optional getTileEntityIdFromCombinedId(int combinedId) { - BlockState blockState = Block.stateById(combinedId); - - if (!blockState.hasBlockEntity()) - return Optional.empty(); - - String id = BlockEntityCache.getBlockEntityId(blockState); - - return Text.isBlank(id) ? Optional.empty() : Optional.of(id); - } - - @Override - public int compareMaterials(Material o1, Material o2) { - int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); - int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); - return Integer.compare(firstMaterial, secondMaterial); - } - - @Override - public short getBlockDataValue(org.bukkit.block.BlockState blockState) { - BlockData blockData = blockState.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getBlockDataValue(org.bukkit.block.Block block) { - BlockData blockData = block.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getMaxBlockDataValue(Material material) { - if (!material.isBlock()) - return 0; - - BlockData blockData = Bukkit.createBlockData(material); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); - } - - @Override - public Key getBlockKey(int combinedId) { - Block block = Block.stateById(combinedId).getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { - AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); - Block block = minecart.getDisplayBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { - FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); - Block block = fallingBlock.getBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public void setCustomModel(ItemMeta itemMeta, int customModel) { - itemMeta.setCustomModelData(customModel); - } - - @Override - public void setItemModel(ItemMeta itemMeta, String itemModel) { - // Doesn't exist - } - - @Override - public void setRarity(ItemMeta itemMeta, String rarity) { - // Doesn't exist - } - - @Override - public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { - // Doesn't exist - } - - @Override - public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { - if (!potionMeta.hasCustomEffects()) - potionMeta.setColor(potionEffect.getType().getColor()); - potionMeta.addCustomEffect(potionEffect, true); - } - @Override public String getMinecraftKey(ItemStack itemStack) { return Registry.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); @@ -224,46 +31,6 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } - @Override - public int getMaxWorldSize() { - return Bukkit.getMaxWorldSize(); - } - - @Override - public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { - MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); - return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); - } - - @Override - public double getCurrentTps() { - try { - return MinecraftServer.getServer().tps1.getAverage(); - } catch (Throwable error) { - //noinspection removal - return MinecraftServer.getServer().recentTps[0]; - } - } - - @Override - public int getDataVersion() { - return CraftMagicNumbers.INSTANCE.getDataVersion(); - } - - @Override - public ClassProcessor getClassProcessor() { - return CLASS_PROCESSOR; - } - - @Override - public void handlePaperChatRenderer(Object event) { - if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) - return; - - io.papermc.paper.chat.ChatRenderer originalRenderer = asyncChatEvent.renderer(); - asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); - } - private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; @@ -289,43 +56,4 @@ private static Enchantment initializeGlowEnchantment() { return glowEnchant; } - private interface MenuCreator extends BiFunction { - - } - - private static class ChatRendererWrapper { - - private static final String MESSAGE_PLACEHOLDER = "{message}"; - private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = - net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); - - private final ChatRenderer renderer = new ChatRenderer() { - @Override - public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, - net.kyori.adventure.text.@NotNull Component sourceDisplayName, - net.kyori.adventure.text.@NotNull Component message, - @NotNull Audience viewer) { - String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer - .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); - Island island = superiorPlayer.getIsland(); - - return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( - Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) - .replaceText(TextReplacementConfig.builder() - .matchLiteral(MESSAGE_PLACEHOLDER) - .replacement(message) - .build()); - } - }; - - private final ChatRenderer originalRenderer; - - public ChatRendererWrapper(ChatRenderer originalRenderer) { - this.originalRenderer = originalRenderer; - } - - } - } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java index 74ab59f8fa..aba28e52c6 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java @@ -1,26 +1,19 @@ package com.bgsoftware.superiorskyblock.nms.v1_17; -import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.api.key.KeyMap; -import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; -import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_17.crops.CropsBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_17.crops.CropsTickingMethod; +import com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_17.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.nms.v1_17.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; @@ -40,12 +33,6 @@ import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkBiomeContainer; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; @@ -53,12 +40,7 @@ import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import net.minecraft.world.phys.AABB; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; @@ -70,36 +52,23 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.concurrent.CompletableFuture; -public class NMSChunksImpl implements NMSChunks { +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSChunks { private static final ReflectField BIOME_BASE_ARRAY = new ReflectField<>( ChunkBiomeContainer.class, Biome[].class, "f"); private static final ReflectField CHUNK_BIOME_CONTAINER = new ReflectField<>( LevelChunk.class, ChunkBiomeContainer.class, Modifier.PRIVATE, 1); - private static final boolean hasStatesIterator = new ReflectMethod<>(PalettedContainer.class, - "forEachLocation", PalettedContainer.CountConsumer.class).isValid(); - - private final SuperiorSkyblockPlugin plugin; - public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - KeyBlocksCache.cacheAllBlocks(); - CropsTickingMethod.register(); + super(plugin); } @Override - public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { - if (chunkPositions.isEmpty()) - return; - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.SET_BIOME, false) { + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); @@ -129,8 +98,14 @@ public void onLoadedChunk(LevelChunk levelChunk) { } @Override - public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag unloadedChunk) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + if (!chunkCompound.contains("Level", 10)) + return; + + CompoundTag unloadedChunk = chunkCompound.getCompound("Level"); + + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); Biome biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome); @@ -143,19 +118,12 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag unloadedChu public void onFinish() { // Do nothing. } - }); + }; } @Override - public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { - if (chunkPositions.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), - chunkPosition.getX(), chunkPosition.getZ(), false)); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.DELETE_CHUNK, false) { + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Arrays.fill(levelChunk.getSections(), LevelChunk.EMPTY_SECTION); @@ -166,8 +134,14 @@ public void onLoadedChunk(LevelChunk levelChunk) { } @Override - public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag unloadedChunk) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + if (!chunkCompound.contains("Level", 10)) + return; + + CompoundTag unloadedChunk = chunkCompound.getCompound("Level"); + + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); ListTag sectionsList = new ListTag(); ListTag tileEntities = new ListTag(); @@ -177,18 +151,13 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag unloadedChu unloadedChunk.put("Entities", new ListTag()); if (!(serverLevel.generator instanceof IslandsGenerator)) { - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + ChunkPos chunkPos = unloadedChunkCompound.chunkPos(); ProtoChunk protoChunk = NMSUtils.createProtoChunk(chunkPos, serverLevel); - try { - CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), serverLevel.generator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(protoChunk), - ChunkStatus.SURFACE, 0); - customChunkGenerator.buildSurface(region, protoChunk); + try { + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } @@ -219,45 +188,33 @@ public void onFinish() { if (onFinish != null) onFinish.run(); } - }); + }; } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); - List chunkPositionsToCalculate = new LinkedList<>(); - - Iterator chunkPositionsIterator = chunkPositions.iterator(); - while (chunkPositionsIterator.hasNext()) { - ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); - if (cachedCalculatedChunk != null) { - allCalculatedChunks.add(cachedCalculatedChunk); - chunkPositionsIterator.remove(); - } else { - chunkPositionsToCalculate.add(chunkPosition); - } - } - - if (chunkPositions.isEmpty()) - return CompletableFuture.completedFuture(allCalculatedChunks); - - CompletableFuture> completableFuture = new CompletableFuture<>(); - - NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback( - ChunkLoadReason.BLOCKS_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); - allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.getSections())); + allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @Override - public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag unloadedChunk) { + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + if (!chunkCompound.contains("Level", 10)) + return; + + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + CompoundTag unloadedChunk = chunkCompound.getCompound("Level"); + ListTag sectionsList = unloadedChunk.getList("Sections", 10); LevelChunkSection[] levelChunkSections = new LevelChunkSection[sectionsList.size()]; @@ -272,7 +229,9 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag unloadedChu } } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, levelChunkSections); + ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); + + CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, levelChunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -283,20 +242,14 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag unloadedChu public void onFinish() { completableFuture.complete(allCalculatedChunks); } - }); - - return completableFuture; + }; } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); - - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - List> unloadedEntityTags = new LinkedList<>(); - - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( - ChunkLoadReason.ENTITIES_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { @@ -308,9 +261,12 @@ public void onLoadedChunk(LevelChunk levelChunk) { } @Override - public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag entityData) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - unloadedEntityTags.add(new Pair<>(serverLevel, entityData.getList("Entities", 10))); + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + if (!chunkCompound.contains("Level", 10)) + return; + + unloadedChunkCompounds.add(unloadedChunkCompound); latchCountDown(); } @@ -318,13 +274,17 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, CompoundTag entityData) @Override public void onFinish() { BukkitExecutor.ensureMain(() -> { - for (Pair worldUnloadedEntityTagsPair : unloadedEntityTags) { - for (Tag entityTag : worldUnloadedEntityTagsPair.getValue()) { + for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getCompound("Level") + .getList("Entities", 10); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + for (Tag entityTag : entitiesTag) { EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); if (entityType == null) continue; - Entity fakeEntity = EntityType.create((CompoundTag) entityTag, worldUnloadedEntityTagsPair.getKey()).orElse(null); + Entity fakeEntity = EntityType.create((CompoundTag) entityTag, serverLevel).orElse(null); if (fakeEntity != null) { fakeEntity.valid = false; if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) @@ -341,160 +301,7 @@ public void onFinish() { completableFuture.complete(chunkEntities); }); } - }); - - return completableFuture; - } - - @Override - public void injectChunkSections(org.bukkit.Chunk chunk) { - // No implementation - } - - @Override - public boolean isChunkEmpty(org.bukkit.Chunk bukkitChunk) { - LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); - return Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> - chunkSection == LevelChunk.EMPTY_SECTION || chunkSection.isEmpty()); - } - - @Override - public org.bukkit.Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); - return chunkAccess instanceof LevelChunk levelChunk ? levelChunk.getBukkitChunk() : null; - } - - @Override - public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean stop) { - if (plugin.getSettings().getCropsInterval() <= 0) - return; - - - if (stop) { - CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); - if (cropsBlockEntity != null) - cropsBlockEntity.remove(); - } else { - LevelChunk levelChunk = ((CraftChunk) chunk).getHandle(); - CropsBlockEntity.create(island, levelChunk); - } - } - - @Override - public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { - if (chunkPositions.isEmpty()) return; - CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> - cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); - } - - @Override - public void shutdown() { - List> pendingTasks = NMSUtils.getPendingChunkActions(); - - if (pendingTasks.isEmpty()) - return; - - Log.info("Waiting for chunk tasks to complete."); - - CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); - } - - @Override - public List getBlockEntities(Chunk chunk) { - LevelChunk levelChunk = ((CraftChunk) chunk).getHandle(); - List blockEntities = new LinkedList<>(); - - World bukkitWorld = chunk.getWorld(); - - levelChunk.getBlockEntities().keySet().forEach(blockPos -> - blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); - - return blockEntities; - } - - private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, LevelChunkSection[] chunkSections) { - KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); - List spawnersLocations = new LinkedList<>(); - - for (LevelChunkSection levelChunkSection : chunkSections) { - if (levelChunkSection != null && !levelChunkSection.isEmpty()) { - if (hasStatesIterator) { - levelChunkSection.getStates().forEachLocation((blockState, locationKey) -> { - int x = locationKey & 0xF; - int y = (locationKey >> 8) & 0xF; - int z = (locationKey >> 4) & 0xF; - calculateChunkInternal(blockState, x, y, z, chunkPosition, levelChunkSection, blockCounts, spawnersLocations); - }); - } else for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { - BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, - levelChunkSection, blockCounts, spawnersLocations); - } - } - } - - return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); - } - - private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, - LevelChunkSection levelChunkSection, KeyMap blockCounts, - List spawnersLocations) { - Block block = blockState.getBlock(); - - if (block == Blocks.AIR) - return; - - Location location = new Location(chunkPosition.getWorld(), - (chunkPosition.getX() << 4) + x, - levelChunkSection.bottomBlockY() + y, - (chunkPosition.getZ() << 4) + z); - - int blockAmount = 1; - - if (NMSUtils.isDoubleBlock(block, blockState)) { - blockAmount = 2; - blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); - } - - Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); - blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); - if (block == Blocks.SPAWNER) { - spawnersLocations.add(location); - } - } - - private static void removeEntities(LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - ServerLevel serverLevel = levelChunk.level; - - int chunkWorldCoordX = chunkPos.x << 4; - int chunkWorldCoordZ = chunkPos.z << 4; - - - AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinBuildHeight(), chunkWorldCoordZ, - chunkWorldCoordX + 15, serverLevel.getMaxBuildHeight(), chunkWorldCoordZ + 15); - - Iterator chunkEntities; - - try { - chunkEntities = levelChunk.entities.iterator(); - } catch (Throwable ex) { - List worldEntities = new LinkedList<>(); - serverLevel.getEntities().get(chunkBounds, worldEntities::add); - chunkEntities = worldEntities.iterator(); - } - - while (chunkEntities.hasNext()) { - Entity entity = chunkEntities.next(); - if (!(entity instanceof net.minecraft.world.entity.player.Player)) - entity.setRemoved(Entity.RemovalReason.DISCARDED); - } - } - - private static void removeBlockEntities(LevelChunk levelChunk) { - new LinkedList<>(levelChunk.getBlockEntities().keySet()).forEach(levelChunk.getLevel()::removeBlockEntity); - levelChunk.getBlockEntities().clear(); + }; } private static void removeBlocks(LevelChunk levelChunk) { diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSDragonFightImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSDragonFightImpl.java deleted file mode 100644 index 19c661d0e6..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSDragonFightImpl.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_17.dragon.EndWorldEndDragonFightHandler; -import com.bgsoftware.superiorskyblock.nms.v1_17.dragon.IslandEndDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_17.dragon.IslandEntityEnderDragon; -import com.bgsoftware.superiorskyblock.nms.v1_17.dragon.SpikesCache; -import com.google.common.cache.LoadingCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.advancement.Advancement; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.entity.Player; - -import java.lang.reflect.Modifier; -import java.util.List; - -public class NMSDragonFightImpl implements NMSDragonFight { - - private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( - EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField( - ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( - SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static boolean firstWorldPreparation = true; - - static { - ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); - } - - @Override - public void prepareEndWorld(World bukkitWorld) { - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); - - if (firstWorldPreparation) { - firstWorldPreparation = false; - SPIKE_CACHE.set(null, SpikesCache.getInstance()); - } - } - - @Nullable - @Override - public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return null; - - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); - return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); - } - - @Override - public void startDragonBattle(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); - } - - @Override - public void removeDragonBattle(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); - - if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { - islandEndDragonFight.removeBattlePlayers(); - islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); - } - } - - @Override - public void awardTheEndAchievement(Player player) { - Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); - if (advancement != null) - player.getAdvancementProgress(advancement).awardCriteria(""); - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSEntitiesImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSEntitiesImpl.java index 5ebfd9f4a4..0d841061a2 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSEntitiesImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSEntitiesImpl.java @@ -1,58 +1,30 @@ package com.bgsoftware.superiorskyblock.nms.v1_17; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; -import net.minecraft.world.level.ItemLike; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftAnimals; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; -import org.bukkit.entity.Animals; import org.bukkit.entity.minecart.PoweredMinecart; -import org.bukkit.inventory.EntityEquipment; -import org.bukkit.inventory.ItemStack; import java.lang.reflect.Modifier; -public class NMSEntitiesImpl implements NMSEntities { +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override - public ItemStack[] getEquipment(EntityEquipment entityEquipment) { - ItemStack[] itemStacks = new ItemStack[7]; - - itemStacks[0] = new ItemStack(Material.ARMOR_STAND); - itemStacks[1] = entityEquipment.getItemInMainHand(); - itemStacks[2] = entityEquipment.getItemInOffHand(); - itemStacks[3] = entityEquipment.getHelmet(); - itemStacks[4] = entityEquipment.getChestplate(); - itemStacks[5] = entityEquipment.getLeggings(); - itemStacks[6] = entityEquipment.getBoots(); - - return itemStacks; - } - - @Override - public boolean isAnimalFood(ItemStack itemStack, Animals animals) { - return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); - } - - @Override - public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override - public int getPortalTicks(org.bukkit.entity.Entity entity) { - return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); + protected int getPortalTicks(Entity entity) { + return PORTAL_TICKS.get(entity); } } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSHologramsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSHologramsImpl.java deleted file mode 100644 index 3618bcd8bc..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSHologramsImpl.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17; - -import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; -import com.bgsoftware.superiorskyblock.nms.NMSHolograms; -import com.google.common.base.Preconditions; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_17_R1.CraftServer; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftArmorStand; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage; -import org.bukkit.entity.Entity; - -@SuppressWarnings("unused") -public class NMSHologramsImpl implements NMSHolograms { - - @Override - public Hologram createHologram(Location location) { - Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); - serverLevel.addFreshEntity(entityHologram); - return entityHologram; - } - - @Override - public boolean isHologram(Entity entity) { - return ((CraftEntity) entity).getHandle() instanceof Hologram; - } - - public static class EntityHologram extends ArmorStand implements Hologram { - - private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); - - private CraftEntity bukkitEntity; - - EntityHologram(ServerLevel serverLevel, double x, double y, double z) { - super(serverLevel, x, y, z); - - setInvisible(true); - setSmall(true); - setShowArms(false); - setNoGravity(true); - setNoBasePlate(true); - setMarker(true); - forceSetBoundingBox(EMPTY_BOUND); - - super.collides = false; - super.setCustomNameVisible(true); - } - - @Override - public void setHologramName(String name) { - super.setCustomName(CraftChatMessage.fromStringOrNull(name)); - } - - @Override - public void removeHologram() { - super.remove(RemovalReason.DISCARDED); - } - - @Override - public org.bukkit.entity.ArmorStand getHandle() { - return this.getBukkitEntity(); - } - - @Override - public void inactiveTick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - @Override - public boolean repositionEntityAfterLoad() { - return false; - } - - @Override - public AABB getBoundingBoxForCulling() { - return EMPTY_BOUND; - } - - @Override - public void setSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { - // Prevent stand being equipped - } - - @Override - public void addAdditionalSaveData(CompoundTag compoundTag) { - // Do not save NBT. - } - - @Override - public void readAdditionalSaveData(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { - // Prevent stand being equipped - return InteractionResult.PASS; - } - - @Override - public void tick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - public void forceSetBoundingBox(AABB boundingBox) { - super.setBoundingBox(boundingBox); - } - - @Override - public CraftArmorStand getBukkitEntity() { - if (bukkitEntity == null) { - bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); - } - return (CraftArmorStand) bukkitEntity; - } - - @Override - public void remove(RemovalReason removalReason) { - // Prevent being killed. - } - - @Override - public void playSound(SoundEvent soundEvent, float volume, float pitch) { - // Remove sounds. - } - - @Override - public boolean saveAsPassenger(CompoundTag compoundTag) { - // Do not save NBT. - return false; - } - - @Override - public CompoundTag saveWithoutId(CompoundTag compoundTag) { - // Do not save NBT. - return compoundTag; - } - - @Override - public void load(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public boolean isInvulnerableTo(DamageSource damageSource) { - /* - * The field Entity.invulnerable is private. - * It's only used while saving NBTTags, but since the entity would be killed - * on chunk unload, we prefer to override isInvulnerable(). - */ - return true; - } - - @Override - public void setCustomName(Component component) { - // Locks the custom name. - } - - @Override - public void setCustomNameVisible(boolean isCustomNameVisible) { - // Locks the custom name. - } - - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSPlayersImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSPlayersImpl.java deleted file mode 100644 index 3d04197100..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSPlayersImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.nms.NMSPlayers; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.bgsoftware.superiorskyblock.nms.v1_17.player.OfflinePlayerDataImpl; -import com.bgsoftware.superiorskyblock.player.PlayerLocales; -import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.level.ServerPlayer; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; -import org.bukkit.entity.Item; -import org.bukkit.entity.Player; - -import java.util.Locale; - -public class NMSPlayersImpl implements NMSPlayers { - - private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(Player.class, "locale"); - - @Override - public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { - return OfflinePlayerDataImpl.create(offlinePlayer); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer) { - Player player = superiorPlayer.asPlayer(); - - if (player == null) - return; - - ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() - .ifPresent(property -> setSkinTexture(superiorPlayer, property)); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { - superiorPlayer.setTextureValue(property.getValue()); - } - - @SuppressWarnings("deprecation") - @Override - public void sendActionBar(Player player, String message) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); - } - - @Override - public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { - BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); - bossBar.addPlayer(player); - return bossBar; - } - - @SuppressWarnings("deprecation") - @Override - public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { - player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); - } - - @Override - public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { - return superiorPlayer.getUniqueId().equals(item.getThrower()); - } - - @Nullable - @Override - public Locale getPlayerLocale(Player player) { - if (PLAYER_LOCALE.isValid()) { - return player.locale(); - } else try { - //noinspection deprecation - return PlayerLocales.getLocale(player.getLocale()); - } catch (IllegalArgumentException error) { - return null; - } - } - - private static class BossBarImpl implements BossBar { - - private final org.bukkit.boss.BossBar bossBar; - private final BossBarTask bossBarTask; - - public BossBarImpl(String message, BarColor color, double ticksToRun) { - bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); - this.bossBarTask = BossBarTask.create(this, ticksToRun); - } - - @Override - public void addPlayer(Player player) { - this.bossBar.addPlayer(player); - this.bossBarTask.registerTask(player); - } - - @Override - public void removeAll() { - this.bossBar.removeAll(); - this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); - } - - @Override - public void setProgress(double progress) { - this.bossBar.setProgress(progress); - } - - @Override - public double getProgress() { - return this.bossBar.getProgress(); - } - - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java index 672f798645..13cac1aebe 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java @@ -1,91 +1,44 @@ package com.bgsoftware.superiorskyblock.nms.v1_17; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.ListTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.mojang.serialization.Dynamic; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; -import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; import java.util.Set; -@SuppressWarnings({"unused"}) -public class NMSTagsImpl implements NMSTags { +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSTags { @Override - public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag()); tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); - return CompoundTag.fromNBT(tagCompound); } @Override - public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { - if (compoundTag.containsKey("NBT")) { - // Old compound version, deserialize it accordingly - return deserializeItemOld(compoundTag); - } - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); - - int currentVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - int itemVersion = tagCompound.getInt("DataVersion"); - if (itemVersion < currentVersion) { - tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, - new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); - } - - ItemStack itemStack = ItemStack.of(tagCompound); - - return CraftItemStack.asCraftMirror(itemStack); + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; } - private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); - Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount").orElse(0); - short data = (short) compoundTag.getShort("data").orElse(0); - CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); - - org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - if (nbtData != null) - itemStack.setTag((net.minecraft.nbt.CompoundTag) nbtData.toNBT()); - - return CraftItemStack.asCraftMirror(itemStack); + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + return ItemStack.of(compoundTag); } @Override - @SuppressWarnings("ConstantConditions") - public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { - net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); - - if (compoundTag == null) - compoundTag = new net.minecraft.nbt.CompoundTag(); - - if (!compoundTag.contains("id")) - //noinspection deprecation - compoundTag.putString("id", entityType.getName()); + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.setTag(compoundTag); + } - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; @@ -147,29 +100,4 @@ public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } - @Override - public Object parseList(ListTag listTag) { - net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); - - for (Tag tag : listTag) - nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); - - return nbtTagList; - } - - @Override - public Object getNBTCompoundTag(Object object, String key) { - return ((net.minecraft.nbt.CompoundTag) object).get(key); - } - - @Override - public void setNBTCompoundTagValue(Object object, String key, Object value) { - ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); - } - - @Override - public int getNBTTagListSize(Object object) { - return ((net.minecraft.nbt.ListTag) object).size(); - } - } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java deleted file mode 100644 index acc2479106..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSUtils.java +++ /dev/null @@ -1,418 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.nms.v1_17.world.PropertiesMapper; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; -import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; -import com.google.common.base.Suppliers; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.storage.EntityStorage; -import net.minecraft.world.level.chunk.storage.IOWorker; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; - -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; - -public class NMSUtils { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( - ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); - private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( - EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); - private static final ReflectMethod> WORKER_LOAD_ASYNC = new ReflectMethod<>( - IOWorker.class, CompletableFuture.class, 1, ChunkPos.class); - - private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); - - public static final ObjectsPool> BLOCK_POS_POOL = - ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); - - private NMSUtils() { - - } - - @Nullable - public static T getBlockEntityAt(Location location, Class type) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); - } - } - - public static void runActionOnEntityChunks(Collection chunksCoords, - ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); - } - - public static void runActionOnChunks(Collection chunksCoords, - boolean saveChunks, ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); - } - - private static void runActionOnChunksInternal(Collection chunksCoords, - ChunkCallback chunkCallback, - Consumer> onUnloadChunkAction) { - List unloadedChunks = new LinkedList<>(); - List loadedChunks = new LinkedList<>(); - - chunksCoords.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - ChunkAccess chunkAccess; - - try { - chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); - } catch (Throwable ex) { - chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); - } - - if (chunkAccess instanceof LevelChunk levelChunk) { - loadedChunks.add(levelChunk); - } else { - unloadedChunks.add(chunkPosition.copy()); - } - }); - - boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); - - if (!loadedChunks.isEmpty()) - runActionOnLoadedChunks(loadedChunks, chunkCallback); - - if (hasUnloadedChunks) { - onUnloadChunkAction.accept(unloadedChunks); - } else { - chunkCallback.onFinish(); - } - } - - private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { - chunks.forEach(chunkCallback::onLoadedChunk); - } - - private static void runActionOnUnloadedChunks(Collection chunks, - boolean saveChunks, ChunkCallback chunkCallback) { - if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { - Iterator chunksIterator = chunks.iterator(); - while (chunksIterator.hasNext()) { - ChunkPosition chunkPosition = chunksIterator.next(); - - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( - chunkPosition.getX(), chunkPosition.getZ()); - if (cachedUnloadedChunk != null) { - chunkCallback.onLoadedChunk(cachedUnloadedChunk); - chunksIterator.remove(); - } - } - - if (chunks.isEmpty()) { - chunkCallback.onFinish(); - return; - } - } - - CompletableFuture pendingTask = new CompletableFuture<>(); - PENDING_CHUNK_ACTIONS.add(pendingTask); - - BukkitExecutor.createTask().runAsync(v -> { - CountDownLatch countDownLatch; - if (chunkCallback.isWaitForChunkLoad) { - countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - } else { - countDownLatch = null; - } - - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - boolean calledCountdown = false; - try { - net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos); - - if (chunkCompound == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.getChunkData(serverLevel.getTypeKey(), - Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, chunkPos, serverLevel); - - if (chunkDataCompound.contains("Level", 10)) { - chunkCallback.onUnloadedChunk(chunkPosition, chunkDataCompound.getCompound("Level")); - calledCountdown = true; - if (saveChunks) - chunkMap.write(chunkPos, chunkDataCompound); - } else { - if (countDownLatch != null) - countDownLatch.countDown(); - } - } catch (Exception error) { - if (!calledCountdown && countDownLatch != null) - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - if (countDownLatch != null) { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - } - }).runSync(v -> { - chunkCallback.onFinish(); - - pendingTask.complete(null); - PENDING_CHUNK_ACTIONS.remove(pendingTask); - }); - } - - private static void runActionOnUnloadedEntityChunks(Collection chunks, - ChunkCallback chunkCallback) { - CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - IOWorker worker = ENTITY_STORAGE_WORKER.get(serverLevel.entityManager.permanentStorage); - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - WORKER_LOAD_ASYNC.invoke(worker, chunkPos).whenComplete((entityData, error) -> { - if (error != null) { - countDownLatch.countDown(); - throw new RuntimeException(error); - } else { - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - } else { - chunkCallback.onUnloadedChunk(chunkPosition, entityData); - } - } - }); - }); - - BukkitExecutor.createTask().runAsync(v -> { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } - - public static List> getPendingChunkActions() { - return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); - } - - public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { - try { - return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel); - } catch (Throwable ex) { - //noinspection deprecation - return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel); - } - } - - public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { - ServerLevel serverLevel = levelChunk.level; - - if (!isValidPosition(serverLevel, blockPos)) - return null; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - serverLevel.setBlock(blockPos, blockState, 3); - return blockState; - } - - int indexY = serverLevel.getSectionIndex(blockPos.getY()); - - LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; - - if (levelChunkSection == LevelChunk.EMPTY_SECTION) { - int yOffset = SectionPos.blockToSectionCoord(blockPos.getY()); - try { - // Paper's constructor for ChunkSection for more optimized chunk sections. - levelChunkSection = levelChunk.getSections()[indexY] = new LevelChunkSection(yOffset, levelChunk, serverLevel, true); - } catch (Throwable ex) { - // Spigot's constructor for ChunkSection - // noinspection deprecation - levelChunkSection = levelChunk.getSections()[indexY] = new LevelChunkSection(yOffset); - } - } - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - boolean isOriginallyChunkSectionEmpty = levelChunkSection.isEmpty(); - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - - levelChunk.setUnsaved(true); - - boolean isChunkSectionEmpty = levelChunkSection.isEmpty(); - - if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) - serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); - - serverLevel.getLightEngine().checkBlock(blockPos); - - if (tileEntity != null) { - net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); - if (tileEntityCompound != null) { - tileEntityCompound.putInt("x", blockPos.getX()); - tileEntityCompound.putInt("y", blockPos.getY()); - tileEntityCompound.putInt("z", blockPos.getZ()); - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.load(tileEntityCompound); - } - } - - return blockState; - } - - public static boolean isDoubleBlock(Block block, BlockState blockState) { - return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && - blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; - } - - private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); - } - - public static abstract class ChunkCallback { - - private final ChunkLoadReason chunkLoadReason; - private final boolean isWaitForChunkLoad; - - @Nullable - protected CountDownLatch chunkLoadLatch; - - public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { - this.chunkLoadReason = chunkLoadReason; - this.isWaitForChunkLoad = isWaitForChunkLoad; - } - - public abstract void onLoadedChunk(LevelChunk levelChunk); - - public abstract void onUnloadedChunk(ChunkPosition chunkPosition, net.minecraft.nbt.CompoundTag unloadedChunk); - - public abstract void onFinish(); - - protected final void latchCountDown() { - if (this.chunkLoadLatch != null) - this.chunkLoadLatch.countDown(); - } - - public final void onChunkNotExist(ChunkPosition chunkPosition) { - if (!plugin.getProviders().hasCustomWorldsSupport()) - return; - - ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { - LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); - BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); - }); - } - - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index d16944e462..fda5296fd3 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -1,119 +1,25 @@ package com.bgsoftware.superiorskyblock.nms.v1_17; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; -import com.bgsoftware.superiorskyblock.nms.ICachedBlock; -import com.bgsoftware.superiorskyblock.nms.NMSWorld; -import com.bgsoftware.superiorskyblock.nms.algorithms.NMSCachedBlock; -import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; -import com.bgsoftware.superiorskyblock.nms.v1_17.generator.IslandsGeneratorImpl; -import com.bgsoftware.superiorskyblock.nms.v1_17.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_17.vibration.IslandSculkSensorBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_17.world.ChunkReaderImpl; -import com.bgsoftware.superiorskyblock.nms.v1_17.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_17.world.WorldEditSessionImpl; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.world.SignType; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.destroystokyo.paper.antixray.ChunkPacketBlockController; -import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.border.WorldBorder; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.BubbleColumn; -import org.bukkit.block.data.type.Sign; -import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; -import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlockState; -import org.bukkit.craftbukkit.v1_17_R1.block.CraftSign; -import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; -import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.function.IntFunction; - -public class NMSWorldImpl implements NMSWorld { - - private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, - Object.class, "chunkPacketBlockController") - .removeFinal(); - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - - private final SuperiorSkyblockPlugin plugin; +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSWorld { public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - - @Override - public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { - Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); - Location location = new Location( - Bukkit.getWorld(chunkSnapshot.getWorldName()), - (chunkSnapshot.getX() << 4) + x, - y, - (chunkSnapshot.getZ() << 4) + z - ); - - return Keys.of(KeyBlocksCache.getBlockKey(block), location); + super(plugin); } @Override - public void listenSpawner(Location location, IntFunction delayChangeCallback) { - SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); - if (spawnerBlockEntity == null) - return; - - ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - - List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel); - Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new LinkedList<>(); - - while (blockEntityTickersIterator.hasNext()) { - TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && - !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { - blockEntityTickersIterator.remove(); - tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); - } - } - - if (!tickersToAdd.isEmpty()) - blockEntityTickers.addAll(tickersToAdd); + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.messages; } @Override @@ -128,237 +34,5 @@ public void replaceSculkSensorListener(Island island, Location location) { serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity)); } - @Override - public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { - if (!plugin.getSettings().isWorldBorders()) - return; - - Player player = superiorPlayer.asPlayer(); - org.bukkit.World world = superiorPlayer.getWorld(); - - if (world == null || player == null) - return; - - int islandSize = island == null ? 0 : island.getIslandSize(); - - boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; - - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - - WorldBorder worldBorder; - - if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { - worldBorder = serverLevel.getWorldBorder(); - } else { - Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); - if (dimension == null) - return; - - Location center = island.getCenter(dimension); - - worldBorder = new WorldBorder(); - worldBorder.world = serverLevel; - worldBorder.setWarningBlocks(0); - worldBorder.setCenter(center.getX(), center.getZ()); - - switch (superiorPlayer.getBorderColor()) { - case BLUE -> { - worldBorder.setSize((islandSize * 2) + 1D); - } - case GREEN -> { - worldBorder.setSize((islandSize * 2) + 1.001D); - worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); - } - case RED -> { - worldBorder.setSize((islandSize * 2) + 1D); - worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); - } - } - } - - ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); - ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); - } - - @Override - public Object getBlockData(org.bukkit.block.Block block) { - return block.getBlockData(); - } - - @Override - public void setBlock(Location location, int combinedId) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - BlockState blockState = - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - - if (blockState != null) { - serverLevel.getChunkSource().blockChanged(blockPos); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); - } - } - } - } - - @Override - public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return NMSCachedBlock.obtain(block); - } - - @Override - public boolean isWaterLogged(org.bukkit.block.Block block) { - if (Materials.isWater(block.getType())) - return true; - - org.bukkit.block.data.BlockData blockData = block.getBlockData(); - - return blockData instanceof BubbleColumn || - (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); - } - - @Override - public SignType getSignType(Object sign) { - if (sign instanceof WallSign) - return SignType.WALL_SIGN; - else if (sign instanceof Sign) - return SignType.STANDING_SIGN; - else - return SignType.UNKNOWN; - } - - @Override - public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { - BlockState blockState = ((CraftBlock) block).getNMS(); - return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; - } - - @Override - public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { - return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); - } - - @Override - public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { - return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); - } - - private int getDefaultAmount(BlockState blockState) { - Block block = blockState.getBlock(); - return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; - } - - @Override - public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { - return !bukkitBlock.isPassable(); - } - - @Override - public void placeSign(Island island, Location location) { - SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); - if (signBlockEntity == null) - return; - - String[] lines = new String[4]; - System.arraycopy(CraftSign.revertComponents(signBlockEntity.messages), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - Component[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } - - System.arraycopy(newLines, 0, signBlockEntity.messages, 0, 4); - } - - @Override - public void playGeneratorSound(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); - } - } - - @Override - public void playBreakAnimation(org.bukkit.block.Block block) { - ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); - } - } - - @Override - public void playPlaceSound(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); - } - } - - @Override - public int getMinHeight(org.bukkit.World world) { - return world.getMinHeight(); - } - - @Override - public void removeAntiXray(org.bukkit.World bukkitWorld) { - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) - CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); - } - - @Override - public IslandsGenerator createGenerator(Dimension dimension) { - return new IslandsGeneratorImpl(dimension); - } - - @Override - public WorldEditSession createEditSession(World world) { - return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); - } - - @Override - public WorldEditSession createPartialEditSession(Dimension dimension) { - return WorldEditSessionImpl.obtain(dimension); - } - - @Override - public ChunkReader createChunkReader(Chunk chunk) { - return new ChunkReaderImpl(chunk); - } } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsBlockEntity.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsBlockEntity.java deleted file mode 100644 index fa2d74dc36..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsBlockEntity.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.crops; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.chunk.LevelChunk; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.function.Consumer; - -public class CropsBlockEntity extends BlockEntity { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - - private final WeakReference island; - private final WeakReference chunk; - - private int currentTick = 0; - - private double cachedCropGrowthMultiplier; - - private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.getLevel().getBlockState(blockPos)); - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(levelChunk); - setLevel(levelChunk.getLevel()); - levelChunk.getLevel().addBlockEntityTicker(new CropsTickingBlockEntity(this)); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; - } - - public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); - return new CropsBlockEntity(island, levelChunk, blockPos); - }); - } - - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); - } - - public static void forEachChunk(List chunkPositions, Consumer cropsTickingTileEntityConsumer) { - if (tickingChunks.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> { - long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsTickingTileEntity = tickingChunks.get(chunkKey); - if (cropsTickingTileEntity != null) - cropsTickingTileEntityConsumer.accept(cropsTickingTileEntity); - }); - } - - public void remove() { - this.remove = true; - } - - public void tick() { - if (++currentTick <= plugin.getSettings().getCropsInterval()) - return; - - LevelChunk levelChunk = this.chunk.get(); - Island island = this.island.get(); - ServerLevel serverLevel = (ServerLevel) getLevel(); - - if (levelChunk == null || island == null || serverLevel == null) { - remove(); - return; - } - - currentTick = 0; - - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - if (chunkRandomTickSpeed > 0) - CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); - } - - public void setCropGrowthMultiplier(double cropGrowthMultiplier) { - this.cachedCropGrowthMultiplier = cropGrowthMultiplier; - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingBlockEntity.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingBlockEntity.java deleted file mode 100644 index 3c1d933f4b..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingBlockEntity.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.crops; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -public record CropsTickingBlockEntity( - CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { - - - @Override - public void tick() { - cropsBlockEntity.tick(); - } - - @Override - public boolean isRemoved() { - return cropsBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return cropsBlockEntity.getBlockPos(); - } - - @Override - public String getType() { - return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java deleted file mode 100644 index b2bee8c987..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/crops/CropsTickingMethod.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.crops; - -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; - -import java.util.HashSet; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; - -public abstract class CropsTickingMethod { - - private static final ReflectField SERVER_LEVEL_RANDOM_TICK_RANDOM = new ReflectField<>( - ServerLevel.class, Random.class, "randomTickRandom"); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static Set CROPS_TO_GROW_CACHE; - - static { - plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); - } - - private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); - - private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? - new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); - - - protected CropsTickingMethod() { - - } - - public static void register() { - // Calls the static initializer which registers the callback. - } - - public static void tick(LevelChunk levelChunk, int tickSpeed) { - INSTANCE.doTick(levelChunk, tickSpeed); - } - - protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); - - private static void onSettingsUpdate() { - CROPS_TO_GROW_CACHE = new HashSet<>(); - plugin.getSettings().getCropsToGrow().forEach(cropName -> { - Key key = Keys.ofMaterialAndData(cropName); - if (key instanceof MaterialKey materialKey) { - Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); - if (block != null && block.defaultBlockState().isRandomlyTicking()) - CROPS_TO_GROW_CACHE.add(block); - } - }); - } - - private static class PaperCropsTickingMethod extends CropsTickingMethod { - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - ServerLevel serverLevel = levelChunk.level; - LevelChunkSection[] sections = levelChunk.getSections(); - - int minSection = serverLevel.getMinSection(); - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - Random randomTickRandom = SERVER_LEVEL_RANDOM_TICK_RANDOM.get(serverLevel); - - for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int tickingBlocks = levelChunkSection.tickingList.size(); - if (tickingBlocks <= 0) { - continue; - } - - int offsetY = (sectionIndex + minSection) << 4; - - for (int i = 0; i < tickSpeed; ++i) { - int index = randomTickRandom.nextInt(0x1000); - - if (index >= tickingBlocks) { - continue; - } - - long raw = levelChunkSection.tickingList.getRaw(index); - int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); - BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); - if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) - continue; - - chunkTickMutablePosition.set((location & 15) | chunkOffsetX, - ((location >>> 8) & 255) | offsetY, - ((location >>> 4) & 15) | chunkOffsetZ); - - blockState.randomTick(serverLevel, chunkTickMutablePosition, randomTickRandom); - } - } - - } - - } - - private static class SpigotCropsTickingMethod extends CropsTickingMethod { - - private static int random = ThreadLocalRandom.current().nextInt(); - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - LevelChunkSection[] sections = levelChunk.getSections(); - ServerLevel serverLevel = levelChunk.level; - - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - - for (int i = 0; i < tickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { - chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); - blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); - } - } - } - } - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/DragonUtils.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/DragonUtils.java deleted file mode 100644 index b9d8b33ce4..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/DragonUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.dragon; - -import com.bgsoftware.common.reflection.ReflectField; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; - -import java.lang.reflect.Modifier; - -public class DragonUtils { - - private static final ReflectField END_PODIUM_LOCATION = new ReflectField( - EndPodiumFeature.class, BlockPos.class, - Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static BlockPos currentPodiumPosition = BlockPos.ZERO; - - private DragonUtils() { - - } - - public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { - try { - END_PODIUM_LOCATION.set(null, podiumPosition); - currentPodiumPosition = podiumPosition; - runnable.run(); - } finally { - END_PODIUM_LOCATION.set(null, BlockPos.ZERO); - currentPodiumPosition = BlockPos.ZERO; - } - } - - public static BlockPos getCurrentPodiumPosition() { - return currentPodiumPosition; - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndWorldEndDragonFightHandler.java deleted file mode 100644 index 4a0de50bde..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndWorldEndDragonFightHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; -import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.dimension.end.EndDragonFight; - -import java.util.LinkedList; -import java.util.List; - -public class EndWorldEndDragonFightHandler extends EndDragonFight { - - private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); - - private final List worldDragonFightsList = new LinkedList<>(); - - public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { - super(serverLevel, serverLevel.getSeed(), new CompoundTag()); - } - - @Override - public void tick() { - this.worldDragonFightsList.forEach(EndDragonFight::tick); - } - - public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); - if (oldDragonFight != null) - this.worldDragonFightsList.remove(oldDragonFight); - this.worldDragonFightsList.add(endDragonFight); - } - - @Nullable - public IslandEndDragonFight getDragonFight(IslandCache islandCache) { - return islandCache.get(CACHE_KEY); - } - - @Nullable - public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { - IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); - if (endDragonFight != null) - this.worldDragonFightsList.remove(endDragonFight); - return endDragonFight; - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEndDragonFight.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEndDragonFight.java deleted file mode 100644 index ce31dc29af..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEndDragonFight.java +++ /dev/null @@ -1,209 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; -import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import net.minecraft.world.level.block.state.pattern.BlockPattern; -import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; -import net.minecraft.world.level.block.state.predicate.BlockPredicate; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -public class IslandEndDragonFight extends EndDragonFight { - - private static final ReflectField DRAGON_BATTLE = new ReflectField( - EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 3); - - private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); - - private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( - DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); - - private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") - .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") - .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) - .build(); - - private final Island island; - private final BlockPos islandBlockPos; - private final Vec3 islandBlockVectored; - private final ServerLevel serverLevel; - - private final IslandEntityEnderDragon entityEnderDragon; - - private byte currentTick = 0; - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { - this(island, serverLevel, new BlockPos(location.getX(), location.getY(), location.getZ()), null); - } - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, - @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { - super(serverLevel, serverLevel.getSeed(), new CompoundTag()); - - - this.island = island; - this.islandBlockPos = islandBlockPos; - this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); - this.serverLevel = serverLevel; - this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; - - SCAN_FOR_LEGACY_PORTALS.set(this, false); - WAS_DRAGON_KILLED.set(this, false); - DRAGON_BATTLE.set(this.entityEnderDragon, this); - } - - @Override - public void tick() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); - - DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); - if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { - LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); - } - - if (++currentTick >= 20) { - updateBattlePlayers(); - currentTick = 0; - } - } - - @Nullable - @Override - public BlockPattern.BlockPatternMatch findExitPortal() { - int chunkX = this.islandBlockPos.getX() >> 4; - int chunkZ = this.islandBlockPos.getZ() >> 4; - - for (int x = -8; x <= 8; ++x) { - for (int z = -8; z <= 8; ++z) { - LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); - - for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { - if (blockEntity instanceof TheEndPortalBlockEntity) { - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( - this.serverLevel, blockEntity.getBlockPos()); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - } - } - - int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); - currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); - for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { - currentPosition.setY(y); - - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - - return null; - } - - @Override - public void resetSpikeCrystals() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); - } - - public void removeBattlePlayers() { - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - for (ServerPlayer serverPlayer : dragonEventPlayers) - this.dragonEvent.removePlayer(serverPlayer); - } - - public IslandEntityEnderDragon getEnderDragon() { - return this.entityEnderDragon; - } - - private void updateBattlePlayers() { - Set nearbyPlayers = new HashSet<>(); - - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - Player bukkitPlayer = superiorPlayer.asPlayer(); - if (bukkitPlayer != null) { - ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); - if (serverPlayer.level.equals(this.serverLevel)) { - this.dragonEvent.addPlayer(serverPlayer); - nearbyPlayers.add(serverPlayer.getUUID()); - } - } - } - - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - - dragonEventPlayers.stream() - .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) - .forEach(this.dragonEvent::removePlayer); - } - - private IslandEntityEnderDragon spawnEnderDragon() { - IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); - - entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); - entityEnderDragon.absMoveTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), - this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); - - this.serverLevel.addEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); - - this.dragonUUID = entityEnderDragon.getUUID(); - this.resetSpikeCrystals(); - - return entityEnderDragon; - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java index 276921581f..335d52beb3 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/IslandEntityEnderDragon.java @@ -2,47 +2,22 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.config.SettingsManager; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEnderDragon; -public class IslandEntityEnderDragon extends EnderDragon { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - @NotNull - public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { - return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : - new EnderDragon(entityTypes, level); - } - - private final ServerLevel serverLevel; - private final Dimension dimension; - private BlockPos islandBlockPos; +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_17.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { - this(level); - this.islandBlockPos = islandBlockPos; + super(level, islandBlockPos); } - private IslandEntityEnderDragon(Level level) { - super(EntityType.ENDER_DRAGON, level); - this.serverLevel = (ServerLevel) level; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + public IslandEntityEnderDragon(Level level) { + super(level); } @Nullable @@ -65,39 +40,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { finalizeIslandEnderDragon(); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - - private void finalizeIslandEnderDragon() { - if (!(this.serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) - return; - - Island island; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); - } - - if (island == null) - return; - - Location middleBlock = island.getCenter(dimension); - - SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); - if (dimensionConfig instanceof SettingsManager.Worlds.End) { - middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); - } - - this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); - - IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); - } - } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/SpikesCache.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/SpikesCache.java deleted file mode 100644 index b489d495bd..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/SpikesCache.java +++ /dev/null @@ -1,179 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.CacheStats; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public class SpikesCache implements LoadingCache> { - - private static final SpikesCache INSTANCE = new SpikesCache(); - - private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() - .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); - - private long worldSeed; - - public static SpikesCache getInstance() { - return INSTANCE; - } - - private SpikesCache() { - - } - - @Override - public List get(Long worldSeed) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public List getUnchecked(Long worldSeed) { - try { - this.worldSeed = worldSeed; - return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public ImmutableMap> getAll(Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public List apply(Long worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void refresh(Long worldSeed) { - try { - this.worldSeed = worldSeed; - cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public ConcurrentMap> asMap() { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Nullable - @Override - public List getIfPresent(Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public List get(Long worldSeed, Callable> loader) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); - } finally { - this.worldSeed = 0; - } - } - - @Override - public ImmutableMap> getAllPresent(Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void put(Long worldSeed, List spikes) { - try { - this.worldSeed = worldSeed; - cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); - } finally { - this.worldSeed = 0; - } - } - - @Override - public void putAll(Map> spikesMap) { - spikesMap.forEach(this::put); - } - - @Override - public void invalidate(Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll(Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll() { - this.cachedSpikes.invalidateAll(); - } - - @Override - public long size() { - return this.cachedSpikes.size(); - } - - @Override - public CacheStats stats() { - return this.cachedSpikes.stats(); - } - - @Override - public void cleanUp() { - this.cachedSpikes.cleanUp(); - } - - private class InternalCacheLoader extends CacheLoader> { - - @Override - public List load(BlockPos blockPos) { - List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); - - Collections.shuffle(list, new Random(worldSeed)); - List spikesList = Lists.newArrayList(); - - for (int i = 0; i < 10; ++i) { - int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int l = list.get(i); - int radius = 2 + l / 3; - int height = 76 + l * 3; - boolean guarded = l == 1 || l == 2; - - spikesList.add(new SpikeFeature.EndSpike(spikeX + blockPos.getX(), - spikeZ + blockPos.getZ(), radius, height, guarded)); - } - - return spikesList; - } - - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/generator/IslandsGeneratorImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/generator/IslandsGeneratorImpl.java deleted file mode 100644 index 7c7d0d408f..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/generator/IslandsGeneratorImpl.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.generator; - -import com.bgsoftware.common.reflection.ClassInfo; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import net.minecraft.core.Registry; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.chunk.ChunkBiomeContainer; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; -import org.bukkit.generator.BlockPopulator; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Random; - -@SuppressWarnings({"unused", "NullableProblems"}) -public class IslandsGeneratorImpl extends IslandsGenerator { - - private static final ReflectField CHUNK_BIOME_CONTAINER = new ReflectField<>( - new ClassInfo("generator.CustomChunkGenerator$CustomBiomeGrid", ClassInfo.PackageType.CRAFTBUKKIT), - ChunkBiomeContainer.class, "biome"); - private static final ReflectField BIOME_BASE_ARRAY = new ReflectField<>( - ChunkBiomeContainer.class, Biome[].class, "f"); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private final Dimension dimension; - - public IslandsGeneratorImpl(Dimension dimension) { - this.dimension = dimension; - } - - @Override - public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biomeGrid) { - ChunkData chunkData = createChunkData(world); - - org.bukkit.block.Biome targetBiome = IslandUtils.getDefaultWorldBiome(this.dimension); - - setBiome(biomeGrid, targetBiome); - - if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { - chunkData.setBlock(0, 99, 0, Material.BEDROCK); - } - - return chunkData; - } - - @Override - public List getDefaultPopulators(World world) { - return Collections.emptyList(); - } - - @Override - public Location getFixedSpawnLocation(World world, Random random) { - return new Location(world, 0, 100, 0); - } - - private static void setBiome(BiomeGrid biomeGrid, org.bukkit.block.Biome bukkitBiome) { - ChunkBiomeContainer chunkBiomeContainer = CHUNK_BIOME_CONTAINER.get(biomeGrid); - Biome[] biomes = BIOME_BASE_ARRAY.get(chunkBiomeContainer); - Biome biome = CraftBlock.biomeToBiomeBase((Registry) chunkBiomeContainer.biomeRegistry, bukkitBiome); - if (biome != null) - Arrays.fill(biomes, biome); - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/hologram/EntityHologram.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/hologram/EntityHologram.java new file mode 100644 index 0000000000..f6edd2e5d6 --- /dev/null +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/hologram/EntityHologram.java @@ -0,0 +1,39 @@ +package com.bgsoftware.superiorskyblock.nms.v1_17.hologram; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_17.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + +} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuBrewingStandBlockEntity.java deleted file mode 100644 index 299987d2cd..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuBrewingStandBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { - - private final InventoryHolder holder; - - public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuDispenserBlockEntity.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuDispenserBlockEntity.java deleted file mode 100644 index 2c26b48323..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuDispenserBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.DispenserBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuDispenserBlockEntity extends DispenserBlockEntity { - - private final InventoryHolder holder; - - public MenuDispenserBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuFurnaceBlockEntity.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuFurnaceBlockEntity.java deleted file mode 100644 index fd599d2256..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuFurnaceBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.FurnaceBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { - - private final InventoryHolder holder; - - public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuHopperBlockEntity.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuHopperBlockEntity.java deleted file mode 100644 index 4b69dc244a..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/menu/MenuHopperBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.HopperBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuHopperBlockEntity extends HopperBlockEntity { - - private final InventoryHolder holder; - - public MenuHopperBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/player/OfflinePlayerDataImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/player/OfflinePlayerDataImpl.java deleted file mode 100644 index acc3062319..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/player/OfflinePlayerDataImpl.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.player; - -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.craftbukkit.v1_17_R1.CraftServer; -import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; -import org.bukkit.entity.Player; - -import java.util.Optional; - -public class OfflinePlayerDataImpl implements OfflinePlayerData { - - private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); - - private Player fakePlayer; - - public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { - return POOL.obtain().initialize(offlinePlayer); - } - - private OfflinePlayerDataImpl() { - - } - - private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), - Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return null; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile); - this.fakePlayer = serverPlayer.getBukkitEntity(); - this.fakePlayer.loadData(); - - return this; - } - - @Override - public Player getFakeOnlinePlayer() { - return this.fakePlayer; - } - - @Override - public void setLocation(Location location) { - ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); - serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); - serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - } - - @Override - public void applyChanges() { - this.fakePlayer.saveData(); - } - - @Override - public void release() { - this.fakePlayer = null; - POOL.release(this); - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/spawners/TickingSpawnerBlockEntityNotifier.java deleted file mode 100644 index f8f31a2c38..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/spawners/TickingSpawnerBlockEntityNotifier.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.spawners; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BaseSpawner; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -import java.util.function.IntFunction; - -public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { - - private final SpawnerBlockEntity spawnerBlockEntity; - private final TickingBlockEntity tickingBlockEntity; - private final IntFunction delayChangeCallback; - - public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, - IntFunction delayChangeCallback) { - this.spawnerBlockEntity = spawnerBlockEntity; - this.tickingBlockEntity = tickingBlockEntity; - this.delayChangeCallback = delayChangeCallback; - updateDelay(); - } - - @Override - public void tick() { - BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); - int startDelay = baseSpawner.spawnDelay; - try { - tickingBlockEntity.tick(); - } finally { - int newDelay = baseSpawner.spawnDelay; - if (newDelay > startDelay) - updateDelay(); - } - } - - @Override - public boolean isRemoved() { - return tickingBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return tickingBlockEntity.getPos(); - } - - @Override - public String getType() { - return tickingBlockEntity.getType(); - } - - public void updateDelay() { - BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); - baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..b13d38659d --- /dev/null +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java @@ -0,0 +1,288 @@ +package com.bgsoftware.superiorskyblock.nms.v1_17.utils; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_17.utils.TickingBlockList; +import com.bgsoftware.superiorskyblock.nms.v1_17.world.WorldEditSessionImpl; +import com.google.common.base.Suppliers; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.minecraft.core.Registry; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.ProtoTickList; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.IOWorker; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage; +import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; + +public class NMSUtilsVersioned { + + private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( + EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); + private static final ReflectMethod> WORKER_LOAD_ASYNC = new ReflectMethod<>( + IOWorker.class, CompletableFuture.class, 1, ChunkPos.class); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) throws IOException { + return chunkMap.read(chunkPos); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) throws IOException { + return chunkMap.getChunkData(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), + chunkCompoundTag, chunkPos, serverLevel); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException { + chunkMap.write(chunkPos, chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + IOWorker worker = ENTITY_STORAGE_WORKER.get(serverLevel.entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + WORKER_LOAD_ASYNC.invoke(worker, chunkPos).whenComplete((entityData, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + try { + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel, serverLevel); + } catch (Throwable ex) { + //noinspection deprecation + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, serverLevel); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + ProtoTickList blockTickScheduler = new ProtoTickList<>(block -> { + return block == null || block.defaultBlockState().isAir(); + }, chunkPos, levelHeightAccessor); + ProtoTickList fluidTickScheduler = new ProtoTickList<>((fluid) -> { + return fluid == null || fluid == Fluids.EMPTY; + }, chunkPos, levelHeightAccessor); + + try { + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, blockTickScheduler, fluidTickScheduler, levelHeightAccessor, serverLevel); + } catch (Throwable error) { + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, blockTickScheduler, fluidTickScheduler, levelHeightAccessor); + } + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.getMaterial().isLiquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.isEmpty(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + blockEntity.load(compoundTag); + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.relight(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + if (compoundTag.getByte("SSB.HasSignLines") == 1) { + // We want to convert the sign lines from raw string to json + for (int i = 1; i <= 4; ++i) { + String line = compoundTag.getString("SSB.Text" + i); + if (!Text.isBlank(line)) { + Component newLine = CraftChatMessage.fromString(line)[0]; + compoundTag.putString("Text" + i, Component.Serializer.toJson(newLine)); + } + } + } + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = DimensionType.NETHER_LOCATION; + case THE_END -> resourceKey = DimensionType.END_LOCATION; + default -> resourceKey = DimensionType.OVERWORLD_LOCATION; + } + + Registry registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY); + return registry.getOrThrow(resourceKey); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + for (int i = 0; i < chunkSections.length; ++i) { + int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i); + + try { + chunkSections[i] = new LevelChunkSection(chunkSectionPos, null, serverLevel, true); + } catch (Throwable error) { + chunkSections[i] = new LevelChunkSection(chunkSectionPos); + } + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ProtoChunk protoChunk) { + CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(protoChunk), + ChunkStatus.SURFACE, 0); + + chunkGenerator.buildSurface(region, protoChunk); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return new LevelChunkSection(0).getStates(); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + CompoundTag data = new CompoundTag(); + original.write(data, "Palette", "BlockStates"); + + PalettedContainer blockids = new PalettedContainer<>(LevelChunkSection.GLOBAL_BLOCKSTATE_PALETTE, + Block.BLOCK_STATE_REGISTRY, NbtUtils::readBlockState, NbtUtils::writeBlockState, + Blocks.AIR.defaultBlockState(), null, false); + blockids.read(data.getList("Palette", CraftMagicNumbers.NBT.TAG_COMPOUND), data.getLongArray("BlockStates")); + + return blockids; + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.save(new CompoundTag()); + } + + public static CompoundTag saveEntity(Entity entity) { + CompoundTag compoundTag = new CompoundTag(); + entity.save(compoundTag); + return compoundTag; + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.tickingList.size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.tickingList.getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addEntity(entity, spawnReason); + } + + public static String getPropertyValue(Property property) { + return property.getValue(); + } + + public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.dragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absMoveTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSection(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinBuildHeight(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxBuildHeight(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.markUnsaved(); + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockEntityCache.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockEntityCache.java deleted file mode 100644 index 7546de6212..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockEntityCache.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.world; - -import net.minecraft.core.Registry; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class BlockEntityCache { - - private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); - - private BlockEntityCache() { - - } - - public static String getBlockEntityId(BlockState blockState) { - return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { - for (BlockEntityType blockEntityType : Registry.BLOCK_ENTITY_TYPE) { - if (blockEntityType.isValid(blockState)) { - ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); - if (resourceLocation != null) - return resourceLocation.toString(); - } - } - - return ""; - }); - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java deleted file mode 100644 index 1fdfb6c1f4..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/ChunkReaderImpl.java +++ /dev/null @@ -1,248 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.nbt.NbtUtils; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.InventoryHolder; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class ChunkReaderImpl implements ChunkReader { - - private static final PalettedContainer EMPTY_STATES = new LevelChunkSection(0).getStates(); - private static final byte[] EMPTY_LIGHT = new byte[2048]; - - private final ServerLevel serverLevel; - private final int x; - private final int z; - - private final Map blockEntities = new HashMap<>(); - private final List entities = new LinkedList<>(); - private final PalettedContainer[] blockids; - private final byte[][] skylight; - private final byte[][] emitlight; - - public ChunkReaderImpl(Chunk bukkitChunk) { - LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); - - this.serverLevel = levelChunk.level; - ChunkPos chunkPos = levelChunk.getPos(); - this.x = chunkPos.x; - this.z = chunkPos.z; - - LevelChunkSection[] levelChunkSections = levelChunk.getSections(); - this.blockids = new PalettedContainer[levelChunkSections.length]; - this.skylight = new byte[levelChunkSections.length][]; - this.emitlight = new byte[levelChunkSections.length][]; - - LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); - - for (int i = 0; i < this.blockids.length; ++i) { - LevelChunkSection levelChunkSection = levelChunkSections[i]; - - if (LevelChunkSection.isEmpty(levelChunkSection)) { - this.blockids[i] = EMPTY_STATES; - this.skylight[i] = EMPTY_LIGHT; - this.emitlight[i] = EMPTY_LIGHT; - } else { - this.blockids[i] = copyPalettedContainer(levelChunkSection.getStates()); - - DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) - .getDataLayerData(SectionPos.of(this.x, i, this.z)); - if (skyLightArray == null) { - this.skylight[i] = EMPTY_LIGHT; - } else { - this.skylight[i] = new byte[2048]; - System.arraycopy(skyLightArray.getIfSet(), 0, this.skylight[i], 0, 2048); - } - - DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) - .getDataLayerData(SectionPos.of(this.x, i, this.z)); - if (emitLightArray == null) { - this.emitlight[i] = EMPTY_LIGHT; - } else { - this.emitlight[i] = new byte[2048]; - System.arraycopy(emitLightArray.getIfSet(), 0, this.emitlight[i], 0, 2048); - } - } - } - - levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.save(new net.minecraft.nbt.CompoundTag()); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - InventoryHolder inventoryHolder = blockEntity.getOwner(); - if (inventoryHolder != null) - compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); - - blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); - }); - - for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) - entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); - } - - @Override - public int getX() { - return this.x; - } - - @Override - public int getZ() { - return this.z; - } - - @Override - public Material getType(int x, int y, int z) { - return CraftMagicNumbers.getMaterial(getBlockState(x, y, z).getBlock()); - } - - @Override - public short getData(int x, int y, int z) { - return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); - } - - @Override - @Nullable - public CompoundTag getTileEntity(int x, int y, int z) { - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); - return this.blockEntities.get(blockPos); - } - } - - @Override - @Nullable - public CompoundTag readBlockStates(int x, int y, int z) { - BlockState blockState = getBlockState(x, y, z); - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = CompoundTag.of(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(int x, int y, int z) { - int off = (y & 15) << 7 | z << 3 | x >> 1; - int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; - } - - @Override - public void forEachEntity(EntityConsumer consumer) { - if (entities.isEmpty()) - return; - - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = wrapper.getHandle(); - for (CachedEntity cachedEntity : entities) { - location.setX(cachedEntity.x); - location.setY(cachedEntity.y); - location.setZ(cachedEntity.z); - location.setYaw(cachedEntity.yaw); - location.setPitch(cachedEntity.pitch); - consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); - } - } - } - - private BlockState getBlockState(int x, int y, int z) { - return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); - } - - private int getSectionIndex(int y) { - int sectionIndex = SectionPos.blockToSectionCoord(y); - return sectionIndex - this.serverLevel.getMinSection(); - } - - private static PalettedContainer copyPalettedContainer(PalettedContainer original) { - net.minecraft.nbt.CompoundTag data = new net.minecraft.nbt.CompoundTag(); - original.write(data, "Palette", "BlockStates"); - - PalettedContainer blockids = new PalettedContainer<>(LevelChunkSection.GLOBAL_BLOCKSTATE_PALETTE, - Block.BLOCK_STATE_REGISTRY, NbtUtils::readBlockState, NbtUtils::writeBlockState, - Blocks.AIR.defaultBlockState(), null, false); - blockids.read(data.getList("Palette", CraftMagicNumbers.NBT.TAG_COMPOUND), data.getLongArray("BlockStates")); - - return blockids; - } - - private static class CachedEntity { - - private final double x; - private final double y; - private final double z; - private final float yaw; - private final float pitch; - private final EntityType entityType; - private final CompoundTag entityTag; - - CachedEntity(Entity entity) { - this.x = entity.getX(); - this.y = entity.getY(); - this.z = entity.getZ(); - this.yaw = entity.getBukkitYaw(); - this.pitch = entity.getXRot(); - this.entityType = entity.getBukkitEntity().getType(); - - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - - this.entityTag = CompoundTag.fromNBT(compoundTag); - } - - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/KeyBlocksCache.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/KeyBlocksCache.java deleted file mode 100644 index ad05e2fc18..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/KeyBlocksCache.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.world; - -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import net.minecraft.core.Registry; -import net.minecraft.world.level.block.Block; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class KeyBlocksCache { - - private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); - - private KeyBlocksCache() { - - } - - public static Key getBlockKey(Block block) { - return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { - Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); - }); - } - - public static void cacheAllBlocks() { - Registry.BLOCK.forEach(KeyBlocksCache::getBlockKey); - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/PropertiesMapper.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/PropertiesMapper.java deleted file mode 100644 index 5191bea804..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/PropertiesMapper.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.world; - -import com.bgsoftware.superiorskyblock.core.logging.Log; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.Property; - -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; - -public class PropertiesMapper { - - private static final Map> nameToProperty = new HashMap<>(); - private static final Map, String> propertyToName = new HashMap<>(); - - static { - Map fieldsToNames = new IdentityHashMap<>(); - - fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); - fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); - fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); - fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); - fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); - fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); - fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); - fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); - fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); - fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); - fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); - fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); - fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); - fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); - fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); - fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); - fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); - fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); - fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); - fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); - fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); - fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); - fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); - fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); - fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); - fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); - fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); - - try { - for (Field field : BlockStateProperties.class.getFields()) { - field.setAccessible(true); - Object value = field.get(null); - if (value instanceof Property) { - Property property = (Property) value; - register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); - } - } - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while loading properties mapper:"); - } - - } - - private static void register(String key, String fieldName, Property property) { - if (nameToProperty.containsKey(key)) { - Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); - } else { - nameToProperty.put(key, property); - propertyToName.put(property, key); - } - } - - public static Property getProperty(String name) { - return nameToProperty.get(name); - } - - public static String getPropertyName(Property property) { - return propertyToName.get(property); - } - -} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/PropertiesMapperVersioned.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..c506bb05a3 --- /dev/null +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/PropertiesMapperVersioned.java @@ -0,0 +1,15 @@ +package com.bgsoftware.superiorskyblock.nms.v1_17.world; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java deleted file mode 100644 index efedfc59af..0000000000 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/WorldEditSessionImpl.java +++ /dev/null @@ -1,464 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_17.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.google.common.base.Preconditions; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Registry; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.chunk.ChunkBiomeContainer; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.ProtoTickList; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.material.Fluid; -import net.minecraft.world.level.material.Fluids; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; -import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; -import org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage; -import org.bukkit.generator.ChunkGenerator; - -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionImpl implements WorldEditSession { - - private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); - - private static final ReflectField BIOME_BASE_ARRAY = new ReflectField<>( - ChunkBiomeContainer.class, Biome[].class, "f"); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.starlight.common.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - - private Dimension dimension; - private LevelHeightAccessor levelHeightAccessor; - - @Nullable - private ServerLevel serverLevel; - - public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { - return POOL.obtain().initialize(serverLevel); - } - - public static WorldEditSessionImpl obtain(Dimension dimension) { - return POOL.obtain().initialize(dimension); - } - - private WorldEditSessionImpl() { - } - - private WorldEditSessionImpl initialize(ServerLevel serverLevel) { - this.serverLevel = serverLevel; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); - this.levelHeightAccessor = serverLevel; - return this; - } - - private WorldEditSessionImpl initialize(Dimension dimension) { - DimensionType dimensionType = getDimensionTypeFromDimension(dimension); - this.serverLevel = null; - this.dimension = dimension; - this.levelHeightAccessor = createLevelHeightAccessor(dimensionType.minY(), dimensionType.height()); - return this; - } - - @Override - public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, - @Nullable CompoundTag blockEntityData) { - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - if (!isValidPosition(blockPos)) - return; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - blocksToUpdate.add(new Pair<>(blockPos, blockState)); - return; - } - - ChunkPos chunkPos = new ChunkPos(blockPos); - - if (blockEntityData != null) - blockEntities.add(new Pair<>(blockPos, blockEntityData)); - - ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); - - if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) - chunkData.lights.add(blockPos); - - LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - } - - @Override - public List getAffectedChunks() { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); - - if (chunks.isEmpty()) - return Collections.emptyList(); - - List chunkPositions = new LinkedList<>(); - World bukkitWorld = serverLevel.getWorld(); - LongIterator iterator = chunks.keyIterator(); - while (iterator.hasNext()) { - long chunkKey = iterator.next(); - int chunkX = (int) chunkKey; - int chunkZ = (int) (chunkKey >> 32); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); - } - return chunkPositions; - } - - @Override - public void applyBlocks(Chunk bukkitChunk) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); - - LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); - ChunkPos chunkPos = levelChunk.getPos(); - - ChunkData chunkData = this.chunks.remove(chunkPos.toLong()); - - if (chunkData == null) - return; - - int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); - for (int i = 0; i < chunkSectionsCount; ++i) { - levelChunk.getSections()[i] = chunkData.chunkSections[i]; - } - - chunkData.heightmaps.forEach(((type, heightmap) -> { - levelChunk.setHeightmap(type, heightmap.getRawData()); - })); - - // Update the biome for the chunk - Biome[] biomes = BIOME_BASE_ARRAY.get(levelChunk.getBiomes()); - if (biomes != null) { - Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); - Biome biome = CraftBlock.biomeToBiomeBase(biomesRegistry, IslandUtils.getDefaultWorldBiome(this.dimension)); - Arrays.fill(biomes, biome); - } - - if (plugin.getSettings().isLightsUpdate()) { - if (isStarLightInterface) { - this.lightenChunks.add(chunkPos); - } else { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); - // Queues chunk light for this chunk. - threadedLevelLightEngine.lightChunk(levelChunk, false); - } - } - - levelChunk.setUnsaved(true); - } - - @Override - public void finish(Island island) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); - - // Update blocks - blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); - - // Update block entities - blockEntities.forEach(data -> { - net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); - if (blockEntityCompound != null) { - BlockPos blockPos = data.getKey(); - blockEntityCompound.putInt("x", blockPos.getX()); - blockEntityCompound.putInt("y", blockPos.getY()); - blockEntityCompound.putInt("z", blockPos.getZ()); - - if (blockEntityCompound.getByte("SSB.HasSignLines") == 1) { - // We want to convert the sign lines from raw string to json - for (int i = 1; i <= 4; ++i) { - String line = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(line)) { - Component newLine = CraftChatMessage.fromString(line)[0]; - blockEntityCompound.putString("Text" + i, Component.Serializer.toJson(newLine)); - } - } - } - - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.load(blockEntityCompound); - } - }); - - if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - threadedLevelLightEngine.relight(lightenChunks, chunkCallback -> { - }, completeCallback -> { - }); - this.lightenChunks.clear(); - } - - release(); - } - - @Override - public Data readData(Location baseLocation) { - return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); - } - - @Override - public void applyData(Data data, Location baseLocation) { - WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // We need to transform all data to the new base location values - - dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, - baseBlockPosZAxis, this, this.chunks); - dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); - dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); - dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); - } - - @Override - public void release() { - this.chunks.clear(); - this.blocksToUpdate.clear(); - this.blockEntities.clear(); - this.lightenChunks.clear(); - this.serverLevel = null; - this.dimension = null; - this.levelHeightAccessor = null; - POOL.release(this); - } - - public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - return new ChunkData(chunkSections, heightmaps, lights); - } - - private boolean isValidPosition(BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); - } - - private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { - ResourceKey resourceKey; - switch (dimension.getEnvironment()) { - case NETHER -> resourceKey = DimensionType.NETHER_LOCATION; - case THE_END -> resourceKey = DimensionType.END_LOCATION; - default -> resourceKey = DimensionType.OVERWORLD_LOCATION; - } - - Registry registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY); - return registry.getOrThrow(resourceKey); - } - - private static LevelHeightAccessor createLevelHeightAccessor(int minY, int height) { - return new LevelHeightAccessor() { - @Override - public int getHeight() { - return height; - } - - @Override - public int getMinBuildHeight() { - return minY; - } - }; - } - - public class ChunkData { - - private final LevelChunkSection[] chunkSections; - private final Map heightmaps; - private final List lights; - - private ChunkData(long chunkKey) { - this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), - isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); - - ChunkPos chunkPos = new ChunkPos(chunkKey); - - createChunkSections(); - - ProtoTickList blockTickScheduler = new ProtoTickList<>(block -> { - return block == null || block.defaultBlockState().isAir(); - }, chunkPos, levelHeightAccessor); - ProtoTickList fluidTickScheduler = new ProtoTickList<>((fluid) -> { - return fluid == null || fluid == Fluids.EMPTY; - }, chunkPos, levelHeightAccessor); - - ProtoChunk tempChunk; - try { - tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, blockTickScheduler, fluidTickScheduler, levelHeightAccessor, serverLevel); - } catch (Throwable error) { - tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, blockTickScheduler, fluidTickScheduler, levelHeightAccessor); - } - - createHeightmaps(tempChunk); - if (serverLevel != null) - runCustomWorldGenerator(tempChunk); - } - - private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - this.chunkSections = chunkSections; - this.heightmaps = heightmaps; - this.lights = lights; - } - - public LevelChunkSection[] chunkSections() { - return this.chunkSections; - } - - public Map heightmaps() { - return this.heightmaps; - } - - public List lights() { - return this.lights; - } - - private void createChunkSections() { - for (int i = 0; i < this.chunkSections.length; ++i) { - int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i); - - try { - this.chunkSections[i] = new LevelChunkSection(chunkSectionPos, null, serverLevel, true); - } catch (Throwable error) { - this.chunkSections[i] = new LevelChunkSection(chunkSectionPos); - } - } - } - - private void runCustomWorldGenerator(ProtoChunk tempChunk) { - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - - if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) - return; - - CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), - bukkitGenerator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(tempChunk), - ChunkStatus.SURFACE, 0); - - chunkGenerator.buildSurface(region, - tempChunk); - - // We want to copy the level chunk sections back - LevelChunkSection[] tempChunkSections = tempChunk.getSections(); - for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { - LevelChunkSection chunkSection = tempChunkSections[i]; - if (chunkSection != null && chunkSection != LevelChunk.EMPTY_SECTION) - this.chunkSections[i] = chunkSection; - } - } - - private void createHeightmaps(ProtoChunk tempChunk) { - for (Heightmap.Types heightmapType : Heightmap.Types.values()) { - if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { - this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); - } - } - } - - } - -} diff --git a/NMS/v1_18/properties b/NMS/v1_18/properties new file mode 100644 index 0000000000..73516ca50b --- /dev/null +++ b/NMS/v1_18/properties @@ -0,0 +1,7 @@ +NMS_VERSION=v1_18 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit.v1_18_R2 +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.Registry +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=java.util.Random \ No newline at end of file diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java index cfe27fc745..a967a10304 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java @@ -1,220 +1,26 @@ package com.bgsoftware.superiorskyblock.nms.v1_18; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; -import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; -import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.nms.algorithms.PaperGlowEnchantment; import com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment; -import com.bgsoftware.superiorskyblock.nms.v1_18.menu.MenuBrewingStandBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_18.menu.MenuDispenserBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_18.menu.MenuFurnaceBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_18.menu.MenuHopperBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_18.world.BlockEntityCache; -import com.bgsoftware.superiorskyblock.nms.v1_18.world.KeyBlocksCache; -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.TextReplacementConfig; -import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.Container; -import net.minecraft.world.entity.item.FallingBlockEntity; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.data.Ageable; -import org.bukkit.block.data.BlockData; -import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.v1_18_R2.CraftServer; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftFallingBlock; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftMinecart; import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; -import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.potion.PotionEffect; -import org.jetbrains.annotations.NotNull; import java.lang.reflect.Field; -import java.util.EnumMap; -import java.util.Optional; -import java.util.function.BiFunction; -public class NMSAlgorithmsImpl implements NMSAlgorithms { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms { private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); - private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); - - static { - MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); - } - - private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { - @Override - public byte[] processClass(byte[] classBytes, String path) { - return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); - } - }; - - @Override - public void registerCommand(BukkitCommand command) { - ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); - } - @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]); } - @Override - public int getCombinedId(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return 0; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(wrapper.getHandle()); - } - return Block.getId(blockState); - } - - @Override - public int getCombinedId(Material material, byte data) { - BlockState blockState; - - if (data == 0) { - Block block = CraftMagicNumbers.getBlock(material); - if (block == null) - return -1; - blockState = block.defaultBlockState(); - } else { - blockState = CraftMagicNumbers.getBlock(material, data); - } - - return blockState == null ? -1 : Block.getId(blockState); - } - - @Override - public Optional getTileEntityIdFromCombinedId(int combinedId) { - BlockState blockState = Block.stateById(combinedId); - - if (!blockState.hasBlockEntity()) - return Optional.empty(); - - String id = BlockEntityCache.getBlockEntityId(blockState); - - return Text.isBlank(id) ? Optional.empty() : Optional.of(id); - } - - @Override - public int compareMaterials(Material o1, Material o2) { - int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); - int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); - return Integer.compare(firstMaterial, secondMaterial); - } - - @Override - public short getBlockDataValue(org.bukkit.block.BlockState blockState) { - BlockData blockData = blockState.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getBlockDataValue(org.bukkit.block.Block block) { - BlockData blockData = block.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getMaxBlockDataValue(Material material) { - if (!material.isBlock()) - return 0; - - BlockData blockData = Bukkit.createBlockData(material); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); - } - - @Override - public Key getBlockKey(int combinedId) { - Block block = Block.stateById(combinedId).getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { - AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); - Block block = minecart.getDisplayBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { - FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); - Block block = fallingBlock.getBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public void setCustomModel(ItemMeta itemMeta, int customModel) { - itemMeta.setCustomModelData(customModel); - } - - @Override - public void setItemModel(ItemMeta itemMeta, String itemModel) { - // Doesn't exist - } - - @Override - public void setRarity(ItemMeta itemMeta, String rarity) { - // Doesn't exist - } - - @Override - public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { - // Doesn't exist - } - - @Override - public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { - if (!potionMeta.hasCustomEffects()) - potionMeta.setColor(potionEffect.getType().getColor()); - potionMeta.addCustomEffect(potionEffect, true); - } - @Override public String getMinecraftKey(ItemStack itemStack) { return Registry.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); @@ -225,47 +31,6 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } - @Override - public int getMaxWorldSize() { - return Bukkit.getMaxWorldSize(); - } - - @Nullable - @Override - public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { - MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); - return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); - } - - @Override - public double getCurrentTps() { - try { - return MinecraftServer.getServer().tps1.getAverage(); - } catch (Throwable error) { - //noinspection removal - return MinecraftServer.getServer().recentTps[0]; - } - } - - @Override - public int getDataVersion() { - return CraftMagicNumbers.INSTANCE.getDataVersion(); - } - - @Override - public ClassProcessor getClassProcessor() { - return CLASS_PROCESSOR; - } - - @Override - public void handlePaperChatRenderer(Object event) { - if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) - return; - - io.papermc.paper.chat.ChatRenderer originalRenderer = asyncChatEvent.renderer(); - asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); - } - private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; @@ -291,42 +56,4 @@ private static Enchantment initializeGlowEnchantment() { return glowEnchant; } - private interface MenuCreator extends BiFunction { - } - - private static class ChatRendererWrapper { - - private static final String MESSAGE_PLACEHOLDER = "{message}"; - private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = - net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); - - private final ChatRenderer renderer = new ChatRenderer() { - @Override - public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, - net.kyori.adventure.text.@NotNull Component sourceDisplayName, - net.kyori.adventure.text.@NotNull Component message, - @NotNull Audience viewer) { - String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer - .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); - Island island = superiorPlayer.getIsland(); - - return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( - Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) - .replaceText(TextReplacementConfig.builder() - .matchLiteral(MESSAGE_PLACEHOLDER) - .replacement(message) - .build()); - } - }; - - private final ChatRenderer originalRenderer; - - public ChatRendererWrapper(ChatRenderer originalRenderer) { - this.originalRenderer = originalRenderer; - } - - } - } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java index f996bd3de4..57d14bb73b 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java @@ -1,24 +1,17 @@ package com.bgsoftware.superiorskyblock.nms.v1_18; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; -import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_18.crops.CropsBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_18.crops.CropsTickingMethod; -import com.bgsoftware.superiorskyblock.nms.v1_18.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_18.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -38,16 +31,12 @@ import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; @@ -55,47 +44,28 @@ import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import net.minecraft.world.phys.AABB; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_18_R2.util.CraftNamespacedKey; +import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; import java.util.concurrent.CompletableFuture; -public class NMSChunksImpl implements NMSChunks { - - private static final boolean hasStatesIterator = new ReflectMethod<>(PalettedContainer.class, - "forEachLocation", PalettedContainer.CountConsumer.class).isValid(); - - private final SuperiorSkyblockPlugin plugin; +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - KeyBlocksCache.cacheAllBlocks(); - CropsTickingMethod.register(); + super(plugin); } @Override - public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, - Collection playersToUpdate) { - if (chunkPositions.isEmpty()) - return; - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.SET_BIOME, false) { + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); @@ -129,6 +99,8 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome); @@ -145,7 +117,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound Tag biomesCompound = dataResult.getOrThrow(false, error -> { }); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); @@ -155,19 +127,12 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { // Do nothing. } - }); + }; } @Override - public void deleteChunks(Island island, List chunkPositions, Runnable onFinish) { - if (chunkPositions.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), - chunkPosition.getX(), chunkPosition.getZ(), false)); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.DELETE_CHUNK, false) { + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); @@ -184,6 +149,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codec( @@ -194,8 +160,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - unloadedChunkCompound.setEntities(new ListTag()); - unloadedChunkCompound.setBlockEntities(tileEntities); + chunkCompound.put("entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, @@ -204,22 +170,14 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound Tag blockStatesCompound = dataResult.getOrThrow(false, error -> { }); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { - CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), serverLevel.generator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(protoChunk), - ChunkStatus.SURFACE, 0); - - customChunkGenerator.buildSurface(region, - serverLevel.structureFeatureManager().forWorldGenRegion(region), - protoChunk); + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } @@ -270,47 +228,28 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound tileEntities.add(blockEntityCompound); } - unloadedChunkCompound.setSections(sectionsList); + chunkCompound.put("sections", sectionsList); } } @Override public void onFinish() { - // Do nothing. + if (onFinish != null) + onFinish.run(); } - }); + }; } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); - List chunkPositionsToCalculate = new LinkedList<>(); - - Iterator chunkPositionsIterator = chunkPositions.iterator(); - while (chunkPositionsIterator.hasNext()) { - ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); - if (cachedCalculatedChunk != null) { - allCalculatedChunks.add(cachedCalculatedChunk); - chunkPositionsIterator.remove(); - } else { - chunkPositionsToCalculate.add(chunkPosition); - } - } - - if (chunkPositions.isEmpty()) - return CompletableFuture.completedFuture(allCalculatedChunks); - - CompletableFuture> completableFuture = new CompletableFuture<>(); - - NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback( - ChunkLoadReason.BLOCKS_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); - allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.getSections())); + allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @@ -319,6 +258,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); Codec> blocksCodec = PalettedContainer.codec( @@ -336,43 +276,43 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { - PalettedContainer blocksDataPalette; + PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); - blocksDataPalette = dataResult.getOrThrow(false, error -> { + blocksPalettedContainer = dataResult.getOrThrow(false, error -> { }); } else { - blocksDataPalette = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } - PalettedContainer> biomesDataPalette; + PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); - biomesDataPalette = dataResult.getOrThrow(false, error -> { + biomesPalettedContainer = dataResult.getOrThrow(false, error -> { }); } else { - biomesDataPalette = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } - chunkSections[sectionIndex] = new LevelChunkSection(yPosition, blocksDataPalette, biomesDataPalette); + chunkSections[sectionIndex] = new LevelChunkSection(yPosition, blocksPalettedContainer, biomesPalettedContainer); } } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, chunkSections); + CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -383,20 +323,14 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { completableFuture.complete(allCalculatedChunks); } - }); - - return completableFuture; + }; } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); - - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - List unloadedChunkCompounds = new LinkedList<>(); - - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( - ChunkLoadReason.ENTITIES_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { @@ -419,8 +353,9 @@ public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - for (Tag entityTag : unloadedChunkCompound.getEntities()) { + for (Tag entityTag : chunkCompound.getList("entities", 10)) { EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); if (entityType == null) continue; @@ -442,170 +377,17 @@ public void onFinish() { completableFuture.complete(chunkEntities); }); } - }); - - return completableFuture; - } - - @Override - public void injectChunkSections(org.bukkit.Chunk chunk) { - // No implementation - } - - @Override - public boolean isChunkEmpty(org.bukkit.Chunk bukkitChunk) { - LevelChunk levelChunk = ((CraftChunk) bukkitChunk).getHandle(); - return Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> - chunkSection == null || chunkSection.hasOnlyAir()); - } - - @Override - public org.bukkit.Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); - return chunkAccess instanceof LevelChunk levelChunk ? levelChunk.getBukkitChunk() : null; - } - - @Override - public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean stop) { - if (plugin.getSettings().getCropsInterval() <= 0) - return; - - - if (stop) { - CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); - if (cropsBlockEntity != null) - cropsBlockEntity.remove(); - } else { - LevelChunk levelChunk = ((CraftChunk) chunk).getHandle(); - CropsBlockEntity.create(island, levelChunk); - } - } - - @Override - public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { - if (chunkPositions.isEmpty()) return; - CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> - cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); - } - - @Override - public void shutdown() { - List> pendingTasks = NMSUtils.getPendingChunkActions(); - - if (pendingTasks.isEmpty()) - return; - - Log.info("Waiting for chunk tasks to complete."); - - CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); - } - - @Override - public List getBlockEntities(Chunk chunk) { - LevelChunk levelChunk = ((CraftChunk) chunk).getHandle(); - List blockEntities = new LinkedList<>(); - - World bukkitWorld = chunk.getWorld(); - - levelChunk.getBlockEntities().keySet().forEach(blockPos -> - blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); - - return blockEntities; - } - - private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, LevelChunkSection[] chunkSections) { - KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); - List spawnersLocations = new LinkedList<>(); - - for (LevelChunkSection levelChunkSection : chunkSections) { - if (levelChunkSection != null && !levelChunkSection.hasOnlyAir()) { - if (hasStatesIterator) { - levelChunkSection.getStates().forEachLocation((blockState, locationKey) -> { - int x = locationKey & 0xF; - int y = (locationKey >> 8) & 0xF; - int z = (locationKey >> 4) & 0xF; - calculateChunkInternal(blockState, x, y, z, chunkPosition, levelChunkSection, blockCounts, spawnersLocations); - }); - } else for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { - BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, - levelChunkSection, blockCounts, spawnersLocations); - } - } - } - - return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); - } - - private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, - LevelChunkSection levelChunkSection, KeyMap blockCounts, - List spawnersLocations) { - Block block = blockState.getBlock(); - - if (block == Blocks.AIR) - return; - - Location location = new Location(chunkPosition.getWorld(), - (chunkPosition.getX() << 4) + x, - levelChunkSection.bottomBlockY() + y, - (chunkPosition.getZ() << 4) + z); - - int blockAmount = 1; - - if (NMSUtils.isDoubleBlock(block, blockState)) { - blockAmount = 2; - blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); - } - - Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); - blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); - if (block == Blocks.SPAWNER) { - spawnersLocations.add(location); - } - } - - private static void removeEntities(ChunkAccess chunk) { - ChunkPos chunkPos = chunk.getPos(); - ServerLevel serverLevel = ((LevelChunk) chunk).level; - - int chunkWorldCoordX = chunkPos.x << 4; - int chunkWorldCoordZ = chunkPos.z << 4; - - AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinBuildHeight(), chunkWorldCoordZ, - chunkWorldCoordX + 15, serverLevel.getMaxBuildHeight(), chunkWorldCoordZ + 15); - - List worldEntities = new LinkedList<>(); - serverLevel.getEntities().get(chunkBounds, worldEntities::add); - - worldEntities.forEach(nmsEntity -> { - if (!(nmsEntity instanceof Player)) - nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); - }); - } - - private static void removeBlockEntities(ChunkAccess chunk) { - chunk.blockEntities.values().forEach(BlockEntity::setRemoved); - chunk.blockEntities.clear(); + }; } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { - CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), - bukkitGenerator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunk), - ChunkStatus.SURFACE, 0); + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; - chunkGenerator.buildSurface(region, - serverLevel.structureFeatureManager().forWorldGenRegion(region), - chunk); - } + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSDragonFightImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSDragonFightImpl.java deleted file mode 100644 index 27536164b3..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSDragonFightImpl.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_18.dragon.EndWorldEndDragonFightHandler; -import com.bgsoftware.superiorskyblock.nms.v1_18.dragon.IslandEndDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_18.dragon.IslandEntityEnderDragon; -import com.bgsoftware.superiorskyblock.nms.v1_18.dragon.SpikesCache; -import com.google.common.cache.LoadingCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.advancement.Advancement; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.entity.Player; - -import java.lang.reflect.Modifier; -import java.util.List; - -public class NMSDragonFightImpl implements NMSDragonFight { - - private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( - EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField( - ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( - SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static boolean firstWorldPreparation = true; - - static { - ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); - } - - @Override - public void prepareEndWorld(World bukkitWorld) { - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); - - if (firstWorldPreparation) { - firstWorldPreparation = false; - SPIKE_CACHE.set(null, SpikesCache.getInstance()); - } - } - - @Nullable - @Override - public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return null; - - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); - return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); - } - - @Override - public void startDragonBattle(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); - } - - @Override - public void removeDragonBattle(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); - - if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { - islandEndDragonFight.removeBattlePlayers(); - islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); - } - } - - @Override - public void awardTheEndAchievement(Player player) { - Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); - if (advancement != null) - player.getAdvancementProgress(advancement).awardCriteria(""); - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSEntitiesImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSEntitiesImpl.java index 83dbf8f5b2..caa18bbbfd 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSEntitiesImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSEntitiesImpl.java @@ -1,57 +1,30 @@ package com.bgsoftware.superiorskyblock.nms.v1_18; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftAnimals; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; -import org.bukkit.entity.Animals; import org.bukkit.entity.minecart.PoweredMinecart; -import org.bukkit.inventory.EntityEquipment; -import org.bukkit.inventory.ItemStack; import java.lang.reflect.Modifier; -public class NMSEntitiesImpl implements NMSEntities { +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override - public ItemStack[] getEquipment(EntityEquipment entityEquipment) { - ItemStack[] itemStacks = new ItemStack[7]; - - itemStacks[0] = new ItemStack(Material.ARMOR_STAND); - itemStacks[1] = entityEquipment.getItemInMainHand(); - itemStacks[2] = entityEquipment.getItemInOffHand(); - itemStacks[3] = entityEquipment.getHelmet(); - itemStacks[4] = entityEquipment.getChestplate(); - itemStacks[5] = entityEquipment.getLeggings(); - itemStacks[6] = entityEquipment.getBoots(); - - return itemStacks; - } - - @Override - public boolean isAnimalFood(ItemStack itemStack, Animals animals) { - return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); - } - - @Override - public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override - public int getPortalTicks(org.bukkit.entity.Entity entity) { - return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); + protected int getPortalTicks(Entity entity) { + return PORTAL_TICKS.get(entity); } } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSHologramsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSHologramsImpl.java deleted file mode 100644 index 7796672e04..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSHologramsImpl.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18; - -import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; -import com.bgsoftware.superiorskyblock.nms.NMSHolograms; -import com.google.common.base.Preconditions; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_18_R2.CraftServer; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftArmorStand; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; -import org.bukkit.entity.Entity; - -@SuppressWarnings("unused") -public class NMSHologramsImpl implements NMSHolograms { - - @Override - public Hologram createHologram(Location location) { - Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); - serverLevel.addFreshEntity(entityHologram); - return entityHologram; - } - - @Override - public boolean isHologram(Entity entity) { - return ((CraftEntity) entity).getHandle() instanceof Hologram; - } - - public static class EntityHologram extends ArmorStand implements Hologram { - - private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); - - private CraftEntity bukkitEntity; - - EntityHologram(ServerLevel serverLevel, double x, double y, double z) { - super(serverLevel, x, y, z); - - setInvisible(true); - setSmall(true); - setShowArms(false); - setNoGravity(true); - setNoBasePlate(true); - setMarker(true); - forceSetBoundingBox(EMPTY_BOUND); - - super.collides = false; - super.setCustomNameVisible(true); - } - - @Override - public void setHologramName(String name) { - super.setCustomName(CraftChatMessage.fromStringOrNull(name)); - } - - @Override - public void removeHologram() { - super.remove(RemovalReason.DISCARDED); - } - - @Override - public org.bukkit.entity.ArmorStand getHandle() { - return this.getBukkitEntity(); - } - - @Override - public void inactiveTick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - @Override - public boolean repositionEntityAfterLoad() { - return false; - } - - @Override - public AABB getBoundingBoxForCulling() { - return EMPTY_BOUND; - } - - @Override - public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { - // Prevent stand being equipped - } - - @Override - public void addAdditionalSaveData(CompoundTag compoundTag) { - // Do not save NBT. - } - - @Override - public void readAdditionalSaveData(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { - // Prevent stand being equipped - return InteractionResult.PASS; - } - - @Override - public void tick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - public void forceSetBoundingBox(AABB boundingBox) { - super.setBoundingBox(boundingBox); - } - - @Override - public CraftArmorStand getBukkitEntity() { - if (bukkitEntity == null) { - bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); - } - return (CraftArmorStand) bukkitEntity; - } - - @Override - public void remove(RemovalReason removalReason) { - // Prevent being killed. - } - - @Override - public void playSound(SoundEvent soundEvent, float volume, float pitch) { - // Remove sounds. - } - - @Override - public boolean saveAsPassenger(CompoundTag compoundTag) { - // Do not save NBT. - return false; - } - - @Override - public CompoundTag saveWithoutId(CompoundTag compoundTag) { - // Do not save NBT. - return compoundTag; - } - - @Override - public void load(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public boolean isInvulnerableTo(DamageSource damageSource) { - /* - * The field Entity.invulnerable is private. - * It's only used while saving NBTTags, but since the entity would be killed - * on chunk unload, we prefer to override isInvulnerable(). - */ - return true; - } - - @Override - public void setCustomName(Component component) { - // Locks the custom name. - } - - @Override - public void setCustomNameVisible(boolean isCustomNameVisible) { - // Locks the custom name. - } - - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSPlayersImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSPlayersImpl.java deleted file mode 100644 index e1564f1b9a..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSPlayersImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.nms.NMSPlayers; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.bgsoftware.superiorskyblock.nms.v1_18.player.OfflinePlayerDataImpl; -import com.bgsoftware.superiorskyblock.player.PlayerLocales; -import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.level.ServerPlayer; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; -import org.bukkit.entity.Item; -import org.bukkit.entity.Player; - -import java.util.Locale; - -public class NMSPlayersImpl implements NMSPlayers { - - private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(Player.class, "locale"); - - @Override - public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { - return OfflinePlayerDataImpl.create(offlinePlayer); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer) { - Player player = superiorPlayer.asPlayer(); - - if (player == null) - return; - - ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() - .ifPresent(property -> setSkinTexture(superiorPlayer, property)); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { - superiorPlayer.setTextureValue(property.getValue()); - } - - @SuppressWarnings("deprecation") - @Override - public void sendActionBar(Player player, String message) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); - } - - @Override - public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { - BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); - bossBar.addPlayer(player); - return bossBar; - } - - @SuppressWarnings("deprecation") - @Override - public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { - player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); - } - - @Override - public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { - return superiorPlayer.getUniqueId().equals(item.getThrower()); - } - - @Nullable - @Override - public Locale getPlayerLocale(Player player) { - if (PLAYER_LOCALE.isValid()) { - return player.locale(); - } else try { - //noinspection deprecation - return PlayerLocales.getLocale(player.getLocale()); - } catch (IllegalArgumentException error) { - return null; - } - } - - private static class BossBarImpl implements BossBar { - - private final org.bukkit.boss.BossBar bossBar; - private final BossBarTask bossBarTask; - - public BossBarImpl(String message, BarColor color, double ticksToRun) { - bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); - this.bossBarTask = BossBarTask.create(this, ticksToRun); - } - - @Override - public void addPlayer(Player player) { - this.bossBar.addPlayer(player); - this.bossBarTask.registerTask(player); - } - - @Override - public void removeAll() { - this.bossBar.removeAll(); - this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); - } - - @Override - public void setProgress(double progress) { - this.bossBar.setProgress(progress); - } - - @Override - public double getProgress() { - return this.bossBar.getProgress(); - } - - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java index a44b570218..1f0750dfc3 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java @@ -1,91 +1,44 @@ package com.bgsoftware.superiorskyblock.nms.v1_18; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.ListTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.mojang.serialization.Dynamic; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; -import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; import java.util.Set; -@SuppressWarnings({"unused"}) -public class NMSTagsImpl implements NMSTags { +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSTags { @Override - public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag()); tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); - return CompoundTag.fromNBT(tagCompound); } @Override - public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { - if (compoundTag.containsKey("NBT")) { - // Old compound version, deserialize it accordingly - return deserializeItemOld(compoundTag); - } - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); - - int currentVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - int itemVersion = tagCompound.getInt("DataVersion"); - if (itemVersion < currentVersion) { - tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, - new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); - } - - ItemStack itemStack = ItemStack.of(tagCompound); - - return CraftItemStack.asCraftMirror(itemStack); + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; } - private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); - Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount").orElse(0); - short data = (short) compoundTag.getShort("data").orElse(0); - CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); - - org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - if (nbtData != null) - itemStack.setTag((net.minecraft.nbt.CompoundTag) nbtData.toNBT()); - - return CraftItemStack.asCraftMirror(itemStack); + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + return ItemStack.of(compoundTag); } @Override - @SuppressWarnings("ConstantConditions") - public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { - net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); - - if (compoundTag == null) - compoundTag = new net.minecraft.nbt.CompoundTag(); - - if (!compoundTag.contains("id")) - //noinspection deprecation - compoundTag.putString("id", entityType.getName()); + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.setTag(compoundTag); + } - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; @@ -147,29 +100,4 @@ public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } - @Override - public Object parseList(ListTag listTag) { - net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); - - for (Tag tag : listTag) - nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); - - return nbtTagList; - } - - @Override - public Object getNBTCompoundTag(Object object, String key) { - return ((net.minecraft.nbt.CompoundTag) object).get(key); - } - - @Override - public void setNBTCompoundTagValue(Object object, String key, Object value) { - ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); - } - - @Override - public int getNBTTagListSize(Object object) { - return ((net.minecraft.nbt.ListTag) object).size(); - } - } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index 149c666c20..efd986740b 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -1,120 +1,25 @@ package com.bgsoftware.superiorskyblock.nms.v1_18; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; -import com.bgsoftware.superiorskyblock.nms.ICachedBlock; -import com.bgsoftware.superiorskyblock.nms.NMSWorld; -import com.bgsoftware.superiorskyblock.nms.algorithms.NMSCachedBlock; -import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; -import com.bgsoftware.superiorskyblock.nms.v1_18.generator.IslandsGeneratorImpl; -import com.bgsoftware.superiorskyblock.nms.v1_18.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_18.vibration.IslandSculkSensorBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_18.world.ChunkReaderImpl; -import com.bgsoftware.superiorskyblock.nms.v1_18.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_18.world.WorldEditSessionImpl; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.world.SignType; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.destroystokyo.paper.antixray.ChunkPacketBlockController; -import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.border.WorldBorder; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.BubbleColumn; -import org.bukkit.block.data.type.Sign; -import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; -import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlockState; -import org.bukkit.craftbukkit.v1_18_R2.block.CraftSign; -import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; -import org.bukkit.entity.Player; -import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.function.IntFunction; - -public class NMSWorldImpl implements NMSWorld { - - private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, - Object.class, "chunkPacketBlockController") - .removeFinal(); - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - - private final SuperiorSkyblockPlugin plugin; +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSWorld { public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - - @Override - public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { - Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); - Location location = new Location( - Bukkit.getWorld(chunkSnapshot.getWorldName()), - (chunkSnapshot.getX() << 4) + x, - y, - (chunkSnapshot.getZ() << 4) + z - ); - - return Keys.of(KeyBlocksCache.getBlockKey(block), location); + super(plugin); } @Override - public void listenSpawner(Location location, IntFunction delayChangeCallback) { - SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); - if (spawnerBlockEntity == null) - return; - - ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - - List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel); - Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new LinkedList<>(); - - while (blockEntityTickersIterator.hasNext()) { - TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && - !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { - blockEntityTickersIterator.remove(); - tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); - } - } - - if (!tickersToAdd.isEmpty()) - blockEntityTickers.addAll(tickersToAdd); + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.messages; } @Override @@ -129,239 +34,5 @@ public void replaceSculkSensorListener(Island island, Location location) { serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity)); } - @Override - public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { - if (!plugin.getSettings().isWorldBorders()) - return; - - Player player = superiorPlayer.asPlayer(); - org.bukkit.World world = superiorPlayer.getWorld(); - - if (world == null || player == null) - return; - - int islandSize = island == null ? 0 : island.getIslandSize(); - - boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; - - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - - WorldBorder worldBorder; - - if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { - worldBorder = serverLevel.getWorldBorder(); - } else { - Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); - if (dimension == null) - return; - - Location center = island.getCenter(dimension); - - worldBorder = new WorldBorder(); - worldBorder.world = serverLevel; - worldBorder.setWarningBlocks(0); - worldBorder.setCenter(center.getX(), center.getZ()); - - switch (superiorPlayer.getBorderColor()) { - case BLUE -> { - worldBorder.setSize((islandSize * 2) + 1D); - } - case GREEN -> { - worldBorder.setSize((islandSize * 2) + 1.001D); - worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); - } - case RED -> { - worldBorder.setSize((islandSize * 2) + 1D); - worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); - } - } - } - - ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); - ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); - } - - @Override - public Object getBlockData(org.bukkit.block.Block block) { - return block.getBlockData(); - } - - @Override - public void setBlock(Location location, int combinedId) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - BlockState blockState = - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - - if (blockState != null) { - serverLevel.getChunkSource().blockChanged(blockPos); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); - } - } - } - } - - @Override - public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return NMSCachedBlock.obtain(block); - } - - @Override - public boolean isWaterLogged(org.bukkit.block.Block block) { - if (Materials.isWater(block.getType())) - return true; - - BlockData blockData = block.getBlockData(); - - return blockData instanceof BubbleColumn || - (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); - } - - @Override - public SignType getSignType(Object sign) { - if (sign instanceof WallSign) - return SignType.WALL_SIGN; - else if (sign instanceof Sign) - return SignType.STANDING_SIGN; - else - return SignType.UNKNOWN; - } - - @Override - public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { - BlockState blockState = ((CraftBlock) block).getNMS(); - return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; - } - - @Override - public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { - return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); - } - - @Override - public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { - return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); - } - - private int getDefaultAmount(BlockState blockState) { - Block block = blockState.getBlock(); - return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; - } - - @Override - public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { - return !bukkitBlock.isPassable(); - } - - @Override - public void placeSign(Island island, Location location) { - SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); - if (signBlockEntity == null) - return; - - String[] lines = new String[4]; - System.arraycopy(CraftSign.revertComponents(signBlockEntity.messages), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - Component[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } - - System.arraycopy(newLines, 0, signBlockEntity.messages, 0, 4); - } - - @Override - public void playGeneratorSound(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); - } - } - - @Override - public void playBreakAnimation(org.bukkit.block.Block block) { - ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); - } - } - - @Override - public void playPlaceSound(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); - } - } - - @Override - public int getMinHeight(org.bukkit.World world) { - return world.getMinHeight(); - } - - @Override - public void removeAntiXray(org.bukkit.World bukkitWorld) { - if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); - } - - @Override - public IslandsGenerator createGenerator(Dimension dimension) { - return new IslandsGeneratorImpl(dimension); - } - - @Override - public WorldEditSession createEditSession(World world) { - return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); - } - - @Override - public WorldEditSession createPartialEditSession(Dimension dimension) { - return WorldEditSessionImpl.obtain(dimension); - } - - @Override - public ChunkReader createChunkReader(Chunk chunk) { - return new ChunkReaderImpl(chunk); - } } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsBlockEntity.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsBlockEntity.java deleted file mode 100644 index fa88f7dda7..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsBlockEntity.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.crops; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.chunk.LevelChunk; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.function.Consumer; - -public class CropsBlockEntity extends BlockEntity { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - - private final WeakReference island; - private final WeakReference chunk; - - private int currentTick = 0; - - private double cachedCropGrowthMultiplier; - - private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(levelChunk); - setLevel(levelChunk.level); - levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; - } - - public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); - return new CropsBlockEntity(island, levelChunk, blockPos); - }); - } - - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); - } - - public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { - if (tickingChunks.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> { - long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); - if (cropsBlockEntity != null) - cropsBlockEntityConsumer.accept(cropsBlockEntity); - }); - } - - public void remove() { - this.remove = true; - } - - public void tick() { - if (++currentTick <= plugin.getSettings().getCropsInterval()) - return; - - LevelChunk levelChunk = this.chunk.get(); - Island island = this.island.get(); - ServerLevel serverLevel = (ServerLevel) getLevel(); - - if (levelChunk == null || island == null || serverLevel == null) { - remove(); - return; - } - - currentTick = 0; - - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - if (chunkRandomTickSpeed > 0) - CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); - } - - public void setCropGrowthMultiplier(double cropGrowthMultiplier) { - this.cachedCropGrowthMultiplier = cropGrowthMultiplier; - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingBlockEntity.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingBlockEntity.java deleted file mode 100644 index 96b1e92def..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingBlockEntity.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.crops; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -public record CropsTickingBlockEntity( - CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { - - - @Override - public void tick() { - cropsBlockEntity.tick(); - } - - @Override - public boolean isRemoved() { - return cropsBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return cropsBlockEntity.getBlockPos(); - } - - @Override - public String getType() { - return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java deleted file mode 100644 index 4e91181ec9..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/crops/CropsTickingMethod.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.crops; - -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; - -import java.util.HashSet; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; - -public abstract class CropsTickingMethod { - - private static final ReflectField SERVER_LEVEL_RANDOM_TICK_RANDOM = new ReflectField<>( - ServerLevel.class, Random.class, "randomTickRandom"); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static Set CROPS_TO_GROW_CACHE; - - static { - plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); - } - - private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); - - private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? - new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); - - - protected CropsTickingMethod() { - - } - - public static void register() { - // Calls the static initializer which registers the callback. - } - - public static void tick(LevelChunk levelChunk, int tickSpeed) { - INSTANCE.doTick(levelChunk, tickSpeed); - } - - protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); - - private static void onSettingsUpdate() { - CROPS_TO_GROW_CACHE = new HashSet<>(); - plugin.getSettings().getCropsToGrow().forEach(cropName -> { - Key key = Keys.ofMaterialAndData(cropName); - if (key instanceof MaterialKey materialKey) { - Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); - if (block != null && block.defaultBlockState().isRandomlyTicking()) - CROPS_TO_GROW_CACHE.add(block); - } - }); - } - - private static class PaperCropsTickingMethod extends CropsTickingMethod { - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - ServerLevel serverLevel = levelChunk.level; - LevelChunkSection[] sections = levelChunk.getSections(); - - int minSection = serverLevel.getMinSection(); - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - Random randomTickRandom = SERVER_LEVEL_RANDOM_TICK_RANDOM.get(serverLevel); - - for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int tickingBlocks = levelChunkSection.tickingList.size(); - if (tickingBlocks <= 0) { - continue; - } - - int offsetY = (sectionIndex + minSection) << 4; - - for (int i = 0; i < tickSpeed; ++i) { - int index = randomTickRandom.nextInt(0x1000); - - if (index >= tickingBlocks) { - continue; - } - - long raw = levelChunkSection.tickingList.getRaw(index); - int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); - BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); - if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) - continue; - - chunkTickMutablePosition.set((location & 15) | chunkOffsetX, - ((location >>> 8) & 255) | offsetY, - ((location >>> 4) & 15) | chunkOffsetZ); - - blockState.randomTick(serverLevel, chunkTickMutablePosition, randomTickRandom); - } - } - - } - - } - - private static class SpigotCropsTickingMethod extends CropsTickingMethod { - - private static int random = ThreadLocalRandom.current().nextInt(); - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - LevelChunkSection[] sections = levelChunk.getSections(); - ServerLevel serverLevel = levelChunk.level; - - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - - for (int i = 0; i < tickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { - chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); - blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); - } - } - } - } - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndWorldEndDragonFightHandler.java deleted file mode 100644 index 0a0748561d..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndWorldEndDragonFightHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; -import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.dimension.end.EndDragonFight; - -import java.util.LinkedList; -import java.util.List; - -public class EndWorldEndDragonFightHandler extends EndDragonFight { - - private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); - - private final List worldDragonFightsList = new LinkedList<>(); - - public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { - super(serverLevel, serverLevel.getSeed(), new CompoundTag()); - } - - @Override - public void tick() { - this.worldDragonFightsList.forEach(EndDragonFight::tick); - } - - public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); - if (oldDragonFight != null) - this.worldDragonFightsList.remove(oldDragonFight); - this.worldDragonFightsList.add(endDragonFight); - } - - @Nullable - public IslandEndDragonFight getDragonFight(IslandCache islandCache) { - return islandCache.get(CACHE_KEY); - } - - @Nullable - public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { - IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); - if (endDragonFight != null) - this.worldDragonFightsList.remove(endDragonFight); - return endDragonFight; - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEndDragonFight.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEndDragonFight.java deleted file mode 100644 index e4fcbd1911..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEndDragonFight.java +++ /dev/null @@ -1,206 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; -import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import net.minecraft.world.level.block.state.pattern.BlockPattern; -import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; -import net.minecraft.world.level.block.state.predicate.BlockPredicate; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -public class IslandEndDragonFight extends EndDragonFight { - - private static final ReflectField DRAGON_BATTLE = new ReflectField( - EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 3); - private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); - private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( - DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); - - private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") - .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") - .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) - .build(); - - private final Island island; - private final BlockPos islandBlockPos; - private final Vec3 islandBlockVectored; - private final ServerLevel serverLevel; - private final IslandEntityEnderDragon entityEnderDragon; - - private byte currentTick = 0; - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { - this(island, serverLevel, new BlockPos(location.getX(), location.getY(), location.getZ()), null); - } - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, - @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { - super(serverLevel, serverLevel.getSeed(), new CompoundTag()); - - this.island = island; - this.islandBlockPos = islandBlockPos; - this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); - this.serverLevel = serverLevel; - this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; - - SCAN_FOR_LEGACY_PORTALS.set(this, false); - WAS_DRAGON_KILLED.set(this, false); - DRAGON_BATTLE.set(this.entityEnderDragon, this); - } - - @Override - public void tick() { - // doServerTick - - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); - - DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); - if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { - LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); - } - - if (++currentTick >= 20) { - updateBattlePlayers(); - currentTick = 0; - } - } - - @Nullable - @Override - public BlockPattern.BlockPatternMatch findExitPortal() { - int chunkX = this.islandBlockPos.getX() >> 4; - int chunkZ = this.islandBlockPos.getZ() >> 4; - - for (int x = -8; x <= 8; ++x) { - for (int z = -8; z <= 8; ++z) { - LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); - - for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { - if (blockEntity instanceof TheEndPortalBlockEntity) { - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( - this.serverLevel, blockEntity.getBlockPos()); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - } - } - - int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); - currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); - for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { - currentPosition.setY(y); - - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - - return null; - } - - @Override - public void resetSpikeCrystals() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); - } - - public void removeBattlePlayers() { - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - for (ServerPlayer serverPlayer : dragonEventPlayers) - this.dragonEvent.removePlayer(serverPlayer); - } - - public IslandEntityEnderDragon getEnderDragon() { - return this.entityEnderDragon; - } - - private void updateBattlePlayers() { - Set nearbyPlayers = new HashSet<>(); - - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - Player bukkitPlayer = superiorPlayer.asPlayer(); - if (bukkitPlayer != null) { - ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); - if (serverPlayer.level.equals(this.serverLevel)) { - this.dragonEvent.addPlayer(serverPlayer); - nearbyPlayers.add(serverPlayer.getUUID()); - } - } - } - - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - - dragonEventPlayers.stream() - .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) - .forEach(this.dragonEvent::removePlayer); - } - - private IslandEntityEnderDragon spawnEnderDragon() { - IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); - - entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); - entityEnderDragon.absMoveTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), - this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); - - this.serverLevel.addFreshEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); - - this.dragonUUID = entityEnderDragon.getUUID(); - this.resetSpikeCrystals(); - - return entityEnderDragon; - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java index 31570857bd..147b54daf5 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/IslandEntityEnderDragon.java @@ -2,47 +2,22 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.config.SettingsManager; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftEnderDragon; -public class IslandEntityEnderDragon extends EnderDragon { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - @NotNull - public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { - return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : - new EnderDragon(entityTypes, level); - } - - private final ServerLevel serverLevel; - private final Dimension dimension; - private BlockPos islandBlockPos; +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_18.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { - this(level); - this.islandBlockPos = islandBlockPos; + super(level, islandBlockPos); } - private IslandEntityEnderDragon(Level level) { - super(EntityType.ENDER_DRAGON, level); - this.serverLevel = (ServerLevel) level; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + public IslandEntityEnderDragon(Level level) { + super(level); } @Nullable @@ -65,40 +40,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { finalizeIslandEnderDragon(); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - - private void finalizeIslandEnderDragon() { - if (!(this.serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) - return; - - Island island; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); - } - - if (island == null) - return; - - Location middleBlock = island.getCenter(dimension); - - SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); - if (dimensionConfig instanceof SettingsManager.Worlds.End) { - middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); - } - - this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); - - IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); - } - } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/SpikesCache.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/SpikesCache.java deleted file mode 100644 index ec6f2b27ea..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/SpikesCache.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.dragon; - - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.common.annotations.Nullable; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.CacheStats; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public class SpikesCache implements LoadingCache> { - - private static final SpikesCache INSTANCE = new SpikesCache(); - - private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() - .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); - - private long worldSeed; - - public static SpikesCache getInstance() { - return INSTANCE; - } - - private SpikesCache() { - - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - List getUnchecked(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public List apply(@NotNull Long worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void refresh(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ConcurrentMap> asMap() { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Nullable - @Override - public List getIfPresent(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed, - @NotNull Callable> loader) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAllPresent(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void put(@NotNull Long worldSeed, @NotNull List spikes) { - try { - this.worldSeed = worldSeed; - cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); - } finally { - this.worldSeed = 0; - } - } - - @Override - public void putAll(Map> spikesMap) { - spikesMap.forEach(this::put); - } - - @Override - public void invalidate(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll() { - this.cachedSpikes.invalidateAll(); - } - - @Override - public long size() { - return this.cachedSpikes.size(); - } - - @Override - public @NotNull - CacheStats stats() { - return this.cachedSpikes.stats(); - } - - @Override - public void cleanUp() { - this.cachedSpikes.cleanUp(); - } - - private class InternalCacheLoader extends CacheLoader> { - - @Override - public @NotNull - List load(@NotNull BlockPos blockPos) { - List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); - - Collections.shuffle(list, new Random(worldSeed)); - List spikesList = Lists.newArrayList(); - - for (int i = 0; i < 10; ++i) { - int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int l = list.get(i); - int radius = 2 + l / 3; - int height = 76 + l * 3; - boolean guarded = l == 1 || l == 2; - - spikesList.add(new SpikeFeature.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded)); - } - - return spikesList; - } - - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/generator/IslandsGeneratorImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/generator/IslandsGeneratorImpl.java deleted file mode 100644 index eaf228b84c..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/generator/IslandsGeneratorImpl.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.generator; - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; -import org.bukkit.generator.WorldInfo; - -import java.util.Collections; -import java.util.List; -import java.util.Random; - -public class IslandsGeneratorImpl extends IslandsGenerator { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private final Dimension dimension; - - public IslandsGeneratorImpl(Dimension dimension) { - this.dimension = dimension; - } - - @Override - public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, - @NotNull ChunkData chunkData) { - if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { - chunkData.setBlock(0, 99, 0, Material.BEDROCK); - } - } - - @Override - public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { - return new BiomeProvider() { - @Override - public @NotNull - Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { - return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension); - } - - @Override - public @NotNull - List getBiomes(@NotNull WorldInfo worldInfo) { - return IslandUtils.getDefaultWorldBiomes(); - } - - }; - } - - @Override - public List getDefaultPopulators(World world) { - return Collections.emptyList(); - } - - @Override - public Location getFixedSpawnLocation(World world, Random random) { - return new Location(world, 0, 100, 0); - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/hologram/EntityHologram.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/hologram/EntityHologram.java new file mode 100644 index 0000000000..ea0460f312 --- /dev/null +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/hologram/EntityHologram.java @@ -0,0 +1,39 @@ +package com.bgsoftware.superiorskyblock.nms.v1_18.hologram; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_18.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuBrewingStandBlockEntity.java deleted file mode 100644 index 2a18cab37f..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuBrewingStandBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { - - private final InventoryHolder holder; - - public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuDispenserBlockEntity.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuDispenserBlockEntity.java deleted file mode 100644 index 27e4909362..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuDispenserBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.DispenserBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuDispenserBlockEntity extends DispenserBlockEntity { - - private final InventoryHolder holder; - - public MenuDispenserBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuFurnaceBlockEntity.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuFurnaceBlockEntity.java deleted file mode 100644 index f4f78381b6..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuFurnaceBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.FurnaceBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { - - private final InventoryHolder holder; - - public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuHopperBlockEntity.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuHopperBlockEntity.java deleted file mode 100644 index 2cf92d134d..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/menu/MenuHopperBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.HopperBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuHopperBlockEntity extends HopperBlockEntity { - - private final InventoryHolder holder; - - public MenuHopperBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/player/OfflinePlayerDataImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/player/OfflinePlayerDataImpl.java deleted file mode 100644 index 1489eb7f8a..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/player/OfflinePlayerDataImpl.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.player; - -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.craftbukkit.v1_18_R2.CraftServer; -import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; -import org.bukkit.entity.Player; - -import java.util.Optional; - -public class OfflinePlayerDataImpl implements OfflinePlayerData { - - private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); - - private Player fakePlayer; - - public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { - return POOL.obtain().initialize(offlinePlayer); - } - - private OfflinePlayerDataImpl() { - - } - - private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), - Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return null; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile); - this.fakePlayer = serverPlayer.getBukkitEntity(); - this.fakePlayer.loadData(); - - return this; - } - - @Override - public Player getFakeOnlinePlayer() { - return this.fakePlayer; - } - - @Override - public void setLocation(Location location) { - ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); - serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); - serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - } - - @Override - public void applyChanges() { - this.fakePlayer.saveData(); - } - - @Override - public void release() { - this.fakePlayer = null; - POOL.release(this); - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/spawners/TickingSpawnerBlockEntityNotifier.java deleted file mode 100644 index dfc9fcac21..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/spawners/TickingSpawnerBlockEntityNotifier.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.spawners; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BaseSpawner; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -import java.util.function.IntFunction; - -public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { - - private final SpawnerBlockEntity spawnerBlockEntity; - private final TickingBlockEntity tickingBlockEntity; - private final IntFunction delayChangeCallback; - - public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, - IntFunction delayChangeCallback) { - this.spawnerBlockEntity = spawnerBlockEntity; - this.tickingBlockEntity = tickingBlockEntity; - this.delayChangeCallback = delayChangeCallback; - updateDelay(); - } - - @Override - public void tick() { - BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); - int startDelay = baseSpawner.spawnDelay; - try { - tickingBlockEntity.tick(); - } finally { - int newDelay = baseSpawner.spawnDelay; - if (newDelay > startDelay) - updateDelay(); - } - } - - @Override - public boolean isRemoved() { - return tickingBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return tickingBlockEntity.getPos(); - } - - @Override - public String getType() { - return tickingBlockEntity.getType(); - } - - public void updateDelay() { - BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); - baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..60a2c97dd6 --- /dev/null +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java @@ -0,0 +1,279 @@ +package com.bgsoftware.superiorskyblock.nms.v1_18.utils; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_18.utils.TickingBlockList; +import com.google.common.base.Suppliers; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.IOWorker; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; +import org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; +import org.bukkit.craftbukkit.v1_18_R2.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; + +public class NMSUtilsVersioned { + + private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( + EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); + private static final ReflectMethod> WORKER_LOAD_ASYNC = new ReflectMethod<>( + IOWorker.class, CompletableFuture.class, 1, ChunkPos.class); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) throws IOException { + return chunkMap.read(chunkPos); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) throws IOException { + return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), + chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException { + chunkMap.write(chunkPos, chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + IOWorker worker = ENTITY_STORAGE_WORKER.get(serverLevel.entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + WORKER_LOAD_ASYNC.invoke(worker, chunkPos).whenComplete((entityData, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + serverLevel.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY), + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.getMaterial().isLiquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + blockEntity.load(compoundTag); + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.relight(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + if (compoundTag.getByte("SSB.HasSignLines") == 1) { + // We want to convert the sign lines from raw string to json + for (int i = 1; i <= 4; ++i) { + String line = compoundTag.getString("SSB.Text" + i); + if (!Text.isBlank(line)) { + Component newLine = CraftChatMessage.fromString(line)[0]; + compoundTag.putString("Text" + i, Component.Serializer.toJson(newLine)); + } + } + } + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = DimensionType.NETHER_LOCATION; + case THE_END -> resourceKey = DimensionType.END_LOCATION; + default -> resourceKey = DimensionType.OVERWORLD_LOCATION; + } + + Registry registry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY); + return registry.getOrThrow(resourceKey); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY); + + Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, + IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i); + + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + + chunkSections[i] = new LevelChunkSection(chunkSectionPos, statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunkAccess), + ChunkStatus.SURFACE, 0); + + chunkGenerator.buildSurface(region, + serverLevel.structureFeatureManager().forWorldGenRegion(region), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(); + } + + public static CompoundTag saveEntity(Entity entity) { + CompoundTag compoundTag = new CompoundTag(); + entity.save(compoundTag); + return compoundTag; + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.tickingList.size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.tickingList.getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + public static String getPropertyValue(Property property) { + return property.getValue(); + } + + public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.dragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absMoveTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSection(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinBuildHeight(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxBuildHeight(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.setUnsaved(true); + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/PropertiesMapper.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/PropertiesMapper.java deleted file mode 100644 index b7cbb9b9ed..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/PropertiesMapper.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.world; - -import com.bgsoftware.superiorskyblock.core.logging.Log; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.Property; - -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; - -public class PropertiesMapper { - - private static final Map> nameToProperty = new HashMap<>(); - private static final Map, String> propertyToName = new HashMap<>(); - - static { - Map fieldsToNames = new IdentityHashMap<>(); - - fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); - fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); - fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); - fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); - fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); - fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); - fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); - fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); - fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); - fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); - fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); - fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); - fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); - fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); - fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); - fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); - fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); - fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); - fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); - fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); - fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); - fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); - fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); - fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); - fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); - fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); - fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); - - try { - for (Field field : BlockStateProperties.class.getFields()) { - field.setAccessible(true); - Object value = field.get(null); - if (value instanceof Property) { - Property property = (Property) value; - register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); - } - } - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while loading properties mapper:"); - } - - } - - private static void register(String key, String fieldName, Property property) { - if (nameToProperty.containsKey(key)) { - Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); - } else { - nameToProperty.put(key, property); - propertyToName.put(property, key); - } - } - - public static Property getProperty(String name) { - return nameToProperty.get(name); - } - - public static String getPropertyName(Property property) { - return propertyToName.get(property); - } - -} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/PropertiesMapperVersioned.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..fa82a47f16 --- /dev/null +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/PropertiesMapperVersioned.java @@ -0,0 +1,15 @@ +package com.bgsoftware.superiorskyblock.nms.v1_18.world; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionDataImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionDataImpl.java deleted file mode 100644 index 8c145adfdd..0000000000 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/WorldEditSessionDataImpl.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_18.world; - -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionDataImpl implements WorldEditSession.Data { - - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private final List> chunks = new LinkedList<>(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); - - public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, - List> blocksToUpdate, - List> blockEntities, - Set lightenChunks) { - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // Convert chunk data - Iterator> chunksIterator = chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); - int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); - WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); - - List> lights; - if (isStarLightInterface || chunkData.lights().isEmpty()) { - lights = Collections.emptyList(); - } else { - lights = new LinkedList<>(); - chunkData.lights().forEach(lightPosition -> { - lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, - lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, - null)); - }); - } - - PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), - chunkData.heightmaps(), lights); - - this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, - currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); - } - - // Convert blocksToUpdate - blocksToUpdate.forEach(blockToUpdate -> { - BlockPos blockPos = blockToUpdate.getKey(); - this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockToUpdate.getValue())); - }); - - // Convert blockEntities - blockEntities.forEach(blockEntity -> { - BlockPos blockPos = blockEntity.getKey(); - this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockEntity.getValue())); - }); - - // Convert lights - lightenChunks.forEach(lightPosition -> { - this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, - lightPosition.z - baseChunkPosZAxis, null)); - }); - } - - public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, - int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, - Long2ObjectMapView chunks) { - this.chunks.forEach(chunkDataPositioned -> { - long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, - baseChunkPosZAxis + chunkDataPositioned.zOffset); - - List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - chunkDataPositioned.object.lights.forEach(lightPositioned -> { - lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, - baseBlockPosYAxis + lightPositioned.yOffset, - baseBlockPosZAxis + lightPositioned.zOffset)); - }); - - chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, - chunkDataPositioned.object.heightmaps, lights)); - }); - } - - public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { - this.blocksToUpdate.forEach(blockToUpdatePositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, - baseBlockPosYAxis + blockToUpdatePositioned.yOffset, - baseBlockPosZAxis + blockToUpdatePositioned.zOffset); - blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); - }); - } - - public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { - this.blockEntities.forEach(blockEntityPositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, - baseBlockPosYAxis + blockEntityPositioned.yOffset, - baseBlockPosZAxis + blockEntityPositioned.zOffset); - blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); - }); - } - - public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { - this.lightenChunks.forEach(lightPositioned -> { - ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, - baseChunkPosZAxis + lightPositioned.zOffset); - lightenChunks.add(newPos); - }); - } - - private static class PositionedObject { - - private final int xOffset; - private final int yOffset; - private final int zOffset; - private final V object; - - PositionedObject(int xOffset, int zOffset, V object) { - this(xOffset, 0, zOffset, object); - } - - PositionedObject(int xOffset, int yOffset, int zOffset, V object) { - this.xOffset = xOffset; - this.yOffset = yOffset; - this.zOffset = zOffset; - this.object = object; - } - - } - - private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, - List> lights) { - } - -} diff --git a/NMS/v1_19/properties b/NMS/v1_19/properties new file mode 100644 index 0000000000..955961c644 --- /dev/null +++ b/NMS/v1_19/properties @@ -0,0 +1,7 @@ +NMS_VERSION=v1_19 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit.v1_19_R3 +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java index f79f31f176..e4463c6593 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java @@ -1,218 +1,50 @@ package com.bgsoftware.superiorskyblock.nms.v1_19; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; -import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; -import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.nms.algorithms.PaperGlowEnchantment; import com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment; -import com.bgsoftware.superiorskyblock.nms.v1_19.menu.MenuBrewingStandBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_19.menu.MenuDispenserBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_19.menu.MenuFurnaceBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_19.menu.MenuHopperBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_19.world.BlockEntityCache; -import com.bgsoftware.superiorskyblock.nms.v1_19.world.KeyBlocksCache; -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.TextReplacementConfig; -import net.minecraft.core.BlockPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.Container; -import net.minecraft.world.entity.item.FallingBlockEntity; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.data.Ageable; -import org.bukkit.block.data.BlockData; -import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.v1_19_R3.CraftServer; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftFallingBlock; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftMinecart; +import org.bukkit.NamespacedKey; import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage; -import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.potion.PotionEffect; -import org.jetbrains.annotations.NotNull; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; import java.lang.reflect.Field; -import java.util.EnumMap; -import java.util.Optional; -import java.util.function.BiFunction; +import java.util.Locale; +import java.util.Objects; -public class NMSAlgorithmsImpl implements NMSAlgorithms { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms { private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); - private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); - - static { - MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); - } - - private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { - @Override - public byte[] processClass(byte[] classBytes, String path) { - return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); - } - }; - - @Override - public void registerCommand(BukkitCommand command) { - ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); - } - @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]); } - @Override - public int getCombinedId(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return 0; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(wrapper.getHandle()); - } - return Block.getId(blockState); - } - - @Override - public int getCombinedId(Material material, byte data) { - BlockState blockState; - - if (data == 0) { - Block block = CraftMagicNumbers.getBlock(material); - if (block == null) - return -1; - blockState = block.defaultBlockState(); - } else { - blockState = CraftMagicNumbers.getBlock(material, data); - } - - return blockState == null ? -1 : Block.getId(blockState); - } - - @Override - public Optional getTileEntityIdFromCombinedId(int combinedId) { - BlockState blockState = Block.stateById(combinedId); - - if (!blockState.hasBlockEntity()) - return Optional.empty(); - - String id = BlockEntityCache.getBlockEntityId(blockState); - - return Text.isBlank(id) ? Optional.empty() : Optional.of(id); - } - - @Override - public int compareMaterials(Material o1, Material o2) { - int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); - int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); - return Integer.compare(firstMaterial, secondMaterial); - } - - @Override - public short getBlockDataValue(org.bukkit.block.BlockState blockState) { - BlockData blockData = blockState.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getBlockDataValue(org.bukkit.block.Block block) { - BlockData blockData = block.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getMaxBlockDataValue(Material material) { - if (!material.isBlock()) - return 0; - - BlockData blockData = Bukkit.createBlockData(material); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); - } - - @Override - public Key getBlockKey(int combinedId) { - Block block = Block.stateById(combinedId).getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { - AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); - Block block = minecart.getDisplayBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { - FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); - Block block = fallingBlock.getBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public void setCustomModel(ItemMeta itemMeta, int customModel) { - itemMeta.setCustomModelData(customModel); - } - - @Override - public void setItemModel(ItemMeta itemMeta, String itemModel) { - // Doesn't exist - } - - @Override - public void setRarity(ItemMeta itemMeta, String rarity) { - // Doesn't exist - } - @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { - // Doesn't exist (Experimental) - } - - @Override - public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { - if (!potionMeta.hasCustomEffects()) - potionMeta.setColor(potionEffect.getType().getColor()); - potionMeta.addCustomEffect(potionEffect, true); + if (itemMeta instanceof ArmorMeta armorMeta) { + TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } } @Override @@ -225,47 +57,6 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } - @Nullable - @Override - public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { - MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); - return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); - } - - @Override - public int getMaxWorldSize() { - return Bukkit.getMaxWorldSize(); - } - - @Override - public double getCurrentTps() { - try { - return MinecraftServer.getServer().tps1.getAverage(); - } catch (Throwable error) { - //noinspection removal - return MinecraftServer.getServer().recentTps[0]; - } - } - - @Override - public int getDataVersion() { - return CraftMagicNumbers.INSTANCE.getDataVersion(); - } - - @Override - public ClassProcessor getClassProcessor() { - return CLASS_PROCESSOR; - } - - @Override - public void handlePaperChatRenderer(Object event) { - if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) - return; - - io.papermc.paper.chat.ChatRenderer originalRenderer = asyncChatEvent.renderer(); - asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); - } - private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; @@ -291,42 +82,4 @@ private static Enchantment initializeGlowEnchantment() { return glowEnchant; } - private interface MenuCreator extends BiFunction { - } - - private static class ChatRendererWrapper { - - private static final String MESSAGE_PLACEHOLDER = "{message}"; - private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = - net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); - - private final ChatRenderer renderer = new ChatRenderer() { - @Override - public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, - net.kyori.adventure.text.@NotNull Component sourceDisplayName, - net.kyori.adventure.text.@NotNull Component message, - @NotNull Audience viewer) { - String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer - .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); - Island island = superiorPlayer.getIsland(); - - return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( - Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) - .replaceText(TextReplacementConfig.builder() - .matchLiteral(MESSAGE_PLACEHOLDER) - .replacement(message) - .build()); - } - }; - - private final ChatRenderer originalRenderer; - - public ChatRendererWrapper(ChatRenderer originalRenderer) { - this.originalRenderer = originalRenderer; - } - - } - } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java index dbe60e9a1c..00a698d366 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java @@ -1,25 +1,17 @@ package com.bgsoftware.superiorskyblock.nms.v1_19; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; -import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_19.crops.CropsBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_19.crops.CropsTickingMethod; -import com.bgsoftware.superiorskyblock.nms.v1_19.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_19.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -40,16 +32,12 @@ import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; @@ -58,48 +46,28 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import net.minecraft.world.phys.AABB; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_19_R3.util.CraftNamespacedKey; +import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; -import java.util.Objects; import java.util.concurrent.CompletableFuture; -public class NMSChunksImpl implements NMSChunks { - - private static final boolean hasStatesIterator = new ReflectMethod<>(PalettedContainer.class, - "forEachLocation", PalettedContainer.CountConsumer.class).isValid(); - - private final SuperiorSkyblockPlugin plugin; +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - KeyBlocksCache.cacheAllBlocks(); - CropsTickingMethod.register(); + super(plugin); } @Override - public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, - Collection playersToUpdate) { - if (chunkPositions.isEmpty()) - return; - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.SET_BIOME, false) { + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -133,6 +101,8 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, bukkitBiome); @@ -149,7 +119,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound Tag biomesCompound = dataResult.getOrThrow(false, error -> { }); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); @@ -159,19 +129,12 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { // Do nothing. } - }); + }; } @Override - public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { - if (chunkPositions.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), - chunkPosition.getX(), chunkPosition.getZ(), false)); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.DELETE_CHUNK, false) { + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -188,6 +151,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( @@ -198,8 +162,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - unloadedChunkCompound.setEntities(new ListTag()); - unloadedChunkCompound.setBlockEntities(tileEntities); + chunkCompound.put("entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, @@ -208,27 +172,19 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound Tag blockStatesCompound = dataResult.getOrThrow(false, error -> { }); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { - CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), serverLevel.generator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(protoChunk), - ChunkStatus.SURFACE, 0); - - customChunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - protoChunk); + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); + Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), @@ -275,7 +231,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound tileEntities.add(blockEntityCompound); } - unloadedChunkCompound.setSections(sectionsList); + chunkCompound.put("sections", sectionsList); } } @@ -284,39 +240,19 @@ public void onFinish() { if (onFinish != null) onFinish.run(); } - }); + }; } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); - List chunkPositionsToCalculate = new LinkedList<>(); - - Iterator chunkPositionsIterator = chunkPositions.iterator(); - while (chunkPositionsIterator.hasNext()) { - ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); - if (cachedCalculatedChunk != null) { - allCalculatedChunks.add(cachedCalculatedChunk); - chunkPositionsIterator.remove(); - } else { - chunkPositionsToCalculate.add(chunkPosition); - } - } - - if (chunkPositions.isEmpty()) - return CompletableFuture.completedFuture(allCalculatedChunks); - - CompletableFuture> completableFuture = new CompletableFuture<>(); - - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( - ChunkLoadReason.BLOCKS_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); - allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.getSections())); + allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); latchCountDown(); } @@ -325,6 +261,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( @@ -342,43 +279,43 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { - PalettedContainer blocksDataPalette; + PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); - blocksDataPalette = dataResult.getOrThrow(false, error -> { + blocksPalettedContainer = dataResult.getOrThrow(false, error -> { }); } else { - blocksDataPalette = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } - PalettedContainer> biomesDataPalette; + PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); - biomesDataPalette = dataResult.getOrThrow(false, error -> { + biomesPalettedContainer = dataResult.getOrThrow(false, error -> { }); } else { - biomesDataPalette = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } - chunkSections[sectionIndex] = new LevelChunkSection(yPosition, blocksDataPalette, biomesDataPalette); + chunkSections[sectionIndex] = new LevelChunkSection(yPosition, blocksPalettedContainer, biomesPalettedContainer); } } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, chunkSections); + CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -389,20 +326,14 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { completableFuture.complete(allCalculatedChunks); } - }); - - return completableFuture; + }; } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); - - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - List unloadedChunkCompounds = new LinkedList<>(); - - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( - ChunkLoadReason.ENTITIES_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { @@ -425,8 +356,9 @@ public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - for (Tag entityTag : unloadedChunkCompound.getEntities()) { + for (Tag entityTag : chunkCompound.getList("entities", 10)) { EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); if (entityType == null) continue; @@ -448,171 +380,17 @@ public void onFinish() { completableFuture.complete(chunkEntities); }); } - }); - - return completableFuture; - } - - @Override - public void injectChunkSections(org.bukkit.Chunk chunk) { - // No implementation - } - - @Override - public boolean isChunkEmpty(org.bukkit.Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> - chunkSection == null || chunkSection.hasOnlyAir()); - } - - @Override - public org.bukkit.Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); - return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; - } - - @Override - public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean stop) { - if (plugin.getSettings().getCropsInterval() <= 0) - return; - - - if (stop) { - CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); - if (cropsBlockEntity != null) - cropsBlockEntity.remove(); - } else { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - CropsBlockEntity.create(island, levelChunk); - } - } - - @Override - public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { - if (chunkPositions.isEmpty()) return; - CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> - cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); - } - - @Override - public void shutdown() { - List> pendingTasks = NMSUtils.getPendingChunkActions(); - - if (pendingTasks.isEmpty()) - return; - - Log.info("Waiting for chunk tasks to complete."); - - CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); - } - - @Override - public List getBlockEntities(Chunk chunk) { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - List blockEntities = new LinkedList<>(); - - World bukkitWorld = chunk.getWorld(); - - levelChunk.getBlockEntities().keySet().forEach(blockPos -> - blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); - - return blockEntities; - } - - private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, LevelChunkSection[] chunkSections) { - KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); - List spawnersLocations = new LinkedList<>(); - - for (LevelChunkSection levelChunkSection : chunkSections) { - if (levelChunkSection != null && !levelChunkSection.hasOnlyAir()) { - if (hasStatesIterator) { - levelChunkSection.getStates().forEachLocation((blockState, locationKey) -> { - int x = locationKey & 0xF; - int y = (locationKey >> 8) & 0xF; - int z = (locationKey >> 4) & 0xF; - calculateChunkInternal(blockState, x, y, z, chunkPosition, levelChunkSection, blockCounts, spawnersLocations); - }); - } else for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { - BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, - levelChunkSection, blockCounts, spawnersLocations); - } - } - } - - return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); - } - - private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, - LevelChunkSection levelChunkSection, KeyMap blockCounts, - List spawnersLocations) { - Block block = blockState.getBlock(); - - if (block == Blocks.AIR) - return; - - Location location = new Location(chunkPosition.getWorld(), - (chunkPosition.getX() << 4) + x, - levelChunkSection.bottomBlockY() + y, - (chunkPosition.getZ() << 4) + z); - - int blockAmount = 1; - - if (NMSUtils.isDoubleBlock(block, blockState)) { - blockAmount = 2; - blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); - } - - Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); - blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); - if (block == Blocks.SPAWNER) { - spawnersLocations.add(location); - } - } - - private static void removeEntities(ChunkAccess chunk) { - ChunkPos chunkPos = chunk.getPos(); - ServerLevel serverLevel = ((LevelChunk) chunk).level; - - int chunkWorldCoordX = chunkPos.x << 4; - int chunkWorldCoordZ = chunkPos.z << 4; - - AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinBuildHeight(), chunkWorldCoordZ, - chunkWorldCoordX + 15, serverLevel.getMaxBuildHeight(), chunkWorldCoordZ + 15); - - List worldEntities = new LinkedList<>(); - serverLevel.getEntities().get(chunkBounds, worldEntities::add); - - worldEntities.forEach(nmsEntity -> { - if (!(nmsEntity instanceof Player)) - nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); - }); - } - - private static void removeBlockEntities(ChunkAccess chunk) { - chunk.blockEntities.values().forEach(BlockEntity::setRemoved); - chunk.blockEntities.clear(); + }; } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { - CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), - bukkitGenerator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunk), - ChunkStatus.SURFACE, 0); + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; - chunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - chunk); - } + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSDragonFightImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSDragonFightImpl.java deleted file mode 100644 index 67c889826b..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSDragonFightImpl.java +++ /dev/null @@ -1,119 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_19.dragon.EndWorldEndDragonFightHandler; -import com.bgsoftware.superiorskyblock.nms.v1_19.dragon.IslandEndDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_19.dragon.IslandEntityEnderDragon; -import com.bgsoftware.superiorskyblock.nms.v1_19.dragon.SpikesCache; -import com.google.common.cache.LoadingCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.advancement.Advancement; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.entity.Player; - -import java.lang.reflect.Modifier; -import java.util.List; - -public class NMSDragonFightImpl implements NMSDragonFight { - - private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( - EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField( - ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( - SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static boolean firstWorldPreparation = true; - - static { - ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); - } - - @Override - public void prepareEndWorld(World bukkitWorld) { - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); - - if (firstWorldPreparation) { - firstWorldPreparation = false; - SPIKE_CACHE.set(null, SpikesCache.getInstance()); - } - } - - @Nullable - @Override - public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return null; - - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); - return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); - } - - @Override - public void startDragonBattle(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); - } - - @Override - public void removeDragonBattle(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); - - if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { - islandEndDragonFight.removeBattlePlayers(); - islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); - } - } - - @Override - public void awardTheEndAchievement(Player player) { - Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); - if (advancement != null) - player.getAdvancementProgress(advancement).awardCriteria(""); - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSEntitiesImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSEntitiesImpl.java index bc5ef35a58..9f1b37e7be 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSEntitiesImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSEntitiesImpl.java @@ -1,57 +1,30 @@ package com.bgsoftware.superiorskyblock.nms.v1_19; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftAnimals; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; -import org.bukkit.entity.Animals; import org.bukkit.entity.minecart.PoweredMinecart; -import org.bukkit.inventory.EntityEquipment; -import org.bukkit.inventory.ItemStack; import java.lang.reflect.Modifier; -public class NMSEntitiesImpl implements NMSEntities { +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override - public ItemStack[] getEquipment(EntityEquipment entityEquipment) { - ItemStack[] itemStacks = new ItemStack[7]; - - itemStacks[0] = new ItemStack(Material.ARMOR_STAND); - itemStacks[1] = entityEquipment.getItemInMainHand(); - itemStacks[2] = entityEquipment.getItemInOffHand(); - itemStacks[3] = entityEquipment.getHelmet(); - itemStacks[4] = entityEquipment.getChestplate(); - itemStacks[5] = entityEquipment.getLeggings(); - itemStacks[6] = entityEquipment.getBoots(); - - return itemStacks; - } - - @Override - public boolean isAnimalFood(ItemStack itemStack, Animals animals) { - return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); - } - - @Override - public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override - public int getPortalTicks(org.bukkit.entity.Entity entity) { - return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); + protected int getPortalTicks(Entity entity) { + return PORTAL_TICKS.get(entity); } } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSHologramsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSHologramsImpl.java deleted file mode 100644 index 23ca28e332..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSHologramsImpl.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19; - -import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; -import com.bgsoftware.superiorskyblock.nms.NMSHolograms; -import com.google.common.base.Preconditions; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_19_R3.CraftServer; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftArmorStand; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage; -import org.bukkit.entity.Entity; - -@SuppressWarnings("unused") -public class NMSHologramsImpl implements NMSHolograms { - - @Override - public Hologram createHologram(Location location) { - Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); - serverLevel.addFreshEntity(entityHologram); - return entityHologram; - } - - @Override - public boolean isHologram(Entity entity) { - return ((CraftEntity) entity).getHandle() instanceof Hologram; - } - - public static class EntityHologram extends ArmorStand implements Hologram { - - private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); - - private CraftEntity bukkitEntity; - - EntityHologram(ServerLevel serverLevel, double x, double y, double z) { - super(serverLevel, x, y, z); - - setInvisible(true); - setSmall(true); - setShowArms(false); - setNoGravity(true); - setNoBasePlate(true); - setMarker(true); - forceSetBoundingBox(EMPTY_BOUND); - - super.collides = false; - super.setCustomNameVisible(true); - } - - @Override - public void setHologramName(String name) { - super.setCustomName(CraftChatMessage.fromStringOrNull(name)); - } - - @Override - public void removeHologram() { - super.remove(RemovalReason.DISCARDED); - } - - @Override - public org.bukkit.entity.ArmorStand getHandle() { - return this.getBukkitEntity(); - } - - @Override - public void inactiveTick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - @Override - public boolean repositionEntityAfterLoad() { - return false; - } - - @Override - public AABB getBoundingBoxForCulling() { - return EMPTY_BOUND; - } - - @Override - public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { - // Prevent stand being equipped - } - - @Override - public void addAdditionalSaveData(CompoundTag compoundTag) { - // Do not save NBT. - } - - @Override - public void readAdditionalSaveData(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { - // Prevent stand being equipped - return InteractionResult.PASS; - } - - @Override - public void tick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - public void forceSetBoundingBox(AABB boundingBox) { - super.setBoundingBox(boundingBox); - } - - @Override - public CraftArmorStand getBukkitEntity() { - if (bukkitEntity == null) { - bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); - } - return (CraftArmorStand) bukkitEntity; - } - - @Override - public void remove(RemovalReason removalReason) { - // Prevent being killed. - } - - @Override - public void playSound(SoundEvent soundEvent, float volume, float pitch) { - // Remove sounds. - } - - @Override - public boolean saveAsPassenger(CompoundTag compoundTag) { - // Do not save NBT. - return false; - } - - @Override - public CompoundTag saveWithoutId(CompoundTag compoundTag) { - // Do not save NBT. - return compoundTag; - } - - @Override - public void load(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public boolean isInvulnerableTo(DamageSource damageSource) { - /* - * The field Entity.invulnerable is private. - * It's only used while saving NBTTags, but since the entity would be killed - * on chunk unload, we prefer to override isInvulnerable(). - */ - return true; - } - - @Override - public void setCustomName(Component component) { - // Locks the custom name. - } - - @Override - public void setCustomNameVisible(boolean isCustomNameVisible) { - // Locks the custom name. - } - - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSPlayersImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSPlayersImpl.java deleted file mode 100644 index 1292eb192c..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSPlayersImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.nms.NMSPlayers; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.bgsoftware.superiorskyblock.nms.v1_19.player.OfflinePlayerDataImpl; -import com.bgsoftware.superiorskyblock.player.PlayerLocales; -import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.level.ServerPlayer; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; -import org.bukkit.entity.Item; -import org.bukkit.entity.Player; - -import java.util.Locale; - -public class NMSPlayersImpl implements NMSPlayers { - - private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - - @Override - public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { - return OfflinePlayerDataImpl.create(offlinePlayer); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer) { - Player player = superiorPlayer.asPlayer(); - - if (player == null) - return; - - ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() - .ifPresent(property -> setSkinTexture(superiorPlayer, property)); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { - superiorPlayer.setTextureValue(property.getValue()); - } - - @SuppressWarnings("deprecation") - @Override - public void sendActionBar(Player player, String message) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); - } - - @Override - public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { - BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); - bossBar.addPlayer(player); - return bossBar; - } - - @SuppressWarnings("deprecation") - @Override - public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { - player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); - } - - @Override - public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { - return superiorPlayer.getUniqueId().equals(item.getThrower()); - } - - @Nullable - @Override - public Locale getPlayerLocale(Player player) { - if (PLAYER_LOCALE.isValid()) { - return player.locale(); - } else try { - //noinspection deprecation - return PlayerLocales.getLocale(player.getLocale()); - } catch (IllegalArgumentException error) { - return null; - } - } - - private static class BossBarImpl implements BossBar { - - private final org.bukkit.boss.BossBar bossBar; - private final BossBarTask bossBarTask; - - public BossBarImpl(String message, BarColor color, double ticksToRun) { - bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); - this.bossBarTask = BossBarTask.create(this, ticksToRun); - } - - @Override - public void addPlayer(Player player) { - this.bossBar.addPlayer(player); - this.bossBarTask.registerTask(player); - } - - @Override - public void removeAll() { - this.bossBar.removeAll(); - this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); - } - - @Override - public void setProgress(double progress) { - this.bossBar.setProgress(progress); - } - - @Override - public double getProgress() { - return this.bossBar.getProgress(); - } - - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java index 1855b25ba0..9c595fbc23 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java @@ -1,91 +1,44 @@ package com.bgsoftware.superiorskyblock.nms.v1_19; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.ListTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.mojang.serialization.Dynamic; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; -import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; import java.util.Set; -@SuppressWarnings({"unused"}) -public class NMSTagsImpl implements NMSTags { +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSTags { @Override - public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag()); tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); - return CompoundTag.fromNBT(tagCompound); } @Override - public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { - if (compoundTag.containsKey("NBT")) { - // Old compound version, deserialize it accordingly - return deserializeItemOld(compoundTag); - } - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); - - int currentVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - int itemVersion = tagCompound.getInt("DataVersion"); - if (itemVersion < currentVersion) { - tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, - new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); - } - - ItemStack itemStack = ItemStack.of(tagCompound); - - return CraftItemStack.asCraftMirror(itemStack); + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; } - private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); - Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount").orElse(0); - short data = (short) compoundTag.getShort("data").orElse(0); - CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); - - org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - if (nbtData != null) - itemStack.setTag((net.minecraft.nbt.CompoundTag) nbtData.toNBT()); - - return CraftItemStack.asCraftMirror(itemStack); + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + return ItemStack.of(compoundTag); } @Override - @SuppressWarnings("ConstantConditions") - public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { - net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); - - if (compoundTag == null) - compoundTag = new net.minecraft.nbt.CompoundTag(); - - if (!compoundTag.contains("id")) - //noinspection deprecation - compoundTag.putString("id", entityType.getName()); + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.setTag(compoundTag); + } - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; @@ -147,29 +100,4 @@ public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } - @Override - public Object parseList(ListTag listTag) { - net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); - - for (Tag tag : listTag) - nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); - - return nbtTagList; - } - - @Override - public Object getNBTCompoundTag(Object object, String key) { - return ((net.minecraft.nbt.CompoundTag) object).get(key); - } - - @Override - public void setNBTCompoundTagValue(Object object, String key, Object value) { - ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); - } - - @Override - public int getNBTTagListSize(Object object) { - return ((net.minecraft.nbt.ListTag) object).size(); - } - } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java deleted file mode 100644 index 30b2627e2a..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSUtils.java +++ /dev/null @@ -1,508 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.nms.v1_19.world.PropertiesMapper; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; -import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; -import com.google.common.base.Suppliers; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.storage.EntityStorage; -import net.minecraft.world.level.chunk.storage.IOWorker; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; - -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; - -public class NMSUtils { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( - ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); - private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( - ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); - private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( - EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); - - private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); - - public static final ObjectsPool> BLOCK_POS_POOL = - ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); - - private NMSUtils() { - - } - - @Nullable - public static T getBlockEntityAt(Location location, Class type) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); - } - } - - public static void runActionOnEntityChunks(Collection chunksCoords, - ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); - } - - public static void runActionOnChunks(Collection chunksCoords, - boolean saveChunks, ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); - } - - private static void runActionOnChunksInternal(Collection chunksCoords, - ChunkCallback chunkCallback, - Consumer> onUnloadChunkAction) { - List unloadedChunks = new LinkedList<>(); - List loadedChunks = new LinkedList<>(); - - chunksCoords.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - ChunkAccess chunkAccess; - - try { - chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); - } catch (Throwable ex) { - chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); - } - - if (chunkAccess instanceof LevelChunk levelChunk) { - loadedChunks.add(levelChunk); - } else { - unloadedChunks.add(chunkPosition.copy()); - } - }); - - boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); - - if (!loadedChunks.isEmpty()) - runActionOnLoadedChunks(loadedChunks, chunkCallback); - - if (hasUnloadedChunks) { - onUnloadChunkAction.accept(unloadedChunks); - } else { - chunkCallback.onFinish(); - } - } - - private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { - chunks.forEach(chunkCallback::onLoadedChunk); - } - - private static void runActionOnUnloadedChunks(Collection chunks, - boolean saveChunks, - ChunkCallback chunkCallback) { - if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { - Iterator chunksIterator = chunks.iterator(); - while (chunksIterator.hasNext()) { - ChunkPosition chunkPosition = chunksIterator.next(); - - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( - chunkPosition.getX(), chunkPosition.getZ()); - if (cachedUnloadedChunk != null) { - chunkCallback.onLoadedChunk(cachedUnloadedChunk); - chunksIterator.remove(); - } - } - - if (chunks.isEmpty()) { - chunkCallback.onFinish(); - return; - } - } - - CompletableFuture pendingTask = new CompletableFuture<>(); - PENDING_CHUNK_ACTIONS.add(pendingTask); - - BukkitExecutor.createTask().runAsync(v -> { - CountDownLatch countDownLatch; - if (chunkCallback.isWaitForChunkLoad) { - countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - } else { - countDownLatch = null; - } - - List chunkCompounds = new LinkedList<>(); - - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - boolean calledCountdown = false; - try { - net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); - - if (chunkCompound == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), - Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, - Optional.empty(), chunkPos, serverLevel); - - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - calledCountdown = true; - - if (saveChunks) - chunkCompounds.add(unloadedChunkCompound); - } catch (Exception error) { - if (!calledCountdown && countDownLatch != null) - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPos, ":"); - } - }); - - if (countDownLatch != null) { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - } - - return chunkCompounds; - }).runSync(chunkCompounds -> { - chunkCompounds.forEach(unloadedChunkCompound -> { - ChunkMap chunkMap = unloadedChunkCompound.serverLevel().getChunkSource().chunkMap; - - try { - chunkMap.write(unloadedChunkCompound.chunkPos(), unloadedChunkCompound.chunkCompound); - } catch (IOException error) { - Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); - } - }); - - chunkCallback.onFinish(); - - pendingTask.complete(null); - PENDING_CHUNK_ACTIONS.remove(pendingTask); - }); - } - - private static void runActionOnUnloadedEntityChunks(Collection chunks, - ChunkCallback chunkCallback) { - CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); - IOWorker worker = ENTITY_STORAGE_WORKER.get(entityManager.permanentStorage); - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> { - if (error != null) { - countDownLatch.countDown(); - throw new RuntimeException(error); - } else { - net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - } else { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } - } - }); - }); - - BukkitExecutor.createTask().runAsync(v -> { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } else { - BukkitExecutor.createTask().runAsync(v -> { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - try { - net.minecraft.nbt.CompoundTag entityData = serverLevel.entityDataControllerNew.readData( - chunkPosition.getX(), chunkPosition.getZ()); - - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } catch (IOException error) { - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } - } - - public static List> getPendingChunkActions() { - return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); - } - - public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { - return new ProtoChunk(chunkPos, - UpgradeData.EMPTY, - serverLevel, - serverLevel.registryAccess().registryOrThrow(Registries.BIOME), - null); - } - - public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { - ServerLevel serverLevel = levelChunk.level; - - if (!isValidPosition(serverLevel, blockPos)) - return null; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - serverLevel.setBlock(blockPos, blockState, 3); - return blockState; - } - - int indexY = serverLevel.getSectionIndex(blockPos.getY()); - - LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; - - if (levelChunkSection == null) { - int yOffset = SectionPos.blockToSectionCoord(blockPos.getY()); - //noinspection deprecation - levelChunkSection = levelChunk.getSections()[indexY] = new LevelChunkSection(yOffset, levelChunk.biomeRegistry); - } - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - boolean isOriginallyChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - - levelChunk.setUnsaved(true); - - boolean isChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) - serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); - - serverLevel.getLightEngine().checkBlock(blockPos); - - if (tileEntity != null) { - net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); - if (tileEntityCompound != null) { - tileEntityCompound.putInt("x", blockPos.getX()); - tileEntityCompound.putInt("y", blockPos.getY()); - tileEntityCompound.putInt("z", blockPos.getZ()); - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.load(tileEntityCompound); - } - } - - return blockState; - } - - public static boolean isDoubleBlock(Block block, BlockState blockState) { - return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && - blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; - } - - @Nullable - public static LevelChunk getCraftChunkHandle(CraftChunk craftChunk) { - ServerLevel serverLevel = craftChunk.getCraftWorld().getHandle(); - LevelChunk loadedChunk = serverLevel.getChunkIfLoaded(craftChunk.getX(), craftChunk.getZ()); - if (loadedChunk != null) - return loadedChunk; - - return (LevelChunk) serverLevel.getChunk(craftChunk.getX(), craftChunk.getZ(), ChunkStatus.FULL, true); - } - - public record UnloadedChunkCompound(ChunkPosition chunkPosition, - net.minecraft.nbt.CompoundTag chunkCompound) { - - public ListTag getSections() { - return chunkCompound.getList("sections", 10); - } - - public ListTag getEntities() { - return chunkCompound.getList("Entities", 10); - } - - public void setSections(ListTag sectionsList) { - chunkCompound.put("sections", sectionsList); - } - - public void setEntities(ListTag entitiesList) { - chunkCompound.put("entities", entitiesList); - } - - public void setBlockEntities(ListTag blockEntitiesList) { - chunkCompound.put("block_entities", blockEntitiesList); - } - - public ServerLevel serverLevel() { - return ((CraftWorld) chunkPosition.getWorld()).getHandle(); - } - - public ChunkPos chunkPos() { - return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - } - } - - private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); - } - - public static abstract class ChunkCallback { - - private final ChunkLoadReason chunkLoadReason; - private final boolean isWaitForChunkLoad; - - @Nullable - protected CountDownLatch chunkLoadLatch; - - public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { - this.chunkLoadReason = chunkLoadReason; - this.isWaitForChunkLoad = isWaitForChunkLoad; - } - - public abstract void onLoadedChunk(LevelChunk levelChunk); - - public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - - public abstract void onFinish(); - - protected final void latchCountDown() { - if (this.chunkLoadLatch != null) - this.chunkLoadLatch.countDown(); - } - - public final void onChunkNotExist(ChunkPosition chunkPosition) { - if (!plugin.getProviders().hasCustomWorldsSupport()) - return; - - ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { - LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); - }); - } - - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index 52747b6f8f..ee377ac070 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -1,122 +1,28 @@ package com.bgsoftware.superiorskyblock.nms.v1_19; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; -import com.bgsoftware.superiorskyblock.nms.ICachedBlock; -import com.bgsoftware.superiorskyblock.nms.NMSWorld; -import com.bgsoftware.superiorskyblock.nms.algorithms.NMSCachedBlock; -import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; -import com.bgsoftware.superiorskyblock.nms.v1_19.generator.IslandsGeneratorImpl; -import com.bgsoftware.superiorskyblock.nms.v1_19.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_19.vibration.IslandSculkSensorBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_19.world.ChunkReaderImpl; -import com.bgsoftware.superiorskyblock.nms.v1_19.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_19.world.WorldEditSessionImpl; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.destroystokyo.paper.antixray.ChunkPacketBlockController; -import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.border.WorldBorder; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.BubbleColumn; import org.bukkit.block.data.type.HangingSign; -import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.WallHangingSign; -import org.bukkit.block.data.type.WallSign; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; -import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockState; -import org.bukkit.craftbukkit.v1_19_R3.block.CraftSign; -import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; -import org.bukkit.entity.Player; -import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.function.IntFunction; - -public class NMSWorldImpl implements NMSWorld { - - private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, - Object.class, "chunkPacketBlockController") - .removeFinal(); - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - - private final SuperiorSkyblockPlugin plugin; +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSWorld { public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); } @Override - public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { - Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); - Location location = new Location( - Bukkit.getWorld(chunkSnapshot.getWorldName()), - (chunkSnapshot.getX() << 4) + x, - y, - (chunkSnapshot.getZ() << 4) + z - ); - - return Keys.of(KeyBlocksCache.getBlockKey(block), location); - } - - @Override - public void listenSpawner(Location location, IntFunction delayChangeCallback) { - SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); - if (spawnerBlockEntity == null) - return; - - ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - - List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel); - Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new LinkedList<>(); - - while (blockEntityTickersIterator.hasNext()) { - TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && - !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { - blockEntityTickersIterator.remove(); - tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); - } - } - - if (!tickersToAdd.isEmpty()) - blockEntityTickers.addAll(tickersToAdd); + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.messages; } @Override @@ -131,241 +37,14 @@ public void replaceSculkSensorListener(Island island, Location location) { serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity)); } - @Override - public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { - if (!plugin.getSettings().isWorldBorders()) - return; - - Player player = superiorPlayer.asPlayer(); - org.bukkit.World world = superiorPlayer.getWorld(); - - if (world == null || player == null) - return; - - int islandSize = island == null ? 0 : island.getIslandSize(); - - boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; - - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - - WorldBorder worldBorder; - - if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { - worldBorder = serverLevel.getWorldBorder(); - } else { - Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); - if (dimension == null) - return; - - Location center = island.getCenter(dimension); - - worldBorder = new WorldBorder(); - worldBorder.world = serverLevel; - worldBorder.setWarningBlocks(0); - worldBorder.setCenter(center.getX(), center.getZ()); - - switch (superiorPlayer.getBorderColor()) { - case BLUE -> { - worldBorder.setSize((islandSize * 2) + 1D); - } - case GREEN -> { - worldBorder.setSize((islandSize * 2) + 1.001D); - worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); - } - case RED -> { - worldBorder.setSize((islandSize * 2) + 1D); - worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); - } - } - } - - ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); - ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); - } - - @Override - public Object getBlockData(org.bukkit.block.Block block) { - return block.getBlockData(); - } - - @Override - public void setBlock(Location location, int combinedId) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - BlockState blockState = - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - - if (blockState != null) { - serverLevel.getChunkSource().blockChanged(blockPos); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); - } - } - } - } - - @Override - public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return NMSCachedBlock.obtain(block); - } - - @Override - public boolean isWaterLogged(org.bukkit.block.Block block) { - if (Materials.isWater(block.getType())) - return true; - - BlockData blockData = block.getBlockData(); - - return blockData instanceof BubbleColumn || - (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); - } - @Override public SignType getSignType(Object sign) { - if (sign instanceof WallSign) - return SignType.WALL_SIGN; - else if (sign instanceof Sign) - return SignType.STANDING_SIGN; - else if (sign instanceof HangingSign) + if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else - return SignType.UNKNOWN; - } - - @Override - public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { - BlockState blockState = ((CraftBlock) block).getNMS(); - return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; - } - - @Override - public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { - return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); - } - - @Override - public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { - return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); - } - - private int getDefaultAmount(BlockState blockState) { - Block block = blockState.getBlock(); - return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; - } - - @Override - public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { - return !bukkitBlock.isPassable(); - } - - @Override - public void placeSign(Island island, Location location) { - SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); - if (signBlockEntity == null) - return; - - String[] lines = new String[4]; - System.arraycopy(CraftSign.revertComponents(signBlockEntity.messages), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - Component[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } - - System.arraycopy(newLines, 0, signBlockEntity.messages, 0, 4); - } - - @Override - public void playGeneratorSound(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); - } - } - - @Override - public void playBreakAnimation(org.bukkit.block.Block block) { - ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); - } - } - - @Override - public void playPlaceSound(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); - } - } - - @Override - public int getMinHeight(org.bukkit.World world) { - return world.getMinHeight(); - } - - @Override - public void removeAntiXray(org.bukkit.World bukkitWorld) { - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) - CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); - } - - @Override - public IslandsGenerator createGenerator(Dimension dimension) { - return new IslandsGeneratorImpl(dimension); - } - - @Override - public WorldEditSession createEditSession(World world) { - return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); - } - - @Override - public WorldEditSession createPartialEditSession(Dimension dimension) { - return WorldEditSessionImpl.obtain(dimension); - } - - @Override - public ChunkReader createChunkReader(Chunk chunk) { - return new ChunkReaderImpl(chunk); + return super.getSignType(sign); } } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsBlockEntity.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsBlockEntity.java deleted file mode 100644 index 2fd51021c9..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsBlockEntity.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.crops; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.chunk.LevelChunk; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.function.Consumer; - -public class CropsBlockEntity extends BlockEntity { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - - private final WeakReference island; - private final WeakReference chunk; - - private int currentTick = 0; - - private double cachedCropGrowthMultiplier; - - private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(levelChunk); - setLevel(levelChunk.level); - levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; - } - - public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); - return new CropsBlockEntity(island, levelChunk, blockPos); - }); - } - - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); - } - - public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { - if (tickingChunks.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> { - long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); - if (cropsBlockEntity != null) - cropsBlockEntityConsumer.accept(cropsBlockEntity); - }); - } - - public void remove() { - this.remove = true; - } - - public void tick() { - if (++currentTick <= plugin.getSettings().getCropsInterval()) - return; - - LevelChunk levelChunk = this.chunk.get(); - Island island = this.island.get(); - ServerLevel serverLevel = (ServerLevel) getLevel(); - - if (levelChunk == null || island == null || serverLevel == null) { - remove(); - return; - } - - currentTick = 0; - - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - if (chunkRandomTickSpeed > 0) - CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); - } - - public void setCropGrowthMultiplier(double cropGrowthMultiplier) { - this.cachedCropGrowthMultiplier = cropGrowthMultiplier; - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingBlockEntity.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingBlockEntity.java deleted file mode 100644 index 0c7bfbfdc2..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingBlockEntity.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.crops; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { - - - @Override - public void tick() { - cropsBlockEntity.tick(); - } - - @Override - public boolean isRemoved() { - return cropsBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return cropsBlockEntity.getBlockPos(); - } - - @Override - public String getType() { - return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java deleted file mode 100644 index 145c7c0bd2..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/crops/CropsTickingMethod.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.crops; - -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; - -public abstract class CropsTickingMethod { - - private static final ReflectField SERVER_LEVEL_RANDOM_TICK_RANDOM = new ReflectField<>( - ServerLevel.class, RandomSource.class, "randomTickRandom"); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static Set CROPS_TO_GROW_CACHE; - - static { - plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); - } - - private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); - - private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? - new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); - - - protected CropsTickingMethod() { - - } - - public static void register() { - // Calls the static initializer which registers the callback. - } - - public static void tick(LevelChunk levelChunk, int tickSpeed) { - INSTANCE.doTick(levelChunk, tickSpeed); - } - - protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); - - private static void onSettingsUpdate() { - CROPS_TO_GROW_CACHE = new HashSet<>(); - plugin.getSettings().getCropsToGrow().forEach(cropName -> { - Key key = Keys.ofMaterialAndData(cropName); - if (key instanceof MaterialKey materialKey) { - Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); - if (block != null && block.defaultBlockState().isRandomlyTicking()) - CROPS_TO_GROW_CACHE.add(block); - } - }); - } - - private static class PaperCropsTickingMethod extends CropsTickingMethod { - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - ServerLevel serverLevel = levelChunk.level; - LevelChunkSection[] sections = levelChunk.getSections(); - - int minSection = serverLevel.getMinSection(); - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - RandomSource randomTickRandom = SERVER_LEVEL_RANDOM_TICK_RANDOM.get(serverLevel); - - for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int tickingBlocks = levelChunkSection.tickingList.size(); - if (tickingBlocks <= 0) { - continue; - } - - int offsetY = (sectionIndex + minSection) << 4; - - for (int i = 0; i < tickSpeed; ++i) { - int index = randomTickRandom.nextInt(0x1000); - - if (index >= tickingBlocks) { - continue; - } - - long raw = levelChunkSection.tickingList.getRaw(index); - int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); - BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); - if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) - continue; - - chunkTickMutablePosition.set((location & 15) | chunkOffsetX, - ((location >>> 8) & 255) | offsetY, - ((location >>> 4) & 15) | chunkOffsetZ); - - blockState.randomTick(serverLevel, chunkTickMutablePosition, randomTickRandom); - } - } - - } - - } - - private static class SpigotCropsTickingMethod extends CropsTickingMethod { - - private static int random = ThreadLocalRandom.current().nextInt(); - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - LevelChunkSection[] sections = levelChunk.getSections(); - ServerLevel serverLevel = levelChunk.level; - - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - - for (int i = 0; i < tickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { - chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); - blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); - } - } - } - } - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/DragonUtils.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/DragonUtils.java deleted file mode 100644 index 44c258aabd..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/DragonUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.dragon; - -import com.bgsoftware.common.reflection.ReflectField; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; - -import java.lang.reflect.Modifier; - -public class DragonUtils { - - private static final ReflectField END_PODIUM_LOCATION = new ReflectField( - EndPodiumFeature.class, BlockPos.class, - Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static BlockPos currentPodiumPosition = BlockPos.ZERO; - - private DragonUtils() { - - } - - public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { - try { - END_PODIUM_LOCATION.set(null, podiumPosition); - currentPodiumPosition = podiumPosition; - runnable.run(); - } finally { - END_PODIUM_LOCATION.set(null, BlockPos.ZERO); - currentPodiumPosition = BlockPos.ZERO; - } - } - - public static BlockPos getCurrentPodiumPosition() { - return currentPodiumPosition; - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndWorldEndDragonFightHandler.java deleted file mode 100644 index 95aa749947..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndWorldEndDragonFightHandler.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; -import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.dimension.end.EndDragonFight; - -import java.util.LinkedList; -import java.util.List; - -public class EndWorldEndDragonFightHandler extends EndDragonFight { - - private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); - - private final List worldDragonFightsList = new LinkedList<>(); - - public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { - super(serverLevel, serverLevel.getSeed(), new CompoundTag()); - } - - @Override - public void tick() { - this.worldDragonFightsList.forEach(EndDragonFight::tick); - } - - public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); - if (oldDragonFight != null) - this.worldDragonFightsList.remove(oldDragonFight); - this.worldDragonFightsList.add(endDragonFight); - } - - @Nullable - public IslandEndDragonFight getDragonFight(IslandCache islandCache) { - return islandCache.get(CACHE_KEY); - } - - @Nullable - public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { - IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); - if (endDragonFight != null) - this.worldDragonFightsList.remove(endDragonFight); - return endDragonFight; - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEndDragonFight.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEndDragonFight.java deleted file mode 100644 index 8a5b904513..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEndDragonFight.java +++ /dev/null @@ -1,206 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; -import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; -import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import net.minecraft.world.level.block.state.pattern.BlockPattern; -import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; -import net.minecraft.world.level.block.state.predicate.BlockPredicate; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -public class IslandEndDragonFight extends EndDragonFight { - - private static final ReflectField DRAGON_BATTLE = new ReflectField( - EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 3); - private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); - private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( - DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); - - private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") - .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") - .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) - .build(); - - private final Island island; - private final BlockPos islandBlockPos; - private final Vec3 islandBlockVectored; - private final ServerLevel serverLevel; - private final IslandEntityEnderDragon entityEnderDragon; - - private byte currentTick = 0; - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { - this(island, serverLevel, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), null); - } - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, - @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { - super(serverLevel, serverLevel.getSeed(), new CompoundTag()); - - this.island = island; - this.islandBlockPos = islandBlockPos; - this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); - this.serverLevel = serverLevel; - this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; - - SCAN_FOR_LEGACY_PORTALS.set(this, false); - WAS_DRAGON_KILLED.set(this, false); - DRAGON_BATTLE.set(this.entityEnderDragon, this); - } - - @Override - public void tick() { - // doServerTick - - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); - - DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); - if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { - LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); - } - - if (++currentTick >= 20) { - updateBattlePlayers(); - currentTick = 0; - } - } - - @Nullable - @Override - public BlockPattern.BlockPatternMatch findExitPortal() { - int chunkX = this.islandBlockPos.getX() >> 4; - int chunkZ = this.islandBlockPos.getZ() >> 4; - - for (int x = -8; x <= 8; ++x) { - for (int z = -8; z <= 8; ++z) { - LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); - - for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { - if (blockEntity instanceof TheEndPortalBlockEntity) { - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( - this.serverLevel, blockEntity.getBlockPos()); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - } - } - - int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); - currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); - for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { - currentPosition.setY(y); - - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - - return null; - } - - @Override - public void resetSpikeCrystals() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); - } - - public void removeBattlePlayers() { - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - for (ServerPlayer serverPlayer : dragonEventPlayers) - this.dragonEvent.removePlayer(serverPlayer); - } - - public IslandEntityEnderDragon getEnderDragon() { - return this.entityEnderDragon; - } - - private void updateBattlePlayers() { - Set nearbyPlayers = new HashSet<>(); - - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - Player bukkitPlayer = superiorPlayer.asPlayer(); - if (bukkitPlayer != null) { - ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); - if (serverPlayer.level.equals(this.serverLevel)) { - this.dragonEvent.addPlayer(serverPlayer); - nearbyPlayers.add(serverPlayer.getUUID()); - } - } - } - - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - - dragonEventPlayers.stream() - .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) - .forEach(this.dragonEvent::removePlayer); - } - - private IslandEntityEnderDragon spawnEnderDragon() { - IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); - - entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); - entityEnderDragon.absMoveTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), - this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); - - this.serverLevel.addFreshEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); - - this.dragonUUID = entityEnderDragon.getUUID(); - this.resetSpikeCrystals(); - - return entityEnderDragon; - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java index 0914b4d4bd..9ed95a1be9 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/IslandEntityEnderDragon.java @@ -2,47 +2,22 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.config.SettingsManager; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEnderDragon; -public class IslandEntityEnderDragon extends EnderDragon { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - @NotNull - public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { - return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : - new EnderDragon(entityTypes, level); - } - - private final ServerLevel serverLevel; - private final Dimension dimension; - private BlockPos islandBlockPos; +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_19.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { - this(level); - this.islandBlockPos = islandBlockPos; + super(level, islandBlockPos); } - private IslandEntityEnderDragon(Level level) { - super(EntityType.ENDER_DRAGON, level); - this.serverLevel = (ServerLevel) level; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + public IslandEntityEnderDragon(Level level) { + super(level); } @Nullable @@ -65,40 +40,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { finalizeIslandEnderDragon(); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - - private void finalizeIslandEnderDragon() { - if (!(this.serverLevel.dragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) - return; - - Island island; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); - } - - if (island == null) - return; - - Location middleBlock = island.getCenter(dimension); - - SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); - if (dimensionConfig instanceof SettingsManager.Worlds.End) { - middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); - } - - this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); - - IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); - } - } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/hologram/EntityHologram.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/hologram/EntityHologram.java new file mode 100644 index 0000000000..cad2f29de6 --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/hologram/EntityHologram.java @@ -0,0 +1,39 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.hologram; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_19.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuBrewingStandBlockEntity.java deleted file mode 100644 index 79bd6e088f..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuBrewingStandBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { - - private final InventoryHolder holder; - - public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuDispenserBlockEntity.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuDispenserBlockEntity.java deleted file mode 100644 index 4083d019a6..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuDispenserBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.DispenserBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuDispenserBlockEntity extends DispenserBlockEntity { - - private final InventoryHolder holder; - - public MenuDispenserBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuFurnaceBlockEntity.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuFurnaceBlockEntity.java deleted file mode 100644 index 43a7ba1e32..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuFurnaceBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.FurnaceBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { - - private final InventoryHolder holder; - - public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuHopperBlockEntity.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuHopperBlockEntity.java deleted file mode 100644 index 008707cc64..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/menu/MenuHopperBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.HopperBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuHopperBlockEntity extends HopperBlockEntity { - - private final InventoryHolder holder; - - public MenuHopperBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/player/OfflinePlayerDataImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/player/OfflinePlayerDataImpl.java deleted file mode 100644 index 70e0be16af..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/player/OfflinePlayerDataImpl.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.player; - -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.craftbukkit.v1_19_R3.CraftServer; -import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; -import org.bukkit.entity.Player; - -import java.util.Optional; - -public class OfflinePlayerDataImpl implements OfflinePlayerData { - - private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); - - private Player fakePlayer; - - public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { - return POOL.obtain().initialize(offlinePlayer); - } - - private OfflinePlayerDataImpl() { - - } - - private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), - Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return null; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile); - this.fakePlayer = serverPlayer.getBukkitEntity(); - this.fakePlayer.loadData(); - - return this; - } - - @Override - public Player getFakeOnlinePlayer() { - return this.fakePlayer; - } - - @Override - public void setLocation(Location location) { - ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); - serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); - serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - } - - @Override - public void applyChanges() { - this.fakePlayer.saveData(); - } - - @Override - public void release() { - this.fakePlayer = null; - POOL.release(this); - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..c7b074641c --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java @@ -0,0 +1,310 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.utils; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_19.utils.TickingBlockList; +import com.google.common.base.Suppliers; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.IOWorker; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; +import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage; +import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; + +public class NMSUtilsVersioned { + + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( + EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { + return chunkMap.read(chunkPos).join().orElse(null); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { + return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), + chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException { + chunkMap.write(chunkPos, chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + IOWorker worker = ENTITY_STORAGE_WORKER.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } else { + return BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + CompoundTag entityData = serverLevel.entityDataControllerNew.readData( + chunkPosition.getX(), chunkPosition.getZ()); + + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + return; + } + + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } catch (IOException error) { + countDownLatch.countDown(); + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + serverLevel.registryAccess().registryOrThrow(Registries.BIOME), + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.getMaterial().isLiquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + blockEntity.load(compoundTag); + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.relight(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + if (compoundTag.getByte("SSB.HasSignLines") == 1) { + // We want to convert the sign lines from raw string to json + for (int i = 1; i <= 4; ++i) { + String line = compoundTag.getString("SSB.Text" + i); + if (!Text.isBlank(line)) { + Component newLine = CraftChatMessage.fromString(line)[0]; + compoundTag.putString("Text" + i, Component.Serializer.toJson(newLine)); + } + } + } + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); + + Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, + IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i); + + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + + chunkSections[i] = new LevelChunkSection(chunkSectionPos, statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunkAccess), + ChunkStatus.SURFACE, 0); + + chunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(); + } + + public static CompoundTag saveEntity(Entity entity) { + CompoundTag compoundTag = new CompoundTag(); + entity.save(compoundTag); + return compoundTag; + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.tickingList.size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.tickingList.getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + public static String getPropertyValue(Property property) { + return property.getValue(); + } + + public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.dragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absMoveTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSection(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinBuildHeight(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxBuildHeight(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.setUnsaved(true); + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockEntityCache.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockEntityCache.java deleted file mode 100644 index 97c991f53f..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockEntityCache.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.world; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class BlockEntityCache { - - private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); - - private BlockEntityCache() { - - } - - public static String getBlockEntityId(BlockState blockState) { - return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { - for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - if (blockEntityType.isValid(blockState)) { - ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); - if (resourceLocation != null) - return resourceLocation.toString(); - } - } - - return ""; - }); - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java deleted file mode 100644 index 0138394d63..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/ChunkReaderImpl.java +++ /dev/null @@ -1,231 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_19_R3.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.InventoryHolder; - -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class ChunkReaderImpl implements ChunkReader { - - private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - private static final byte[] EMPTY_LIGHT = new byte[2048]; - - private final ServerLevel serverLevel; - private final int x; - private final int z; - - private final Map blockEntities = new HashMap<>(); - private final List entities = new LinkedList<>(); - private final PalettedContainerRO[] blockids; - private final byte[][] skylight; - private final byte[][] emitlight; - - public ChunkReaderImpl(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - - this.serverLevel = levelChunk.level; - ChunkPos chunkPos = levelChunk.getPos(); - this.x = chunkPos.x; - this.z = chunkPos.z; - - LevelChunkSection[] levelChunkSections = levelChunk.getSections(); - this.blockids = new PalettedContainerRO[levelChunkSections.length]; - this.skylight = new byte[levelChunkSections.length][]; - this.emitlight = new byte[levelChunkSections.length][]; - - LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); - - for (int i = 0; i < this.blockids.length; ++i) { - LevelChunkSection levelChunkSection = levelChunkSections[i]; - - this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); - - DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) - .getDataLayerData(SectionPos.of(this.x, i, this.z)); - if (skyLightArray == null) { - this.skylight[i] = EMPTY_LIGHT; - } else { - this.skylight[i] = new byte[2048]; - System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); - } - - DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) - .getDataLayerData(SectionPos.of(this.x, i, this.z)); - if (emitLightArray == null) { - this.emitlight[i] = EMPTY_LIGHT; - } else { - this.emitlight[i] = new byte[2048]; - System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); - } - } - - levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - InventoryHolder inventoryHolder = blockEntity.getOwner(); - if (inventoryHolder != null) - compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); - - blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); - }); - - for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) - entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); - } - - @Override - public int getX() { - return this.x; - } - - @Override - public int getZ() { - return this.z; - } - - @Override - public Material getType(int x, int y, int z) { - return CraftMagicNumbers.getMaterial(getBlockState(x, y, z).getBlock()); - } - - @Override - public short getData(int x, int y, int z) { - return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); - } - - @Override - @Nullable - public CompoundTag getTileEntity(int x, int y, int z) { - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); - return this.blockEntities.get(blockPos); - } - } - - @Override - @Nullable - public CompoundTag readBlockStates(int x, int y, int z) { - BlockState blockState = getBlockState(x, y, z); - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = CompoundTag.of(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(int x, int y, int z) { - int off = (y & 15) << 7 | z << 3 | x >> 1; - int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; - } - - @Override - public void forEachEntity(EntityConsumer consumer) { - if (entities.isEmpty()) - return; - - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = wrapper.getHandle(); - for (CachedEntity cachedEntity : entities) { - location.setX(cachedEntity.x); - location.setY(cachedEntity.y); - location.setZ(cachedEntity.z); - location.setYaw(cachedEntity.yaw); - location.setPitch(cachedEntity.pitch); - consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); - } - } - } - - private BlockState getBlockState(int x, int y, int z) { - return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); - } - - private int getSectionIndex(int y) { - int sectionIndex = SectionPos.blockToSectionCoord(y); - return sectionIndex - this.serverLevel.getMinSection(); - } - - private static class CachedEntity { - - private final double x; - private final double y; - private final double z; - private final float yaw; - private final float pitch; - private final EntityType entityType; - private final CompoundTag entityTag; - - CachedEntity(Entity entity) { - this.x = entity.getX(); - this.y = entity.getY(); - this.z = entity.getZ(); - this.yaw = entity.getBukkitYaw(); - this.pitch = entity.getXRot(); - this.entityType = entity.getBukkitEntity().getType(); - - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - - this.entityTag = CompoundTag.fromNBT(compoundTag); - } - - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/KeyBlocksCache.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/KeyBlocksCache.java deleted file mode 100644 index 772a984ce0..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/KeyBlocksCache.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.world; - -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.level.block.Block; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_19_R3.util.CraftMagicNumbers; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class KeyBlocksCache { - - private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); - - private KeyBlocksCache() { - - } - - public static Key getBlockKey(Block block) { - return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { - Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); - }); - } - - public static void cacheAllBlocks() { - BuiltInRegistries.BLOCK.forEach(KeyBlocksCache::getBlockKey); - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/PropertiesMapperVersioned.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..fa93d585be --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/PropertiesMapperVersioned.java @@ -0,0 +1,17 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.world; + +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionDataImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionDataImpl.java deleted file mode 100644 index ae41146158..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionDataImpl.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.world; - -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionDataImpl implements WorldEditSession.Data { - - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private final List> chunks = new LinkedList<>(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); - - public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, - List> blocksToUpdate, - List> blockEntities, - Set lightenChunks) { - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // Convert chunk data - Iterator> chunksIterator = chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); - int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); - WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); - - List> lights; - if (isStarLightInterface || chunkData.lights().isEmpty()) { - lights = Collections.emptyList(); - } else { - lights = new LinkedList<>(); - chunkData.lights().forEach(lightPosition -> { - lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, - lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, - null)); - }); - } - - PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), - chunkData.heightmaps(), lights); - - this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, - currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); - } - - // Convert blocksToUpdate - blocksToUpdate.forEach(blockToUpdate -> { - BlockPos blockPos = blockToUpdate.getKey(); - this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockToUpdate.getValue())); - }); - - // Convert blockEntities - blockEntities.forEach(blockEntity -> { - BlockPos blockPos = blockEntity.getKey(); - this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockEntity.getValue())); - }); - - // Convert lights - lightenChunks.forEach(lightPosition -> { - this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, - lightPosition.z - baseChunkPosZAxis, null)); - }); - } - - public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, - int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, - Long2ObjectMapView chunks) { - this.chunks.forEach(chunkDataPositioned -> { - long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, - baseChunkPosZAxis + chunkDataPositioned.zOffset); - - List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - chunkDataPositioned.object.lights.forEach(lightPositioned -> { - lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, - baseBlockPosYAxis + lightPositioned.yOffset, - baseBlockPosZAxis + lightPositioned.zOffset)); - }); - - chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, - chunkDataPositioned.object.heightmaps, lights)); - }); - } - - public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { - this.blocksToUpdate.forEach(blockToUpdatePositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, - baseBlockPosYAxis + blockToUpdatePositioned.yOffset, - baseBlockPosZAxis + blockToUpdatePositioned.zOffset); - blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); - }); - } - - public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { - this.blockEntities.forEach(blockEntityPositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, - baseBlockPosYAxis + blockEntityPositioned.yOffset, - baseBlockPosZAxis + blockEntityPositioned.zOffset); - blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); - }); - } - - public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { - this.lightenChunks.forEach(lightPositioned -> { - ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, - baseChunkPosZAxis + lightPositioned.zOffset); - lightenChunks.add(newPos); - }); - } - - private static class PositionedObject { - - private final int xOffset; - private final int yOffset; - private final int zOffset; - private final V object; - - PositionedObject(int xOffset, int zOffset, V object) { - this(xOffset, 0, zOffset, object); - } - - PositionedObject(int xOffset, int yOffset, int zOffset, V object) { - this.xOffset = xOffset; - this.yOffset = yOffset; - this.zOffset = zOffset; - this.object = object; - } - - } - - private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, - List> lights) { - } - -} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java deleted file mode 100644 index c016a815b1..0000000000 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/WorldEditSessionImpl.java +++ /dev/null @@ -1,440 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_19.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.google.common.base.Preconditions; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.HolderLookup; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.ticks.ProtoChunkTicks; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; -import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; -import org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage; -import org.bukkit.generator.ChunkGenerator; - -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionImpl implements WorldEditSession { - - private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.starlight.common.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - - private Dimension dimension; - private LevelHeightAccessor levelHeightAccessor; - - @Nullable - private ServerLevel serverLevel; - - public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { - return POOL.obtain().initialize(serverLevel); - } - - public static WorldEditSessionImpl obtain(Dimension dimension) { - return POOL.obtain().initialize(dimension); - } - - private WorldEditSessionImpl() { - } - - private WorldEditSessionImpl initialize(ServerLevel serverLevel) { - this.serverLevel = serverLevel; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); - this.levelHeightAccessor = serverLevel; - return this; - } - - private WorldEditSessionImpl initialize(Dimension dimension) { - DimensionType dimensionType = getDimensionTypeFromDimension(dimension); - this.serverLevel = null; - this.dimension = dimension; - this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); - return this; - } - - @Override - public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, - @Nullable CompoundTag blockEntityData) { - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - if (!isValidPosition(blockPos)) - return; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.getMaterial().isLiquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - blocksToUpdate.add(new Pair<>(blockPos, blockState)); - return; - } - - ChunkPos chunkPos = new ChunkPos(blockPos); - - if (blockEntityData != null) - blockEntities.add(new Pair<>(blockPos, blockEntityData)); - - ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); - - if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) - chunkData.lights.add(blockPos); - - LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - } - - @Override - public List getAffectedChunks() { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); - - if (chunks.isEmpty()) - return Collections.emptyList(); - - List chunkPositions = new LinkedList<>(); - World bukkitWorld = serverLevel.getWorld(); - LongIterator iterator = chunks.keyIterator(); - while (iterator.hasNext()) { - long chunkKey = iterator.next(); - int chunkX = (int) chunkKey; - int chunkZ = (int) (chunkKey >> 32); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); - } - return chunkPositions; - } - - @Override - public void applyBlocks(Chunk bukkitChunk) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); - - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); - ChunkPos chunkPos = levelChunk.getPos(); - - long chunkKey = chunkPos.toLong(); - ChunkData chunkData = this.chunks.remove(chunkKey); - - if (chunkData == null) - return; - - int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); - for (int i = 0; i < chunkSectionsCount; ++i) { - levelChunk.getSections()[i] = chunkData.chunkSections[i]; - } - - chunkData.heightmaps.forEach(((type, heightmap) -> { - levelChunk.setHeightmap(type, heightmap.getRawData()); - })); - - if (plugin.getSettings().isLightsUpdate()) { - if (isStarLightInterface) { - this.lightenChunks.add(chunkPos); - } else { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); - // Queues chunk light for this chunk. - threadedLevelLightEngine.lightChunk(levelChunk, false); - } - } - - levelChunk.setUnsaved(true); - } - - @Override - public void finish(Island island) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); - - // Update blocks - blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); - - // Update block entities - blockEntities.forEach(data -> { - net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); - if (blockEntityCompound != null) { - BlockPos blockPos = data.getKey(); - blockEntityCompound.putInt("x", blockPos.getX()); - blockEntityCompound.putInt("y", blockPos.getY()); - blockEntityCompound.putInt("z", blockPos.getZ()); - - if (blockEntityCompound.getByte("SSB.HasSignLines") == 1) { - // We want to convert the sign lines from raw string to json - for (int i = 1; i <= 4; ++i) { - String line = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(line)) { - Component newLine = CraftChatMessage.fromString(line)[0]; - blockEntityCompound.putString("Text" + i, Component.Serializer.toJson(newLine)); - } - } - } - - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.load(blockEntityCompound); - } - }); - - if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - threadedLevelLightEngine.relight(lightenChunks, chunkCallback -> { - }, completeCallback -> { - }); - this.lightenChunks.clear(); - } - - release(); - } - - @Override - public Data readData(Location baseLocation) { - return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); - } - - @Override - public void applyData(Data data, Location baseLocation) { - WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // We need to transform all data to the new base location values - - dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, - baseBlockPosZAxis, this, this.chunks); - dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); - dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); - dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); - } - - @Override - public void release() { - this.chunks.clear(); - this.blocksToUpdate.clear(); - this.blockEntities.clear(); - this.lightenChunks.clear(); - this.serverLevel = null; - this.dimension = null; - this.levelHeightAccessor = null; - POOL.release(this); - } - - public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - return new ChunkData(chunkSections, heightmaps, lights); - } - - private boolean isValidPosition(BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); - } - - private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { - ResourceKey resourceKey; - switch (dimension.getEnvironment()) { - case NETHER -> resourceKey = LevelStem.NETHER; - case THE_END -> resourceKey = LevelStem.END; - default -> resourceKey = LevelStem.OVERWORLD; - } - HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); - return registry.getOrThrow(resourceKey).value().type().value(); - } - - public class ChunkData { - - private final LevelChunkSection[] chunkSections; - private final Map heightmaps; - private final List lights; - - private ChunkData(long chunkKey) { - this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), - isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); - - ChunkPos chunkPos = new ChunkPos(chunkKey); - - Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); - - createChunkSections(biomesRegistry); - - ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); - - createHeightmaps(tempChunk); - if (serverLevel != null) - runCustomWorldGenerator(tempChunk); - } - - private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - this.chunkSections = chunkSections; - this.heightmaps = heightmaps; - this.lights = lights; - } - - public LevelChunkSection[] chunkSections() { - return this.chunkSections; - } - - public Map heightmaps() { - return this.heightmaps; - } - - public List lights() { - return this.lights; - } - - private void createChunkSections(Registry biomesRegistry) { - Holder biome = CraftBlock.biomeToBiomeBase(biomesRegistry, - IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); - - for (int i = 0; i < this.chunkSections.length; ++i) { - int chunkSectionPos = levelHeightAccessor.getSectionYFromSectionIndex(i); - - PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), - biome, PalettedContainer.Strategy.SECTION_BIOMES); - PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - - this.chunkSections[i] = new LevelChunkSection(chunkSectionPos, statesContainer, biomesContainer); - } - } - - private void runCustomWorldGenerator(ProtoChunk tempChunk) { - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - - if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) - return; - - CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), - bukkitGenerator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(tempChunk), - ChunkStatus.SURFACE, 0); - - chunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - tempChunk); - - // We want to copy the level chunk sections back - LevelChunkSection[] tempChunkSections = tempChunk.getSections(); - for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { - LevelChunkSection chunkSection = tempChunkSections[i]; - if (chunkSection != null) - this.chunkSections[i] = chunkSection; - } - } - - private void createHeightmaps(ProtoChunk tempChunk) { - for (Heightmap.Types heightmapType : Heightmap.Types.values()) { - if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { - this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); - } - } - } - - } - - -} diff --git a/NMS/v1_20_3/properties b/NMS/v1_20_3/properties new file mode 100644 index 0000000000..d57d752166 --- /dev/null +++ b/NMS/v1_20_3/properties @@ -0,0 +1,7 @@ +NMS_VERSION=v1_20_3 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit.v1_20_R3 +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java index dd0a27987d..73993fa5ed 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java @@ -1,246 +1,33 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_3; -import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; -import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; -import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.PaperGlowEnchantment; import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.SpigotGlowEnchantment; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.menu.MenuBrewingStandBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.menu.MenuDispenserBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.menu.MenuFurnaceBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.menu.MenuHopperBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.BlockEntityCache; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.KeyBlocksCache; -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.TextReplacementConfig; -import net.minecraft.core.BlockPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.Container; -import net.minecraft.world.entity.item.FallingBlockEntity; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; -import org.bukkit.block.data.Ageable; -import org.bukkit.block.data.BlockData; -import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_20_R3.CraftRegistry; -import org.bukkit.craftbukkit.v1_20_R3.CraftServer; -import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftFallingBlock; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftMinecart; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; -import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.inventory.meta.trim.ArmorTrim; -import org.bukkit.inventory.meta.trim.TrimMaterial; -import org.bukkit.inventory.meta.trim.TrimPattern; -import org.bukkit.potion.PotionEffect; -import org.jetbrains.annotations.NotNull; -import java.util.EnumMap; -import java.util.Locale; import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.function.BiFunction; -public class NMSAlgorithmsImpl implements NMSAlgorithms { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms { private static final ReflectField> REGISTRY_CACHE = new ReflectField<>(CraftRegistry.class, Map.class, "cache"); private static final Enchantment GLOW_ENCHANT = initializeGlowEnchantment(); - private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); - - static { - MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); - } - - private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { - @Override - public byte[] processClass(byte[] classBytes, String path) { - return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); - } - }; - - @Override - public void registerCommand(BukkitCommand command) { - ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); - } - @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]); } - @Override - public int getCombinedId(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return 0; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(wrapper.getHandle()); - } - return Block.getId(blockState); - } - - @Override - public int getCombinedId(Material material, byte data) { - BlockState blockState; - - if (data == 0) { - Block block = CraftMagicNumbers.getBlock(material); - if (block == null) - return -1; - blockState = block.defaultBlockState(); - } else { - blockState = CraftMagicNumbers.getBlock(material, data); - } - - return blockState == null ? -1 : Block.getId(blockState); - } - - @Override - public Optional getTileEntityIdFromCombinedId(int combinedId) { - BlockState blockState = Block.stateById(combinedId); - - if (!blockState.hasBlockEntity()) - return Optional.empty(); - - String id = BlockEntityCache.getBlockEntityId(blockState); - - return Text.isBlank(id) ? Optional.empty() : Optional.of(id); - } - - @Override - public int compareMaterials(Material o1, Material o2) { - int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); - int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); - return Integer.compare(firstMaterial, secondMaterial); - } - - @Override - public short getBlockDataValue(org.bukkit.block.BlockState blockState) { - BlockData blockData = blockState.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getBlockDataValue(org.bukkit.block.Block block) { - BlockData blockData = block.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getMaxBlockDataValue(Material material) { - if (!material.isBlock()) - return 0; - - BlockData blockData = Bukkit.createBlockData(material); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); - } - - @Override - public Key getBlockKey(int combinedId) { - Block block = Block.stateById(combinedId).getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { - AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); - Block block = minecart.getDisplayBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { - FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); - Block block = fallingBlock.getBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public void setCustomModel(ItemMeta itemMeta, int customModel) { - itemMeta.setCustomModelData(customModel); - } - - @Override - public void setItemModel(ItemMeta itemMeta, String itemModel) { - // Doesn't exist - } - - @Override - public void setRarity(ItemMeta itemMeta, String rarity) { - // Doesn't exist - } - - @Override - public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { - if (itemMeta instanceof ArmorMeta armorMeta) { - TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); - TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); - - if (material == null) - throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + - " into trim material, skipping..."); - if (pattern == null) - throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + - " into trim pattern, skipping..."); - - ArmorTrim armorTrim = new ArmorTrim(material, pattern); - armorMeta.setTrim(armorTrim); - } - } - - @Override - public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { - if (!potionMeta.hasCustomEffects()) - potionMeta.setColor(potionEffect.getType().getColor()); - potionMeta.addCustomEffect(potionEffect, true); - } - @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); @@ -251,47 +38,6 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } - @Nullable - @Override - public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { - MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); - return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); - } - - @Override - public int getMaxWorldSize() { - return Bukkit.getMaxWorldSize(); - } - - @Override - public double getCurrentTps() { - try { - return MinecraftServer.getServer().tps1.getAverage(); - } catch (Throwable error) { - //noinspection removal - return MinecraftServer.getServer().recentTps[0]; - } - } - - @Override - public int getDataVersion() { - return CraftMagicNumbers.INSTANCE.getDataVersion(); - } - - @Override - public ClassProcessor getClassProcessor() { - return CLASS_PROCESSOR; - } - - @Override - public void handlePaperChatRenderer(Object event) { - if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) - return; - - io.papermc.paper.chat.ChatRenderer originalRenderer = asyncChatEvent.renderer(); - asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); - } - private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; @@ -308,42 +54,4 @@ private static Enchantment initializeGlowEnchantment() { return glowEnchant; } - private interface MenuCreator extends BiFunction { - } - - private static class ChatRendererWrapper { - - private static final String MESSAGE_PLACEHOLDER = "{message}"; - private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = - net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); - - private final ChatRenderer renderer = new ChatRenderer() { - @Override - public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, - net.kyori.adventure.text.@NotNull Component sourceDisplayName, - net.kyori.adventure.text.@NotNull Component message, - @NotNull Audience viewer) { - String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer - .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); - Island island = superiorPlayer.getIsland(); - - return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( - Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) - .replaceText(TextReplacementConfig.builder() - .matchLiteral(MESSAGE_PLACEHOLDER) - .replacement(message) - .build()); - } - }; - - private final ChatRenderer originalRenderer; - - public ChatRendererWrapper(ChatRenderer originalRenderer) { - this.originalRenderer = originalRenderer; - } - - } - } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java index 1569ba10a7..1a3e6cb7b7 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java @@ -1,26 +1,17 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_3; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; -import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.crops.CropsBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.crops.CropsTickingMethod; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -38,83 +29,46 @@ import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.storage.EntityStorage; -import net.minecraft.world.level.chunk.storage.IOWorker; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; import net.minecraft.world.level.lighting.LevelLightEngine; -import net.minecraft.world.phys.AABB; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntityType; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey; +import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; -import java.lang.reflect.Modifier; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; -import java.util.Objects; import java.util.concurrent.CompletableFuture; -public class NMSChunksImpl implements NMSChunks { - - private static final boolean hasStatesIterator = new ReflectMethod<>(PalettedContainer.class, - "forEachLocation", PalettedContainer.CountConsumer.class).isValid(); - private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( - ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); - private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( - EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); - - private final SuperiorSkyblockPlugin plugin; +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - KeyBlocksCache.cacheAllBlocks(); - CropsTickingMethod.register(); + super(plugin); } @Override - public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, - Collection playersToUpdate) { - if (chunkPositions.isEmpty()) - return; - - Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.SET_BIOME, false) { + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); @@ -132,7 +86,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null); + levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); @@ -143,7 +97,11 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { - Registry biomesRegistry = unloadedChunkCompound.serverLevel().registryAccess().registryOrThrow(Registries.BIOME); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), @@ -157,7 +115,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound Tag biomesCompound = dataResult.getOrThrow(false, error -> { }); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); @@ -167,19 +125,12 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { // Do nothing. } - }); + }; } @Override - public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { - if (chunkPositions.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), - chunkPosition.getX(), chunkPosition.getZ(), false)); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.DELETE_CHUNK, false) { + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -196,6 +147,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( @@ -206,8 +158,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - unloadedChunkCompound.setEntities(new ListTag()); - unloadedChunkCompound.setBlockEntities(tileEntities); + chunkCompound.put("entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, @@ -216,27 +168,19 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound Tag blockStatesCompound = dataResult.getOrThrow(false, error -> { }); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { - CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), serverLevel.generator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(protoChunk), - ChunkStatus.SURFACE, 0); - - customChunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - protoChunk); + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); + Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), @@ -283,7 +227,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound tileEntities.add(blockEntityCompound); } - unloadedChunkCompound.setSections(sectionsList); + chunkCompound.put("sections", sectionsList); } } @@ -292,34 +236,14 @@ public void onFinish() { if (onFinish != null) onFinish.run(); } - }); + }; } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); - List chunkPositionsToCalculate = new LinkedList<>(); - - Iterator chunkPositionsIterator = chunkPositions.iterator(); - while (chunkPositionsIterator.hasNext()) { - ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); - if (cachedCalculatedChunk != null) { - allCalculatedChunks.add(cachedCalculatedChunk); - chunkPositionsIterator.remove(); - } else { - chunkPositionsToCalculate.add(chunkPosition); - } - } - - if (chunkPositions.isEmpty()) - return CompletableFuture.completedFuture(allCalculatedChunks); - - CompletableFuture> completableFuture = new CompletableFuture<>(); - - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( - ChunkLoadReason.BLOCKS_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -333,6 +257,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( @@ -350,38 +275,38 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { - PalettedContainer blocksDataPalette; + PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); - blocksDataPalette = dataResult.getOrThrow(false, error -> { + blocksPalettedContainer = dataResult.getOrThrow(false, error -> { }); } else { - blocksDataPalette = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } - PalettedContainer> biomesDataPalette; + PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); - biomesDataPalette = dataResult.getOrThrow(false, error -> { + biomesPalettedContainer = dataResult.getOrThrow(false, error -> { }); } else { - biomesDataPalette = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } - chunkSections[sectionIndex] = new LevelChunkSection(blocksDataPalette, biomesDataPalette); + chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } @@ -397,20 +322,14 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { completableFuture.complete(allCalculatedChunks); } - }); - - return completableFuture; + }; } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); - - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - List unloadedChunkCompounds = new LinkedList<>(); - - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( - ChunkLoadReason.ENTITIES_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { @@ -433,8 +352,9 @@ public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - for (Tag entityTag : unloadedChunkCompound.getEntities()) { + for (Tag entityTag : chunkCompound.getList("entities", 10)) { EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); if (entityType == null) continue; @@ -446,7 +366,9 @@ public void onFinish() { continue; } - Key entityKey = Keys.of(CraftEntityType.minecraftToBukkit(entityType)); + Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( + CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); + chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); } } @@ -454,173 +376,17 @@ public void onFinish() { completableFuture.complete(chunkEntities); }); } - }); - - return completableFuture; - } - - @Override - public void injectChunkSections(org.bukkit.Chunk chunk) { - // No implementation - } - - @Override - public boolean isChunkEmpty(org.bukkit.Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> - chunkSection == null || chunkSection.hasOnlyAir()); - } - - @Override - public org.bukkit.Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); - return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; - } - - @Override - public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean stop) { - if (plugin.getSettings().getCropsInterval() <= 0) - return; - - - if (stop) { - CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); - if (cropsBlockEntity != null) - cropsBlockEntity.remove(); - } else { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - CropsBlockEntity.create(island, levelChunk); - } - } - - @Override - public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { - if (chunkPositions.isEmpty()) return; - CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> - cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); - } - - @Override - public void shutdown() { - List> pendingTasks = NMSUtils.getPendingChunkActions(); - - if (pendingTasks.isEmpty()) - return; - - Log.info("Waiting for chunk tasks to complete."); - - CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); - } - - @Override - public List getBlockEntities(Chunk chunk) { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - List blockEntities = new LinkedList<>(); - - World bukkitWorld = chunk.getWorld(); - - levelChunk.getBlockEntities().keySet().forEach(blockPos -> - blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); - - return blockEntities; - } - - private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { - KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); - List spawnersLocations = new LinkedList<>(); - - for (int i = 0; i < chunkSections.length; ++i) { - LevelChunkSection levelChunkSection = chunkSections[i]; - if (levelChunkSection != null && !levelChunkSection.hasOnlyAir()) { - int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4; - if (hasStatesIterator) { - levelChunkSection.getStates().forEachLocation((blockState, locationKey) -> { - int x = locationKey & 0xF; - int y = (locationKey >> 8) & 0xF; - int z = (locationKey >> 4) & 0xF; - calculateChunkInternal(blockState, x, y, z, chunkPosition, sectionBottomY, blockCounts, spawnersLocations); - }); - } else for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { - BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, - sectionBottomY, blockCounts, spawnersLocations); - } - } - } - - return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); - } - - private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, - int sectionBottomY, KeyMap blockCounts, - List spawnersLocations) { - Block block = blockState.getBlock(); - - if (block == Blocks.AIR) - return; - - Location location = new Location(chunkPosition.getWorld(), - (chunkPosition.getX() << 4) + x, - sectionBottomY + y, - (chunkPosition.getZ() << 4) + z); - - int blockAmount = 1; - - if (NMSUtils.isDoubleBlock(block, blockState)) { - blockAmount = 2; - blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); - } - - Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); - blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); - if (block == Blocks.SPAWNER) { - spawnersLocations.add(location); - } - } - - private static void removeEntities(ChunkAccess chunk) { - ChunkPos chunkPos = chunk.getPos(); - ServerLevel serverLevel = ((LevelChunk) chunk).level; - - int chunkWorldCoordX = chunkPos.x << 4; - int chunkWorldCoordZ = chunkPos.z << 4; - - AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinBuildHeight(), chunkWorldCoordZ, - chunkWorldCoordX + 15, serverLevel.getMaxBuildHeight(), chunkWorldCoordZ + 15); - - List worldEntities = new LinkedList<>(); - serverLevel.getEntities().get(chunkBounds, worldEntities::add); - - worldEntities.forEach(nmsEntity -> { - if (!(nmsEntity instanceof Player)) - nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); - }); - } - - private static void removeBlockEntities(ChunkAccess chunk) { - chunk.blockEntities.values().forEach(BlockEntity::setRemoved); - chunk.blockEntities.clear(); + }; } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { - CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), - bukkitGenerator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunk), - ChunkStatus.SURFACE, 0); + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; - chunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - chunk); - } + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSDragonFightImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSDragonFightImpl.java deleted file mode 100644 index c2485597d0..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSDragonFightImpl.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon.EndWorldEndDragonFightHandler; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon.IslandEndDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon.IslandEntityEnderDragon; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon.SpikesCache; -import com.google.common.cache.LoadingCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.advancement.Advancement; -import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; -import org.bukkit.entity.Player; - -import java.lang.reflect.Modifier; -import java.util.List; - -public class NMSDragonFightImpl implements NMSDragonFight { - - private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( - EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField<>( - ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE, 1); - - private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( - SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static boolean firstWorldPreparation = true; - - static { - ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); - } - - @Override - public void prepareEndWorld(World bukkitWorld) { - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); - - if (firstWorldPreparation) { - firstWorldPreparation = false; - SPIKE_CACHE.set(null, SpikesCache.getInstance()); - } - } - - @Nullable - @Override - public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return null; - - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); - return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); - } - - @Override - public void startDragonBattle(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); - } - - @Override - public void removeDragonBattle(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); - - if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { - islandEndDragonFight.removeBattlePlayers(); - islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); - } - } - - @Override - public void awardTheEndAchievement(Player player) { - Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); - if (advancement != null) - player.getAdvancementProgress(advancement).awardCriteria(""); - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSEntitiesImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSEntitiesImpl.java index 950a5490ac..fe35c83dcc 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSEntitiesImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSEntitiesImpl.java @@ -1,57 +1,30 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_3; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftAnimals; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; -import org.bukkit.entity.Animals; import org.bukkit.entity.minecart.PoweredMinecart; -import org.bukkit.inventory.EntityEquipment; -import org.bukkit.inventory.ItemStack; import java.lang.reflect.Modifier; -public class NMSEntitiesImpl implements NMSEntities { +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override - public ItemStack[] getEquipment(EntityEquipment entityEquipment) { - ItemStack[] itemStacks = new ItemStack[7]; - - itemStacks[0] = new ItemStack(Material.ARMOR_STAND); - itemStacks[1] = entityEquipment.getItemInMainHand(); - itemStacks[2] = entityEquipment.getItemInOffHand(); - itemStacks[3] = entityEquipment.getHelmet(); - itemStacks[4] = entityEquipment.getChestplate(); - itemStacks[5] = entityEquipment.getLeggings(); - itemStacks[6] = entityEquipment.getBoots(); - - return itemStacks; - } - - @Override - public boolean isAnimalFood(ItemStack itemStack, Animals animals) { - return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); - } - - @Override - public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override - public int getPortalTicks(org.bukkit.entity.Entity entity) { - return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); + protected int getPortalTicks(Entity entity) { + return PORTAL_TICKS.get(entity); } } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSHologramsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSHologramsImpl.java deleted file mode 100644 index e70b8356fd..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSHologramsImpl.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3; - -import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; -import com.bgsoftware.superiorskyblock.nms.NMSHolograms; -import com.google.common.base.Preconditions; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_20_R3.CraftServer; -import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftArmorStand; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; -import org.bukkit.entity.Entity; - -@SuppressWarnings("unused") -public class NMSHologramsImpl implements NMSHolograms { - - @Override - public Hologram createHologram(Location location) { - Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); - serverLevel.addFreshEntity(entityHologram); - return entityHologram; - } - - @Override - public boolean isHologram(Entity entity) { - return ((CraftEntity) entity).getHandle() instanceof Hologram; - } - - public static class EntityHologram extends ArmorStand implements Hologram { - - private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); - - private CraftEntity bukkitEntity; - - EntityHologram(ServerLevel serverLevel, double x, double y, double z) { - super(serverLevel, x, y, z); - - setInvisible(true); - setSmall(true); - setShowArms(false); - setNoGravity(true); - setNoBasePlate(true); - setMarker(true); - forceSetBoundingBox(EMPTY_BOUND); - - super.collides = false; - super.setCustomNameVisible(true); - } - - @Override - public void setHologramName(String name) { - super.setCustomName(CraftChatMessage.fromStringOrNull(name)); - } - - @Override - public void removeHologram() { - super.remove(RemovalReason.DISCARDED); - } - - @Override - public org.bukkit.entity.ArmorStand getHandle() { - return this.getBukkitEntity(); - } - - @Override - public void inactiveTick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - @Override - public boolean repositionEntityAfterLoad() { - return false; - } - - @Override - public AABB getBoundingBoxForCulling() { - return EMPTY_BOUND; - } - - @Override - public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { - // Prevent stand being equipped - } - - @Override - public void addAdditionalSaveData(CompoundTag compoundTag) { - // Do not save NBT. - } - - @Override - public void readAdditionalSaveData(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { - // Prevent stand being equipped - return InteractionResult.PASS; - } - - @Override - public void tick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - public void forceSetBoundingBox(AABB boundingBox) { - super.setBoundingBox(boundingBox); - } - - @Override - public CraftArmorStand getBukkitEntity() { - if (bukkitEntity == null) { - bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); - } - return (CraftArmorStand) bukkitEntity; - } - - @Override - public void remove(RemovalReason removalReason) { - // Prevent being killed. - } - - @Override - public void playSound(SoundEvent soundEvent, float volume, float pitch) { - // Remove sounds. - } - - @Override - public boolean saveAsPassenger(CompoundTag compoundTag) { - // Do not save NBT. - return false; - } - - @Override - public CompoundTag saveWithoutId(CompoundTag compoundTag) { - // Do not save NBT. - return compoundTag; - } - - @Override - public void load(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public boolean isInvulnerableTo(DamageSource damageSource) { - /* - * The field Entity.invulnerable is private. - * It's only used while saving NBTTags, but since the entity would be killed - * on chunk unload, we prefer to override isInvulnerable(). - */ - return true; - } - - @Override - public void setCustomName(Component component) { - // Locks the custom name. - } - - @Override - public void setCustomNameVisible(boolean isCustomNameVisible) { - // Locks the custom name. - } - - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSPlayersImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSPlayersImpl.java deleted file mode 100644 index 0efc372f8b..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSPlayersImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.nms.NMSPlayers; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.player.OfflinePlayerDataImpl; -import com.bgsoftware.superiorskyblock.player.PlayerLocales; -import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.level.ServerPlayer; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; -import org.bukkit.entity.Item; -import org.bukkit.entity.Player; - -import java.util.Locale; - -public class NMSPlayersImpl implements NMSPlayers { - - private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - - @Override - public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { - return OfflinePlayerDataImpl.create(offlinePlayer); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer) { - Player player = superiorPlayer.asPlayer(); - - if (player == null) - return; - - ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() - .ifPresent(property -> setSkinTexture(superiorPlayer, property)); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { - superiorPlayer.setTextureValue(property.value()); - } - - @SuppressWarnings("deprecation") - @Override - public void sendActionBar(Player player, String message) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); - } - - @Override - public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { - BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); - bossBar.addPlayer(player); - return bossBar; - } - - @SuppressWarnings("deprecation") - @Override - public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { - player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); - } - - @Override - public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { - return superiorPlayer.getUniqueId().equals(item.getThrower()); - } - - @Nullable - @Override - public Locale getPlayerLocale(Player player) { - if (PLAYER_LOCALE.isValid()) { - return player.locale(); - } else try { - //noinspection deprecation - return PlayerLocales.getLocale(player.getLocale()); - } catch (IllegalArgumentException error) { - return null; - } - } - - private static class BossBarImpl implements BossBar { - - private final org.bukkit.boss.BossBar bossBar; - private final BossBarTask bossBarTask; - - public BossBarImpl(String message, BarColor color, double ticksToRun) { - bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); - this.bossBarTask = BossBarTask.create(this, ticksToRun); - } - - @Override - public void addPlayer(Player player) { - this.bossBar.addPlayer(player); - this.bossBarTask.registerTask(player); - } - - @Override - public void removeAll() { - this.bossBar.removeAll(); - this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); - } - - @Override - public void setProgress(double progress) { - this.bossBar.setProgress(progress); - } - - @Override - public double getProgress() { - return this.bossBar.getProgress(); - } - - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java index 7b5f22efde..067fbd8963 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java @@ -1,91 +1,44 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_3; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.ListTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.mojang.serialization.Dynamic; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; -import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; import java.util.Set; -@SuppressWarnings({"unused"}) -public class NMSTagsImpl implements NMSTags { +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSTags { @Override - public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag()); tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); - return CompoundTag.fromNBT(tagCompound); } @Override - public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { - if (compoundTag.containsKey("NBT")) { - // Old compound version, deserialize it accordingly - return deserializeItemOld(compoundTag); - } - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); - - int currentVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - int itemVersion = tagCompound.getInt("DataVersion"); - if (itemVersion < currentVersion) { - tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, - new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); - } - - ItemStack itemStack = ItemStack.of(tagCompound); - - return CraftItemStack.asCraftMirror(itemStack); + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; } - private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); - Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount").orElse(0); - short data = (short) compoundTag.getShort("data").orElse(0); - CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); - - org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - if (nbtData != null) - itemStack.setTag((net.minecraft.nbt.CompoundTag) nbtData.toNBT()); - - return CraftItemStack.asCraftMirror(itemStack); + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + return ItemStack.of(compoundTag); } @Override - @SuppressWarnings("ConstantConditions") - public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { - net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); - - if (compoundTag == null) - compoundTag = new net.minecraft.nbt.CompoundTag(); - - if (!compoundTag.contains("id")) - //noinspection deprecation - compoundTag.putString("id", entityType.getName()); + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.setTag(compoundTag); + } - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; @@ -147,29 +100,4 @@ public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } - @Override - public Object parseList(ListTag listTag) { - net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); - - for (Tag tag : listTag) - nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); - - return nbtTagList; - } - - @Override - public Object getNBTCompoundTag(Object object, String key) { - return ((net.minecraft.nbt.CompoundTag) object).get(key); - } - - @Override - public void setNBTCompoundTagValue(Object object, String key, Object value) { - ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); - } - - @Override - public int getNBTTagListSize(Object object) { - return ((net.minecraft.nbt.ListTag) object).size(); - } - } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java deleted file mode 100644 index 81a35ff74e..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSUtils.java +++ /dev/null @@ -1,502 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.PropertiesMapper; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; -import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; -import com.google.common.base.Suppliers; -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.storage.EntityStorage; -import net.minecraft.world.level.chunk.storage.IOWorker; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; - -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; - -public class NMSUtils { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( - ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); - private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( - ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); - private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( - EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); - - private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); - - public static final ObjectsPool> BLOCK_POS_POOL = - ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); - - private NMSUtils() { - - } - - @Nullable - public static T getBlockEntityAt(Location location, Class type) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); - } - } - - public static void runActionOnEntityChunks(Collection chunksCoords, - ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); - } - - public static void runActionOnChunks(Collection chunksCoords, - boolean saveChunks, ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); - } - - private static void runActionOnChunksInternal(Collection chunksCoords, - ChunkCallback chunkCallback, - Consumer> onUnloadChunkAction) { - List unloadedChunks = new LinkedList<>(); - List loadedChunks = new LinkedList<>(); - - chunksCoords.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - ChunkAccess chunkAccess; - - try { - chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); - } catch (Throwable ex) { - chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); - } - - if (chunkAccess instanceof LevelChunk levelChunk) { - loadedChunks.add(levelChunk); - } else { - unloadedChunks.add(chunkPosition.copy()); - } - }); - - boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); - - if (!loadedChunks.isEmpty()) - runActionOnLoadedChunks(loadedChunks, chunkCallback); - - if (hasUnloadedChunks) { - onUnloadChunkAction.accept(unloadedChunks); - } else { - chunkCallback.onFinish(); - } - } - - private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { - chunks.forEach(chunkCallback::onLoadedChunk); - } - - private static void runActionOnUnloadedChunks(Collection chunks, - boolean saveChunks, ChunkCallback chunkCallback) { - if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { - Iterator chunksIterator = chunks.iterator(); - while (chunksIterator.hasNext()) { - ChunkPosition chunkPosition = chunksIterator.next(); - - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( - chunkPosition.getX(), chunkPosition.getZ()); - if (cachedUnloadedChunk != null) { - chunkCallback.onLoadedChunk(cachedUnloadedChunk); - chunksIterator.remove(); - } - } - - if (chunks.isEmpty()) { - chunkCallback.onFinish(); - return; - } - } - - CompletableFuture pendingTask = new CompletableFuture<>(); - PENDING_CHUNK_ACTIONS.add(pendingTask); - - BukkitExecutor.createTask().runAsync(v -> { - CountDownLatch countDownLatch; - if (chunkCallback.isWaitForChunkLoad) { - countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - } else { - countDownLatch = null; - } - - List chunkCompounds = new LinkedList<>(); - - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - boolean calledCountdown = false; - try { - net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); - - if (chunkCompound == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), - Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, - Optional.empty(), chunkPos, serverLevel); - - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - calledCountdown = true; - - if (saveChunks) - chunkCompounds.add(unloadedChunkCompound); - } catch (Exception error) { - if (!calledCountdown && countDownLatch != null) - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - if (countDownLatch != null) { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - } - - return chunkCompounds; - }).runSync(chunkCompounds -> { - chunkCompounds.forEach(unloadedChunkCompound -> { - ChunkMap chunkMap = unloadedChunkCompound.serverLevel().getChunkSource().chunkMap; - - try { - chunkMap.write(unloadedChunkCompound.chunkPos(), unloadedChunkCompound.chunkCompound); - } catch (IOException error) { - Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); - } - }); - - chunkCallback.onFinish(); - - pendingTask.complete(null); - PENDING_CHUNK_ACTIONS.remove(pendingTask); - }); - } - - private static void runActionOnUnloadedEntityChunks(Collection chunks, - ChunkCallback chunkCallback) { - CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); - IOWorker worker = ENTITY_STORAGE_WORKER.get(entityManager.permanentStorage); - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> { - if (error != null) { - countDownLatch.countDown(); - throw new RuntimeException(error); - } else { - net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - } else { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } - } - }); - }); - - BukkitExecutor.createTask().runAsync(v -> { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } else { - BukkitExecutor.createTask().runAsync(v -> { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - try { - net.minecraft.nbt.CompoundTag entityData = serverLevel.entityDataControllerNew.readData( - chunkPosition.getX(), chunkPosition.getZ()); - - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } catch (IOException error) { - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } - } - - public static List> getPendingChunkActions() { - return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); - } - - public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { - return new ProtoChunk(chunkPos, - UpgradeData.EMPTY, - serverLevel, - serverLevel.registryAccess().registryOrThrow(Registries.BIOME), - null); - } - - public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { - ServerLevel serverLevel = levelChunk.level; - - if (!isValidPosition(serverLevel, blockPos)) - return null; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - serverLevel.setBlock(blockPos, blockState, 3); - return blockState; - } - - int indexY = serverLevel.getSectionIndex(blockPos.getY()); - - LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - boolean isOriginallyChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - - levelChunk.setUnsaved(true); - - boolean isChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) - serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); - - serverLevel.getLightEngine().checkBlock(blockPos); - - if (tileEntity != null) { - net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); - if (tileEntityCompound != null) { - tileEntityCompound.putInt("x", blockPos.getX()); - tileEntityCompound.putInt("y", blockPos.getY()); - tileEntityCompound.putInt("z", blockPos.getZ()); - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.load(tileEntityCompound); - } - } - - return blockState; - } - - public static boolean isDoubleBlock(Block block, BlockState blockState) { - return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && - blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; - } - - @Nullable - public static LevelChunk getCraftChunkHandle(CraftChunk craftChunk) { - ServerLevel serverLevel = craftChunk.getCraftWorld().getHandle(); - LevelChunk loadedChunk = serverLevel.getChunkIfLoaded(craftChunk.getX(), craftChunk.getZ()); - if (loadedChunk != null) - return loadedChunk; - - return (LevelChunk) serverLevel.getChunk(craftChunk.getX(), craftChunk.getZ(), ChunkStatus.FULL, true); - } - - public record UnloadedChunkCompound(ChunkPosition chunkPosition, - net.minecraft.nbt.CompoundTag chunkCompound) { - - public ListTag getSections() { - return chunkCompound.getList("sections", 10); - } - - public ListTag getEntities() { - return chunkCompound.getList("Entities", 10); - } - - public void setSections(ListTag sectionsList) { - chunkCompound.put("sections", sectionsList); - } - - public void setEntities(ListTag entitiesList) { - chunkCompound.put("entities", entitiesList); - } - - public void setBlockEntities(ListTag blockEntitiesList) { - chunkCompound.put("block_entities", blockEntitiesList); - } - - public ServerLevel serverLevel() { - return ((CraftWorld) chunkPosition.getWorld()).getHandle(); - } - - public ChunkPos chunkPos() { - return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - } - - } - - private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); - } - - public static abstract class ChunkCallback { - - private final ChunkLoadReason chunkLoadReason; - private final boolean isWaitForChunkLoad; - - @Nullable - protected CountDownLatch chunkLoadLatch; - - public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { - this.chunkLoadReason = chunkLoadReason; - this.isWaitForChunkLoad = isWaitForChunkLoad; - } - - public abstract void onLoadedChunk(LevelChunk levelChunk); - - public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - - public abstract void onFinish(); - - protected final void latchCountDown() { - if (this.chunkLoadLatch != null) - this.chunkLoadLatch.countDown(); - } - - public final void onChunkNotExist(ChunkPosition chunkPosition) { - if (!plugin.getProviders().hasCustomWorldsSupport()) - return; - - ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { - LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); - }); - } - - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index 3a169aa41d..a4d4416b0f 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -3,124 +3,31 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; -import com.bgsoftware.superiorskyblock.nms.ICachedBlock; -import com.bgsoftware.superiorskyblock.nms.NMSWorld; -import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.generator.IslandsGeneratorImpl; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_3.vibration.IslandVibrationUser; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.ChunkReaderImpl; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.WorldEditSessionImpl; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.destroystokyo.paper.antixray.ChunkPacketBlockController; -import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.BubbleColumn; import org.bukkit.block.data.type.HangingSign; -import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.WallHangingSign; -import org.bukkit.block.data.type.WallSign; -import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; -import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockState; -import org.bukkit.craftbukkit.v1_20_R3.block.CraftSign; -import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; -import org.bukkit.entity.Player; import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.function.IntFunction; -public class NMSWorldImpl implements NMSWorld { +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); - private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, - Object.class, "chunkPacketBlockController") - .removeFinal(); - - private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); } @Override - public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { - Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); - Location location = new Location( - Bukkit.getWorld(chunkSnapshot.getWorldName()), - (chunkSnapshot.getX() << 4) + x, - y, - (chunkSnapshot.getZ() << 4) + z - ); - - return Keys.of(KeyBlocksCache.getBlockKey(block), location); - } - - @Override - public void listenSpawner(Location location, IntFunction delayChangeCallback) { - SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); - if (spawnerBlockEntity == null) - return; - - ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - - List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? - LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; - - Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new LinkedList<>(); - - while (blockEntityTickersIterator.hasNext()) { - TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && - !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { - blockEntityTickersIterator.remove(); - tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); - } - } - - if (!tickersToAdd.isEmpty()) - blockEntityTickers.addAll(tickersToAdd); + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); } @Override @@ -132,254 +39,14 @@ public void replaceSculkSensorListener(Island island, Location location) { SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } - @Override - public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { - if (!plugin.getSettings().isWorldBorders()) - return; - - Player player = superiorPlayer.asPlayer(); - org.bukkit.World world = superiorPlayer.getWorld(); - - if (world == null || player == null) - return; - - int islandSize = island == null ? 0 : island.getIslandSize(); - - boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; - - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - - WorldBorder worldBorder; - - if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { - worldBorder = serverLevel.getWorldBorder(); - } else { - Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); - if (dimension == null) - return; - - Location center = island.getCenter(dimension); - - worldBorder = new WorldBorder(); - worldBorder.world = serverLevel; - worldBorder.setWarningBlocks(0); - worldBorder.setCenter(center.getX(), center.getZ()); - - switch (superiorPlayer.getBorderColor()) { - case BLUE -> { - worldBorder.setSize((islandSize * 2) + 1D); - } - case GREEN -> { - worldBorder.setSize((islandSize * 2) + 1.001D); - worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); - } - case RED -> { - worldBorder.setSize((islandSize * 2) + 1D); - worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); - } - } - } - - ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); - ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); - } - - @Override - public Object getBlockData(org.bukkit.block.Block block) { - return block.getBlockData(); - } - - @Override - public void setBlock(Location location, int combinedId) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - BlockState blockState = - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - - if (blockState != null) { - serverLevel.getChunkSource().blockChanged(blockPos); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); - } - } - } - } - - @Override - public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return NMSCachedBlock.obtain(block); - } - - @Override - public boolean isWaterLogged(org.bukkit.block.Block block) { - if (Materials.isWater(block.getType())) - return true; - - BlockData blockData = block.getBlockData(); - - return blockData instanceof BubbleColumn || - (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); - } - @Override public SignType getSignType(Object sign) { - if (sign instanceof WallSign) - return SignType.WALL_SIGN; - else if (sign instanceof Sign) - return SignType.STANDING_SIGN; - else if (sign instanceof HangingSign) + if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else - return SignType.UNKNOWN; - } - - @Override - public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { - BlockState blockState = ((CraftBlock) block).getNMS(); - return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; - } - - @Override - public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { - return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); - } - - @Override - public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { - return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); - } - - private int getDefaultAmount(BlockState blockState) { - Block block = blockState.getBlock(); - return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; - } - - @Override - public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { - return !bukkitBlock.isPassable(); - } - - @Override - public void placeSign(Island island, Location location) { - SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); - if (signBlockEntity == null) - return; - - String[] lines = new String[4]; - Component[] messages = signBlockEntity.getFrontText().getMessages(false); - System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - Component[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } - - System.arraycopy(newLines, 0, messages, 0, 4); - } - - @Override - public void playGeneratorSound(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); - } - } - - @Override - public void playBreakAnimation(org.bukkit.block.Block block) { - ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); - } - } - - @Override - public void playPlaceSound(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); - } - } - - @Override - public int getMinHeight(org.bukkit.World world) { - return world.getMinHeight(); - } - - @Override - public void removeAntiXray(org.bukkit.World bukkitWorld) { - if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); - } - - @Override - public IslandsGenerator createGenerator(Dimension dimension) { - return new IslandsGeneratorImpl(dimension); - } - - @Override - public WorldEditSession createEditSession(World world) { - return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); - } - - @Override - public WorldEditSession createPartialEditSession(Dimension dimension) { - return WorldEditSessionImpl.obtain(dimension); - } - - @Override - public ChunkReader createChunkReader(Chunk chunk) { - return new ChunkReaderImpl(chunk); - } - - private static ReflectField> initializeLevelBlockEntityTickersField() { - ReflectField> field = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - - if (!field.isValid()) - field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); - - return field; + return super.getSignType(sign); } } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsBlockEntity.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsBlockEntity.java deleted file mode 100644 index b53aa44c98..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsBlockEntity.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.crops; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.chunk.LevelChunk; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.function.Consumer; - -public class CropsBlockEntity extends BlockEntity { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - - private final WeakReference island; - private final WeakReference chunk; - - private int currentTick = 0; - - private double cachedCropGrowthMultiplier; - - private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(levelChunk); - setLevel(levelChunk.level); - levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; - } - - public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); - return new CropsBlockEntity(island, levelChunk, blockPos); - }); - } - - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); - } - - public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { - if (tickingChunks.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> { - long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); - if (cropsBlockEntity != null) - cropsBlockEntityConsumer.accept(cropsBlockEntity); - }); - } - - public void remove() { - this.remove = true; - } - - public void tick() { - if (++currentTick <= plugin.getSettings().getCropsInterval()) - return; - - LevelChunk levelChunk = this.chunk.get(); - Island island = this.island.get(); - ServerLevel serverLevel = (ServerLevel) getLevel(); - - if (levelChunk == null || island == null || serverLevel == null) { - remove(); - return; - } - - currentTick = 0; - - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - if (chunkRandomTickSpeed > 0) - CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); - } - - public void setCropGrowthMultiplier(double cropGrowthMultiplier) { - this.cachedCropGrowthMultiplier = cropGrowthMultiplier; - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingBlockEntity.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingBlockEntity.java deleted file mode 100644 index 898386068b..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingBlockEntity.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.crops; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { - - - @Override - public void tick() { - cropsBlockEntity.tick(); - } - - @Override - public boolean isRemoved() { - return cropsBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return cropsBlockEntity.getBlockPos(); - } - - @Override - public String getType() { - return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java deleted file mode 100644 index 1fb93d680a..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/crops/CropsTickingMethod.java +++ /dev/null @@ -1,157 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.crops; - -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; - -public abstract class CropsTickingMethod { - - private static final ReflectField SERVER_LEVEL_RANDOM_TICK_RANDOM = new ReflectField<>( - ServerLevel.class, RandomSource.class, "randomTickRandom"); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static Set CROPS_TO_GROW_CACHE; - - static { - plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); - } - - private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); - - private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? - new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); - - - protected CropsTickingMethod() { - - } - - public static void register() { - // Calls the static initializer which registers the callback. - } - - public static void tick(LevelChunk levelChunk, int tickSpeed) { - INSTANCE.doTick(levelChunk, tickSpeed); - } - - protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); - - private static void onSettingsUpdate() { - CROPS_TO_GROW_CACHE = new HashSet<>(); - plugin.getSettings().getCropsToGrow().forEach(cropName -> { - Key key = Keys.ofMaterialAndData(cropName); - if (key instanceof MaterialKey materialKey) { - Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); - if (block != null && block.defaultBlockState().isRandomlyTicking()) - CROPS_TO_GROW_CACHE.add(block); - } - }); - } - - private static class PaperCropsTickingMethod extends CropsTickingMethod { - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - ServerLevel serverLevel = levelChunk.level; - LevelChunkSection[] sections = levelChunk.getSections(); - - int minSection = serverLevel.getMinSection(); - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - RandomSource randomTickRandom = SERVER_LEVEL_RANDOM_TICK_RANDOM.get(serverLevel); - - for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int tickingBlocks = levelChunkSection.tickingList.size(); - if (tickingBlocks <= 0) { - continue; - } - - int offsetY = (sectionIndex + minSection) << 4; - - for (int i = 0; i < tickSpeed; ++i) { - int index = randomTickRandom.nextInt(0x1000); - - if (index >= tickingBlocks) { - continue; - } - - long raw = levelChunkSection.tickingList.getRaw(index); - int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); - BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); - if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) - continue; - - chunkTickMutablePosition.set((location & 15) | chunkOffsetX, - ((location >>> 8) & 255) | offsetY, - ((location >>> 4) & 15) | chunkOffsetZ); - - blockState.randomTick(serverLevel, chunkTickMutablePosition, randomTickRandom); - } - } - - } - - } - - private static class SpigotCropsTickingMethod extends CropsTickingMethod { - - private static int random = ThreadLocalRandom.current().nextInt(); - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - LevelChunkSection[] sections = levelChunk.getSections(); - ServerLevel serverLevel = levelChunk.level; - - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - - for (int i = 0; i < tickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { - chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); - blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); - } - } - } - } - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/DragonUtils.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/DragonUtils.java deleted file mode 100644 index f8e6ca41b2..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/DragonUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon; - -import com.bgsoftware.common.reflection.ReflectField; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; - -import java.lang.reflect.Modifier; - -public class DragonUtils { - - private static final ReflectField END_PODIUM_LOCATION = new ReflectField( - EndPodiumFeature.class, BlockPos.class, - Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static BlockPos currentPodiumPosition = BlockPos.ZERO; - - private DragonUtils() { - - } - - public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { - try { - END_PODIUM_LOCATION.set(null, podiumPosition); - currentPodiumPosition = podiumPosition; - runnable.run(); - } finally { - END_PODIUM_LOCATION.set(null, BlockPos.ZERO); - currentPodiumPosition = BlockPos.ZERO; - } - } - - public static BlockPos getCurrentPodiumPosition() { - return currentPodiumPosition; - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndWorldEndDragonFightHandler.java deleted file mode 100644 index b45d366953..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndWorldEndDragonFightHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; -import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.dimension.end.EndDragonFight; - -import java.util.LinkedList; -import java.util.List; - -public class EndWorldEndDragonFightHandler extends EndDragonFight { - - private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); - - private final List worldDragonFightsList = new LinkedList<>(); - - public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); - } - - @Override - public void tick() { - this.worldDragonFightsList.forEach(EndDragonFight::tick); - } - - public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); - if (oldDragonFight != null) - this.worldDragonFightsList.remove(oldDragonFight); - this.worldDragonFightsList.add(endDragonFight); - } - - @Nullable - public IslandEndDragonFight getDragonFight(IslandCache islandCache) { - return islandCache.get(CACHE_KEY); - } - - @Nullable - public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { - IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); - if (endDragonFight != null) - this.worldDragonFightsList.remove(endDragonFight); - return endDragonFight; - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEndDragonFight.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEndDragonFight.java deleted file mode 100644 index bc4084bba9..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEndDragonFight.java +++ /dev/null @@ -1,211 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; -import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import net.minecraft.world.level.block.state.pattern.BlockPattern; -import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; -import net.minecraft.world.level.block.state.predicate.BlockPredicate; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -public class IslandEndDragonFight extends EndDragonFight { - - private static final ReflectField DRAGON_BATTLE = new ReflectField( - EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 4); - private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); - - private static final ReflectField TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>( - EndDragonFight.class, int.class, Modifier.PRIVATE, 4); - private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( - DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); - - private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") - .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") - .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) - .build(); - - private final Island island; - private final BlockPos islandBlockPos; - private final Vec3 islandBlockVectored; - private final ServerLevel serverLevel; - private final IslandEntityEnderDragon entityEnderDragon; - - private byte currentTick = 0; - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { - this(island, serverLevel, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), null); - } - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, - @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); - - this.island = island; - this.islandBlockPos = islandBlockPos; - this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); - this.serverLevel = serverLevel; - this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; - - SCAN_FOR_LEGACY_PORTALS.set(this, false); - WAS_DRAGON_KILLED.set(this, false); - DRAGON_BATTLE.set(this.entityEnderDragon, this); - - TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); - } - - @Override - public void tick() { - // doServerTick - - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); - - DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); - if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { - LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); - } - - if (++currentTick >= 20) { - updateBattlePlayers(); - currentTick = 0; - TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); - } - } - - @Nullable - @Override - public BlockPattern.BlockPatternMatch findExitPortal() { - int chunkX = this.islandBlockPos.getX() >> 4; - int chunkZ = this.islandBlockPos.getZ() >> 4; - - for (int x = -8; x <= 8; ++x) { - for (int z = -8; z <= 8; ++z) { - LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); - - for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { - if (blockEntity instanceof TheEndPortalBlockEntity) { - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( - this.serverLevel, blockEntity.getBlockPos()); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - } - } - - int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); - currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); - for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { - currentPosition.setY(y); - - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - - return null; - } - - @Override - public void resetSpikeCrystals() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); - } - - public void removeBattlePlayers() { - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - for (ServerPlayer serverPlayer : dragonEventPlayers) - this.dragonEvent.removePlayer(serverPlayer); - } - - public IslandEntityEnderDragon getEnderDragon() { - return this.entityEnderDragon; - } - - private void updateBattlePlayers() { - Set nearbyPlayers = new HashSet<>(); - - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - Player bukkitPlayer = superiorPlayer.asPlayer(); - if (bukkitPlayer != null) { - ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); - if (serverPlayer.serverLevel().equals(this.serverLevel)) { - this.dragonEvent.addPlayer(serverPlayer); - nearbyPlayers.add(serverPlayer.getUUID()); - } - } - } - - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - - dragonEventPlayers.stream() - .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) - .forEach(this.dragonEvent::removePlayer); - } - - private IslandEntityEnderDragon spawnEnderDragon() { - IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); - - entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); - entityEnderDragon.absMoveTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), - this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); - - this.serverLevel.addFreshEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); - - this.dragonUUID = entityEnderDragon.getUUID(); - this.resetSpikeCrystals(); - - return entityEnderDragon; - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java index 6c8441e575..82766a4afa 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/IslandEntityEnderDragon.java @@ -2,47 +2,22 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.config.SettingsManager; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; -import org.bukkit.Location; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEnderDragon; -public class IslandEntityEnderDragon extends EnderDragon { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - @NotNull - public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { - return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : - new EnderDragon(entityTypes, level); - } - - private final ServerLevel serverLevel; - private final Dimension dimension; - private BlockPos islandBlockPos; +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { - this(level); - this.islandBlockPos = islandBlockPos; + super(level, islandBlockPos); } - private IslandEntityEnderDragon(Level level) { - super(EntityType.ENDER_DRAGON, level); - this.serverLevel = (ServerLevel) level; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + public IslandEntityEnderDragon(Level level) { + super(level); } @Nullable @@ -65,40 +40,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { finalizeIslandEnderDragon(); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - - private void finalizeIslandEnderDragon() { - if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) - return; - - Island island; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); - } - - if (island == null) - return; - - Location middleBlock = island.getCenter(dimension); - - SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); - if (dimensionConfig instanceof SettingsManager.Worlds.End) { - middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); - } - - this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); - - IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); - } - } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/SpikesCache.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/SpikesCache.java deleted file mode 100644 index 924677326b..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/SpikesCache.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon; - - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.common.annotations.Nullable; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.CacheStats; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public class SpikesCache implements LoadingCache> { - - private static final SpikesCache INSTANCE = new SpikesCache(); - - private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() - .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); - - private long worldSeed; - - public static SpikesCache getInstance() { - return INSTANCE; - } - - private SpikesCache() { - - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - List getUnchecked(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public List apply(@NotNull Long worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void refresh(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ConcurrentMap> asMap() { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Nullable - @Override - public List getIfPresent(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed, - @NotNull Callable> loader) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAllPresent(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void put(@NotNull Long worldSeed, @NotNull List spikes) { - try { - this.worldSeed = worldSeed; - cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); - } finally { - this.worldSeed = 0; - } - } - - @Override - public void putAll(Map> spikesMap) { - spikesMap.forEach(this::put); - } - - @Override - public void invalidate(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll() { - this.cachedSpikes.invalidateAll(); - } - - @Override - public long size() { - return this.cachedSpikes.size(); - } - - @Override - public @NotNull - CacheStats stats() { - return this.cachedSpikes.stats(); - } - - @Override - public void cleanUp() { - this.cachedSpikes.cleanUp(); - } - - private class InternalCacheLoader extends CacheLoader> { - - @Override - public @NotNull - List load(@NotNull BlockPos blockPos) { - List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); - - Collections.shuffle(list, new Random(worldSeed)); - List spikesList = Lists.newArrayList(); - - for (int i = 0; i < 10; ++i) { - int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int l = list.get(i); - int radius = 2 + l / 3; - int height = 76 + l * 3; - boolean guarded = l == 1 || l == 2; - - spikesList.add(new SpikeFeature.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded)); - } - - return spikesList; - } - - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/generator/IslandsGeneratorImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/generator/IslandsGeneratorImpl.java deleted file mode 100644 index ab6c6c5c04..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/generator/IslandsGeneratorImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.generator; - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; -import org.bukkit.generator.WorldInfo; - -import java.util.Collections; -import java.util.List; -import java.util.Random; - -@SuppressWarnings({"unused", "NullableProblems"}) -public class IslandsGeneratorImpl extends IslandsGenerator { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private final Dimension dimension; - - public IslandsGeneratorImpl(Dimension dimension) { - this.dimension = dimension; - } - - @Override - public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, - @NotNull ChunkData chunkData) { - if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { - chunkData.setBlock(0, 99, 0, Material.BEDROCK); - } - } - - @Override - public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { - return new BiomeProvider() { - @Override - public @NotNull - Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { - return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension); - } - - @Override - public @NotNull - List getBiomes(@NotNull WorldInfo worldInfo) { - return IslandUtils.getDefaultWorldBiomes(); - } - - }; - } - - @Override - public List getDefaultPopulators(World world) { - return Collections.emptyList(); - } - - @Override - public Location getFixedSpawnLocation(World world, Random random) { - return new Location(world, 0, 100, 0); - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/hologram/EntityHologram.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/hologram/EntityHologram.java new file mode 100644 index 0000000000..566c8cb5d2 --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/hologram/EntityHologram.java @@ -0,0 +1,39 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.hologram; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_20_3.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuBrewingStandBlockEntity.java deleted file mode 100644 index 5bfe69501e..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuBrewingStandBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { - - private final InventoryHolder holder; - - public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuDispenserBlockEntity.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuDispenserBlockEntity.java deleted file mode 100644 index 272ea77fa8..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuDispenserBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.DispenserBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuDispenserBlockEntity extends DispenserBlockEntity { - - private final InventoryHolder holder; - - public MenuDispenserBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuFurnaceBlockEntity.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuFurnaceBlockEntity.java deleted file mode 100644 index 583821b3a7..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuFurnaceBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.FurnaceBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { - - private final InventoryHolder holder; - - public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuHopperBlockEntity.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuHopperBlockEntity.java deleted file mode 100644 index 7eeb09070d..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/menu/MenuHopperBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.HopperBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuHopperBlockEntity extends HopperBlockEntity { - - private final InventoryHolder holder; - - public MenuHopperBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.setCustomName(Component.nullToEmpty(title)); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/player/OfflinePlayerDataImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/player/OfflinePlayerDataImpl.java deleted file mode 100644 index 0e49213191..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/player/OfflinePlayerDataImpl.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.player; - -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.craftbukkit.v1_20_R3.CraftServer; -import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; -import org.bukkit.entity.Player; - -import java.util.Optional; - -public class OfflinePlayerDataImpl implements OfflinePlayerData { - - private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); - - private Player fakePlayer; - - public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { - return POOL.obtain().initialize(offlinePlayer); - } - - private OfflinePlayerDataImpl() { - - } - - private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), - Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return null; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - this.fakePlayer = serverPlayer.getBukkitEntity(); - this.fakePlayer.loadData(); - - return this; - } - - @Override - public Player getFakeOnlinePlayer() { - return this.fakePlayer; - } - - @Override - public void setLocation(Location location) { - ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); - serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); - serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - } - - @Override - public void applyChanges() { - this.fakePlayer.saveData(); - } - - @Override - public void release() { - this.fakePlayer = null; - POOL.release(this); - } - -} - diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/spawners/TickingSpawnerBlockEntityNotifier.java deleted file mode 100644 index 2cece98229..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/spawners/TickingSpawnerBlockEntityNotifier.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.spawners; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BaseSpawner; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -import java.util.function.IntFunction; - -public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { - - private final SpawnerBlockEntity spawnerBlockEntity; - private final TickingBlockEntity tickingBlockEntity; - private final IntFunction delayChangeCallback; - - public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, - IntFunction delayChangeCallback) { - this.spawnerBlockEntity = spawnerBlockEntity; - this.tickingBlockEntity = tickingBlockEntity; - this.delayChangeCallback = delayChangeCallback; - updateDelay(); - } - - @Override - public void tick() { - BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); - int startDelay = baseSpawner.spawnDelay; - try { - tickingBlockEntity.tick(); - } finally { - int newDelay = baseSpawner.spawnDelay; - if (newDelay > startDelay) - updateDelay(); - } - } - - @Override - public boolean isRemoved() { - return tickingBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return tickingBlockEntity.getPos(); - } - - @Override - public String getType() { - return tickingBlockEntity.getType(); - } - - public void updateDelay() { - BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); - baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..063a1be085 --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java @@ -0,0 +1,307 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.utils; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.utils.TickingBlockList; +import com.google.common.base.Suppliers; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.IOWorker; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; +import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +public class NMSUtilsVersioned { + + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( + EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { + return chunkMap.read(chunkPos).join().orElse(null); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { + return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), + chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException { + chunkMap.write(chunkPos, chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + IOWorker worker = ENTITY_STORAGE_WORKER.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } else { + return BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + CompoundTag entityData = serverLevel.entityDataControllerNew.readData( + chunkPosition.getX(), chunkPosition.getZ()); + + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + return; + } + + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } catch (IOException error) { + countDownLatch.countDown(); + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + serverLevel.registryAccess().registryOrThrow(Registries.BIOME), + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.liquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + blockEntity.load(compoundTag); + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.relight(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + if (compoundTag.getByte("SSB.HasSignLines") == 1) { + // We want to convert the sign lines from raw string to json + for (int i = 1; i <= 4; ++i) { + String line = compoundTag.getString("SSB.Text" + i); + if (!Text.isBlank(line)) { + Component newLine = CraftChatMessage.fromString(line)[0]; + compoundTag.putString("Text" + i, Component.Serializer.toJson(newLine)); + } + } + } + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); + + Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + + chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunkAccess), + ChunkStatus.SURFACE, 0); + + chunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(); + } + + public static CompoundTag saveEntity(Entity entity) { + CompoundTag compoundTag = new CompoundTag(); + entity.save(compoundTag); + return compoundTag; + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.tickingList.size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.tickingList.getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + public static String getPropertyValue(Property property) { + return property.value(); + } + + public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.getDragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absMoveTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSection(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinBuildHeight(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxBuildHeight(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.setUnsaved(true); + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockEntityCache.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockEntityCache.java deleted file mode 100644 index 45ef688d63..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockEntityCache.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class BlockEntityCache { - - private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); - - private BlockEntityCache() { - - } - - public static String getBlockEntityId(BlockState blockState) { - return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { - for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - if (blockEntityType.isValid(blockState)) { - ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); - if (resourceLocation != null) - return resourceLocation.toString(); - } - } - - return ""; - }); - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java deleted file mode 100644 index 887780d3df..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/ChunkReaderImpl.java +++ /dev/null @@ -1,242 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockType; -import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; -import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.InventoryHolder; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class ChunkReaderImpl implements ChunkReader { - - private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - private static final byte[] FULL_LIGHT = new byte[2048]; - private static final byte[] EMPTY_LIGHT = new byte[2048]; - - static { - Arrays.fill(FULL_LIGHT, (byte) 0xFF); - } - - private final ServerLevel serverLevel; - private final int x; - private final int z; - - private final Map blockEntities = new HashMap<>(); - private final List entities = new LinkedList<>(); - private final PalettedContainerRO[] blockids; - private final byte[][] skylight; - private final byte[][] emitlight; - - public ChunkReaderImpl(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - - this.serverLevel = levelChunk.level; - ChunkPos chunkPos = levelChunk.getPos(); - this.x = chunkPos.x; - this.z = chunkPos.z; - - LevelChunkSection[] levelChunkSections = levelChunk.getSections(); - this.blockids = new PalettedContainerRO[levelChunkSections.length]; - this.skylight = new byte[levelChunkSections.length][]; - this.emitlight = new byte[levelChunkSections.length][]; - - LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); - - for (int i = 0; i < this.blockids.length; ++i) { - LevelChunkSection levelChunkSection = levelChunkSections[i]; - - this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); - - DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (skyLightArray == null) { - this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; - } else { - this.skylight[i] = new byte[2048]; - System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); - } - - DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (emitLightArray == null) { - this.emitlight[i] = EMPTY_LIGHT; - } else { - this.emitlight[i] = new byte[2048]; - System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); - } - } - - levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - InventoryHolder inventoryHolder = blockEntity.getOwner(); - if (inventoryHolder != null) - compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); - - blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); - }); - - for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) - entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); - } - - @Override - public int getX() { - return this.x; - } - - @Override - public int getZ() { - return this.z; - } - - @Override - public Material getType(int x, int y, int z) { - return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); - } - - @Override - public short getData(int x, int y, int z) { - return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); - } - - @Override - @Nullable - public CompoundTag getTileEntity(int x, int y, int z) { - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); - return this.blockEntities.get(blockPos); - } - } - - @Override - @Nullable - public CompoundTag readBlockStates(int x, int y, int z) { - BlockState blockState = getBlockState(x, y, z); - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = CompoundTag.of(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(int x, int y, int z) { - int off = (y & 15) << 7 | z << 3 | x >> 1; - int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; - } - - @Override - public void forEachEntity(EntityConsumer consumer) { - if (entities.isEmpty()) - return; - - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = wrapper.getHandle(); - for (CachedEntity cachedEntity : entities) { - location.setX(cachedEntity.x); - location.setY(cachedEntity.y); - location.setZ(cachedEntity.z); - location.setYaw(cachedEntity.yaw); - location.setPitch(cachedEntity.pitch); - consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); - } - } - } - - private BlockState getBlockState(int x, int y, int z) { - return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); - } - - private int getSectionIndex(int y) { - int sectionIndex = SectionPos.blockToSectionCoord(y); - return sectionIndex - this.serverLevel.getMinSection(); - } - - private int getSectionYFromSectionIndex(int index) { - return index + this.serverLevel.getMinSection(); - } - - private static class CachedEntity { - - private final double x; - private final double y; - private final double z; - private final float yaw; - private final float pitch; - private final EntityType entityType; - private final CompoundTag entityTag; - - CachedEntity(Entity entity) { - this.x = entity.getX(); - this.y = entity.getY(); - this.z = entity.getZ(); - this.yaw = entity.getBukkitYaw(); - this.pitch = entity.getXRot(); - this.entityType = entity.getBukkitEntity().getType(); - - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - - this.entityTag = CompoundTag.fromNBT(compoundTag); - } - - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/KeyBlocksCache.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/KeyBlocksCache.java deleted file mode 100644 index 9f87ed3a19..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/KeyBlocksCache.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; - -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.level.block.Block; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class KeyBlocksCache { - - private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); - - private KeyBlocksCache() { - - } - - public static Key getBlockKey(Block block) { - return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { - Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); - }); - } - - public static void cacheAllBlocks() { - BuiltInRegistries.BLOCK.forEach(KeyBlocksCache::getBlockKey); - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/PropertiesMapper.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/PropertiesMapper.java deleted file mode 100644 index 9d07d59410..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/PropertiesMapper.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; - -import com.bgsoftware.superiorskyblock.core.logging.Log; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.Property; - -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; - -public class PropertiesMapper { - - private static final Map> nameToProperty = new HashMap<>(); - private static final Map, String> propertyToName = new HashMap<>(); - - static { - Map fieldsToNames = new IdentityHashMap<>(); - - fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); - fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); - fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); - fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); - fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); - fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); - fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); - fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); - fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); - fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); - fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); - fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); - fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); - fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); - fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); - fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); - fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); - fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); - fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); - fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); - fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); - fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); - fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); - fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); - fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); - fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); - fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); - fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); - - try { - for (Field field : BlockStateProperties.class.getFields()) { - field.setAccessible(true); - Object value = field.get(null); - if (value instanceof Property) { - Property property = (Property) value; - register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); - } - } - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while loading properties mapper:"); - } - - } - - private static void register(String key, String fieldName, Property property) { - if (nameToProperty.containsKey(key)) { - Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); - } else { - nameToProperty.put(key, property); - propertyToName.put(property, key); - } - } - - public static Property getProperty(String name) { - return nameToProperty.get(name); - } - - public static String getPropertyName(Property property) { - return propertyToName.get(property); - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/PropertiesMapperVersioned.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..c5944f54ee --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/PropertiesMapperVersioned.java @@ -0,0 +1,17 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; + +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionDataImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionDataImpl.java deleted file mode 100644 index 9bdfaf2f74..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionDataImpl.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; - -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionDataImpl implements WorldEditSession.Data { - - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private final List> chunks = new LinkedList<>(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); - - public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, - List> blocksToUpdate, - List> blockEntities, - Set lightenChunks) { - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // Convert chunk data - Iterator> chunksIterator = chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); - int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); - WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); - - List> lights; - if (isStarLightInterface || chunkData.lights().isEmpty()) { - lights = Collections.emptyList(); - } else { - lights = new LinkedList<>(); - chunkData.lights().forEach(lightPosition -> { - lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, - lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, - null)); - }); - } - - PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), - chunkData.heightmaps(), lights); - - this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, - currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); - } - - // Convert blocksToUpdate - blocksToUpdate.forEach(blockToUpdate -> { - BlockPos blockPos = blockToUpdate.getKey(); - this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockToUpdate.getValue())); - }); - - // Convert blockEntities - blockEntities.forEach(blockEntity -> { - BlockPos blockPos = blockEntity.getKey(); - this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockEntity.getValue())); - }); - - // Convert lights - lightenChunks.forEach(lightPosition -> { - this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, - lightPosition.z - baseChunkPosZAxis, null)); - }); - } - - public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, - int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, - Long2ObjectMapView chunks) { - this.chunks.forEach(chunkDataPositioned -> { - long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, - baseChunkPosZAxis + chunkDataPositioned.zOffset); - - List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - chunkDataPositioned.object.lights.forEach(lightPositioned -> { - lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, - baseBlockPosYAxis + lightPositioned.yOffset, - baseBlockPosZAxis + lightPositioned.zOffset)); - }); - - chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, - chunkDataPositioned.object.heightmaps, lights)); - }); - } - - public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { - this.blocksToUpdate.forEach(blockToUpdatePositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, - baseBlockPosYAxis + blockToUpdatePositioned.yOffset, - baseBlockPosZAxis + blockToUpdatePositioned.zOffset); - blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); - }); - } - - public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { - this.blockEntities.forEach(blockEntityPositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, - baseBlockPosYAxis + blockEntityPositioned.yOffset, - baseBlockPosZAxis + blockEntityPositioned.zOffset); - blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); - }); - } - - public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { - this.lightenChunks.forEach(lightPositioned -> { - ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, - baseChunkPosZAxis + lightPositioned.zOffset); - lightenChunks.add(newPos); - }); - } - - private static class PositionedObject { - - private final int xOffset; - private final int yOffset; - private final int zOffset; - private final V object; - - PositionedObject(int xOffset, int zOffset, V object) { - this(xOffset, 0, zOffset, object); - } - - PositionedObject(int xOffset, int yOffset, int zOffset, V object) { - this.xOffset = xOffset; - this.yOffset = yOffset; - this.zOffset = zOffset; - this.object = object; - } - - } - - private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, - List> lights) { - } - -} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java deleted file mode 100644 index 08a8f4eee7..0000000000 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/WorldEditSessionImpl.java +++ /dev/null @@ -1,492 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.google.common.base.Preconditions; -import com.google.gson.JsonParseException; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.HolderLookup; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.SignText; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.ticks.ProtoChunkTicks; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome; -import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; -import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; -import org.bukkit.generator.ChunkGenerator; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionImpl implements WorldEditSession { - - private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.starlight.common.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; - - private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - - private Dimension dimension; - private LevelHeightAccessor levelHeightAccessor; - - @Nullable - private ServerLevel serverLevel; - - public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { - return POOL.obtain().initialize(serverLevel); - } - - public static WorldEditSessionImpl obtain(Dimension dimension) { - return POOL.obtain().initialize(dimension); - } - - private WorldEditSessionImpl() { - } - - private WorldEditSessionImpl initialize(ServerLevel serverLevel) { - this.serverLevel = serverLevel; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); - this.levelHeightAccessor = serverLevel; - return this; - } - - private WorldEditSessionImpl initialize(Dimension dimension) { - DimensionType dimensionType = getDimensionTypeFromDimension(dimension); - this.serverLevel = null; - this.dimension = dimension; - this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); - return this; - } - - @Override - public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, - @Nullable CompoundTag blockEntityData) { - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - if (!isValidPosition(blockPos)) - return; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - blocksToUpdate.add(new Pair<>(blockPos, blockState)); - return; - } - - ChunkPos chunkPos = new ChunkPos(blockPos); - - if (blockEntityData != null) - blockEntities.add(new Pair<>(blockPos, blockEntityData)); - - ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); - - if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) - chunkData.lights.add(blockPos); - - LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - } - - @Override - public List getAffectedChunks() { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); - - if (chunks.isEmpty()) - return Collections.emptyList(); - - List chunkPositions = new LinkedList<>(); - World bukkitWorld = serverLevel.getWorld(); - LongIterator iterator = chunks.keyIterator(); - while (iterator.hasNext()) { - long chunkKey = iterator.next(); - int chunkX = (int) chunkKey; - int chunkZ = (int) (chunkKey >> 32); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); - } - return chunkPositions; - } - - @Override - public void applyBlocks(Chunk bukkitChunk) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); - - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); - ChunkPos chunkPos = levelChunk.getPos(); - - long chunkKey = chunkPos.toLong(); - ChunkData chunkData = this.chunks.remove(chunkKey); - - if (chunkData == null) - return; - - int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); - for (int i = 0; i < chunkSectionsCount; ++i) { - levelChunk.getSections()[i] = chunkData.chunkSections[i]; - } - - chunkData.heightmaps.forEach(((type, heightmap) -> { - levelChunk.setHeightmap(type, heightmap.getRawData()); - })); - - if (plugin.getSettings().isLightsUpdate()) { - if (isStarLightInterface) { - this.lightenChunks.add(chunkPos); - } else { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); - // Queues chunk light for this chunk. - threadedLevelLightEngine.lightChunk(levelChunk, false); - } - } - - levelChunk.setUnsaved(true); - } - - @Override - public void finish(Island island) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); - - // Update blocks - blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); - - // Update block entities - blockEntities.forEach(data -> { - net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); - if (blockEntityCompound != null) { - BlockPos blockPos = data.getKey(); - blockEntityCompound.putInt("x", blockPos.getX()); - blockEntityCompound.putInt("y", blockPos.getY()); - blockEntityCompound.putInt("z", blockPos.getZ()); - - applySignTextLines(blockEntityCompound, "front_text"); - applySignTextLines(blockEntityCompound, "back_text"); - convertLegacySignTextLines(blockEntityCompound); - - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.load(blockEntityCompound); - } - }); - - if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - threadedLevelLightEngine.relight(lightenChunks, chunkCallback -> { - }, completeCallback -> { - }); - this.lightenChunks.clear(); - } - - release(); - } - - @Override - public Data readData(Location baseLocation) { - return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); - } - - @Override - public void applyData(Data data, Location baseLocation) { - WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // We need to transform all data to the new base location values - - dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, - baseBlockPosZAxis, this, this.chunks); - dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); - dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); - dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); - } - - @Override - public void release() { - this.chunks.clear(); - this.blocksToUpdate.clear(); - this.blockEntities.clear(); - this.lightenChunks.clear(); - this.serverLevel = null; - this.dimension = null; - this.levelHeightAccessor = null; - POOL.release(this); - } - - public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - return new ChunkData(chunkSections, heightmaps, lights); - } - - private boolean isValidPosition(BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); - } - - private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { - if (blockEntityCompound.contains(key)) { - net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); - ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); - List textLines = new ArrayList<>(); - for (net.minecraft.nbt.Tag lineTag : messages) { - try { - textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); - } catch (JsonParseException error) { - textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); - } - } - - while (textLines.size() < 4) - textLines.add(Component.empty()); - - Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); - - SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); - } - } - - private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { - Component[] signLines = new Component[4]; - Arrays.fill(signLines, Component.empty()); - boolean hasAnySignLines = false; - // We try to convert old text sign lines - for (int i = 1; i <= 4; ++i) { - if (blockEntityCompound.contains("SSB.Text" + i)) { - String signLine = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; - hasAnySignLines = true; - } - } else { - String signLine = blockEntityCompound.getString("Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromJSON(signLine); - hasAnySignLines = true; - } - } - } - - if (hasAnySignLines) { - SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); - } - } - - private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { - ResourceKey resourceKey; - switch (dimension.getEnvironment()) { - case NETHER -> resourceKey = LevelStem.NETHER; - case THE_END -> resourceKey = LevelStem.END; - default -> resourceKey = LevelStem.OVERWORLD; - } - HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); - return registry.getOrThrow(resourceKey).value().type().value(); - } - - public class ChunkData { - - private final LevelChunkSection[] chunkSections; - private final Map heightmaps; - private final List lights; - - public ChunkData(long chunkKey) { - this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), - isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); - - ChunkPos chunkPos = new ChunkPos(chunkKey); - - Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); - - createChunkSections(biomesRegistry); - - ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); - - createHeightmaps(tempChunk); - if (serverLevel != null) - runCustomWorldGenerator(tempChunk); - } - - private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - this.chunkSections = chunkSections; - this.heightmaps = heightmaps; - this.lights = lights; - } - - public LevelChunkSection[] chunkSections() { - return this.chunkSections; - } - - public Map heightmaps() { - return this.heightmaps; - } - - public List lights() { - return this.lights; - } - - private void createChunkSections(Registry biomesRegistry) { - Holder biome = CraftBiome.bukkitToMinecraftHolder( - IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); - - for (int i = 0; i < this.chunkSections.length; ++i) { - PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), - biome, PalettedContainer.Strategy.SECTION_BIOMES); - PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - - this.chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); - } - } - - private void runCustomWorldGenerator(ProtoChunk tempChunk) { - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - - if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) - return; - - CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), - bukkitGenerator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(tempChunk), - ChunkStatus.SURFACE, 0); - - chunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - tempChunk); - - // We want to copy the level chunk sections back - LevelChunkSection[] tempChunkSections = tempChunk.getSections(); - for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { - LevelChunkSection chunkSection = tempChunkSections[i]; - if (chunkSection != null) - this.chunkSections[i] = chunkSection; - } - } - - private void createHeightmaps(ProtoChunk tempChunk) { - for (Heightmap.Types heightmapType : Heightmap.Types.values()) { - if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { - this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); - } - } - } - - } - - -} diff --git a/NMS/v1_20_4/properties b/NMS/v1_20_4/properties new file mode 100644 index 0000000000..151398b620 --- /dev/null +++ b/NMS/v1_20_4/properties @@ -0,0 +1,7 @@ +NMS_VERSION=v1_20_4 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java index cdf914b008..3df07dcf65 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java @@ -1,242 +1,20 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_4; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; -import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; -import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.menu.MenuBrewingStandBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.menu.MenuDispenserBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.menu.MenuFurnaceBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.menu.MenuHopperBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.BlockEntityCache; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.KeyBlocksCache; -import com.google.common.collect.Multimap; -import com.google.common.collect.MultimapBuilder; -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.TextReplacementConfig; -import net.minecraft.core.BlockPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.Container; -import net.minecraft.world.entity.item.FallingBlockEntity; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.attribute.Attribute; -import org.bukkit.attribute.AttributeModifier; -import org.bukkit.block.data.Ageable; -import org.bukkit.block.data.BlockData; -import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftFallingBlock; -import org.bukkit.craftbukkit.entity.CraftMinecart; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.PotionMeta; -import org.bukkit.inventory.meta.trim.ArmorTrim; -import org.bukkit.inventory.meta.trim.TrimMaterial; -import org.bukkit.inventory.meta.trim.TrimPattern; -import org.bukkit.potion.PotionEffect; -import org.jetbrains.annotations.NotNull; -import java.util.EnumMap; -import java.util.Locale; -import java.util.Objects; -import java.util.Optional; -import java.util.function.BiFunction; - -public class NMSAlgorithmsImpl implements NMSAlgorithms { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Multimap EMPTY_ATTRIBUTES_MAP = - MultimapBuilder.hashKeys().hashSetValues().build(); - - private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); - - static { - MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); - } - - private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { - @Override - public byte[] processClass(byte[] classBytes, String path) { - return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); - } - }; - - @Override - public void registerCommand(BukkitCommand command) { - ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); - } +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms { @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); } - @Override - public int getCombinedId(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return 0; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(wrapper.getHandle()); - } - return Block.getId(blockState); - } - - @Override - public int getCombinedId(Material material, byte data) { - BlockState blockState; - - if (data == 0) { - Block block = CraftMagicNumbers.getBlock(material); - if (block == null) - return -1; - blockState = block.defaultBlockState(); - } else { - blockState = CraftMagicNumbers.getBlock(material, data); - } - - return blockState == null ? -1 : Block.getId(blockState); - } - - @Override - public Optional getTileEntityIdFromCombinedId(int combinedId) { - BlockState blockState = Block.stateById(combinedId); - - if (!blockState.hasBlockEntity()) - return Optional.empty(); - - String id = BlockEntityCache.getBlockEntityId(blockState); - - return Text.isBlank(id) ? Optional.empty() : Optional.of(id); - } - - @Override - public int compareMaterials(Material o1, Material o2) { - int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); - int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); - return Integer.compare(firstMaterial, secondMaterial); - } - - @Override - public short getBlockDataValue(org.bukkit.block.BlockState blockState) { - BlockData blockData = blockState.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getBlockDataValue(org.bukkit.block.Block block) { - BlockData blockData = block.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getMaxBlockDataValue(Material material) { - if (!material.isBlock()) - return 0; - - BlockData blockData = Bukkit.createBlockData(material); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); - } - - @Override - public Key getBlockKey(int combinedId) { - Block block = Block.stateById(combinedId).getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { - AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); - Block block = minecart.getDisplayBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { - FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); - Block block = fallingBlock.getBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public void setCustomModel(ItemMeta itemMeta, int customModel) { - itemMeta.setCustomModelData(customModel); - } - - @Override - public void setItemModel(ItemMeta itemMeta, String itemModel) { - // Doesn't exist - } - - @Override - public void setRarity(ItemMeta itemMeta, String rarity) { - itemMeta.setRarity(ItemRarity.valueOf(rarity)); - } - - @Override - public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { - if (itemMeta instanceof ArmorMeta armorMeta) { - TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); - TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); - - if (material == null) - throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + - " into trim material, skipping..."); - if (pattern == null) - throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + - " into trim pattern, skipping..."); - - ArmorTrim armorTrim = new ArmorTrim(material, pattern); - armorMeta.setTrim(armorTrim); - } - } - - @Override - public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { - if (!potionMeta.hasCustomEffects()) - potionMeta.setColor(potionEffect.getType().getColor()); - potionMeta.addCustomEffect(potionEffect, true); - } - @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); @@ -247,88 +25,4 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } - @Nullable - @Override - public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { - MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); - return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); - } - - @Override - public int getMaxWorldSize() { - return Bukkit.getMaxWorldSize(); - } - - @Override - public double getCurrentTps() { - try { - return MinecraftServer.getServer().tps1.getAverage(); - } catch (Throwable error) { - //noinspection removal - return MinecraftServer.getServer().recentTps[0]; - } - } - - @Override - public int getDataVersion() { - return CraftMagicNumbers.INSTANCE.getDataVersion(); - } - - @Override - public ClassProcessor getClassProcessor() { - return CLASS_PROCESSOR; - } - - @Override - public void handlePaperChatRenderer(Object event) { - if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) - return; - - io.papermc.paper.chat.ChatRenderer originalRenderer = asyncChatEvent.renderer(); - asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); - } - - @Override - public void hideAttributes(ItemMeta itemMeta) { - itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); - } - - private interface MenuCreator extends BiFunction { - } - - private static class ChatRendererWrapper { - - private static final String MESSAGE_PLACEHOLDER = "{message}"; - private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = - net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); - - private final ChatRenderer renderer = new ChatRenderer() { - @Override - public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, - net.kyori.adventure.text.@NotNull Component sourceDisplayName, - net.kyori.adventure.text.@NotNull Component message, - @NotNull Audience viewer) { - String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer - .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); - Island island = superiorPlayer.getIsland(); - - return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( - Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) - .replaceText(TextReplacementConfig.builder() - .matchLiteral(MESSAGE_PLACEHOLDER) - .replacement(message) - .build()); - } - }; - - private final ChatRenderer originalRenderer; - - public ChatRendererWrapper(ChatRenderer originalRenderer) { - this.originalRenderer = originalRenderer; - } - - } - } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java index f6aa57651a..2fe657aa47 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java @@ -1,25 +1,17 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_4; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; -import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.crops.CropsBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.crops.CropsTickingMethod; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -38,75 +30,45 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.lighting.LevelLightEngine; -import net.minecraft.world.phys.AABB; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.entity.CraftEntityType; import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; -import java.util.Arrays; import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; -import java.util.Objects; import java.util.concurrent.CompletableFuture; -public class NMSChunksImpl implements NMSChunks { - - private static final boolean hasStatesIterator = new ReflectMethod<>(PalettedContainer.class, - "forEachLocation", PalettedContainer.CountConsumer.class).isValid(); - - private final SuperiorSkyblockPlugin plugin; +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - KeyBlocksCache.cacheAllBlocks(); - CropsTickingMethod.register(); + super(plugin); } @Override - public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, - Collection playersToUpdate) { - if (chunkPositions.isEmpty()) - return; - - Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.SET_BIOME, false) { + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); @@ -124,7 +86,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null); + levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); @@ -135,7 +97,11 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { - Registry biomesRegistry = unloadedChunkCompound.serverLevel().registryAccess().registryOrThrow(Registries.BIOME); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), @@ -148,7 +114,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); @@ -158,19 +124,12 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { // Do nothing. } - }); + }; } @Override - public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { - if (chunkPositions.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), - chunkPosition.getX(), chunkPosition.getZ(), false)); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.DELETE_CHUNK, false) { + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -187,6 +146,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( @@ -197,8 +157,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - unloadedChunkCompound.setEntities(new ListTag()); - unloadedChunkCompound.setBlockEntities(tileEntities); + chunkCompound.put("entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, @@ -206,27 +166,19 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { - CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), serverLevel.generator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(protoChunk), - ChunkStatus.SURFACE, 0); - - customChunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - protoChunk); + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); + Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), @@ -272,7 +224,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound tileEntities.add(blockEntityCompound); } - unloadedChunkCompound.setSections(sectionsList); + chunkCompound.put("sections", sectionsList); } } @@ -281,34 +233,14 @@ public void onFinish() { if (onFinish != null) onFinish.run(); } - }); + }; } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); - List chunkPositionsToCalculate = new LinkedList<>(); - - Iterator chunkPositionsIterator = chunkPositions.iterator(); - while (chunkPositionsIterator.hasNext()) { - ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); - if (cachedCalculatedChunk != null) { - allCalculatedChunks.add(cachedCalculatedChunk); - chunkPositionsIterator.remove(); - } else { - chunkPositionsToCalculate.add(chunkPosition); - } - } - - if (chunkPositions.isEmpty()) - return CompletableFuture.completedFuture(allCalculatedChunks); - - CompletableFuture> completableFuture = new CompletableFuture<>(); - - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( - ChunkLoadReason.BLOCKS_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -322,6 +254,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( @@ -339,36 +272,36 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { - PalettedContainer blocksDataPalette; + PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); - blocksDataPalette = dataResult.getOrThrow(); + blocksPalettedContainer = dataResult.getOrThrow(); } else { - blocksDataPalette = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } - PalettedContainer> biomesDataPalette; + PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); - biomesDataPalette = dataResult.getOrThrow(); + biomesPalettedContainer = dataResult.getOrThrow(); } else { - biomesDataPalette = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } - chunkSections[sectionIndex] = new LevelChunkSection(blocksDataPalette, biomesDataPalette); + chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } @@ -384,20 +317,14 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { completableFuture.complete(allCalculatedChunks); } - }); - - return completableFuture; + }; } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); - - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - List unloadedChunkCompounds = new LinkedList<>(); - - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( - ChunkLoadReason.ENTITIES_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { @@ -420,8 +347,9 @@ public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - for (Tag entityTag : unloadedChunkCompound.getEntities()) { + for (Tag entityTag : chunkCompound.getList("entities", 10)) { EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); if (entityType == null) continue; @@ -433,7 +361,9 @@ public void onFinish() { continue; } - Key entityKey = Keys.of(CraftEntityType.minecraftToBukkit(entityType)); + Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( + CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); + chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); } } @@ -441,173 +371,17 @@ public void onFinish() { completableFuture.complete(chunkEntities); }); } - }); - - return completableFuture; - } - - @Override - public void injectChunkSections(Chunk chunk) { - // No implementation - } - - @Override - public boolean isChunkEmpty(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> - chunkSection == null || chunkSection.hasOnlyAir()); - } - - @Override - public Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); - return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; - } - - @Override - public void startTickingChunk(Island island, Chunk chunk, boolean stop) { - if (plugin.getSettings().getCropsInterval() <= 0) - return; - - - if (stop) { - CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); - if (cropsBlockEntity != null) - cropsBlockEntity.remove(); - } else { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - CropsBlockEntity.create(island, levelChunk); - } - } - - @Override - public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { - if (chunkPositions.isEmpty()) return; - CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> - cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); - } - - @Override - public void shutdown() { - List> pendingTasks = NMSUtils.getPendingChunkActions(); - - if (pendingTasks.isEmpty()) - return; - - Log.info("Waiting for chunk tasks to complete."); - - CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); - } - - @Override - public List getBlockEntities(Chunk chunk) { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - List blockEntities = new LinkedList<>(); - - World bukkitWorld = chunk.getWorld(); - - levelChunk.getBlockEntities().keySet().forEach(blockPos -> - blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); - - return blockEntities; - } - - private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { - KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); - List spawnersLocations = new LinkedList<>(); - - for (int i = 0; i < chunkSections.length; ++i) { - LevelChunkSection levelChunkSection = chunkSections[i]; - if (levelChunkSection != null && !levelChunkSection.hasOnlyAir()) { - int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4; - if (hasStatesIterator) { - levelChunkSection.getStates().forEachLocation((blockState, locationKey) -> { - int x = locationKey & 0xF; - int y = (locationKey >> 8) & 0xF; - int z = (locationKey >> 4) & 0xF; - calculateChunkInternal(blockState, x, y, z, chunkPosition, sectionBottomY, blockCounts, spawnersLocations); - }); - } else for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { - BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, - sectionBottomY, blockCounts, spawnersLocations); - } - } - } - - return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); - } - - private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, - int sectionBottomY, KeyMap blockCounts, - List spawnersLocations) { - Block block = blockState.getBlock(); - - if (block == Blocks.AIR) - return; - - Location location = new Location(chunkPosition.getWorld(), - (chunkPosition.getX() << 4) + x, - sectionBottomY + y, - (chunkPosition.getZ() << 4) + z); - - int blockAmount = 1; - - if (NMSUtils.isDoubleBlock(block, blockState)) { - blockAmount = 2; - blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); - } - - Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); - blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); - if (block == Blocks.SPAWNER) { - spawnersLocations.add(location); - } - } - - private static void removeEntities(ChunkAccess chunk) { - ChunkPos chunkPos = chunk.getPos(); - ServerLevel serverLevel = ((LevelChunk) chunk).level; - - int chunkWorldCoordX = chunkPos.x << 4; - int chunkWorldCoordZ = chunkPos.z << 4; - - AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinBuildHeight(), chunkWorldCoordZ, - chunkWorldCoordX + 15, serverLevel.getMaxBuildHeight(), chunkWorldCoordZ + 15); - - List worldEntities = new LinkedList<>(); - serverLevel.getEntities().get(chunkBounds, worldEntities::add); - - worldEntities.forEach(nmsEntity -> { - if (!(nmsEntity instanceof Player)) - nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); - }); - } - - private static void removeBlockEntities(ChunkAccess chunk) { - chunk.blockEntities.values().forEach(BlockEntity::setRemoved); - chunk.blockEntities.clear(); + }; } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { - CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), - bukkitGenerator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunk), - ChunkStatus.SURFACE, 0); + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; - chunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - chunk); - } + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSEntitiesImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSEntitiesImpl.java index b36262b712..2c935e0455 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSEntitiesImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSEntitiesImpl.java @@ -1,57 +1,30 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_4; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; -import org.bukkit.Material; -import org.bukkit.craftbukkit.entity.CraftAnimals; -import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; -import org.bukkit.entity.Animals; import org.bukkit.entity.minecart.PoweredMinecart; -import org.bukkit.inventory.EntityEquipment; -import org.bukkit.inventory.ItemStack; import java.lang.reflect.Modifier; -public class NMSEntitiesImpl implements NMSEntities { +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSEntities { private static final ReflectField PORTAL_TICKS = new ReflectField<>( Entity.class, int.class, Modifier.PROTECTED, 2); private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override - public ItemStack[] getEquipment(EntityEquipment entityEquipment) { - ItemStack[] itemStacks = new ItemStack[7]; - - itemStacks[0] = new ItemStack(Material.ARMOR_STAND); - itemStacks[1] = entityEquipment.getItemInMainHand(); - itemStacks[2] = entityEquipment.getItemInOffHand(); - itemStacks[3] = entityEquipment.getHelmet(); - itemStacks[4] = entityEquipment.getChestplate(); - itemStacks[5] = entityEquipment.getLeggings(); - itemStacks[6] = entityEquipment.getBoots(); - - return itemStacks; - } - - @Override - public boolean isAnimalFood(ItemStack itemStack, Animals animals) { - return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); - } - - @Override - public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override - public int getPortalTicks(org.bukkit.entity.Entity entity) { - return PORTAL_TICKS.get(((CraftEntity) entity).getHandle()); + protected int getPortalTicks(Entity entity) { + return PORTAL_TICKS.get(entity); } } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSHologramsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSHologramsImpl.java deleted file mode 100644 index 1e326a9f74..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSHologramsImpl.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4; - -import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; -import com.bgsoftware.superiorskyblock.nms.NMSHolograms; -import com.google.common.base.Preconditions; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftArmorStand; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.entity.Entity; - -@SuppressWarnings("unused") -public class NMSHologramsImpl implements NMSHolograms { - - @Override - public Hologram createHologram(Location location) { - Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); - serverLevel.addFreshEntity(entityHologram); - return entityHologram; - } - - @Override - public boolean isHologram(Entity entity) { - return ((CraftEntity) entity).getHandle() instanceof Hologram; - } - - public static class EntityHologram extends ArmorStand implements Hologram { - - private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); - - private CraftEntity bukkitEntity; - - EntityHologram(ServerLevel serverLevel, double x, double y, double z) { - super(serverLevel, x, y, z); - - setInvisible(true); - setSmall(true); - setShowArms(false); - setNoGravity(true); - setNoBasePlate(true); - setMarker(true); - forceSetBoundingBox(EMPTY_BOUND); - - super.collides = false; - super.setCustomNameVisible(true); - } - - @Override - public void setHologramName(String name) { - super.setCustomName(CraftChatMessage.fromStringOrNull(name)); - } - - @Override - public void removeHologram() { - super.remove(RemovalReason.DISCARDED); - } - - @Override - public org.bukkit.entity.ArmorStand getHandle() { - return this.getBukkitEntity(); - } - - @Override - public void inactiveTick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - @Override - public boolean repositionEntityAfterLoad() { - return false; - } - - @Override - public AABB getBoundingBoxForCulling() { - return EMPTY_BOUND; - } - - @Override - public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { - // Prevent stand being equipped - } - - @Override - public void addAdditionalSaveData(CompoundTag compoundTag) { - // Do not save NBT. - } - - @Override - public void readAdditionalSaveData(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { - // Prevent stand being equipped - return InteractionResult.PASS; - } - - @Override - public void tick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - public void forceSetBoundingBox(AABB boundingBox) { - super.setBoundingBox(boundingBox); - } - - @Override - public CraftArmorStand getBukkitEntity() { - if (bukkitEntity == null) { - bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); - } - return (CraftArmorStand) bukkitEntity; - } - - @Override - public void remove(RemovalReason removalReason) { - // Prevent being killed. - } - - @Override - public void playSound(SoundEvent soundEvent, float volume, float pitch) { - // Remove sounds. - } - - @Override - public boolean saveAsPassenger(CompoundTag compoundTag) { - // Do not save NBT. - return false; - } - - @Override - public CompoundTag saveWithoutId(CompoundTag compoundTag) { - // Do not save NBT. - return compoundTag; - } - - @Override - public void load(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public boolean isInvulnerableTo(DamageSource damageSource) { - /* - * The field Entity.invulnerable is private. - * It's only used while saving NBTTags, but since the entity would be killed - * on chunk unload, we prefer to override isInvulnerable(). - */ - return true; - } - - @Override - public void setCustomName(Component component) { - // Locks the custom name. - } - - @Override - public void setCustomNameVisible(boolean isCustomNameVisible) { - // Locks the custom name. - } - - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java index 926623604c..c36d3a821f 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java @@ -1,85 +1,27 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_4; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.ListTag; -import com.bgsoftware.superiorskyblock.tag.Tag; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; -import com.mojang.serialization.Dynamic; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; -import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.util.Optional; import java.util.Set; -@SuppressWarnings({"unused"}) -public class NMSTagsImpl implements NMSTags { - - @Override - public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) - itemStack.save(MinecraftServer.getServer().registryAccess()); - tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); - - return CompoundTag.fromNBT(tagCompound); - } - - @Override - public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { - if (compoundTag.containsKey("NBT")) { - // Old compound version, deserialize it accordingly - return deserializeItemOld(compoundTag); - } - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); - - int currentVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); - int itemVersion = tagCompound.getInt("DataVersion"); - if (itemVersion < currentVersion) { - tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, - new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); - } - - ItemStack itemStack = ItemStack.parse(MinecraftServer.getServer().registryAccess(), tagCompound).orElseThrow(); - - return CraftItemStack.asCraftMirror(itemStack); - } - - private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); - Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount").orElse(0); - short data = (short) compoundTag.getShort("data").orElse(0); - CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); - - org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - if (nbtData != null) - itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); - - return CraftItemStack.asCraftMirror(itemStack); - } +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSTags { @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { @@ -96,18 +38,30 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I } @Override - @SuppressWarnings("ConstantConditions") - public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { - net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) + itemStack.save(MinecraftServer.getServer().registryAccess()); + tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + return CompoundTag.fromNBT(tagCompound); + } + + @Override + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; + } - if (compoundTag == null) - compoundTag = new net.minecraft.nbt.CompoundTag(); + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow(); + } - if (!compoundTag.contains("id")) - //noinspection deprecation - compoundTag.putString("id", entityType.getName()); + @Override + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); + } - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; @@ -169,29 +123,4 @@ public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } - @Override - public Object parseList(ListTag listTag) { - net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); - - for (Tag tag : listTag) - nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); - - return nbtTagList; - } - - @Override - public Object getNBTCompoundTag(Object object, String key) { - return ((net.minecraft.nbt.CompoundTag) object).get(key); - } - - @Override - public void setNBTCompoundTagValue(Object object, String key, Object value) { - ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); - } - - @Override - public int getNBTTagListSize(Object object) { - return ((net.minecraft.nbt.ListTag) object).size(); - } - } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java deleted file mode 100644 index 5bde897d71..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSUtils.java +++ /dev/null @@ -1,504 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.PropertiesMapper; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; -import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; -import com.google.common.base.Suppliers; -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.chunk.storage.EntityStorage; -import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; - -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; - -public class NMSUtils { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( - ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); - private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( - ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); - private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( - EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); - - private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); - - public static final ObjectsPool> BLOCK_POS_POOL = - ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); - - private NMSUtils() { - - } - - @Nullable - public static T getBlockEntityAt(Location location, Class type) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); - } - } - - public static void runActionOnEntityChunks(Collection chunksCoords, - ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); - } - - public static void runActionOnChunks(Collection chunksCoords, - boolean saveChunks, ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); - } - - private static void runActionOnChunksInternal(Collection chunksCoords, - ChunkCallback chunkCallback, - Consumer> onUnloadChunkAction) { - List unloadedChunks = new LinkedList<>(); - List loadedChunks = new LinkedList<>(); - - chunksCoords.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - ChunkAccess chunkAccess; - - try { - chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); - } catch (Throwable ex) { - chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); - } - - if (chunkAccess instanceof LevelChunk levelChunk) { - loadedChunks.add(levelChunk); - } else { - unloadedChunks.add(chunkPosition.copy()); - } - }); - - boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); - - if (!loadedChunks.isEmpty()) - runActionOnLoadedChunks(loadedChunks, chunkCallback); - - if (hasUnloadedChunks) { - onUnloadChunkAction.accept(unloadedChunks); - } else { - chunkCallback.onFinish(); - } - } - - private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { - chunks.forEach(chunkCallback::onLoadedChunk); - } - - private static void runActionOnUnloadedChunks(Collection chunks, - boolean saveChunks, ChunkCallback chunkCallback) { - if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { - Iterator chunksIterator = chunks.iterator(); - while (chunksIterator.hasNext()) { - ChunkPosition chunkPosition = chunksIterator.next(); - - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( - chunkPosition.getX(), chunkPosition.getZ()); - - if (cachedUnloadedChunk != null) { - chunkCallback.onLoadedChunk(cachedUnloadedChunk); - chunksIterator.remove(); - } - } - - if (chunks.isEmpty()) { - chunkCallback.onFinish(); - return; - } - } - - CompletableFuture pendingTask = new CompletableFuture<>(); - PENDING_CHUNK_ACTIONS.add(pendingTask); - - BukkitExecutor.createTask().runAsync(v -> { - CountDownLatch countDownLatch; - if (chunkCallback.isWaitForChunkLoad) { - countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - } else { - countDownLatch = null; - } - - List chunkCompounds = new LinkedList<>(); - - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - boolean calledCountdown = false; - try { - net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); - - if (chunkCompound == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), - Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, - Optional.empty(), chunkPos, serverLevel); - - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - calledCountdown = true; - - if (saveChunks) - chunkCompounds.add(unloadedChunkCompound); - } catch (Exception error) { - if (!calledCountdown && countDownLatch != null) - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - if (countDownLatch != null) { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - } - - return chunkCompounds; - }).runSync(chunkCompounds -> { - chunkCompounds.forEach(unloadedChunkCompound -> { - ChunkMap chunkMap = unloadedChunkCompound.serverLevel().getChunkSource().chunkMap; - - try { - chunkMap.write(unloadedChunkCompound.chunkPos(), unloadedChunkCompound.chunkCompound); - } catch (IOException error) { - Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); - } - }); - - chunkCallback.onFinish(); - - pendingTask.complete(null); - PENDING_CHUNK_ACTIONS.remove(pendingTask); - }); - } - - private static void runActionOnUnloadedEntityChunks(Collection chunks, - ChunkCallback chunkCallback) { - CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); - SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { - if (error != null) { - countDownLatch.countDown(); - throw new RuntimeException(error); - } else { - net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - } else { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } - } - }); - }); - - BukkitExecutor.createTask().runAsync(v -> { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } else { - BukkitExecutor.createTask().runAsync(v -> { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - try { - net.minecraft.nbt.CompoundTag entityData = serverLevel.entityDataControllerNew.readData( - chunkPosition.getX(), chunkPosition.getZ()); - - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } catch (IOException error) { - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } - } - - public static List> getPendingChunkActions() { - return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); - } - - public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { - return new ProtoChunk(chunkPos, - UpgradeData.EMPTY, - serverLevel, - serverLevel.registryAccess().registryOrThrow(Registries.BIOME), - null); - } - - public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { - ServerLevel serverLevel = levelChunk.level; - - if (!isValidPosition(serverLevel, blockPos)) - return null; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - serverLevel.setBlock(blockPos, blockState, 3); - return blockState; - } - - int indexY = serverLevel.getSectionIndex(blockPos.getY()); - - LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - boolean isOriginallyChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - - levelChunk.setUnsaved(true); - - boolean isChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) - serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); - - serverLevel.getLightEngine().checkBlock(blockPos); - - if (tileEntity != null) { - net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); - if (tileEntityCompound != null) { - tileEntityCompound.putInt("x", blockPos.getX()); - tileEntityCompound.putInt("y", blockPos.getY()); - tileEntityCompound.putInt("z", blockPos.getZ()); - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.loadWithComponents(tileEntityCompound, MinecraftServer.getServer().registryAccess()); - } - } - - return blockState; - } - - public static boolean isDoubleBlock(Block block, BlockState blockState) { - return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && - blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; - } - - @Nullable - public static LevelChunk getCraftChunkHandle(CraftChunk craftChunk) { - ServerLevel serverLevel = craftChunk.getCraftWorld().getHandle(); - LevelChunk loadedChunk = serverLevel.getChunkIfLoaded(craftChunk.getX(), craftChunk.getZ()); - if (loadedChunk != null) - return loadedChunk; - - return (LevelChunk) serverLevel.getChunk(craftChunk.getX(), craftChunk.getZ(), ChunkStatus.FULL, true); - } - - public record UnloadedChunkCompound(ChunkPosition chunkPosition, - net.minecraft.nbt.CompoundTag chunkCompound) { - - public ListTag getSections() { - return chunkCompound.getList("sections", 10); - } - - public ListTag getEntities() { - return chunkCompound.getList("Entities", 10); - } - - public void setSections(ListTag sectionsList) { - chunkCompound.put("sections", sectionsList); - } - - public void setEntities(ListTag entitiesList) { - chunkCompound.put("entities", entitiesList); - } - - public void setBlockEntities(ListTag blockEntitiesList) { - chunkCompound.put("block_entities", blockEntitiesList); - } - - public ServerLevel serverLevel() { - return ((CraftWorld) chunkPosition.getWorld()).getHandle(); - } - - public ChunkPos chunkPos() { - return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - } - - } - - private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); - } - - public static abstract class ChunkCallback { - - private final ChunkLoadReason chunkLoadReason; - private final boolean isWaitForChunkLoad; - - @Nullable - protected CountDownLatch chunkLoadLatch; - - public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { - this.chunkLoadReason = chunkLoadReason; - this.isWaitForChunkLoad = isWaitForChunkLoad; - } - - public abstract void onLoadedChunk(LevelChunk levelChunk); - - public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - - public abstract void onFinish(); - - protected final void latchCountDown() { - if (this.chunkLoadLatch != null) - this.chunkLoadLatch.countDown(); - } - - public final void onChunkNotExist(ChunkPosition chunkPosition) { - if (!plugin.getProviders().hasCustomWorldsSupport()) - return; - - ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { - LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); - }); - } - - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index eaa3dd747f..a796c96512 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -3,124 +3,31 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; -import com.bgsoftware.superiorskyblock.nms.ICachedBlock; -import com.bgsoftware.superiorskyblock.nms.NMSWorld; -import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.generator.IslandsGeneratorImpl; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_4.vibration.IslandVibrationUser; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.ChunkReaderImpl; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.WorldEditSessionImpl; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.destroystokyo.paper.antixray.ChunkPacketBlockController; -import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.BubbleColumn; import org.bukkit.block.data.type.HangingSign; -import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.WallHangingSign; -import org.bukkit.block.data.type.WallSign; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.block.CraftBlock; -import org.bukkit.craftbukkit.block.CraftBlockState; -import org.bukkit.craftbukkit.block.CraftSign; -import org.bukkit.craftbukkit.block.data.CraftBlockData; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.function.IntFunction; -public class NMSWorldImpl implements NMSWorld { +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); - private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, - Object.class, "chunkPacketBlockController") - .removeFinal(); - - private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); } @Override - public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { - Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); - Location location = new Location( - Bukkit.getWorld(chunkSnapshot.getWorldName()), - (chunkSnapshot.getX() << 4) + x, - y, - (chunkSnapshot.getZ() << 4) + z - ); - - return Keys.of(KeyBlocksCache.getBlockKey(block), location); - } - - @Override - public void listenSpawner(Location location, IntFunction delayChangeCallback) { - SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); - if (spawnerBlockEntity == null) - return; - - ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - - List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? - LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; - - Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new LinkedList<>(); - - while (blockEntityTickersIterator.hasNext()) { - TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && - !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { - blockEntityTickersIterator.remove(); - tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); - } - } - - if (!tickersToAdd.isEmpty()) - blockEntityTickers.addAll(tickersToAdd); + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); } @Override @@ -132,254 +39,14 @@ public void replaceSculkSensorListener(Island island, Location location) { SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } - @Override - public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { - if (!plugin.getSettings().isWorldBorders()) - return; - - Player player = superiorPlayer.asPlayer(); - World world = superiorPlayer.getWorld(); - - if (world == null || player == null) - return; - - int islandSize = island == null ? 0 : island.getIslandSize(); - - boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; - - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - - WorldBorder worldBorder; - - if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { - worldBorder = serverLevel.getWorldBorder(); - } else { - Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); - if (dimension == null) - return; - - Location center = island.getCenter(dimension); - - worldBorder = new WorldBorder(); - worldBorder.world = serverLevel; - worldBorder.setWarningBlocks(0); - worldBorder.setCenter(center.getX(), center.getZ()); - - switch (superiorPlayer.getBorderColor()) { - case BLUE -> { - worldBorder.setSize((islandSize * 2) + 1D); - } - case GREEN -> { - worldBorder.setSize((islandSize * 2) + 1.001D); - worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); - } - case RED -> { - worldBorder.setSize((islandSize * 2) + 1D); - worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); - } - } - } - - ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); - ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); - } - - @Override - public Object getBlockData(org.bukkit.block.Block block) { - return block.getBlockData(); - } - - @Override - public void setBlock(Location location, int combinedId) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - BlockState blockState = - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - - if (blockState != null) { - serverLevel.getChunkSource().blockChanged(blockPos); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); - } - } - } - } - - @Override - public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return NMSCachedBlock.obtain(block); - } - - @Override - public boolean isWaterLogged(org.bukkit.block.Block block) { - if (Materials.isWater(block.getType())) - return true; - - BlockData blockData = block.getBlockData(); - - return blockData instanceof BubbleColumn || - (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); - } - @Override public SignType getSignType(Object sign) { - if (sign instanceof WallSign) - return SignType.WALL_SIGN; - else if (sign instanceof Sign) - return SignType.STANDING_SIGN; - else if (sign instanceof HangingSign) + if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else - return SignType.UNKNOWN; - } - - @Override - public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { - BlockState blockState = ((CraftBlock) block).getNMS(); - return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; - } - - @Override - public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { - return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); - } - - @Override - public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { - return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); - } - - private int getDefaultAmount(BlockState blockState) { - Block block = blockState.getBlock(); - return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; - } - - @Override - public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { - return !bukkitBlock.isPassable(); - } - - @Override - public void placeSign(Island island, Location location) { - SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); - if (signBlockEntity == null) - return; - - String[] lines = new String[4]; - Component[] messages = signBlockEntity.getFrontText().getMessages(false); - System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - Component[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } - - System.arraycopy(newLines, 0, messages, 0, 4); - } - - @Override - public void playGeneratorSound(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); - } - } - - @Override - public void playBreakAnimation(org.bukkit.block.Block block) { - ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); - } - } - - @Override - public void playPlaceSound(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); - } - } - - @Override - public int getMinHeight(World world) { - return world.getMinHeight(); - } - - @Override - public void removeAntiXray(org.bukkit.World bukkitWorld) { - if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); - } - - @Override - public IslandsGenerator createGenerator(Dimension dimension) { - return new IslandsGeneratorImpl(dimension); - } - - @Override - public WorldEditSession createEditSession(World world) { - return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); - } - - @Override - public WorldEditSession createPartialEditSession(Dimension dimension) { - return WorldEditSessionImpl.obtain(dimension); - } - - @Override - public ChunkReader createChunkReader(Chunk chunk) { - return new ChunkReaderImpl(chunk); - } - - private static ReflectField> initializeLevelBlockEntityTickersField() { - ReflectField> field = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - - if (!field.isValid()) - field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); - - return field; + return super.getSignType(sign); } } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsBlockEntity.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsBlockEntity.java deleted file mode 100644 index 05432e1ad1..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsBlockEntity.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.crops; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.chunk.LevelChunk; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.function.Consumer; - -public class CropsBlockEntity extends BlockEntity { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - - private final WeakReference island; - private final WeakReference chunk; - - private int currentTick = 0; - - private double cachedCropGrowthMultiplier; - - private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(levelChunk); - setLevel(levelChunk.level); - levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; - } - - public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); - return new CropsBlockEntity(island, levelChunk, blockPos); - }); - } - - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); - } - - public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { - if (tickingChunks.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> { - long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); - if (cropsBlockEntity != null) - cropsBlockEntityConsumer.accept(cropsBlockEntity); - }); - } - - public void remove() { - this.remove = true; - } - - public void tick() { - if (++currentTick <= plugin.getSettings().getCropsInterval()) - return; - - LevelChunk levelChunk = this.chunk.get(); - Island island = this.island.get(); - ServerLevel serverLevel = (ServerLevel) getLevel(); - - if (levelChunk == null || island == null || serverLevel == null) { - remove(); - return; - } - - currentTick = 0; - - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - if (chunkRandomTickSpeed > 0) - CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); - } - - public void setCropGrowthMultiplier(double cropGrowthMultiplier) { - this.cachedCropGrowthMultiplier = cropGrowthMultiplier; - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java deleted file mode 100644 index 3b7231bc36..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/crops/CropsTickingMethod.java +++ /dev/null @@ -1,156 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.crops; - -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; - -public abstract class CropsTickingMethod { - - private static final ReflectField SERVER_LEVEL_RANDOM_TICK_RANDOM = new ReflectField<>( - ServerLevel.class, RandomSource.class, "randomTickRandom"); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static Set CROPS_TO_GROW_CACHE; - - static { - plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); - } - - private static final BlockPos.MutableBlockPos chunkTickMutablePosition = new BlockPos.MutableBlockPos(); - - private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_RANDOM_TICK_RANDOM.isValid() ? - new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); - - protected CropsTickingMethod() { - - } - - public static void register() { - // Calls the static initializer which registers the callback. - } - - public static void tick(LevelChunk levelChunk, int tickSpeed) { - INSTANCE.doTick(levelChunk, tickSpeed); - } - - protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); - - private static void onSettingsUpdate() { - CROPS_TO_GROW_CACHE = new HashSet<>(); - plugin.getSettings().getCropsToGrow().forEach(cropName -> { - Key key = Keys.ofMaterialAndData(cropName); - if (key instanceof MaterialKey materialKey) { - Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); - if (block != null && block.defaultBlockState().isRandomlyTicking()) - CROPS_TO_GROW_CACHE.add(block); - } - }); - } - - private static class PaperCropsTickingMethod extends CropsTickingMethod { - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - ServerLevel serverLevel = levelChunk.level; - LevelChunkSection[] sections = levelChunk.getSections(); - - int minSection = serverLevel.getMinSection(); - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - RandomSource randomTickRandom = SERVER_LEVEL_RANDOM_TICK_RANDOM.get(serverLevel); - - for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int tickingBlocks = levelChunkSection.tickingList.size(); - if (tickingBlocks <= 0) { - continue; - } - - int offsetY = (sectionIndex + minSection) << 4; - - for (int i = 0; i < tickSpeed; ++i) { - int index = randomTickRandom.nextInt(0x1000); - - if (index >= tickingBlocks) { - continue; - } - - long raw = levelChunkSection.tickingList.getRaw(index); - int location = com.destroystokyo.paper.util.maplist.IBlockDataList.getLocationFromRaw(raw); - BlockState blockState = com.destroystokyo.paper.util.maplist.IBlockDataList.getBlockDataFromRaw(raw); - if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) - continue; - - chunkTickMutablePosition.set((location & 15) | chunkOffsetX, - ((location >>> 8) & 255) | offsetY, - ((location >>> 4) & 15) | chunkOffsetZ); - - blockState.randomTick(serverLevel, chunkTickMutablePosition, randomTickRandom); - } - } - - } - - } - - private static class SpigotCropsTickingMethod extends CropsTickingMethod { - - private static int random = ThreadLocalRandom.current().nextInt(); - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - LevelChunkSection[] sections = levelChunk.getSections(); - ServerLevel serverLevel = levelChunk.level; - - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - - for (int i = 0; i < tickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { - chunkTickMutablePosition.set(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); - blockState.randomTick(serverLevel, chunkTickMutablePosition, serverLevel.getRandom()); - } - } - } - } - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/DragonUtils.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/DragonUtils.java deleted file mode 100644 index fc7b8806f5..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/DragonUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon; - -import com.bgsoftware.common.reflection.ReflectField; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; - -import java.lang.reflect.Modifier; - -public class DragonUtils { - - private static final ReflectField END_PODIUM_LOCATION = new ReflectField( - EndPodiumFeature.class, BlockPos.class, - Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static BlockPos currentPodiumPosition = BlockPos.ZERO; - - private DragonUtils() { - - } - - public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { - try { - END_PODIUM_LOCATION.set(null, podiumPosition); - currentPodiumPosition = podiumPosition; - runnable.run(); - } finally { - END_PODIUM_LOCATION.set(null, BlockPos.ZERO); - currentPodiumPosition = BlockPos.ZERO; - } - } - - public static BlockPos getCurrentPodiumPosition() { - return currentPodiumPosition; - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEndDragonFight.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEndDragonFight.java deleted file mode 100644 index e2d96c2ae3..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEndDragonFight.java +++ /dev/null @@ -1,211 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; -import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import net.minecraft.world.level.block.state.pattern.BlockPattern; -import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; -import net.minecraft.world.level.block.state.predicate.BlockPredicate; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -public class IslandEndDragonFight extends EndDragonFight { - - private static final ReflectField DRAGON_BATTLE = new ReflectField( - EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 4); - private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); - - private static final ReflectField TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>( - EndDragonFight.class, int.class, Modifier.PRIVATE, 4); - private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( - DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); - - private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") - .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") - .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) - .build(); - - private final Island island; - private final BlockPos islandBlockPos; - private final Vec3 islandBlockVectored; - private final ServerLevel serverLevel; - private final IslandEntityEnderDragon entityEnderDragon; - - private byte currentTick = 0; - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { - this(island, serverLevel, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), null); - } - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, - @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); - - this.island = island; - this.islandBlockPos = islandBlockPos; - this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); - this.serverLevel = serverLevel; - this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; - - SCAN_FOR_LEGACY_PORTALS.set(this, false); - WAS_DRAGON_KILLED.set(this, false); - DRAGON_BATTLE.set(this.entityEnderDragon, this); - - TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); - } - - @Override - public void tick() { - // doServerTick - - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); - - DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); - if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { - LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); - } - - if (++currentTick >= 20) { - updateBattlePlayers(); - currentTick = 0; - TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); - } - } - - @Nullable - @Override - public BlockPattern.BlockPatternMatch findExitPortal() { - int chunkX = this.islandBlockPos.getX() >> 4; - int chunkZ = this.islandBlockPos.getZ() >> 4; - - for (int x = -8; x <= 8; ++x) { - for (int z = -8; z <= 8; ++z) { - LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); - - for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { - if (blockEntity instanceof TheEndPortalBlockEntity) { - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( - this.serverLevel, blockEntity.getBlockPos()); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - } - } - - int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); - currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); - for (int y = highestBlock; y >= this.serverLevel.getMinBuildHeight(); --y) { - currentPosition.setY(y); - - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - - return null; - } - - @Override - public void resetSpikeCrystals() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); - } - - public void removeBattlePlayers() { - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - for (ServerPlayer serverPlayer : dragonEventPlayers) - this.dragonEvent.removePlayer(serverPlayer); - } - - public IslandEntityEnderDragon getEnderDragon() { - return this.entityEnderDragon; - } - - private void updateBattlePlayers() { - Set nearbyPlayers = new HashSet<>(); - - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - Player bukkitPlayer = superiorPlayer.asPlayer(); - if (bukkitPlayer != null) { - ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); - if (serverPlayer.serverLevel().equals(this.serverLevel)) { - this.dragonEvent.addPlayer(serverPlayer); - nearbyPlayers.add(serverPlayer.getUUID()); - } - } - } - - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - - dragonEventPlayers.stream() - .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) - .forEach(this.dragonEvent::removePlayer); - } - - private IslandEntityEnderDragon spawnEnderDragon() { - IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); - - entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); - entityEnderDragon.absMoveTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), - this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); - - this.serverLevel.addFreshEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); - - this.dragonUUID = entityEnderDragon.getUUID(); - this.resetSpikeCrystals(); - - return entityEnderDragon; - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java index 9fba3e662c..327be553fe 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/IslandEntityEnderDragon.java @@ -2,50 +2,25 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.config.SettingsManager; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; -import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftEnderDragon; -public class IslandEntityEnderDragon extends EnderDragon { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - @NotNull - public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { - return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : - new EnderDragon(entityTypes, level); - } - - private final ServerLevel serverLevel; - private final Dimension dimension; - private BlockPos islandBlockPos; +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { - this(level); - this.islandBlockPos = islandBlockPos; + super(level, islandBlockPos); } - private IslandEntityEnderDragon(Level level) { - super(EntityType.ENDER_DRAGON, level); - this.serverLevel = (ServerLevel) level; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + public IslandEntityEnderDragon(Level level) { + super(level); } - @Nullable + @javax.annotation.Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, @@ -64,40 +39,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { finalizeIslandEnderDragon(); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - - private void finalizeIslandEnderDragon() { - if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) - return; - - Island island; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); - } - - if (island == null) - return; - - Location middleBlock = island.getCenter(dimension); - - SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); - if (dimensionConfig instanceof SettingsManager.Worlds.End) { - middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); - } - - this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); - - IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); - } - } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/SpikesCache.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/SpikesCache.java deleted file mode 100644 index 3451687902..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/SpikesCache.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon; - - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.common.annotations.Nullable; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.CacheStats; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public class SpikesCache implements LoadingCache> { - - private static final SpikesCache INSTANCE = new SpikesCache(); - - private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() - .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); - - private long worldSeed; - - public static SpikesCache getInstance() { - return INSTANCE; - } - - private SpikesCache() { - - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - List getUnchecked(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public List apply(@NotNull Long worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void refresh(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ConcurrentMap> asMap() { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Nullable - @Override - public List getIfPresent(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed, - @NotNull Callable> loader) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAllPresent(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void put(@NotNull Long worldSeed, @NotNull List spikes) { - try { - this.worldSeed = worldSeed; - cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); - } finally { - this.worldSeed = 0; - } - } - - @Override - public void putAll(Map> spikesMap) { - spikesMap.forEach(this::put); - } - - @Override - public void invalidate(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll() { - this.cachedSpikes.invalidateAll(); - } - - @Override - public long size() { - return this.cachedSpikes.size(); - } - - @Override - public @NotNull - CacheStats stats() { - return this.cachedSpikes.stats(); - } - - @Override - public void cleanUp() { - this.cachedSpikes.cleanUp(); - } - - private class InternalCacheLoader extends CacheLoader> { - - @Override - public @NotNull - List load(@NotNull BlockPos blockPos) { - List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); - - Collections.shuffle(list, new Random(worldSeed)); - List spikesList = Lists.newArrayList(); - - for (int i = 0; i < 10; ++i) { - int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int l = list.get(i); - int radius = 2 + l / 3; - int height = 76 + l * 3; - boolean guarded = l == 1 || l == 2; - - spikesList.add(new SpikeFeature.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded)); - } - - return spikesList; - } - - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/generator/IslandsGeneratorImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/generator/IslandsGeneratorImpl.java deleted file mode 100644 index 2960df51ac..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/generator/IslandsGeneratorImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.generator; - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; -import org.bukkit.generator.WorldInfo; - -import java.util.Collections; -import java.util.List; -import java.util.Random; - -@SuppressWarnings({"unused", "NullableProblems"}) -public class IslandsGeneratorImpl extends IslandsGenerator { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private final Dimension dimension; - - public IslandsGeneratorImpl(Dimension dimension) { - this.dimension = dimension; - } - - @Override - public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, - @NotNull ChunkData chunkData) { - if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { - chunkData.setBlock(0, 99, 0, Material.BEDROCK); - } - } - - @Override - public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { - return new BiomeProvider() { - @Override - public @NotNull - Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { - return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension); - } - - @Override - public @NotNull - List getBiomes(@NotNull WorldInfo worldInfo) { - return IslandUtils.getDefaultWorldBiomes(); - } - - }; - } - - @Override - public List getDefaultPopulators(World world) { - return Collections.emptyList(); - } - - @Override - public Location getFixedSpawnLocation(World world, Random random) { - return new Location(world, 0, 100, 0); - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/hologram/EntityHologram.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/hologram/EntityHologram.java new file mode 100644 index 0000000000..99fe663b4d --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/hologram/EntityHologram.java @@ -0,0 +1,39 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.hologram; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_20_4.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuBrewingStandBlockEntity.java deleted file mode 100644 index 09d7474f4b..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuBrewingStandBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { - - private final InventoryHolder holder; - - public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuDispenserBlockEntity.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuDispenserBlockEntity.java deleted file mode 100644 index 93175aca34..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuDispenserBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.DispenserBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuDispenserBlockEntity extends DispenserBlockEntity { - - private final InventoryHolder holder; - - public MenuDispenserBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuFurnaceBlockEntity.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuFurnaceBlockEntity.java deleted file mode 100644 index 40397d3635..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/menu/MenuFurnaceBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.FurnaceBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { - - private final InventoryHolder holder; - - public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/player/OfflinePlayerDataImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/player/OfflinePlayerDataImpl.java deleted file mode 100644 index 1cf351f162..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/player/OfflinePlayerDataImpl.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.player; - -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; - -import java.util.Optional; - -public class OfflinePlayerDataImpl implements OfflinePlayerData { - - private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); - - private Player fakePlayer; - - public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { - return POOL.obtain().initialize(offlinePlayer); - } - - private OfflinePlayerDataImpl() { - - } - - private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), - Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return null; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - this.fakePlayer = serverPlayer.getBukkitEntity(); - this.fakePlayer.loadData(); - - return this; - } - - @Override - public Player getFakeOnlinePlayer() { - return this.fakePlayer; - } - - @Override - public void setLocation(Location location) { - ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); - serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); - serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - } - - @Override - public void applyChanges() { - this.fakePlayer.saveData(); - } - - @Override - public void release() { - this.fakePlayer = null; - POOL.release(this); - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/spawners/TickingSpawnerBlockEntityNotifier.java deleted file mode 100644 index f7abf99606..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/spawners/TickingSpawnerBlockEntityNotifier.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.spawners; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BaseSpawner; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -import java.util.function.IntFunction; - -public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { - - private final SpawnerBlockEntity spawnerBlockEntity; - private final TickingBlockEntity tickingBlockEntity; - private final IntFunction delayChangeCallback; - - public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, - IntFunction delayChangeCallback) { - this.spawnerBlockEntity = spawnerBlockEntity; - this.tickingBlockEntity = tickingBlockEntity; - this.delayChangeCallback = delayChangeCallback; - updateDelay(); - } - - @Override - public void tick() { - BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); - int startDelay = baseSpawner.spawnDelay; - try { - tickingBlockEntity.tick(); - } finally { - int newDelay = baseSpawner.spawnDelay; - if (newDelay > startDelay) - updateDelay(); - } - } - - @Override - public boolean isRemoved() { - return tickingBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return tickingBlockEntity.getPos(); - } - - @Override - public String getType() { - return tickingBlockEntity.getType(); - } - - public void updateDelay() { - BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); - baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..7bf65fe9b3 --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java @@ -0,0 +1,361 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.utils; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.utils.TickingBlockList; +import com.google.common.base.Suppliers; +import com.google.gson.JsonParseException; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.IOWorker; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +public class NMSUtilsVersioned { + + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( + EntityStorage.class, IOWorker.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { + return chunkMap.read(chunkPos).join().orElse(null); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { + return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), + chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException { + chunkMap.write(chunkPos, chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + IOWorker worker = ENTITY_STORAGE_WORKER.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + worker.loadAsync(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } else { + return BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + CompoundTag entityData = serverLevel.entityDataControllerNew.readData( + chunkPosition.getX(), chunkPosition.getZ()); + + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + return; + } + + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } catch (IOException error) { + countDownLatch.countDown(); + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + serverLevel.registryAccess().registryOrThrow(Registries.BIOME), + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.liquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess()); + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.relight(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + applySignTextLines(compoundTag, "front_text"); + applySignTextLines(compoundTag, "back_text"); + convertLegacySignTextLines(compoundTag); + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); + + Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + + chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(chunkAccess), + ChunkStatus.SURFACE, 0); + + chunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + } + + public static CompoundTag saveEntity(Entity entity) { + CompoundTag compoundTag = new CompoundTag(); + entity.save(compoundTag); + return compoundTag; + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.tickingList.size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.tickingList.getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { + if (blockEntityCompound.contains(key)) { + net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); + ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); + List textLines = new ArrayList<>(); + for (net.minecraft.nbt.Tag lineTag : messages) { + try { + textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); + } catch (JsonParseException error) { + textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); + } + } + + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); + } + } + + private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + + public static String getPropertyValue(Property property) { + return property.value(); + } + + public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.getDragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absMoveTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSection(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinBuildHeight(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxBuildHeight(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.setUnsaved(true); + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockEntityCache.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockEntityCache.java deleted file mode 100644 index 6753f01bca..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockEntityCache.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class BlockEntityCache { - - private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); - - private BlockEntityCache() { - - } - - public static String getBlockEntityId(BlockState blockState) { - return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { - for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - if (blockEntityType.isValid(blockState)) { - ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); - if (resourceLocation != null) - return resourceLocation.toString(); - } - } - - return ""; - }); - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java deleted file mode 100644 index f437e7886a..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/ChunkReaderImpl.java +++ /dev/null @@ -1,243 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.block.CraftBlockType; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.InventoryHolder; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class ChunkReaderImpl implements ChunkReader { - - private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - private static final byte[] FULL_LIGHT = new byte[2048]; - private static final byte[] EMPTY_LIGHT = new byte[2048]; - - static { - Arrays.fill(FULL_LIGHT, (byte) 0xFF); - } - - private final ServerLevel serverLevel; - private final int x; - private final int z; - - private final Map blockEntities = new HashMap<>(); - private final List entities = new LinkedList<>(); - private final PalettedContainerRO[] blockids; - private final byte[][] skylight; - private final byte[][] emitlight; - - public ChunkReaderImpl(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - - this.serverLevel = levelChunk.level; - ChunkPos chunkPos = levelChunk.getPos(); - this.x = chunkPos.x; - this.z = chunkPos.z; - - LevelChunkSection[] levelChunkSections = levelChunk.getSections(); - this.blockids = new PalettedContainerRO[levelChunkSections.length]; - this.skylight = new byte[levelChunkSections.length][]; - this.emitlight = new byte[levelChunkSections.length][]; - - LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); - - for (int i = 0; i < this.blockids.length; ++i) { - LevelChunkSection levelChunkSection = levelChunkSections[i]; - - this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); - - DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (skyLightArray == null) { - this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; - } else { - this.skylight[i] = new byte[2048]; - System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); - } - - DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (emitLightArray == null) { - this.emitlight[i] = EMPTY_LIGHT; - } else { - this.emitlight[i] = new byte[2048]; - System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); - } - } - - levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - InventoryHolder inventoryHolder = blockEntity.getOwner(); - if (inventoryHolder != null) - compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); - - blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); - }); - - for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) - entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); - } - - @Override - public int getX() { - return this.x; - } - - @Override - public int getZ() { - return this.z; - } - - @Override - public Material getType(int x, int y, int z) { - return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); - } - - @Override - public short getData(int x, int y, int z) { - return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); - } - - @Override - @Nullable - public CompoundTag getTileEntity(int x, int y, int z) { - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); - return this.blockEntities.get(blockPos); - } - } - - @Override - @Nullable - public CompoundTag readBlockStates(int x, int y, int z) { - BlockState blockState = getBlockState(x, y, z); - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = CompoundTag.of(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(int x, int y, int z) { - int off = (y & 15) << 7 | z << 3 | x >> 1; - int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; - } - - @Override - public void forEachEntity(EntityConsumer consumer) { - if (entities.isEmpty()) - return; - - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = wrapper.getHandle(); - for (CachedEntity cachedEntity : entities) { - location.setX(cachedEntity.x); - location.setY(cachedEntity.y); - location.setZ(cachedEntity.z); - location.setYaw(cachedEntity.yaw); - location.setPitch(cachedEntity.pitch); - consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); - } - } - } - - private BlockState getBlockState(int x, int y, int z) { - return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); - } - - private int getSectionIndex(int y) { - int sectionIndex = SectionPos.blockToSectionCoord(y); - return sectionIndex - this.serverLevel.getMinSection(); - } - - private int getSectionYFromSectionIndex(int index) { - return index + this.serverLevel.getMinSection(); - } - - private static class CachedEntity { - - private final double x; - private final double y; - private final double z; - private final float yaw; - private final float pitch; - private final EntityType entityType; - private final CompoundTag entityTag; - - CachedEntity(Entity entity) { - this.x = entity.getX(); - this.y = entity.getY(); - this.z = entity.getZ(); - this.yaw = entity.getBukkitYaw(); - this.pitch = entity.getXRot(); - this.entityType = entity.getBukkitEntity().getType(); - - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - - this.entityTag = CompoundTag.fromNBT(compoundTag); - } - - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/KeyBlocksCache.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/KeyBlocksCache.java deleted file mode 100644 index df45d7b9d2..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/KeyBlocksCache.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; - -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.level.block.Block; -import org.bukkit.Material; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class KeyBlocksCache { - - private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); - - private KeyBlocksCache() { - - } - - public static Key getBlockKey(Block block) { - return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { - Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); - }); - } - - public static void cacheAllBlocks() { - BuiltInRegistries.BLOCK.forEach(KeyBlocksCache::getBlockKey); - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/PropertiesMapper.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/PropertiesMapper.java deleted file mode 100644 index 8fd74d5d3b..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/PropertiesMapper.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; - -import com.bgsoftware.superiorskyblock.core.logging.Log; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.Property; - -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; - -public class PropertiesMapper { - - private static final Map> nameToProperty = new HashMap<>(); - private static final Map, String> propertyToName = new HashMap<>(); - - static { - Map fieldsToNames = new IdentityHashMap<>(); - - fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); - fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); - fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); - fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); - fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); - fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); - fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); - fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); - fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); - fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); - fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); - fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); - fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); - fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); - fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); - fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); - fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); - fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); - fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); - fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); - fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); - fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); - fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); - fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); - fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); - fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); - fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); - fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); - - try { - for (Field field : BlockStateProperties.class.getFields()) { - field.setAccessible(true); - Object value = field.get(null); - if (value instanceof Property) { - Property property = (Property) value; - register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); - } - } - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while loading properties mapper:"); - } - - } - - private static void register(String key, String fieldName, Property property) { - if (nameToProperty.containsKey(key)) { - Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); - } else { - nameToProperty.put(key, property); - propertyToName.put(property, key); - } - } - - public static Property getProperty(String name) { - return nameToProperty.get(name); - } - - public static String getPropertyName(Property property) { - return propertyToName.get(property); - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/PropertiesMapperVersioned.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..100b246fda --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/PropertiesMapperVersioned.java @@ -0,0 +1,17 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; + +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionDataImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionDataImpl.java deleted file mode 100644 index 8175642aec..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionDataImpl.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; - -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionDataImpl implements WorldEditSession.Data { - - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private final List> chunks = new LinkedList<>(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); - - public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, - List> blocksToUpdate, - List> blockEntities, - Set lightenChunks) { - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // Convert chunk data - Iterator> chunksIterator = chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); - int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); - WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); - - List> lights; - if (isStarLightInterface || chunkData.lights().isEmpty()) { - lights = Collections.emptyList(); - } else { - lights = new LinkedList<>(); - chunkData.lights().forEach(lightPosition -> { - lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, - lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, - null)); - }); - } - - PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), - chunkData.heightmaps(), lights); - - this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, - currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); - } - - // Convert blocksToUpdate - blocksToUpdate.forEach(blockToUpdate -> { - BlockPos blockPos = blockToUpdate.getKey(); - this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockToUpdate.getValue())); - }); - - // Convert blockEntities - blockEntities.forEach(blockEntity -> { - BlockPos blockPos = blockEntity.getKey(); - this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockEntity.getValue())); - }); - - // Convert lights - lightenChunks.forEach(lightPosition -> { - this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, - lightPosition.z - baseChunkPosZAxis, null)); - }); - } - - public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, - int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, - Long2ObjectMapView chunks) { - this.chunks.forEach(chunkDataPositioned -> { - long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, - baseChunkPosZAxis + chunkDataPositioned.zOffset); - - List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - chunkDataPositioned.object.lights.forEach(lightPositioned -> { - lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, - baseBlockPosYAxis + lightPositioned.yOffset, - baseBlockPosZAxis + lightPositioned.zOffset)); - }); - - chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, - chunkDataPositioned.object.heightmaps, lights)); - }); - } - - public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { - this.blocksToUpdate.forEach(blockToUpdatePositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, - baseBlockPosYAxis + blockToUpdatePositioned.yOffset, - baseBlockPosZAxis + blockToUpdatePositioned.zOffset); - blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); - }); - } - - public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { - this.blockEntities.forEach(blockEntityPositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, - baseBlockPosYAxis + blockEntityPositioned.yOffset, - baseBlockPosZAxis + blockEntityPositioned.zOffset); - blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); - }); - } - - public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { - this.lightenChunks.forEach(lightPositioned -> { - ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, - baseChunkPosZAxis + lightPositioned.zOffset); - lightenChunks.add(newPos); - }); - } - - private static class PositionedObject { - - private final int xOffset; - private final int yOffset; - private final int zOffset; - private final V object; - - PositionedObject(int xOffset, int zOffset, V object) { - this(xOffset, 0, zOffset, object); - } - - PositionedObject(int xOffset, int yOffset, int zOffset, V object) { - this.xOffset = xOffset; - this.yOffset = yOffset; - this.zOffset = zOffset; - this.object = object; - } - - } - - private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, - List> lights) { - } - -} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java deleted file mode 100644 index 3040645e92..0000000000 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/WorldEditSessionImpl.java +++ /dev/null @@ -1,486 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.google.common.base.Preconditions; -import com.google.gson.JsonParseException; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.HolderLookup; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.SignText; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.ticks.ProtoChunkTicks; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.generator.CustomChunkGenerator; -import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.generator.ChunkGenerator; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionImpl implements WorldEditSession { - - private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.starlight.common.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; - - private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - - private Dimension dimension; - private LevelHeightAccessor levelHeightAccessor; - - @Nullable - private ServerLevel serverLevel; - - public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { - return POOL.obtain().initialize(serverLevel); - } - - public static WorldEditSessionImpl obtain(Dimension dimension) { - return POOL.obtain().initialize(dimension); - } - - private WorldEditSessionImpl() { - } - - private WorldEditSessionImpl initialize(ServerLevel serverLevel) { - this.serverLevel = serverLevel; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); - this.levelHeightAccessor = serverLevel; - return this; - } - - private WorldEditSessionImpl initialize(Dimension dimension) { - DimensionType dimensionType = getDimensionTypeFromDimension(dimension); - this.serverLevel = null; - this.dimension = dimension; - this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); - return this; - } - - @Override - public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, - @Nullable CompoundTag blockEntityData) { - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - if (!isValidPosition(blockPos)) - return; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - blocksToUpdate.add(new Pair<>(blockPos, blockState)); - return; - } - - ChunkPos chunkPos = new ChunkPos(blockPos); - - if (blockEntityData != null) - blockEntities.add(new Pair<>(blockPos, blockEntityData)); - - ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); - - if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) - chunkData.lights.add(blockPos); - - LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - } - - @Override - public List getAffectedChunks() { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); - - if (chunks.isEmpty()) - return Collections.emptyList(); - - List chunkPositions = new LinkedList<>(); - World bukkitWorld = serverLevel.getWorld(); - LongIterator iterator = chunks.keyIterator(); - while (iterator.hasNext()) { - long chunkKey = iterator.next(); - int chunkX = (int) chunkKey; - int chunkZ = (int) (chunkKey >> 32); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); - } - return chunkPositions; - } - - @Override - public void applyBlocks(Chunk bukkitChunk) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); - - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); - ChunkPos chunkPos = levelChunk.getPos(); - - long chunkKey = chunkPos.toLong(); - ChunkData chunkData = this.chunks.remove(chunkKey); - - if (chunkData == null) - return; - - int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); - for (int i = 0; i < chunkSectionsCount; ++i) { - levelChunk.getSections()[i] = chunkData.chunkSections[i]; - } - - chunkData.heightmaps.forEach(((type, heightmap) -> { - levelChunk.setHeightmap(type, heightmap.getRawData()); - })); - - if (plugin.getSettings().isLightsUpdate()) { - if (isStarLightInterface) { - this.lightenChunks.add(chunkPos); - } else { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); - // Queues chunk light for this chunk. - threadedLevelLightEngine.lightChunk(levelChunk, false); - } - } - - levelChunk.setUnsaved(true); - } - - @Override - public void finish(Island island) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); - - // Update blocks - blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); - - // Update block entities - blockEntities.forEach(data -> { - net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); - if (blockEntityCompound != null) { - BlockPos blockPos = data.getKey(); - blockEntityCompound.putInt("x", blockPos.getX()); - blockEntityCompound.putInt("y", blockPos.getY()); - blockEntityCompound.putInt("z", blockPos.getZ()); - - applySignTextLines(blockEntityCompound, "front_text"); - applySignTextLines(blockEntityCompound, "back_text"); - convertLegacySignTextLines(blockEntityCompound); - - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.loadWithComponents(blockEntityCompound, MinecraftServer.getServer().registryAccess()); - } - }); - - if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - threadedLevelLightEngine.relight(lightenChunks, chunkCallback -> { - }, completeCallback -> { - }); - this.lightenChunks.clear(); - } - - release(); - } - - @Override - public Data readData(Location baseLocation) { - return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); - } - - @Override - public void applyData(Data data, Location baseLocation) { - WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // We need to transform all data to the new base location values - - dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, - baseBlockPosZAxis, this, this.chunks); - dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); - dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); - dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); - } - - @Override - public void release() { - this.chunks.clear(); - this.blocksToUpdate.clear(); - this.blockEntities.clear(); - this.lightenChunks.clear(); - this.serverLevel = null; - this.dimension = null; - this.levelHeightAccessor = null; - POOL.release(this); - } - - public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - return new ChunkData(chunkSections, heightmaps, lights); - } - - private boolean isValidPosition(BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); - } - - private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { - if (blockEntityCompound.contains(key)) { - net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); - ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); - List textLines = new ArrayList<>(); - for (net.minecraft.nbt.Tag lineTag : messages) { - try { - textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); - } catch (JsonParseException error) { - textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); - } - } - - while (textLines.size() < 4) - textLines.add(Component.empty()); - - Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); - - SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); - } - } - - private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { - Component[] signLines = new Component[4]; - Arrays.fill(signLines, Component.empty()); - boolean hasAnySignLines = false; - // We try to convert old text sign lines - for (int i = 1; i <= 4; ++i) { - if (blockEntityCompound.contains("SSB.Text" + i)) { - String signLine = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; - hasAnySignLines = true; - } - } else { - String signLine = blockEntityCompound.getString("Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromJSON(signLine); - hasAnySignLines = true; - } - } - } - - if (hasAnySignLines) { - SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); - } - } - - private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { - ResourceKey resourceKey; - switch (dimension.getEnvironment()) { - case NETHER -> resourceKey = LevelStem.NETHER; - case THE_END -> resourceKey = LevelStem.END; - default -> resourceKey = LevelStem.OVERWORLD; - } - HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); - return registry.getOrThrow(resourceKey).value().type().value(); - } - - public class ChunkData { - - private final LevelChunkSection[] chunkSections; - private final Map heightmaps; - private final List lights; - - private ChunkData(long chunkKey) { - this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), - isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); - ChunkPos chunkPos = new ChunkPos(chunkKey); - - Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); - - createChunkSections(biomesRegistry); - - ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); - - createHeightmaps(tempChunk); - if (serverLevel != null) - runCustomWorldGenerator(tempChunk); - } - - private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - this.chunkSections = chunkSections; - this.heightmaps = heightmaps; - this.lights = lights; - } - - public LevelChunkSection[] chunkSections() { - return this.chunkSections; - } - - public Map heightmaps() { - return this.heightmaps; - } - - public List lights() { - return this.lights; - } - - private void createChunkSections(Registry biomesRegistry) { - Holder biome = CraftBiome.bukkitToMinecraftHolder( - IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); - - for (int i = 0; i < this.chunkSections.length; ++i) { - PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), - biome, PalettedContainer.Strategy.SECTION_BIOMES); - PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - - this.chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); - } - } - - private void runCustomWorldGenerator(ProtoChunk tempChunk) { - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - - if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) - return; - - CustomChunkGenerator chunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), - bukkitGenerator); - - WorldGenRegion region = new WorldGenRegion(serverLevel, Collections.singletonList(tempChunk), - ChunkStatus.SURFACE, 0); - - chunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - tempChunk); - - // We want to copy the level chunk sections back - System.arraycopy(tempChunk.getSections(), 0, this.chunkSections, 0, this.chunkSections.length); - } - - private void createHeightmaps(ProtoChunk tempChunk) { - for (Heightmap.Types heightmapType : Heightmap.Types.values()) { - if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { - this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); - } - } - } - - } - - -} diff --git a/NMS/v1_21/properties b/NMS/v1_21/properties new file mode 100644 index 0000000000..9e52643419 --- /dev/null +++ b/NMS/v1_21/properties @@ -0,0 +1,7 @@ +NMS_VERSION=v1_21 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java index 4ff97dc30e..5e7fe03610 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java @@ -1,276 +1,30 @@ package com.bgsoftware.superiorskyblock.nms.v1_21; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; -import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; -import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_21.menu.MenuBrewingStandBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21.menu.MenuDispenserBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21.menu.MenuFurnaceBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21.menu.MenuHopperBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21.world.BlockEntityCache; -import com.bgsoftware.superiorskyblock.nms.v1_21.world.KeyBlocksCache; -import com.google.common.collect.Multimap; -import com.google.common.collect.MultimapBuilder; -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.TextReplacementConfig; -import net.minecraft.SharedConstants; -import net.minecraft.core.BlockPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.Container; -import net.minecraft.world.entity.item.FallingBlockEntity; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.attribute.Attribute; -import org.bukkit.attribute.AttributeModifier; -import org.bukkit.block.data.Ageable; -import org.bukkit.block.data.BlockData; -import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftFallingBlock; -import org.bukkit.craftbukkit.entity.CraftMinecart; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; -import org.bukkit.potion.PotionEffect; -import org.jetbrains.annotations.NotNull; -import java.util.EnumMap; import java.util.Locale; import java.util.Objects; -import java.util.Optional; -import java.util.function.BiFunction; -public class NMSAlgorithmsImpl implements NMSAlgorithms { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Multimap EMPTY_ATTRIBUTES_MAP = - MultimapBuilder.hashKeys().hashSetValues().build(); - - private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); - - static { - MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); - } - - private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { - @Override - public byte[] processClass(byte[] classBytes, String path) { - return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); - } - }; - - @Override - public void registerCommand(BukkitCommand command) { - ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); - } +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms { @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); } - @Override - public int getCombinedId(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return 0; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(wrapper.getHandle()); - } - return Block.getId(blockState); - } - - @Override - public int getCombinedId(Material material, byte data) { - BlockState blockState; - - if (data == 0) { - Block block = CraftMagicNumbers.getBlock(material); - if (block == null) - return -1; - blockState = block.defaultBlockState(); - } else { - blockState = CraftMagicNumbers.getBlock(material, data); - } - - return blockState == null ? -1 : Block.getId(blockState); - } - - @Override - public Optional getTileEntityIdFromCombinedId(int combinedId) { - BlockState blockState = Block.stateById(combinedId); - - if (!blockState.hasBlockEntity()) - return Optional.empty(); - - String id = BlockEntityCache.getBlockEntityId(blockState); - - return Text.isBlank(id) ? Optional.empty() : Optional.of(id); - } - - @Override - public int compareMaterials(Material o1, Material o2) { - int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); - int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); - return Integer.compare(firstMaterial, secondMaterial); - } - - @Override - public short getBlockDataValue(org.bukkit.block.BlockState blockState) { - BlockData blockData = blockState.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getBlockDataValue(org.bukkit.block.Block block) { - BlockData blockData = block.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getMaxBlockDataValue(Material material) { - if (!material.isBlock()) - return 0; - - BlockData blockData = Bukkit.createBlockData(material); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); - } - - @Override - public Key getBlockKey(int combinedId) { - Block block = Block.stateById(combinedId).getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { - AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); - Block block = minecart.getDisplayBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { - FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); - Block block = fallingBlock.getBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public void setCustomModel(ItemMeta itemMeta, int customModel) { - itemMeta.setCustomModelData(customModel); - } - - @Override - public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { - if (!potionMeta.hasCustomEffects()) - potionMeta.setColor(potionEffect.getType().getColor()); - potionMeta.addCustomEffect(potionEffect, true); - } - - @Override - public String getMinecraftKey(ItemStack itemStack) { - return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); - } - - @Override - public void makeItemGlow(ItemMeta itemMeta) { - itemMeta.setEnchantmentGlintOverride(true); - } - - @Nullable - @Override - public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { - MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); - return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); - } - - @Override - public int getMaxWorldSize() { - return Bukkit.getMaxWorldSize(); - } - - @Override - public double getCurrentTps() { - try { - return MinecraftServer.getServer().tps1.getAverage(); - } catch (Throwable error) { - //noinspection removal - return MinecraftServer.getServer().recentTps[0]; - } - } - - @Override - public int getDataVersion() { - return SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - } - - @Override - public ClassProcessor getClassProcessor() { - return CLASS_PROCESSOR; - } - - @Override - public void handlePaperChatRenderer(Object event) { - if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) - return; - - io.papermc.paper.chat.ChatRenderer originalRenderer = asyncChatEvent.renderer(); - asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); - } - - @Override - public void hideAttributes(ItemMeta itemMeta) { - itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); - } - - @Override - public void setItemModel(ItemMeta itemMeta, String itemModel) { - // Doesn't exist - } - @Override public void setRarity(ItemMeta itemMeta, String rarity) { itemMeta.setRarity(ItemRarity.valueOf(rarity)); @@ -294,42 +48,14 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } - private interface MenuCreator extends BiFunction { + @Override + public String getMinecraftKey(ItemStack itemStack) { + return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); } - private static class ChatRendererWrapper { - - private static final String MESSAGE_PLACEHOLDER = "{message}"; - private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = - net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); - - private final ChatRenderer renderer = new ChatRenderer() { - @Override - public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, - net.kyori.adventure.text.@NotNull Component sourceDisplayName, - net.kyori.adventure.text.@NotNull Component message, - @NotNull Audience viewer) { - String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer - .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); - Island island = superiorPlayer.getIsland(); - - return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( - Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) - .replaceText(TextReplacementConfig.builder() - .matchLiteral(MESSAGE_PLACEHOLDER) - .replacement(message) - .build()); - } - }; - - private final ChatRenderer originalRenderer; - - public ChatRendererWrapper(ChatRenderer originalRenderer) { - this.originalRenderer = originalRenderer; - } - + @Override + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.setEnchantmentGlintOverride(true); } } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java index d64e69653d..1d7ad80e16 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java @@ -1,25 +1,17 @@ package com.bgsoftware.superiorskyblock.nms.v1_21; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; -import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_21.crops.CropsBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21.crops.CropsTickingMethod; -import com.bgsoftware.superiorskyblock.nms.v1_21.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -38,20 +30,14 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.BitStorage; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -59,48 +45,30 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import net.minecraft.world.phys.AABB; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.entity.CraftEntityType; import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; -import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; -import java.util.Objects; import java.util.concurrent.CompletableFuture; -public class NMSChunksImpl implements NMSChunks { - - private final SuperiorSkyblockPlugin plugin; +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - KeyBlocksCache.cacheAllBlocks(); - CropsTickingMethod.register(); + super(plugin); } @Override - public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, - Collection playersToUpdate) { - if (chunkPositions.isEmpty()) - return; - - Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.SET_BIOME, false) { + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); @@ -118,7 +86,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null); + levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); @@ -129,9 +97,11 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), @@ -144,7 +114,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); @@ -154,19 +124,12 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { // Do nothing. } - }); + }; } @Override - public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { - if (chunkPositions.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), - chunkPosition.getX(), chunkPosition.getZ(), false)); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.DELETE_CHUNK, false) { + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().registryOrThrow(Registries.BIOME); @@ -183,6 +146,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( @@ -193,8 +157,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - unloadedChunkCompound.setEntities(new ListTag()); - unloadedChunkCompound.setBlockEntities(tileEntities); + chunkCompound.put("entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, @@ -202,18 +166,19 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { - NMSUtils.buildSurfaceForChunk(serverLevel, protoChunk); + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); + Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), @@ -259,7 +224,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound tileEntities.add(blockEntityCompound); } - unloadedChunkCompound.setSections(sectionsList); + chunkCompound.put("sections", sectionsList); } } @@ -268,34 +233,14 @@ public void onFinish() { if (onFinish != null) onFinish.run(); } - }); + }; } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); - List chunkPositionsToCalculate = new LinkedList<>(); - - Iterator chunkPositionsIterator = chunkPositions.iterator(); - while (chunkPositionsIterator.hasNext()) { - ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); - if (cachedCalculatedChunk != null) { - allCalculatedChunks.add(cachedCalculatedChunk); - chunkPositionsIterator.remove(); - } else { - chunkPositionsToCalculate.add(chunkPosition); - } - } - - if (chunkPositions.isEmpty()) - return CompletableFuture.completedFuture(allCalculatedChunks); - - CompletableFuture> completableFuture = new CompletableFuture<>(); - - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( - ChunkLoadReason.BLOCKS_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -309,6 +254,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().registryOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( @@ -326,36 +272,36 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { - PalettedContainer blocksDataPalette; + PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); - blocksDataPalette = dataResult.getOrThrow(); + blocksPalettedContainer = dataResult.getOrThrow(); } else { - blocksDataPalette = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } - PalettedContainer> biomesDataPalette; + PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); - biomesDataPalette = dataResult.getOrThrow(); + biomesPalettedContainer = dataResult.getOrThrow(); } else { - biomesDataPalette = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } - chunkSections[sectionIndex] = new LevelChunkSection(blocksDataPalette, biomesDataPalette); + chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } @@ -371,20 +317,14 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { completableFuture.complete(allCalculatedChunks); } - }); - - return completableFuture; + }; } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); - - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - List unloadedChunkCompounds = new LinkedList<>(); - - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( - ChunkLoadReason.ENTITIES_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { @@ -407,8 +347,9 @@ public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - for (Tag entityTag : unloadedChunkCompound.getEntities()) { + for (Tag entityTag : chunkCompound.getList("entities", 10)) { EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); if (entityType == null) continue; @@ -420,7 +361,9 @@ public void onFinish() { continue; } - Key entityKey = Keys.of(CraftEntityType.minecraftToBukkit(entityType)); + Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( + CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); + chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); } } @@ -428,161 +371,17 @@ public void onFinish() { completableFuture.complete(chunkEntities); }); } - }); - - return completableFuture; - } - - @Override - public void injectChunkSections(Chunk chunk) { - // No implementation - } - - @Override - public boolean isChunkEmpty(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> - chunkSection == null || chunkSection.hasOnlyAir()); - } - - @Override - public Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); - return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; - } - - @Override - public void startTickingChunk(Island island, Chunk chunk, boolean stop) { - if (plugin.getSettings().getCropsInterval() <= 0) - return; - - if (stop) { - CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); - if (cropsBlockEntity != null) - cropsBlockEntity.remove(); - } else { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - CropsBlockEntity.create(island, levelChunk); - } - } - - @Override - public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { - if (chunkPositions.isEmpty()) return; - CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> - cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); - } - - @Override - public void shutdown() { - List> pendingTasks = NMSUtils.getPendingChunkActions(); - - if (pendingTasks.isEmpty()) - return; - - Log.info("Waiting for chunk tasks to complete."); - - CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); - } - - @Override - public List getBlockEntities(Chunk chunk) { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - List blockEntities = new LinkedList<>(); - - World bukkitWorld = chunk.getWorld(); - - levelChunk.getBlockEntities().keySet().forEach(blockPos -> - blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); - - return blockEntities; - } - - private static final ReflectField PALETTED_CONTAINER_DATA = new ReflectField<>( - PalettedContainer.class, Object.class, "d"); - - private static final ReflectField PALETTED_CONTAINER_DATA_STORAGE = new ReflectField<>( - PalettedContainer.class, BitStorage.class, "b"); - - private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { - KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); - List spawnersLocations = new LinkedList<>(); - - for (int i = 0; i < chunkSections.length; ++i) { - LevelChunkSection levelChunkSection = chunkSections[i]; - if (levelChunkSection != null && !levelChunkSection.hasOnlyAir()) { - int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4; - for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { - BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, - sectionBottomY, blockCounts, spawnersLocations); - } - } - } - - return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); - } - - private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, - int sectionBottomY, KeyMap blockCounts, - List spawnersLocations) { - Block block = blockState.getBlock(); - - if (block == Blocks.AIR) - return; - - Location location = new Location(chunkPosition.getWorld(), - (chunkPosition.getX() << 4) + x, - sectionBottomY + y, - (chunkPosition.getZ() << 4) + z); - - int blockAmount = 1; - - if (NMSUtils.isDoubleBlock(block, blockState)) { - blockAmount = 2; - blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); - } - - Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); - blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); - if (block == Blocks.SPAWNER) { - spawnersLocations.add(location); - } - } - - private static void removeEntities(ChunkAccess chunk) { - ChunkPos chunkPos = chunk.getPos(); - ServerLevel serverLevel = ((LevelChunk) chunk).level; - - int chunkWorldCoordX = chunkPos.x << 4; - int chunkWorldCoordZ = chunkPos.z << 4; - - AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinBuildHeight(), chunkWorldCoordZ, - chunkWorldCoordX + 15, serverLevel.getMaxBuildHeight(), chunkWorldCoordZ + 15); - - List worldEntities = new LinkedList<>(); - serverLevel.getEntities().get(chunkBounds, worldEntities::add); - - worldEntities.forEach(nmsEntity -> { - if (!(nmsEntity instanceof Player)) - nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); - }); - } - - private static void removeBlockEntities(ChunkAccess chunk) { - chunk.blockEntities.values().forEach(BlockEntity::setRemoved); - chunk.blockEntities.clear(); + }; } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { - NMSUtils.buildSurfaceForChunk(serverLevel, chunk); - } + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; + + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSDragonFightImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSDragonFightImpl.java deleted file mode 100644 index 14ddfe1921..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSDragonFightImpl.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_21.dragon.EndWorldEndDragonFightHandler; -import com.bgsoftware.superiorskyblock.nms.v1_21.dragon.IslandEndDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_21.dragon.IslandEntityEnderDragon; -import com.bgsoftware.superiorskyblock.nms.v1_21.dragon.SpikesCache; -import com.google.common.cache.LoadingCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.advancement.Advancement; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.entity.Player; - -import java.lang.reflect.Modifier; -import java.util.List; - -public class NMSDragonFightImpl implements NMSDragonFight { - - private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( - EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField<>( - ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE, 1); - - private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( - SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static boolean firstWorldPreparation = true; - - static { - ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); - } - - @Override - public void prepareEndWorld(World bukkitWorld) { - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); - - if (firstWorldPreparation) { - firstWorldPreparation = false; - SPIKE_CACHE.set(null, SpikesCache.getInstance()); - } - } - - @Nullable - @Override - public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return null; - - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); - return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); - } - - @Override - public void startDragonBattle(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); - } - - @Override - public void removeDragonBattle(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); - - if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { - islandEndDragonFight.removeBattlePlayers(); - islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); - } - } - - @Override - public void awardTheEndAchievement(Player player) { - Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); - if (advancement != null) - player.getAdvancementProgress(advancement).awardCriteria(""); - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSEntitiesImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSEntitiesImpl.java index e36a9e15d2..a557b9880d 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSEntitiesImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSEntitiesImpl.java @@ -1,53 +1,25 @@ package com.bgsoftware.superiorskyblock.nms.v1_21; -import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; import net.minecraft.world.item.Items; import net.minecraft.world.item.crafting.Ingredient; -import org.bukkit.Material; -import org.bukkit.craftbukkit.entity.CraftAnimals; -import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; -import org.bukkit.entity.Animals; import org.bukkit.entity.minecart.PoweredMinecart; -import org.bukkit.inventory.EntityEquipment; -import org.bukkit.inventory.ItemStack; -public class NMSEntitiesImpl implements NMSEntities { +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSEntities { private static final Ingredient MINECART_FURNACE_INGREDIENT = Ingredient.of(Items.COAL, Items.CHARCOAL); @Override - public ItemStack[] getEquipment(EntityEquipment entityEquipment) { - ItemStack[] itemStacks = new ItemStack[7]; - - itemStacks[0] = new ItemStack(Material.ARMOR_STAND); - itemStacks[1] = entityEquipment.getItemInMainHand(); - itemStacks[2] = entityEquipment.getItemInOffHand(); - itemStacks[3] = entityEquipment.getHelmet(); - itemStacks[4] = entityEquipment.getChestplate(); - itemStacks[5] = entityEquipment.getLeggings(); - itemStacks[6] = entityEquipment.getBoots(); - - return itemStacks; - } - - @Override - public boolean isAnimalFood(ItemStack itemStack, Animals animals) { - return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); - } - - @Override - public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && MINECART_FURNACE_INGREDIENT.test(CraftItemStack.asNMSCopy(bukkitItem)); } @Override - public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); + protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSHologramsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSHologramsImpl.java deleted file mode 100644 index f36cbe204f..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSHologramsImpl.java +++ /dev/null @@ -1,193 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21; - -import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; -import com.bgsoftware.superiorskyblock.nms.NMSHolograms; -import com.google.common.base.Preconditions; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftArmorStand; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.entity.Entity; - -@SuppressWarnings("unused") -public class NMSHologramsImpl implements NMSHolograms { - - @Override - public Hologram createHologram(Location location) { - Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); - serverLevel.addFreshEntity(entityHologram); - return entityHologram; - } - - @Override - public boolean isHologram(Entity entity) { - return ((CraftEntity) entity).getHandle() instanceof Hologram; - } - - public static class EntityHologram extends ArmorStand implements Hologram { - - private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); - - private CraftEntity bukkitEntity; - - EntityHologram(ServerLevel serverLevel, double x, double y, double z) { - super(serverLevel, x, y, z); - - setInvisible(true); - setSmall(true); - setShowArms(false); - setNoGravity(true); - setNoBasePlate(true); - setMarker(true); - forceSetBoundingBox(EMPTY_BOUND); - - super.collides = false; - super.setCustomNameVisible(true); - } - - @Override - public void setHologramName(String name) { - super.setCustomName(CraftChatMessage.fromStringOrNull(name)); - } - - @Override - public void removeHologram() { - super.remove(RemovalReason.DISCARDED); - } - - @Override - public org.bukkit.entity.ArmorStand getHandle() { - return this.getBukkitEntity(); - } - - @Override - public void inactiveTick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - @Override - public boolean repositionEntityAfterLoad() { - return false; - } - - @Override - public AABB getBoundingBoxForCulling() { - return EMPTY_BOUND; - } - - @Override - public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { - // Prevent stand being equipped - } - - @Override - public void addAdditionalSaveData(CompoundTag compoundTag) { - // Do not save NBT. - } - - @Override - public void readAdditionalSaveData(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { - // Prevent stand being equipped - return InteractionResult.PASS; - } - - @Override - public void tick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - public void forceSetBoundingBox(AABB boundingBox) { - super.setBoundingBox(boundingBox); - } - - @Override - public CraftArmorStand getBukkitEntity() { - if (bukkitEntity == null) { - bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); - } - return (CraftArmorStand) bukkitEntity; - } - - @Override - public void remove(RemovalReason removalReason) { - // Prevent being killed. - } - - @Override - public void playSound(SoundEvent soundEvent, float volume, float pitch) { - // Remove sounds. - } - - @Override - public boolean saveAsPassenger(CompoundTag compoundTag) { - // Do not save NBT. - return false; - } - - @Override - public CompoundTag saveWithoutId(CompoundTag compoundTag) { - // Do not save NBT. - return compoundTag; - } - - @Override - public void load(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public boolean isInvulnerableTo(DamageSource damageSource) { - /* - * The field Entity.invulnerable is private. - * It's only used while saving NBTTags, but since the entity would be killed - * on chunk unload, we prefer to override isInvulnerable(). - */ - return true; - } - - @Override - public void setCustomName(Component component) { - // Locks the custom name. - } - - @Override - public void setCustomNameVisible(boolean isCustomNameVisible) { - // Locks the custom name. - } - - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSPlayersImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSPlayersImpl.java deleted file mode 100644 index 625b905c3c..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSPlayersImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.nms.NMSPlayers; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.bgsoftware.superiorskyblock.nms.v1_21.player.OfflinePlayerDataImpl; -import com.bgsoftware.superiorskyblock.player.PlayerLocales; -import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.level.ServerPlayer; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Item; -import org.bukkit.entity.Player; - -import java.util.Locale; - -public class NMSPlayersImpl implements NMSPlayers { - - private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - - @Override - public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { - return OfflinePlayerDataImpl.create(offlinePlayer); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer) { - Player player = superiorPlayer.asPlayer(); - - if (player == null) - return; - - ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() - .ifPresent(property -> setSkinTexture(superiorPlayer, property)); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { - superiorPlayer.setTextureValue(property.value()); - } - - @SuppressWarnings("deprecation") - @Override - public void sendActionBar(Player player, String message) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); - } - - @Override - public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { - BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); - bossBar.addPlayer(player); - return bossBar; - } - - @SuppressWarnings("deprecation") - @Override - public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { - player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); - } - - @Override - public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { - return superiorPlayer.getUniqueId().equals(item.getThrower()); - } - - @Nullable - @Override - public Locale getPlayerLocale(Player player) { - if (PLAYER_LOCALE.isValid()) { - return player.locale(); - } else try { - //noinspection deprecation - return PlayerLocales.getLocale(player.getLocale()); - } catch (IllegalArgumentException error) { - return null; - } - } - - private static class BossBarImpl implements BossBar { - - private final org.bukkit.boss.BossBar bossBar; - private final BossBarTask bossBarTask; - - public BossBarImpl(String message, BarColor color, double ticksToRun) { - bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); - this.bossBarTask = BossBarTask.create(this, ticksToRun); - } - - @Override - public void addPlayer(Player player) { - this.bossBar.addPlayer(player); - this.bossBarTask.registerTask(player); - } - - @Override - public void removeAll() { - this.bossBar.removeAll(); - this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); - } - - @Override - public void setProgress(double progress) { - this.bossBar.setProgress(progress); - } - - @Override - public double getProgress() { - return this.bossBar.getProgress(); - } - - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java index bc39b97ada..004a790970 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java @@ -1,85 +1,27 @@ package com.bgsoftware.superiorskyblock.nms.v1_21; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.ListTag; -import com.bgsoftware.superiorskyblock.tag.Tag; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; -import com.mojang.serialization.Dynamic; -import net.minecraft.SharedConstants; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; -import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.util.Optional; import java.util.Set; -@SuppressWarnings({"unused"}) -public class NMSTagsImpl implements NMSTags { - - @Override - public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) - itemStack.save(MinecraftServer.getServer().registryAccess()); - tagCompound.putInt("DataVersion", SharedConstants.getCurrentVersion().getDataVersion().getVersion()); - - return CompoundTag.fromNBT(tagCompound); - } - - @Override - public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { - if (compoundTag.containsKey("NBT")) { - // Old compound version, deserialize it accordingly - return deserializeItemOld(compoundTag); - } - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); - - int currentVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - int itemVersion = tagCompound.getInt("DataVersion"); - if (itemVersion < currentVersion) { - tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, - new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); - } - - ItemStack itemStack = ItemStack.parse(MinecraftServer.getServer().registryAccess(), tagCompound).orElseThrow(); - - return CraftItemStack.asCraftMirror(itemStack); - } - - private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); - Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount").orElse(0); - short data = (short) compoundTag.getShort("data").orElse(0); - CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); - - org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - if (nbtData != null) - itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); - - return CraftItemStack.asCraftMirror(itemStack); - } +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSTags { @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { @@ -96,18 +38,30 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I } @Override - @SuppressWarnings("ConstantConditions") - public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { - net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) + itemStack.save(MinecraftServer.getServer().registryAccess()); + tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + return CompoundTag.fromNBT(tagCompound); + } + + @Override + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; + } - if (compoundTag == null) - compoundTag = new net.minecraft.nbt.CompoundTag(); + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow(); + } - if (!compoundTag.contains("id")) - //noinspection deprecation - compoundTag.putString("id", entityType.getName()); + @Override + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); + } - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; @@ -169,29 +123,4 @@ public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } - @Override - public Object parseList(ListTag listTag) { - net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); - - for (Tag tag : listTag) - nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); - - return nbtTagList; - } - - @Override - public Object getNBTCompoundTag(Object object, String key) { - return ((net.minecraft.nbt.CompoundTag) object).get(key); - } - - @Override - public void setNBTCompoundTagValue(Object object, String key, Object value) { - ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); - } - - @Override - public int getNBTTagListSize(Object object) { - return ((net.minecraft.nbt.ListTag) object).size(); - } - } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java deleted file mode 100644 index 10a7713b6f..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSUtils.java +++ /dev/null @@ -1,528 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.nms.v1_21.world.PropertiesMapper; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; -import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; -import com.google.common.base.Suppliers; -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkPyramid; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.chunk.status.ChunkStep; -import net.minecraft.world.level.chunk.storage.EntityStorage; -import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.generator.CustomChunkGenerator; - -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; - -public class NMSUtils { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( - ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); - private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( - ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); - private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( - EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); - - private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); - - public static final ObjectsPool> BLOCK_POS_POOL = - ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); - - private NMSUtils() { - - } - - @Nullable - public static T getBlockEntityAt(Location location, Class type) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); - } - } - - public static void runActionOnEntityChunks(Collection chunksCoords, - ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); - } - - public static void runActionOnChunks(Collection chunksCoords, - boolean saveChunks, ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); - } - - private static void runActionOnChunksInternal(Collection chunksCoords, - ChunkCallback chunkCallback, - Consumer> onUnloadChunkAction) { - List unloadedChunks = new LinkedList<>(); - List loadedChunks = new LinkedList<>(); - - chunksCoords.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - ChunkAccess chunkAccess; - - try { - chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); - } catch (Throwable ex) { - chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); - } - - if (chunkAccess instanceof LevelChunk levelChunk) { - loadedChunks.add(levelChunk); - } else { - unloadedChunks.add(chunkPosition.copy()); - } - }); - - boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); - - if (!loadedChunks.isEmpty()) - runActionOnLoadedChunks(loadedChunks, chunkCallback); - - if (hasUnloadedChunks) { - onUnloadChunkAction.accept(unloadedChunks); - } else { - chunkCallback.onFinish(); - } - } - - private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { - chunks.forEach(chunkCallback::onLoadedChunk); - } - - private static void runActionOnUnloadedChunks(Collection chunks, - boolean saveChunks, ChunkCallback chunkCallback) { - if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { - Iterator chunksIterator = chunks.iterator(); - while (chunksIterator.hasNext()) { - ChunkPosition chunkPosition = chunksIterator.next(); - - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( - chunkPosition.getX(), chunkPosition.getZ()); - - if (cachedUnloadedChunk != null) { - chunkCallback.onLoadedChunk(cachedUnloadedChunk); - chunksIterator.remove(); - } - } - - if (chunks.isEmpty()) { - chunkCallback.onFinish(); - return; - } - } - - CompletableFuture pendingTask = new CompletableFuture<>(); - PENDING_CHUNK_ACTIONS.add(pendingTask); - - BukkitExecutor.createTask().runAsync(v -> { - CountDownLatch countDownLatch; - if (chunkCallback.isWaitForChunkLoad) { - countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - } else { - countDownLatch = null; - } - - List chunkCompounds = new LinkedList<>(); - - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - boolean calledCountdown = false; - try { - net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); - - if (chunkCompound == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), - Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, - Optional.empty(), chunkPos, serverLevel); - - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - calledCountdown = true; - - if (saveChunks) - chunkCompounds.add(unloadedChunkCompound); - } catch (Exception error) { - if (!calledCountdown && countDownLatch != null) - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - if (countDownLatch != null) { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - } - - return chunkCompounds; - }).runSync(chunkCompounds -> { - chunkCompounds.forEach(unloadedChunkCompound -> { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = unloadedChunkCompound.chunkPos(); - - try { - chunkMap.write(chunkPos, unloadedChunkCompound.chunkCompound); - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); - } - }); - - chunkCallback.onFinish(); - - pendingTask.complete(null); - PENDING_CHUNK_ACTIONS.remove(pendingTask); - }); - } - - private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); - SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { - if (error != null) { - countDownLatch.countDown(); - throw new RuntimeException(error); - } else { - net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - } else { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } - } - }); - }); - - BukkitExecutor.createTask().runAsync(v -> { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } else { - BukkitExecutor.createTask().runAsync(v -> { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - try { - net.minecraft.nbt.CompoundTag entityData = serverLevel.moonrise$getEntityChunkDataController() - .readData(chunkPosition.getX(), chunkPosition.getZ()); - - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } catch (IOException error) { - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } - } - - public static List> getPendingChunkActions() { - return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); - } - - public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { - return new ProtoChunk(chunkPos, - UpgradeData.EMPTY, - serverLevel, - serverLevel.registryAccess().registryOrThrow(Registries.BIOME), - null); - } - - public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { - ServerLevel serverLevel = levelChunk.level; - - if (!isValidPosition(serverLevel, blockPos)) - return null; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - serverLevel.setBlock(blockPos, blockState, 3); - return blockState; - } - - int indexY = serverLevel.getSectionIndex(blockPos.getY()); - - LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - boolean isOriginallyChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - - levelChunk.setUnsaved(true); - - boolean isChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) - serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); - - serverLevel.getLightEngine().checkBlock(blockPos); - - if (tileEntity != null) { - net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); - if (tileEntityCompound != null) { - tileEntityCompound.putInt("x", blockPos.getX()); - tileEntityCompound.putInt("y", blockPos.getY()); - tileEntityCompound.putInt("z", blockPos.getZ()); - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.loadWithComponents(tileEntityCompound, MinecraftServer.getServer().registryAccess()); - } - } - - return blockState; - } - - public static boolean isDoubleBlock(Block block, BlockState blockState) { - return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && - blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; - } - - @Nullable - public static LevelChunk getCraftChunkHandle(CraftChunk craftChunk) { - ServerLevel serverLevel = craftChunk.getCraftWorld().getHandle(); - LevelChunk loadedChunk = serverLevel.getChunkIfLoaded(craftChunk.getX(), craftChunk.getZ()); - if (loadedChunk != null) - return loadedChunk; - - return (LevelChunk) serverLevel.getChunk(craftChunk.getX(), craftChunk.getZ(), ChunkStatus.FULL, true); - } - - public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkAccess chunkAccess) { - CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), serverLevel.generator); - - ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); - - // Unsafe: we do not provide chunks cache, even tho it is required. - // Should be fine in normal flow, as the only method that access the chunsk cache - // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: - // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 - WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); - - customChunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - chunkAccess); - } - - public record UnloadedChunkCompound(ChunkPosition chunkPosition, - net.minecraft.nbt.CompoundTag chunkCompound) { - - public ListTag getSections() { - return chunkCompound.getList("sections", 10); - } - - public ListTag getEntities() { - return chunkCompound.getList("Entities", 10); - } - - public void setSections(ListTag sectionsList) { - chunkCompound.put("sections", sectionsList); - } - - public void setEntities(ListTag entitiesList) { - chunkCompound.put("entities", entitiesList); - } - - public void setBlockEntities(ListTag blockEntitiesList) { - chunkCompound.put("block_entities", blockEntitiesList); - } - - public ServerLevel serverLevel() { - return ((CraftWorld) chunkPosition.getWorld()).getHandle(); - } - - public ChunkPos chunkPos() { - return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - } - - } - - private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinBuildHeight() && blockPos.getY() < serverLevel.getMaxBuildHeight(); - } - - public static abstract class ChunkCallback { - - private final ChunkLoadReason chunkLoadReason; - private final boolean isWaitForChunkLoad; - - @Nullable - protected CountDownLatch chunkLoadLatch; - - public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { - this.chunkLoadReason = chunkLoadReason; - this.isWaitForChunkLoad = isWaitForChunkLoad; - } - - public abstract void onLoadedChunk(LevelChunk levelChunk); - - public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - - public abstract void onFinish(); - - protected final void latchCountDown() { - if (this.chunkLoadLatch != null) - this.chunkLoadLatch.countDown(); - } - - public final void onChunkNotExist(ChunkPosition chunkPosition) { - if (!plugin.getProviders().hasCustomWorldsSupport()) - return; - - ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { - LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); - }); - } - - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index 42971f4c84..615e9550af 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -3,131 +3,57 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; -import com.bgsoftware.superiorskyblock.nms.ICachedBlock; -import com.bgsoftware.superiorskyblock.nms.NMSWorld; -import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; -import com.bgsoftware.superiorskyblock.nms.v1_21.generator.IslandsGeneratorImpl; -import com.bgsoftware.superiorskyblock.nms.v1_21.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21.vibration.IslandVibrationUser; -import com.bgsoftware.superiorskyblock.nms.v1_21.world.ChunkReaderImpl; -import com.bgsoftware.superiorskyblock.nms.v1_21.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_21.world.WorldEditSessionImpl; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.destroystokyo.paper.antixray.ChunkPacketBlockController; -import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.BubbleColumn; import org.bukkit.block.data.type.HangingSign; -import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.WallHangingSign; -import org.bukkit.block.data.type.WallSign; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.block.CraftBlock; -import org.bukkit.craftbukkit.block.CraftBlockState; -import org.bukkit.craftbukkit.block.CraftSign; -import org.bukkit.craftbukkit.block.data.CraftBlockData; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.function.IntFunction; -public class NMSWorldImpl implements NMSWorld { +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); - private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, - Object.class, "chunkPacketBlockController") - .removeFinal(); - - private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); } @Override - public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { - Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); - Location location = new Location( - Bukkit.getWorld(chunkSnapshot.getWorldName()), - (chunkSnapshot.getX() << 4) + x, - y, - (chunkSnapshot.getZ() << 4) + z - ); - - return Keys.of(KeyBlocksCache.getBlockKey(block), location); + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); } @Override - public void listenSpawner(Location location, IntFunction delayChangeCallback) { - SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); - if (spawnerBlockEntity == null) + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; - ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - - List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? - LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; - - Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new LinkedList<>(); - - while (blockEntityTickersIterator.hasNext()) { - TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && - !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { - blockEntityTickersIterator.remove(); - tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); - } - } + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } - if (!tickersToAdd.isEmpty()) - blockEntityTickers.addAll(tickersToAdd); + @Override + public SignType getSignType(Object sign) { + if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return super.getSignType(sign); } @Override @@ -174,263 +100,4 @@ public void replaceTrialBlockPlayerDetector(Island island, Location location) { } } - @Override - public void replaceSculkSensorListener(Island island, Location location) { - SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); - if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) - return; - - SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); - } - - @Override - public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { - if (!plugin.getSettings().isWorldBorders()) - return; - - Player player = superiorPlayer.asPlayer(); - World world = superiorPlayer.getWorld(); - - if (world == null || player == null) - return; - - int islandSize = island == null ? 0 : island.getIslandSize(); - - boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; - - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - - WorldBorder worldBorder; - - if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { - worldBorder = serverLevel.getWorldBorder(); - } else { - Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); - if (dimension == null) - return; - - Location center = island.getCenter(dimension); - - worldBorder = new WorldBorder(); - worldBorder.world = serverLevel; - worldBorder.setWarningBlocks(0); - worldBorder.setCenter(center.getX(), center.getZ()); - - switch (superiorPlayer.getBorderColor()) { - case BLUE -> { - worldBorder.setSize((islandSize * 2) + 1D); - } - case GREEN -> { - worldBorder.setSize((islandSize * 2) + 1.001D); - worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); - } - case RED -> { - worldBorder.setSize((islandSize * 2) + 1D); - worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); - } - } - } - - ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); - ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); - } - - @Override - public Object getBlockData(org.bukkit.block.Block block) { - return block.getBlockData(); - } - - @Override - public void setBlock(Location location, int combinedId) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - BlockState blockState = - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - - if (blockState != null) { - serverLevel.getChunkSource().blockChanged(blockPos); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); - } - } - } - } - - @Override - public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return NMSCachedBlock.obtain(block); - } - - @Override - public boolean isWaterLogged(org.bukkit.block.Block block) { - if (Materials.isWater(block.getType())) - return true; - - BlockData blockData = block.getBlockData(); - - return blockData instanceof BubbleColumn || - (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); - } - - @Override - public SignType getSignType(Object sign) { - if (sign instanceof WallSign) - return SignType.WALL_SIGN; - else if (sign instanceof Sign) - return SignType.STANDING_SIGN; - else if (sign instanceof HangingSign) - return SignType.HANGING_SIGN; - else if (sign instanceof WallHangingSign) - return SignType.HANGING_WALL_SIGN; - else - return SignType.UNKNOWN; - } - - @Override - public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { - BlockState blockState = ((CraftBlock) block).getNMS(); - return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; - } - - @Override - public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { - return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); - } - - @Override - public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { - return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); - } - - private int getDefaultAmount(BlockState blockState) { - Block block = blockState.getBlock(); - return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; - } - - @Override - public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { - return !bukkitBlock.isPassable(); - } - - @Override - public void placeSign(Island island, Location location) { - SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); - if (signBlockEntity == null) - return; - - String[] lines = new String[4]; - Component[] messages = signBlockEntity.getFrontText().getMessages(false); - System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - Component[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } - - System.arraycopy(newLines, 0, messages, 0, 4); - } - - @Override - public void playGeneratorSound(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); - } - } - - @Override - public void playBreakAnimation(org.bukkit.block.Block block) { - ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); - } - } - - @Override - public void playPlaceSound(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); - } - } - - @Override - public int getMinHeight(World world) { - return world.getMinHeight(); - } - - @Override - public void removeAntiXray(org.bukkit.World bukkitWorld) { - if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); - } - - @Override - public IslandsGenerator createGenerator(Dimension dimension) { - return new IslandsGeneratorImpl(dimension); - } - - @Override - public WorldEditSession createEditSession(World world) { - return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); - } - - @Override - public WorldEditSession createPartialEditSession(Dimension dimension) { - return WorldEditSessionImpl.obtain(dimension); - } - - @Override - public ChunkReader createChunkReader(Chunk chunk) { - return new ChunkReaderImpl(chunk); - } - - private static ReflectField> initializeLevelBlockEntityTickersField() { - ReflectField> field = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - - if (!field.isValid()) - field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); - - return field; - } - } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingBlockEntity.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingBlockEntity.java deleted file mode 100644 index 5e3376dd74..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingBlockEntity.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.crops; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { - - - @Override - public void tick() { - cropsBlockEntity.tick(); - } - - @Override - public boolean isRemoved() { - return cropsBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return cropsBlockEntity.getBlockPos(); - } - - @Override - public String getType() { - return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java deleted file mode 100644 index aa308d518b..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/crops/CropsTickingMethod.java +++ /dev/null @@ -1,164 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.crops; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.Supplier; - -public abstract class CropsTickingMethod { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static Set CROPS_TO_GROW_CACHE; - - static { - plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); - } - - private static final CropsTickingMethod INSTANCE = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection"); - return new PaperCropsTickingMethod(); - } catch (Throwable error) { - return new SpigotCropsTickingMethod(); - } - }).get(); - - public static void register() { - // Calls the static initializer which registers the callback. - } - - protected CropsTickingMethod() { - - } - - public static void tick(LevelChunk levelChunk, int tickSpeed) { - INSTANCE.doTick(levelChunk, tickSpeed); - } - - protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); - - private static void onSettingsUpdate() { - CROPS_TO_GROW_CACHE = new HashSet<>(); - plugin.getSettings().getCropsToGrow().forEach(cropName -> { - Key key = Keys.ofMaterialAndData(cropName); - if (key instanceof MaterialKey materialKey) { - Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); - if (block != null && block.defaultBlockState().isRandomlyTicking()) - CROPS_TO_GROW_CACHE.add(block); - } - }); - } - - private static class PaperCropsTickingMethod extends CropsTickingMethod { - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - ServerLevel serverLevel = levelChunk.level; - LevelChunkSection[] sections = levelChunk.getSections(); - - int minSection = serverLevel.getMinSection(); - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - RandomSource simpleRandom = serverLevel.random; - - for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - - ca.spottedleaf.moonrise.common.list.IBlockDataList tickList = - levelChunkSection.moonrise$getTickingBlockList(); - int tickingBlocks = tickList.size(); - if (tickingBlocks <= 0) { - continue; - } - - PalettedContainer states = levelChunkSection.states; - - int offsetY = (sectionIndex + minSection) << 4; - - for (int i = 0; i < tickSpeed; ++i) { - int index = simpleRandom.nextInt() & 0xFFF; - - if (index >= tickingBlocks) { - continue; - } - - long raw = tickList.getRaw(index); - int location = ca.spottedleaf.moonrise.common.list.IBlockDataList.getLocationFromRaw(raw); - BlockState blockState = states.get(location); - if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) - continue; - - // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! - BlockPos blockPos = new BlockPos((location & 15) | chunkOffsetX, - ((location >>> 8) & 255) | offsetY, - ((location >>> 4) & 15) | chunkOffsetZ); - - blockState.randomTick(serverLevel, blockPos, simpleRandom); - } - } - - } - - } - - private static class SpigotCropsTickingMethod extends CropsTickingMethod { - - private static int random = ThreadLocalRandom.current().nextInt(); - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - LevelChunkSection[] sections = levelChunk.getSections(); - ServerLevel serverLevel = levelChunk.level; - - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - - for (int i = 0; i < tickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { - BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); - blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); - } - } - } - } - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/DragonUtils.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/DragonUtils.java deleted file mode 100644 index 57cc0fa92d..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/DragonUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.dragon; - -import com.bgsoftware.common.reflection.ReflectField; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; - -import java.lang.reflect.Modifier; - -public class DragonUtils { - - private static final ReflectField END_PODIUM_LOCATION = new ReflectField( - EndPodiumFeature.class, BlockPos.class, - Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static BlockPos currentPodiumPosition = BlockPos.ZERO; - - private DragonUtils() { - - } - - public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { - try { - END_PODIUM_LOCATION.set(null, podiumPosition); - currentPodiumPosition = podiumPosition; - runnable.run(); - } finally { - END_PODIUM_LOCATION.set(null, BlockPos.ZERO); - currentPodiumPosition = BlockPos.ZERO; - } - } - - public static BlockPos getCurrentPodiumPosition() { - return currentPodiumPosition; - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndWorldEndDragonFightHandler.java deleted file mode 100644 index 1655d63a81..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndWorldEndDragonFightHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; -import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.dimension.end.EndDragonFight; - -import java.util.LinkedList; -import java.util.List; - -public class EndWorldEndDragonFightHandler extends EndDragonFight { - - private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); - - private final List worldDragonFightsList = new LinkedList<>(); - - public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); - } - - @Override - public void tick() { - this.worldDragonFightsList.forEach(EndDragonFight::tick); - } - - public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); - if (oldDragonFight != null) - this.worldDragonFightsList.remove(oldDragonFight); - this.worldDragonFightsList.add(endDragonFight); - } - - @Nullable - public IslandEndDragonFight getDragonFight(IslandCache islandCache) { - return islandCache.get(CACHE_KEY); - } - - @Nullable - public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { - IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); - if (endDragonFight != null) - this.worldDragonFightsList.remove(endDragonFight); - return endDragonFight; - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java index 3cc2b65c3f..914083b17f 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/IslandEntityEnderDragon.java @@ -2,50 +2,25 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.config.SettingsManager; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; -import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftEnderDragon; -public class IslandEntityEnderDragon extends EnderDragon { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - @NotNull - public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { - return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : - new EnderDragon(entityTypes, level); - } - - private final ServerLevel serverLevel; - private final Dimension dimension; - private BlockPos islandBlockPos; +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { - this(level); - this.islandBlockPos = islandBlockPos; + super(level, islandBlockPos); } - private IslandEntityEnderDragon(Level level) { - super(EntityType.ENDER_DRAGON, level); - this.serverLevel = (ServerLevel) level; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + public IslandEntityEnderDragon(Level level) { + super(level); } - @Nullable + @javax.annotation.Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, @@ -64,40 +39,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { finalizeIslandEnderDragon(); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - - private void finalizeIslandEnderDragon() { - if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) - return; - - Island island; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); - } - - if (island == null) - return; - - Location middleBlock = island.getCenter(dimension); - - SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); - if (dimensionConfig instanceof SettingsManager.Worlds.End) { - middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); - } - - this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); - - IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); - } - } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/SpikesCache.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/SpikesCache.java deleted file mode 100644 index 995e5430c3..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/SpikesCache.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.dragon; - - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.common.annotations.Nullable; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.CacheStats; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public class SpikesCache implements LoadingCache> { - - private static final SpikesCache INSTANCE = new SpikesCache(); - - private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() - .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); - - private long worldSeed; - - public static SpikesCache getInstance() { - return INSTANCE; - } - - private SpikesCache() { - - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - List getUnchecked(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public List apply(@NotNull Long worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void refresh(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ConcurrentMap> asMap() { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Nullable - @Override - public List getIfPresent(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed, - @NotNull Callable> loader) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAllPresent(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void put(@NotNull Long worldSeed, @NotNull List spikes) { - try { - this.worldSeed = worldSeed; - cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); - } finally { - this.worldSeed = 0; - } - } - - @Override - public void putAll(Map> spikesMap) { - spikesMap.forEach(this::put); - } - - @Override - public void invalidate(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll() { - this.cachedSpikes.invalidateAll(); - } - - @Override - public long size() { - return this.cachedSpikes.size(); - } - - @Override - public @NotNull - CacheStats stats() { - return this.cachedSpikes.stats(); - } - - @Override - public void cleanUp() { - this.cachedSpikes.cleanUp(); - } - - private class InternalCacheLoader extends CacheLoader> { - - @Override - public @NotNull - List load(@NotNull BlockPos blockPos) { - List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); - - Collections.shuffle(list, new Random(worldSeed)); - List spikesList = Lists.newArrayList(); - - for (int i = 0; i < 10; ++i) { - int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int l = list.get(i); - int radius = 2 + l / 3; - int height = 76 + l * 3; - boolean guarded = l == 1 || l == 2; - - spikesList.add(new SpikeFeature.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded)); - } - - return spikesList; - } - - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/generator/IslandsGeneratorImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/generator/IslandsGeneratorImpl.java deleted file mode 100644 index 24466d666f..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/generator/IslandsGeneratorImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.generator; - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; -import org.bukkit.generator.WorldInfo; - -import java.util.Collections; -import java.util.List; -import java.util.Random; - -@SuppressWarnings({"unused", "NullableProblems"}) -public class IslandsGeneratorImpl extends IslandsGenerator { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private final Dimension dimension; - - public IslandsGeneratorImpl(Dimension dimension) { - this.dimension = dimension; - } - - @Override - public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, - @NotNull ChunkData chunkData) { - if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { - chunkData.setBlock(0, 99, 0, Material.BEDROCK); - } - } - - @Override - public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { - return new BiomeProvider() { - @Override - public @NotNull - Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { - return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension); - } - - @Override - public @NotNull - List getBiomes(@NotNull WorldInfo worldInfo) { - return IslandUtils.getDefaultWorldBiomes(); - } - - }; - } - - @Override - public List getDefaultPopulators(World world) { - return Collections.emptyList(); - } - - @Override - public Location getFixedSpawnLocation(World world, Random random) { - return new Location(world, 0, 100, 0); - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/hologram/EntityHologram.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/hologram/EntityHologram.java new file mode 100644 index 0000000000..3d4c5ea3eb --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/hologram/EntityHologram.java @@ -0,0 +1,39 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.hologram; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuHopperBlockEntity.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuHopperBlockEntity.java deleted file mode 100644 index cc5d38fe4d..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/menu/MenuHopperBlockEntity.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.HopperBlock; -import net.minecraft.world.level.block.entity.HopperBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuHopperBlockEntity extends HopperBlockEntity { - - private final InventoryHolder holder; - - public MenuHopperBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.HOPPER.defaultBlockState().setValue(HopperBlock.FACING, Direction.DOWN)); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/player/OfflinePlayerDataImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/player/OfflinePlayerDataImpl.java deleted file mode 100644 index 7087c6d8f1..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/player/OfflinePlayerDataImpl.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.player; - -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; - -import java.util.Optional; - -public class OfflinePlayerDataImpl implements OfflinePlayerData { - - private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); - - private Player fakePlayer; - - public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { - return POOL.obtain().initialize(offlinePlayer); - } - - private OfflinePlayerDataImpl() { - - } - - private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), - Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return null; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - this.fakePlayer = serverPlayer.getBukkitEntity(); - this.fakePlayer.loadData(); - - return this; - } - - @Override - public Player getFakeOnlinePlayer() { - return this.fakePlayer; - } - - @Override - public void setLocation(Location location) { - ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); - serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); - serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - } - - @Override - public void applyChanges() { - this.fakePlayer.saveData(); - } - - @Override - public void release() { - this.fakePlayer = null; - POOL.release(this); - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/spawners/TickingSpawnerBlockEntityNotifier.java deleted file mode 100644 index bba3509443..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/spawners/TickingSpawnerBlockEntityNotifier.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.spawners; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BaseSpawner; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -import java.util.function.IntFunction; - -public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { - - private final SpawnerBlockEntity spawnerBlockEntity; - private final TickingBlockEntity tickingBlockEntity; - private final IntFunction delayChangeCallback; - - public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, - IntFunction delayChangeCallback) { - this.spawnerBlockEntity = spawnerBlockEntity; - this.tickingBlockEntity = tickingBlockEntity; - this.delayChangeCallback = delayChangeCallback; - updateDelay(); - } - - @Override - public void tick() { - BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); - int startDelay = baseSpawner.spawnDelay; - try { - tickingBlockEntity.tick(); - } finally { - int newDelay = baseSpawner.spawnDelay; - if (newDelay > startDelay) - updateDelay(); - } - } - - @Override - public boolean isRemoved() { - return tickingBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return tickingBlockEntity.getPos(); - } - - @Override - public String getType() { - return tickingBlockEntity.getType(); - } - - public void updateDelay() { - BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); - baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..9bf0fd70f1 --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java @@ -0,0 +1,370 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.utils; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21.utils.TickingBlockList; +import com.google.common.base.Suppliers; +import com.google.gson.JsonParseException; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.IOWorker; +import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +public class NMSUtilsVersioned { + + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( + EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { + return chunkMap.read(chunkPos).join().orElse(null); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { + return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), + chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) throws IOException { + chunkMap.write(chunkPos, chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } else { + return BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + net.minecraft.nbt.CompoundTag entityData = serverLevel.moonrise$getEntityChunkDataController() + .readData(chunkPosition.getX(), chunkPosition.getZ()); + + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + return; + } + + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } catch (IOException error) { + countDownLatch.countDown(); + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + serverLevel.registryAccess().registryOrThrow(Registries.BIOME), + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.liquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess()); + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + applySignTextLines(compoundTag, "front_text"); + applySignTextLines(compoundTag, "back_text"); + convertLegacySignTextLines(compoundTag); + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); + + Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + + chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); + + // Unsafe: we do not provide chunks cache, even tho it is required. + // Should be fine in normal flow, as the only method that access the chunks cache + // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 + WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); + + customChunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + } + + public static CompoundTag saveEntity(Entity entity) { + CompoundTag compoundTag = new CompoundTag(); + entity.save(compoundTag); + return compoundTag; + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.moonrise$getTickingBlockList().size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + public static String getPropertyValue(Property property) { + return property.value(); + } + + public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.getDragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absMoveTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSection(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinBuildHeight(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxBuildHeight(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.setUnsaved(true); + } + + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { + if (blockEntityCompound.contains(key)) { + CompoundTag frontText = blockEntityCompound.getCompound(key); + ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); + List textLines = new ArrayList<>(); + for (net.minecraft.nbt.Tag lineTag : messages) { + try { + textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); + } catch (JsonParseException error) { + textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); + } + } + + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); + } + } + + private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockEntityCache.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockEntityCache.java deleted file mode 100644 index 38add37e5f..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockEntityCache.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.world; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class BlockEntityCache { - - private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); - - private BlockEntityCache() { - - } - - public static String getBlockEntityId(BlockState blockState) { - return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { - for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - if (blockEntityType.isValid(blockState)) { - ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); - if (resourceLocation != null) - return resourceLocation.toString(); - } - } - - return ""; - }); - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java deleted file mode 100644 index 67740dd550..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/ChunkReaderImpl.java +++ /dev/null @@ -1,243 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.block.CraftBlockType; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.InventoryHolder; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class ChunkReaderImpl implements ChunkReader { - - private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - private static final byte[] FULL_LIGHT = new byte[2048]; - private static final byte[] EMPTY_LIGHT = new byte[2048]; - - static { - Arrays.fill(FULL_LIGHT, (byte) 0xFF); - } - - private final ServerLevel serverLevel; - private final int x; - private final int z; - - private final Map blockEntities = new HashMap<>(); - private final List entities = new LinkedList<>(); - private final PalettedContainerRO[] blockids; - private final byte[][] skylight; - private final byte[][] emitlight; - - public ChunkReaderImpl(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - - this.serverLevel = levelChunk.level; - ChunkPos chunkPos = levelChunk.getPos(); - this.x = chunkPos.x; - this.z = chunkPos.z; - - LevelChunkSection[] levelChunkSections = levelChunk.getSections(); - this.blockids = new PalettedContainerRO[levelChunkSections.length]; - this.skylight = new byte[levelChunkSections.length][]; - this.emitlight = new byte[levelChunkSections.length][]; - - LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); - - for (int i = 0; i < this.blockids.length; ++i) { - LevelChunkSection levelChunkSection = levelChunkSections[i]; - - this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); - - DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (skyLightArray == null) { - this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; - } else { - this.skylight[i] = new byte[2048]; - System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); - } - - DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (emitLightArray == null) { - this.emitlight[i] = EMPTY_LIGHT; - } else { - this.emitlight[i] = new byte[2048]; - System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); - } - } - - levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - InventoryHolder inventoryHolder = blockEntity.getOwner(); - if (inventoryHolder != null) - compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); - - blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); - }); - - for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) - entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); - } - - @Override - public int getX() { - return this.x; - } - - @Override - public int getZ() { - return this.z; - } - - @Override - public Material getType(int x, int y, int z) { - return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); - } - - @Override - public short getData(int x, int y, int z) { - return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); - } - - @Override - @Nullable - public CompoundTag getTileEntity(int x, int y, int z) { - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); - return this.blockEntities.get(blockPos); - } - } - - @Override - @Nullable - public CompoundTag readBlockStates(int x, int y, int z) { - BlockState blockState = getBlockState(x, y, z); - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = CompoundTag.of(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(int x, int y, int z) { - int off = (y & 15) << 7 | z << 3 | x >> 1; - int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; - } - - @Override - public void forEachEntity(EntityConsumer consumer) { - if (entities.isEmpty()) - return; - - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = wrapper.getHandle(); - for (CachedEntity cachedEntity : entities) { - location.setX(cachedEntity.x); - location.setY(cachedEntity.y); - location.setZ(cachedEntity.z); - location.setYaw(cachedEntity.yaw); - location.setPitch(cachedEntity.pitch); - consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); - } - } - } - - private BlockState getBlockState(int x, int y, int z) { - return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); - } - - private int getSectionIndex(int y) { - int sectionIndex = SectionPos.blockToSectionCoord(y); - return sectionIndex - this.serverLevel.getMinSection(); - } - - private int getSectionYFromSectionIndex(int index) { - return index + this.serverLevel.getMinSection(); - } - - private static class CachedEntity { - - private final double x; - private final double y; - private final double z; - private final float yaw; - private final float pitch; - private final EntityType entityType; - private final CompoundTag entityTag; - - CachedEntity(Entity entity) { - this.x = entity.getX(); - this.y = entity.getY(); - this.z = entity.getZ(); - this.yaw = entity.getBukkitYaw(); - this.pitch = entity.getXRot(); - this.entityType = entity.getBukkitEntity().getType(); - - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - - this.entityTag = CompoundTag.fromNBT(compoundTag); - } - - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/KeyBlocksCache.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/KeyBlocksCache.java deleted file mode 100644 index b21ffec0cb..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/KeyBlocksCache.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.world; - -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.level.block.Block; -import org.bukkit.Material; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class KeyBlocksCache { - - private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); - - private KeyBlocksCache() { - - } - - public static Key getBlockKey(Block block) { - return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { - Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); - }); - } - - public static void cacheAllBlocks() { - BuiltInRegistries.BLOCK.forEach(KeyBlocksCache::getBlockKey); - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/PropertiesMapper.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/PropertiesMapper.java deleted file mode 100644 index 2b2b45479f..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/PropertiesMapper.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.world; - -import com.bgsoftware.superiorskyblock.core.logging.Log; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.Property; - -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; - -public class PropertiesMapper { - - private static final Map> nameToProperty = new HashMap<>(); - private static final Map, String> propertyToName = new HashMap<>(); - - static { - Map fieldsToNames = new IdentityHashMap<>(); - - fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); - fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); - fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); - fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); - fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); - fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); - fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); - fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); - fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); - fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); - fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); - fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); - fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); - fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); - fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); - fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); - fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); - fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); - fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); - fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); - fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); - fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); - fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); - fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); - fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); - fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); - fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); - fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); - - try { - for (Field field : BlockStateProperties.class.getFields()) { - field.setAccessible(true); - Object value = field.get(null); - if (value instanceof Property) { - Property property = (Property) value; - register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); - } - } - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while loading properties mapper:"); - } - - } - - private static void register(String key, String fieldName, Property property) { - if (nameToProperty.containsKey(key)) { - Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); - } else { - nameToProperty.put(key, property); - propertyToName.put(property, key); - } - } - - public static Property getProperty(String name) { - return nameToProperty.get(name); - } - - public static String getPropertyName(Property property) { - return propertyToName.get(property); - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/PropertiesMapperVersioned.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..ff76518af1 --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/PropertiesMapperVersioned.java @@ -0,0 +1,17 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.world; + +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionDataImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionDataImpl.java deleted file mode 100644 index e8cfad922a..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionDataImpl.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.world; - -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionDataImpl implements WorldEditSession.Data { - - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private final List> chunks = new LinkedList<>(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); - - public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, - List> blocksToUpdate, - List> blockEntities, - Set lightenChunks) { - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // Convert chunk data - Iterator> chunksIterator = chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); - int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); - WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); - - List> lights; - if (isStarLightInterface || chunkData.lights().isEmpty()) { - lights = Collections.emptyList(); - } else { - lights = new LinkedList<>(); - chunkData.lights().forEach(lightPosition -> { - lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, - lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, - null)); - }); - } - - PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), - chunkData.heightmaps(), lights); - - this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, - currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); - } - - // Convert blocksToUpdate - blocksToUpdate.forEach(blockToUpdate -> { - BlockPos blockPos = blockToUpdate.getKey(); - this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockToUpdate.getValue())); - }); - - // Convert blockEntities - blockEntities.forEach(blockEntity -> { - BlockPos blockPos = blockEntity.getKey(); - this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockEntity.getValue())); - }); - - // Convert lights - lightenChunks.forEach(lightPosition -> { - this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, - lightPosition.z - baseChunkPosZAxis, null)); - }); - } - - public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, - int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, - Long2ObjectMapView chunks) { - this.chunks.forEach(chunkDataPositioned -> { - long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, - baseChunkPosZAxis + chunkDataPositioned.zOffset); - - List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - chunkDataPositioned.object.lights.forEach(lightPositioned -> { - lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, - baseBlockPosYAxis + lightPositioned.yOffset, - baseBlockPosZAxis + lightPositioned.zOffset)); - }); - - chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, - chunkDataPositioned.object.heightmaps, lights)); - }); - } - - public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { - this.blocksToUpdate.forEach(blockToUpdatePositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, - baseBlockPosYAxis + blockToUpdatePositioned.yOffset, - baseBlockPosZAxis + blockToUpdatePositioned.zOffset); - blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); - }); - } - - public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { - this.blockEntities.forEach(blockEntityPositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, - baseBlockPosYAxis + blockEntityPositioned.yOffset, - baseBlockPosZAxis + blockEntityPositioned.zOffset); - blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); - }); - } - - public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { - this.lightenChunks.forEach(lightPositioned -> { - ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, - baseChunkPosZAxis + lightPositioned.zOffset); - lightenChunks.add(newPos); - }); - } - - private static class PositionedObject { - - private final int xOffset; - private final int yOffset; - private final int zOffset; - private final V object; - - PositionedObject(int xOffset, int zOffset, V object) { - this(xOffset, 0, zOffset, object); - } - - PositionedObject(int xOffset, int yOffset, int zOffset, V object) { - this.xOffset = xOffset; - this.yOffset = yOffset; - this.zOffset = zOffset; - this.object = object; - } - - } - - private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, - List> lights) { - } - -} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java deleted file mode 100644 index 2521e965b6..0000000000 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/WorldEditSessionImpl.java +++ /dev/null @@ -1,480 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.google.common.base.Preconditions; -import com.google.gson.JsonParseException; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.HolderLookup; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.SignText; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.ticks.ProtoChunkTicks; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.generator.ChunkGenerator; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionImpl implements WorldEditSession { - - private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; - - private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - - private Dimension dimension; - private LevelHeightAccessor levelHeightAccessor; - - @Nullable - private ServerLevel serverLevel; - - public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { - return POOL.obtain().initialize(serverLevel); - } - - public static WorldEditSessionImpl obtain(Dimension dimension) { - return POOL.obtain().initialize(dimension); - } - - private WorldEditSessionImpl() { - } - - private WorldEditSessionImpl initialize(ServerLevel serverLevel) { - this.serverLevel = serverLevel; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); - this.levelHeightAccessor = serverLevel; - return this; - } - - private WorldEditSessionImpl initialize(Dimension dimension) { - DimensionType dimensionType = getDimensionTypeFromDimension(dimension); - this.serverLevel = null; - this.dimension = dimension; - this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); - return this; - } - - @Override - public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, - @Nullable CompoundTag blockEntityData) { - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - if (!isValidPosition(blockPos)) - return; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - blocksToUpdate.add(new Pair<>(blockPos, blockState)); - return; - } - - ChunkPos chunkPos = new ChunkPos(blockPos); - - if (blockEntityData != null) - blockEntities.add(new Pair<>(blockPos, blockEntityData)); - - ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); - - if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) - chunkData.lights.add(blockPos); - - LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - } - - @Override - public List getAffectedChunks() { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); - - if (chunks.isEmpty()) - return Collections.emptyList(); - - List chunkPositions = new LinkedList<>(); - World bukkitWorld = serverLevel.getWorld(); - LongIterator iterator = chunks.keyIterator(); - while (iterator.hasNext()) { - long chunkKey = iterator.next(); - int chunkX = (int) chunkKey; - int chunkZ = (int) (chunkKey >> 32); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); - } - return chunkPositions; - } - - @Override - public void applyBlocks(Chunk bukkitChunk) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); - - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); - ChunkPos chunkPos = levelChunk.getPos(); - - long chunkKey = chunkPos.toLong(); - ChunkData chunkData = this.chunks.remove(chunkKey); - - if (chunkData == null) - return; - - int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); - for (int i = 0; i < chunkSectionsCount; ++i) { - levelChunk.getSections()[i] = chunkData.chunkSections[i]; - } - - chunkData.heightmaps.forEach(((type, heightmap) -> { - levelChunk.setHeightmap(type, heightmap.getRawData()); - })); - - if (plugin.getSettings().isLightsUpdate()) { - if (isStarLightInterface) { - this.lightenChunks.add(chunkPos); - } else { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); - // Queues chunk light for this chunk. - threadedLevelLightEngine.lightChunk(levelChunk, false); - } - } - - levelChunk.setUnsaved(true); - } - - @Override - public void finish(Island island) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); - - // Update blocks - blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); - - // Update block entities - blockEntities.forEach(data -> { - net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); - if (blockEntityCompound != null) { - BlockPos blockPos = data.getKey(); - blockEntityCompound.putInt("x", blockPos.getX()); - blockEntityCompound.putInt("y", blockPos.getY()); - blockEntityCompound.putInt("z", blockPos.getZ()); - - applySignTextLines(blockEntityCompound, "front_text"); - applySignTextLines(blockEntityCompound, "back_text"); - convertLegacySignTextLines(blockEntityCompound); - - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.loadWithComponents(blockEntityCompound, MinecraftServer.getServer().registryAccess()); - } - }); - - if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - threadedLevelLightEngine.starlight$serverRelightChunks(lightenChunks, chunkCallback -> { - }, completeCallback -> { - }); - this.lightenChunks.clear(); - } - - release(); - } - - @Override - public Data readData(Location baseLocation) { - return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); - } - - @Override - public void applyData(Data data, Location baseLocation) { - WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // We need to transform all data to the new base location values - - dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, - baseBlockPosZAxis, this, this.chunks); - dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); - dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); - dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); - } - - @Override - public void release() { - this.chunks.clear(); - this.blocksToUpdate.clear(); - this.blockEntities.clear(); - this.lightenChunks.clear(); - this.serverLevel = null; - this.dimension = null; - this.levelHeightAccessor = null; - POOL.release(this); - } - - public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - return new ChunkData(chunkSections, heightmaps, lights); - } - - private boolean isValidPosition(BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); - } - - private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { - if (blockEntityCompound.contains(key)) { - net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); - ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); - List textLines = new ArrayList<>(); - for (net.minecraft.nbt.Tag lineTag : messages) { - try { - textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); - } catch (JsonParseException error) { - textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); - } - } - - while (textLines.size() < 4) - textLines.add(Component.empty()); - - Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); - - SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); - } - } - - private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { - Component[] signLines = new Component[4]; - Arrays.fill(signLines, Component.empty()); - boolean hasAnySignLines = false; - // We try to convert old text sign lines - for (int i = 1; i <= 4; ++i) { - if (blockEntityCompound.contains("SSB.Text" + i)) { - String signLine = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; - hasAnySignLines = true; - } - } else { - String signLine = blockEntityCompound.getString("Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromJSON(signLine); - hasAnySignLines = true; - } - } - } - - if (hasAnySignLines) { - SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); - } - } - - private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { - ResourceKey resourceKey; - switch (dimension.getEnvironment()) { - case NETHER -> resourceKey = LevelStem.NETHER; - case THE_END -> resourceKey = LevelStem.END; - default -> resourceKey = LevelStem.OVERWORLD; - } - HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); - return registry.getOrThrow(resourceKey).value().type().value(); - } - - public class ChunkData { - - private final LevelChunkSection[] chunkSections; - private final Map heightmaps; - private final List lights; - - private ChunkData(long chunkKey) { - this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), - isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); - - ChunkPos chunkPos = new ChunkPos(chunkKey); - - Registry biomesRegistry = MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME); - - createChunkSections(biomesRegistry); - - ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); - - createHeightmaps(tempChunk); - if (serverLevel != null) - runCustomWorldGenerator(tempChunk); - } - - private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - this.chunkSections = chunkSections; - this.heightmaps = heightmaps; - this.lights = lights; - } - - public LevelChunkSection[] chunkSections() { - return this.chunkSections; - } - - public Map heightmaps() { - return this.heightmaps; - } - - public List lights() { - return this.lights; - } - - private void createChunkSections(Registry biomesRegistry) { - Holder biome = CraftBiome.bukkitToMinecraftHolder( - IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); - - for (int i = 0; i < this.chunkSections.length; ++i) { - PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), - biome, PalettedContainer.Strategy.SECTION_BIOMES); - PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - - this.chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); - } - } - - private void runCustomWorldGenerator(ProtoChunk tempChunk) { - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - - if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) - return; - - NMSUtils.buildSurfaceForChunk(serverLevel, tempChunk); - - // We want to copy the level chunk sections back - LevelChunkSection[] tempChunkSections = tempChunk.getSections(); - for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { - LevelChunkSection chunkSection = tempChunkSections[i]; - if (chunkSection != null) - this.chunkSections[i] = chunkSection; - } - } - - private void createHeightmaps(ProtoChunk tempChunk) { - for (Heightmap.Types heightmapType : Heightmap.Types.values()) { - if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { - this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); - } - } - } - - } - - -} diff --git a/NMS/v1_21_3/properties b/NMS/v1_21_3/properties new file mode 100644 index 0000000000..c28e94c157 --- /dev/null +++ b/NMS/v1_21_3/properties @@ -0,0 +1,7 @@ +NMS_VERSION=v1_21_3 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java index 370d5021fb..1113ae7a21 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java @@ -1,208 +1,30 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_3; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; -import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; -import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.menu.MenuBrewingStandBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.menu.MenuDispenserBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.menu.MenuFurnaceBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.menu.MenuHopperBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.BlockEntityCache; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.KeyBlocksCache; -import com.google.common.collect.Multimap; -import com.google.common.collect.MultimapBuilder; -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.TextReplacementConfig; -import net.minecraft.SharedConstants; -import net.minecraft.core.BlockPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.Container; -import net.minecraft.world.entity.item.FallingBlockEntity; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.attribute.Attribute; -import org.bukkit.attribute.AttributeModifier; -import org.bukkit.block.data.Ageable; -import org.bukkit.block.data.BlockData; -import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftFallingBlock; -import org.bukkit.craftbukkit.entity.CraftMinecart; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; -import org.bukkit.potion.PotionEffect; -import org.jetbrains.annotations.NotNull; -import java.util.EnumMap; import java.util.Locale; import java.util.Objects; -import java.util.Optional; -import java.util.function.BiFunction; -public class NMSAlgorithmsImpl implements NMSAlgorithms { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Multimap EMPTY_ATTRIBUTES_MAP = - MultimapBuilder.hashKeys().hashSetValues().build(); - - private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); - - static { - MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); - } - - private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { - @Override - public byte[] processClass(byte[] classBytes, String path) { - return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); - } - }; - - @Override - public void registerCommand(BukkitCommand command) { - ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); - } +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms { @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); } - @Override - public int getCombinedId(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return 0; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(wrapper.getHandle()); - } - return Block.getId(blockState); - } - - @Override - public int getCombinedId(Material material, byte data) { - BlockState blockState; - - if (data == 0) { - Block block = CraftMagicNumbers.getBlock(material); - if (block == null) - return -1; - blockState = block.defaultBlockState(); - } else { - blockState = CraftMagicNumbers.getBlock(material, data); - } - - return blockState == null ? -1 : Block.getId(blockState); - } - - @Override - public Optional getTileEntityIdFromCombinedId(int combinedId) { - BlockState blockState = Block.stateById(combinedId); - - if (!blockState.hasBlockEntity()) - return Optional.empty(); - - String id = BlockEntityCache.getBlockEntityId(blockState); - - return Text.isBlank(id) ? Optional.empty() : Optional.of(id); - } - - @Override - public int compareMaterials(Material o1, Material o2) { - int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); - int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); - return Integer.compare(firstMaterial, secondMaterial); - } - - @Override - public short getBlockDataValue(org.bukkit.block.BlockState blockState) { - BlockData blockData = blockState.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getBlockDataValue(org.bukkit.block.Block block) { - BlockData blockData = block.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getMaxBlockDataValue(Material material) { - if (!material.isBlock()) - return 0; - - BlockData blockData = Bukkit.createBlockData(material); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); - } - - @Override - public Key getBlockKey(int combinedId) { - Block block = Block.stateById(combinedId).getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { - AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); - Block block = minecart.getDisplayBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { - FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); - Block block = fallingBlock.getBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public void setCustomModel(ItemMeta itemMeta, int customModel) { - itemMeta.setCustomModelData(customModel); - } - @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); @@ -231,13 +53,6 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } - @Override - public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { - if (!potionMeta.hasCustomEffects()) - potionMeta.setColor(potionEffect.getType().getColor()); - potionMeta.addCustomEffect(potionEffect, true); - } - @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); @@ -248,88 +63,4 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } - @Nullable - @Override - public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { - MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); - return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); - } - - @Override - public int getMaxWorldSize() { - return Bukkit.getMaxWorldSize(); - } - - @Override - public double getCurrentTps() { - try { - return MinecraftServer.getServer().tps1.getAverage(); - } catch (Throwable error) { - //noinspection removal - return MinecraftServer.getServer().recentTps[0]; - } - } - - @Override - public int getDataVersion() { - return SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - } - - @Override - public ClassProcessor getClassProcessor() { - return CLASS_PROCESSOR; - } - - @Override - public void handlePaperChatRenderer(Object event) { - if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) - return; - - ChatRenderer originalRenderer = asyncChatEvent.renderer(); - asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); - } - - @Override - public void hideAttributes(ItemMeta itemMeta) { - itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); - } - - private interface MenuCreator extends BiFunction { - } - - private static class ChatRendererWrapper { - - private static final String MESSAGE_PLACEHOLDER = "{message}"; - private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = - net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); - - private final ChatRenderer renderer = new ChatRenderer() { - @Override - public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, - net.kyori.adventure.text.@NotNull Component sourceDisplayName, - net.kyori.adventure.text.@NotNull Component message, - @NotNull Audience viewer) { - String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer - .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); - Island island = superiorPlayer.getIsland(); - - return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( - Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) - .replaceText(TextReplacementConfig.builder() - .matchLiteral(MESSAGE_PLACEHOLDER) - .replacement(message) - .build()); - } - }; - - private final ChatRenderer originalRenderer; - - public ChatRendererWrapper(ChatRenderer originalRenderer) { - this.originalRenderer = originalRenderer; - } - - } - } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java index 127b4dd613..56d2897678 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java @@ -1,25 +1,17 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_3; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; -import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.crops.CropsBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.crops.CropsTickingMethod; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -38,21 +30,15 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.BitStorage; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -60,48 +46,30 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import net.minecraft.world.phys.AABB; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.entity.CraftEntityType; import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; -import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; -import java.util.Objects; import java.util.concurrent.CompletableFuture; -public class NMSChunksImpl implements NMSChunks { - - private final SuperiorSkyblockPlugin plugin; +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - KeyBlocksCache.cacheAllBlocks(); - CropsTickingMethod.register(); + super(plugin); } @Override - public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, - Collection playersToUpdate) { - if (chunkPositions.isEmpty()) - return; - - Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.SET_BIOME, false) { + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); @@ -119,7 +87,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null); + levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); @@ -130,9 +98,11 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), @@ -145,7 +115,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); @@ -155,19 +125,12 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { // Do nothing. } - }); + }; } @Override - public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { - if (chunkPositions.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), - chunkPosition.getX(), chunkPosition.getZ(), false)); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.DELETE_CHUNK, false) { + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); @@ -184,6 +147,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( @@ -194,8 +158,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - unloadedChunkCompound.setEntities(new ListTag()); - unloadedChunkCompound.setBlockEntities(tileEntities); + chunkCompound.put("entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, @@ -203,18 +167,19 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { - NMSUtils.buildSurfaceForChunk(serverLevel, protoChunk); + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), @@ -260,7 +225,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound tileEntities.add(blockEntityCompound); } - unloadedChunkCompound.setSections(sectionsList); + chunkCompound.put("sections", sectionsList); } } @@ -269,34 +234,14 @@ public void onFinish() { if (onFinish != null) onFinish.run(); } - }); + }; } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); - List chunkPositionsToCalculate = new LinkedList<>(); - - Iterator chunkPositionsIterator = chunkPositions.iterator(); - while (chunkPositionsIterator.hasNext()) { - ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); - if (cachedCalculatedChunk != null) { - allCalculatedChunks.add(cachedCalculatedChunk); - chunkPositionsIterator.remove(); - } else { - chunkPositionsToCalculate.add(chunkPosition); - } - } - - if (chunkPositions.isEmpty()) - return CompletableFuture.completedFuture(allCalculatedChunks); - - CompletableFuture> completableFuture = new CompletableFuture<>(); - - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( - ChunkLoadReason.BLOCKS_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -310,6 +255,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( @@ -327,36 +273,36 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { - PalettedContainer blocksDataPalette; + PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); - blocksDataPalette = dataResult.getOrThrow(); + blocksPalettedContainer = dataResult.getOrThrow(); } else { - blocksDataPalette = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } - PalettedContainer> biomesDataPalette; + PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); - biomesDataPalette = dataResult.getOrThrow(); + biomesPalettedContainer = dataResult.getOrThrow(); } else { - biomesDataPalette = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } - chunkSections[sectionIndex] = new LevelChunkSection(blocksDataPalette, biomesDataPalette); + chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } @@ -372,20 +318,14 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { completableFuture.complete(allCalculatedChunks); } - }); - - return completableFuture; + }; } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); - - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - List unloadedChunkCompounds = new LinkedList<>(); - - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( - ChunkLoadReason.ENTITIES_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { @@ -408,8 +348,9 @@ public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - for (Tag entityTag : unloadedChunkCompound.getEntities()) { + for (Tag entityTag : chunkCompound.getList("entities", 10)) { EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); if (entityType == null) continue; @@ -421,7 +362,9 @@ public void onFinish() { continue; } - Key entityKey = Keys.of(CraftEntityType.minecraftToBukkit(entityType)); + Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( + CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); + chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); } } @@ -429,161 +372,17 @@ public void onFinish() { completableFuture.complete(chunkEntities); }); } - }); - - return completableFuture; - } - - @Override - public void injectChunkSections(Chunk chunk) { - // No implementation - } - - @Override - public boolean isChunkEmpty(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> - chunkSection == null || chunkSection.hasOnlyAir()); - } - - @Override - public Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); - return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; - } - - @Override - public void startTickingChunk(Island island, Chunk chunk, boolean stop) { - if (plugin.getSettings().getCropsInterval() <= 0) - return; - - if (stop) { - CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); - if (cropsBlockEntity != null) - cropsBlockEntity.remove(); - } else { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - CropsBlockEntity.create(island, levelChunk); - } - } - - @Override - public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { - if (chunkPositions.isEmpty()) return; - CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> - cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); - } - - @Override - public void shutdown() { - List> pendingTasks = NMSUtils.getPendingChunkActions(); - - if (pendingTasks.isEmpty()) - return; - - Log.info("Waiting for chunk tasks to complete."); - - CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); - } - - @Override - public List getBlockEntities(Chunk chunk) { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - List blockEntities = new LinkedList<>(); - - World bukkitWorld = chunk.getWorld(); - - levelChunk.getBlockEntities().keySet().forEach(blockPos -> - blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); - - return blockEntities; - } - - private static final ReflectField PALETTED_CONTAINER_DATA = new ReflectField<>( - PalettedContainer.class, Object.class, "d"); - - private static final ReflectField PALETTED_CONTAINER_DATA_STORAGE = new ReflectField<>( - PalettedContainer.class, BitStorage.class, "b"); - - private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { - KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); - List spawnersLocations = new LinkedList<>(); - - for (int i = 0; i < chunkSections.length; ++i) { - LevelChunkSection levelChunkSection = chunkSections[i]; - if (levelChunkSection != null && !levelChunkSection.hasOnlyAir()) { - int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4; - for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { - BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, - sectionBottomY, blockCounts, spawnersLocations); - } - } - } - - return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); - } - - private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, - int sectionBottomY, KeyMap blockCounts, - List spawnersLocations) { - Block block = blockState.getBlock(); - - if (block == Blocks.AIR) - return; - - Location location = new Location(chunkPosition.getWorld(), - (chunkPosition.getX() << 4) + x, - sectionBottomY + y, - (chunkPosition.getZ() << 4) + z); - - int blockAmount = 1; - - if (NMSUtils.isDoubleBlock(block, blockState)) { - blockAmount = 2; - blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); - } - - Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); - blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); - if (block == Blocks.SPAWNER) { - spawnersLocations.add(location); - } - } - - private static void removeEntities(ChunkAccess chunk) { - ChunkPos chunkPos = chunk.getPos(); - ServerLevel serverLevel = ((LevelChunk) chunk).level; - - int chunkWorldCoordX = chunkPos.x << 4; - int chunkWorldCoordZ = chunkPos.z << 4; - - AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinY(), chunkWorldCoordZ, - chunkWorldCoordX + 15, serverLevel.getMaxY(), chunkWorldCoordZ + 15); - - List worldEntities = new LinkedList<>(); - serverLevel.getEntities().get(chunkBounds, worldEntities::add); - - worldEntities.forEach(nmsEntity -> { - if (!(nmsEntity instanceof Player)) - nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); - }); - } - - private static void removeBlockEntities(ChunkAccess chunk) { - chunk.blockEntities.values().forEach(BlockEntity::setRemoved); - chunk.blockEntities.clear(); + }; } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { - NMSUtils.buildSurfaceForChunk(serverLevel, chunk); - } + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; + + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSDragonFightImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSDragonFightImpl.java deleted file mode 100644 index c06c73f170..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSDragonFightImpl.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon.EndWorldEndDragonFightHandler; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon.IslandEndDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon.IslandEntityEnderDragon; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon.SpikesCache; -import com.google.common.cache.LoadingCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.advancement.Advancement; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.entity.Player; - -import java.lang.reflect.Modifier; -import java.util.List; - -public class NMSDragonFightImpl implements NMSDragonFight { - - private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( - EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField<>( - ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE, 1); - - private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( - SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static boolean firstWorldPreparation = true; - - static { - ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); - } - - @Override - public void prepareEndWorld(World bukkitWorld) { - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); - - if (firstWorldPreparation) { - firstWorldPreparation = false; - SPIKE_CACHE.set(null, SpikesCache.getInstance()); - } - } - - @Nullable - @Override - public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return null; - - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); - return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); - } - - @Override - public void startDragonBattle(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); - } - - @Override - public void removeDragonBattle(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); - - if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { - islandEndDragonFight.removeBattlePlayers(); - islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); - } - } - - @Override - public void awardTheEndAchievement(Player player) { - Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); - if (advancement != null) - player.getAdvancementProgress(advancement).awardCriteria(""); - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSEntitiesImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSEntitiesImpl.java index 939b28b0d9..a773c16c19 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSEntitiesImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSEntitiesImpl.java @@ -1,50 +1,22 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_3; -import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; -import org.bukkit.Material; -import org.bukkit.craftbukkit.entity.CraftAnimals; -import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; -import org.bukkit.entity.Animals; import org.bukkit.entity.minecart.PoweredMinecart; -import org.bukkit.inventory.EntityEquipment; -import org.bukkit.inventory.ItemStack; -public class NMSEntitiesImpl implements NMSEntities { +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSEntities { @Override - public ItemStack[] getEquipment(EntityEquipment entityEquipment) { - ItemStack[] itemStacks = new ItemStack[7]; - - itemStacks[0] = new ItemStack(Material.ARMOR_STAND); - itemStacks[1] = entityEquipment.getItemInMainHand(); - itemStacks[2] = entityEquipment.getItemInOffHand(); - itemStacks[3] = entityEquipment.getHelmet(); - itemStacks[4] = entityEquipment.getChestplate(); - itemStacks[5] = entityEquipment.getLeggings(); - itemStacks[6] = entityEquipment.getBoots(); - - return itemStacks; - } - - @Override - public boolean isAnimalFood(ItemStack itemStack, Animals animals) { - return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); - } - - @Override - public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); } @Override - public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); + protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSHologramsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSHologramsImpl.java deleted file mode 100644 index a819170c5b..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSHologramsImpl.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3; - -import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; -import com.bgsoftware.superiorskyblock.nms.NMSHolograms; -import com.google.common.base.Preconditions; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftArmorStand; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.entity.Entity; - -@SuppressWarnings("unused") -public class NMSHologramsImpl implements NMSHolograms { - - @Override - public Hologram createHologram(Location location) { - Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); - serverLevel.addFreshEntity(entityHologram); - return entityHologram; - } - - @Override - public boolean isHologram(Entity entity) { - return ((CraftEntity) entity).getHandle() instanceof Hologram; - } - - public static class EntityHologram extends ArmorStand implements Hologram { - - private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); - - private CraftEntity bukkitEntity; - - EntityHologram(ServerLevel serverLevel, double x, double y, double z) { - super(serverLevel, x, y, z); - - setInvisible(true); - setSmall(true); - setShowArms(false); - setNoGravity(true); - setNoBasePlate(true); - setMarker(true); - forceSetBoundingBox(EMPTY_BOUND); - - super.collides = false; - super.setCustomNameVisible(true); - } - - @Override - public void setHologramName(String name) { - super.setCustomName(CraftChatMessage.fromStringOrNull(name)); - } - - @Override - public void removeHologram() { - super.remove(RemovalReason.DISCARDED); - } - - @Override - public org.bukkit.entity.ArmorStand getHandle() { - return this.getBukkitEntity(); - } - - @Override - public void inactiveTick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - @Override - public boolean repositionEntityAfterLoad() { - return false; - } - - @Override - public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { - // Prevent stand being equipped - } - - @Override - public void addAdditionalSaveData(CompoundTag compoundTag) { - // Do not save NBT. - } - - @Override - public void readAdditionalSaveData(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { - // Prevent stand being equipped - return InteractionResult.PASS; - } - - @Override - public void tick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - public void forceSetBoundingBox(AABB boundingBox) { - super.setBoundingBox(boundingBox); - } - - @Override - public CraftArmorStand getBukkitEntity() { - if (bukkitEntity == null) { - bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); - } - return (CraftArmorStand) bukkitEntity; - } - - @Override - public void remove(RemovalReason removalReason) { - // Prevent being killed. - } - - @Override - public void playSound(SoundEvent soundEvent, float volume, float pitch) { - // Remove sounds. - } - - @Override - public boolean saveAsPassenger(CompoundTag compoundTag) { - // Do not save NBT. - return false; - } - - @Override - public CompoundTag saveWithoutId(CompoundTag compoundTag) { - // Do not save NBT. - return compoundTag; - } - - @Override - public void load(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public boolean isInvulnerableTo(ServerLevel serverLevel, DamageSource damageSource) { - /* - * The field Entity.invulnerable is private. - * It's only used while saving NBTTags, but since the entity would be killed - * on chunk unload, we prefer to override isInvulnerable(). - */ - return true; - } - - @Override - public void setCustomName(Component component) { - // Locks the custom name. - } - - @Override - public void setCustomNameVisible(boolean isCustomNameVisible) { - // Locks the custom name. - } - - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSPlayersImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSPlayersImpl.java deleted file mode 100644 index 038c7759ce..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSPlayersImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.nms.NMSPlayers; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.player.OfflinePlayerDataImpl; -import com.bgsoftware.superiorskyblock.player.PlayerLocales; -import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.level.ServerPlayer; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Item; -import org.bukkit.entity.Player; - -import java.util.Locale; - -public class NMSPlayersImpl implements NMSPlayers { - - private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - - @Override - public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { - return OfflinePlayerDataImpl.create(offlinePlayer); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer) { - Player player = superiorPlayer.asPlayer(); - - if (player == null) - return; - - ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() - .ifPresent(property -> setSkinTexture(superiorPlayer, property)); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { - superiorPlayer.setTextureValue(property.value()); - } - - @SuppressWarnings("deprecation") - @Override - public void sendActionBar(Player player, String message) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); - } - - @Override - public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { - BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); - bossBar.addPlayer(player); - return bossBar; - } - - @SuppressWarnings("deprecation") - @Override - public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { - player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); - } - - @Override - public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { - return superiorPlayer.getUniqueId().equals(item.getThrower()); - } - - @Nullable - @Override - public Locale getPlayerLocale(Player player) { - if (PLAYER_LOCALE.isValid()) { - return player.locale(); - } else try { - //noinspection deprecation - return PlayerLocales.getLocale(player.getLocale()); - } catch (IllegalArgumentException error) { - return null; - } - } - - private static class BossBarImpl implements BossBar { - - private final org.bukkit.boss.BossBar bossBar; - private final BossBarTask bossBarTask; - - public BossBarImpl(String message, BarColor color, double ticksToRun) { - bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); - this.bossBarTask = BossBarTask.create(this, ticksToRun); - } - - @Override - public void addPlayer(Player player) { - this.bossBar.addPlayer(player); - this.bossBarTask.registerTask(player); - } - - @Override - public void removeAll() { - this.bossBar.removeAll(); - this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); - } - - @Override - public void setProgress(double progress) { - this.bossBar.setProgress(progress); - } - - @Override - public double getProgress() { - return this.bossBar.getProgress(); - } - - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java index 35da93c380..98090c483d 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java @@ -1,86 +1,28 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_3; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.ListTag; -import com.bgsoftware.superiorskyblock.tag.Tag; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; -import com.mojang.serialization.Dynamic; -import net.minecraft.SharedConstants; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; -import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.util.Optional; import java.util.Set; -@SuppressWarnings({"unused"}) -public class NMSTagsImpl implements NMSTags { - - @Override - public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) - itemStack.save(MinecraftServer.getServer().registryAccess()); - tagCompound.putInt("DataVersion", SharedConstants.getCurrentVersion().getDataVersion().getVersion()); - - return CompoundTag.fromNBT(tagCompound); - } - - @Override - public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { - if (compoundTag.containsKey("NBT")) { - // Old compound version, deserialize it accordingly - return deserializeItemOld(compoundTag); - } - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); - - int currentVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - int itemVersion = tagCompound.getInt("DataVersion"); - if (itemVersion < currentVersion) { - tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, - new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); - } - - ItemStack itemStack = ItemStack.parse(MinecraftServer.getServer().registryAccess(), tagCompound).orElseThrow(); - - return CraftItemStack.asCraftMirror(itemStack); - } - - private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); - Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount").orElse(0); - short data = (short) compoundTag.getShort("data").orElse(0); - CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); - - org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - if (nbtData != null) - itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); - - return CraftItemStack.asCraftMirror(itemStack); - } +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSTags { @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { @@ -97,18 +39,30 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I } @Override - @SuppressWarnings("ConstantConditions") - public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { - net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) + itemStack.save(MinecraftServer.getServer().registryAccess()); + tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + return CompoundTag.fromNBT(tagCompound); + } + + @Override + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; + } - if (compoundTag == null) - compoundTag = new net.minecraft.nbt.CompoundTag(); + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow(); + } - if (!compoundTag.contains("id")) - //noinspection deprecation - compoundTag.putString("id", entityType.getName()); + @Override + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); + } - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; @@ -170,29 +124,4 @@ public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } - @Override - public Object parseList(ListTag listTag) { - net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); - - for (Tag tag : listTag) - nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); - - return nbtTagList; - } - - @Override - public Object getNBTCompoundTag(Object object, String key) { - return ((net.minecraft.nbt.CompoundTag) object).get(key); - } - - @Override - public void setNBTCompoundTagValue(Object object, String key, Object value) { - ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); - } - - @Override - public int getNBTTagListSize(Object object) { - return ((net.minecraft.nbt.ListTag) object).size(); - } - } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java deleted file mode 100644 index 7d4133d4fc..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSUtils.java +++ /dev/null @@ -1,535 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3; - -import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.PropertiesMapper; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; -import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; -import com.google.common.base.Suppliers; -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkPyramid; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.chunk.status.ChunkStep; -import net.minecraft.world.level.chunk.storage.EntityStorage; -import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.generator.CustomChunkGenerator; - -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; - -public class NMSUtils { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( - ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); - private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( - ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); - private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( - EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); - - private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); - - public static final ObjectsPool> BLOCK_POS_POOL = - ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); - - private NMSUtils() { - - } - - @Nullable - public static T getBlockEntityAt(Location location, Class type) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); - } - } - - public static void runActionOnEntityChunks(Collection chunksCoords, - ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); - } - - public static void runActionOnChunks(Collection chunksCoords, - boolean saveChunks, ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); - } - - private static void runActionOnChunksInternal(Collection chunksCoords, - ChunkCallback chunkCallback, - Consumer> onUnloadChunkAction) { - List unloadedChunks = new LinkedList<>(); - List loadedChunks = new LinkedList<>(); - - chunksCoords.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - ChunkAccess chunkAccess; - - try { - chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); - } catch (Throwable ex) { - chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); - } - - if (chunkAccess instanceof LevelChunk levelChunk) { - loadedChunks.add(levelChunk); - } else { - unloadedChunks.add(chunkPosition.copy()); - } - }); - - boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); - - if (!loadedChunks.isEmpty()) - runActionOnLoadedChunks(loadedChunks, chunkCallback); - - if (hasUnloadedChunks) { - onUnloadChunkAction.accept(unloadedChunks); - } else { - chunkCallback.onFinish(); - } - } - - private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { - chunks.forEach(chunkCallback::onLoadedChunk); - } - - private static void runActionOnUnloadedChunks(Collection chunks, - boolean saveChunks, ChunkCallback chunkCallback) { - if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { - Iterator chunksIterator = chunks.iterator(); - while (chunksIterator.hasNext()) { - ChunkPosition chunkPosition = chunksIterator.next(); - - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( - chunkPosition.getX(), chunkPosition.getZ()); - - if (cachedUnloadedChunk != null) { - chunkCallback.onLoadedChunk(cachedUnloadedChunk); - chunksIterator.remove(); - } - } - - if (chunks.isEmpty()) { - chunkCallback.onFinish(); - return; - } - } - - CompletableFuture pendingTask = new CompletableFuture<>(); - PENDING_CHUNK_ACTIONS.add(pendingTask); - - BukkitExecutor.createTask().runAsync(v -> { - CountDownLatch countDownLatch; - if (chunkCallback.isWaitForChunkLoad) { - countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - } else { - countDownLatch = null; - } - - List chunkCompounds = new LinkedList<>(); - - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - boolean calledCountdown = false; - try { - net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); - - if (chunkCompound == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), - Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, - Optional.empty(), chunkPos, serverLevel); - - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - calledCountdown = true; - - if (saveChunks) - chunkCompounds.add(unloadedChunkCompound); - } catch (Exception error) { - if (!calledCountdown && countDownLatch != null) - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - if (countDownLatch != null) { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - } - - return chunkCompounds; - }).runSync(chunkCompounds -> { - chunkCompounds.forEach(unloadedChunkCompound -> { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = unloadedChunkCompound.chunkPos(); - - try { - chunkMap.write(chunkPos, () -> unloadedChunkCompound.chunkCompound); - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); - } - }); - - chunkCallback.onFinish(); - - pendingTask.complete(null); - PENDING_CHUNK_ACTIONS.remove(pendingTask); - }); - } - - private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); - SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { - if (error != null) { - countDownLatch.countDown(); - throw new RuntimeException(error); - } else { - net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - } else { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } - } - }); - }); - - BukkitExecutor.createTask().runAsync(v -> { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } else { - BukkitExecutor.createTask().runAsync(v -> { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - try { - MoonriseRegionFileIO.RegionDataController regionDataController = - serverLevel.moonrise$getEntityChunkDataController(); - int chunkX = chunkPosition.getX(); - int chunkZ = chunkPosition.getZ(); - MoonriseRegionFileIO.RegionDataController.ReadData readData = - regionDataController.readData(chunkX, chunkZ); - if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { - net.minecraft.nbt.CompoundTag entityData = readData.syncRead(); - if (entityData != null) { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - return; - } - } - - chunkCallback.onChunkNotExist(chunkPosition); - } catch (IOException error) { - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } - } - - public static List> getPendingChunkActions() { - return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); - } - - public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { - return new ProtoChunk(chunkPos, - UpgradeData.EMPTY, - serverLevel, - serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), - null); - } - - public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { - ServerLevel serverLevel = levelChunk.level; - - if (!isValidPosition(serverLevel, blockPos)) - return null; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - serverLevel.setBlock(blockPos, blockState, 3); - return blockState; - } - - int indexY = serverLevel.getSectionIndex(blockPos.getY()); - - LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - boolean isOriginallyChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - - levelChunk.markUnsaved(); - - boolean isChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) - serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); - - serverLevel.getLightEngine().checkBlock(blockPos); - - if (tileEntity != null) { - net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); - if (tileEntityCompound != null) { - tileEntityCompound.putInt("x", blockPos.getX()); - tileEntityCompound.putInt("y", blockPos.getY()); - tileEntityCompound.putInt("z", blockPos.getZ()); - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.loadWithComponents(tileEntityCompound, MinecraftServer.getServer().registryAccess()); - } - } - - return blockState; - } - - public static boolean isDoubleBlock(Block block, BlockState blockState) { - return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && - blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; - } - - @Nullable - public static LevelChunk getCraftChunkHandle(CraftChunk craftChunk) { - ServerLevel serverLevel = craftChunk.getCraftWorld().getHandle(); - LevelChunk loadedChunk = serverLevel.getChunkIfLoaded(craftChunk.getX(), craftChunk.getZ()); - if (loadedChunk != null) - return loadedChunk; - - return (LevelChunk) serverLevel.getChunk(craftChunk.getX(), craftChunk.getZ(), ChunkStatus.FULL, true); - } - - public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkAccess chunkAccess) { - CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), serverLevel.generator); - - ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); - - // Unsafe: we do not provide chunks cache, even tho it is required. - // Should be fine in normal flow, as the only method that access the chunsk cache - // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: - // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 - WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); - - customChunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - chunkAccess); - } - - public record UnloadedChunkCompound(ChunkPosition chunkPosition, - net.minecraft.nbt.CompoundTag chunkCompound) { - - public ListTag getSections() { - return chunkCompound.getList("sections", 10); - } - - public ListTag getEntities() { - return chunkCompound.getList("Entities", 10); - } - - public void setSections(ListTag sectionsList) { - chunkCompound.put("sections", sectionsList); - } - - public void setEntities(ListTag entitiesList) { - chunkCompound.put("entities", entitiesList); - } - - public void setBlockEntities(ListTag blockEntitiesList) { - chunkCompound.put("block_entities", blockEntitiesList); - } - - public ServerLevel serverLevel() { - return ((CraftWorld) chunkPosition.getWorld()).getHandle(); - } - - public ChunkPos chunkPos() { - return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - } - - } - - private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); - } - - public static abstract class ChunkCallback { - - private final ChunkLoadReason chunkLoadReason; - private final boolean isWaitForChunkLoad; - - @Nullable - protected CountDownLatch chunkLoadLatch; - - public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { - this.chunkLoadReason = chunkLoadReason; - this.isWaitForChunkLoad = isWaitForChunkLoad; - } - - public abstract void onLoadedChunk(LevelChunk levelChunk); - - public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - - public abstract void onFinish(); - - protected final void latchCountDown() { - if (this.chunkLoadLatch != null) - this.chunkLoadLatch.countDown(); - } - - public final void onChunkNotExist(ChunkPosition chunkPosition) { - if (!plugin.getProviders().hasCustomWorldsSupport()) - return; - - ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { - LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); - }); - } - - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index c6ba9d88ec..481da694b9 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -3,131 +3,57 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; -import com.bgsoftware.superiorskyblock.nms.ICachedBlock; -import com.bgsoftware.superiorskyblock.nms.NMSWorld; -import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.generator.IslandsGeneratorImpl; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_3.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_3.vibration.IslandVibrationUser; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.ChunkReaderImpl; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.WorldEditSessionImpl; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.destroystokyo.paper.antixray.ChunkPacketBlockController; -import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.BubbleColumn; import org.bukkit.block.data.type.HangingSign; -import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.WallHangingSign; -import org.bukkit.block.data.type.WallSign; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.block.CraftBlock; -import org.bukkit.craftbukkit.block.CraftBlockState; -import org.bukkit.craftbukkit.block.CraftSign; -import org.bukkit.craftbukkit.block.data.CraftBlockData; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.function.IntFunction; -public class NMSWorldImpl implements NMSWorld { +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); - private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, - Object.class, "chunkPacketBlockController") - .removeFinal(); - - private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); } @Override - public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { - Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); - Location location = new Location( - Bukkit.getWorld(chunkSnapshot.getWorldName()), - (chunkSnapshot.getX() << 4) + x, - y, - (chunkSnapshot.getZ() << 4) + z - ); - - return Keys.of(KeyBlocksCache.getBlockKey(block), location); + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); } @Override - public void listenSpawner(Location location, IntFunction delayChangeCallback) { - SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); - if (spawnerBlockEntity == null) + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; - ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - - List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? - LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; - - Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new LinkedList<>(); - - while (blockEntityTickersIterator.hasNext()) { - TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && - !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { - blockEntityTickersIterator.remove(); - tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); - } - } + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } - if (!tickersToAdd.isEmpty()) - blockEntityTickers.addAll(tickersToAdd); + @Override + public SignType getSignType(Object sign) { + if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return super.getSignType(sign); } @Override @@ -174,263 +100,4 @@ public void replaceTrialBlockPlayerDetector(Island island, Location location) { } } - @Override - public void replaceSculkSensorListener(Island island, Location location) { - SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); - if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) - return; - - SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); - } - - @Override - public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { - if (!plugin.getSettings().isWorldBorders()) - return; - - Player player = superiorPlayer.asPlayer(); - World world = superiorPlayer.getWorld(); - - if (world == null || player == null) - return; - - int islandSize = island == null ? 0 : island.getIslandSize(); - - boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; - - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - - WorldBorder worldBorder; - - if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { - worldBorder = serverLevel.getWorldBorder(); - } else { - Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); - if (dimension == null) - return; - - Location center = island.getCenter(dimension); - - worldBorder = new WorldBorder(); - worldBorder.world = serverLevel; - worldBorder.setWarningBlocks(0); - worldBorder.setCenter(center.getX(), center.getZ()); - - switch (superiorPlayer.getBorderColor()) { - case BLUE -> { - worldBorder.setSize((islandSize * 2) + 1D); - } - case GREEN -> { - worldBorder.setSize((islandSize * 2) + 1.001D); - worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); - } - case RED -> { - worldBorder.setSize((islandSize * 2) + 1D); - worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); - } - } - } - - ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); - ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); - } - - @Override - public Object getBlockData(org.bukkit.block.Block block) { - return block.getBlockData(); - } - - @Override - public void setBlock(Location location, int combinedId) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - BlockState blockState = - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - - if (blockState != null) { - serverLevel.getChunkSource().blockChanged(blockPos); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); - } - } - } - } - - @Override - public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return NMSCachedBlock.obtain(block); - } - - @Override - public boolean isWaterLogged(org.bukkit.block.Block block) { - if (Materials.isWater(block.getType())) - return true; - - BlockData blockData = block.getBlockData(); - - return blockData instanceof BubbleColumn || - (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); - } - - @Override - public SignType getSignType(Object sign) { - if (sign instanceof WallSign) - return SignType.WALL_SIGN; - else if (sign instanceof Sign) - return SignType.STANDING_SIGN; - else if (sign instanceof HangingSign) - return SignType.HANGING_SIGN; - else if (sign instanceof WallHangingSign) - return SignType.HANGING_WALL_SIGN; - else - return SignType.UNKNOWN; - } - - @Override - public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { - BlockState blockState = ((CraftBlock) block).getNMS(); - return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; - } - - @Override - public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { - return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); - } - - @Override - public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { - return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); - } - - private int getDefaultAmount(BlockState blockState) { - Block block = blockState.getBlock(); - return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; - } - - @Override - public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { - return !bukkitBlock.isPassable(); - } - - @Override - public void placeSign(Island island, Location location) { - SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); - if (signBlockEntity == null) - return; - - String[] lines = new String[4]; - Component[] messages = signBlockEntity.getFrontText().getMessages(false); - System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - Component[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } - - System.arraycopy(newLines, 0, messages, 0, 4); - } - - @Override - public void playGeneratorSound(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); - } - } - - @Override - public void playBreakAnimation(org.bukkit.block.Block block) { - ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); - } - } - - @Override - public void playPlaceSound(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); - } - } - - @Override - public int getMinHeight(World world) { - return world.getMinHeight(); - } - - @Override - public void removeAntiXray(org.bukkit.World bukkitWorld) { - if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); - } - - @Override - public IslandsGenerator createGenerator(Dimension dimension) { - return new IslandsGeneratorImpl(dimension); - } - - @Override - public WorldEditSession createEditSession(World world) { - return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); - } - - @Override - public WorldEditSession createPartialEditSession(Dimension dimension) { - return WorldEditSessionImpl.obtain(dimension); - } - - @Override - public ChunkReader createChunkReader(Chunk chunk) { - return new ChunkReaderImpl(chunk); - } - - private static ReflectField> initializeLevelBlockEntityTickersField() { - ReflectField> field = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - - if (!field.isValid()) - field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); - - return field; - } - } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsBlockEntity.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsBlockEntity.java deleted file mode 100644 index baea19acfb..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsBlockEntity.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.crops; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.function.Consumer; - -public class CropsBlockEntity extends BlockEntity { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - - private final WeakReference island; - private final WeakReference chunk; - - private int currentTick = 0; - - private double cachedCropGrowthMultiplier; - - private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(levelChunk); - setLevel(levelChunk.level); - levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; - } - - public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); - return new CropsBlockEntity(island, levelChunk, blockPos); - }); - } - - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); - } - - public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { - if (tickingChunks.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> { - long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); - if (cropsBlockEntity != null) - cropsBlockEntityConsumer.accept(cropsBlockEntity); - }); - } - - @Override - public boolean isValidBlockState(BlockState state) { - return true; - } - - public void remove() { - this.remove = true; - } - - public void tick() { - if (++currentTick <= plugin.getSettings().getCropsInterval()) - return; - - LevelChunk levelChunk = this.chunk.get(); - Island island = this.island.get(); - ServerLevel serverLevel = (ServerLevel) getLevel(); - - if (levelChunk == null || island == null || serverLevel == null) { - remove(); - return; - } - - currentTick = 0; - - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - if (chunkRandomTickSpeed > 0) - CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); - } - - public void setCropGrowthMultiplier(double cropGrowthMultiplier) { - this.cachedCropGrowthMultiplier = cropGrowthMultiplier; - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingBlockEntity.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingBlockEntity.java deleted file mode 100644 index abfac14dd1..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingBlockEntity.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.crops; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { - - - @Override - public void tick() { - cropsBlockEntity.tick(); - } - - @Override - public boolean isRemoved() { - return cropsBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return cropsBlockEntity.getBlockPos(); - } - - @Override - public String getType() { - return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java deleted file mode 100644 index f4afd4f8f0..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/crops/CropsTickingMethod.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.crops; - -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; - -public abstract class CropsTickingMethod { - - private static final ReflectField SERVER_LEVEL_SIMPLE_RANDOM = new ReflectField<>( - ServerLevel.class, RandomSource.class, "simpleRandom"); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static Set CROPS_TO_GROW_CACHE; - - static { - plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); - } - - private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_SIMPLE_RANDOM.isValid() ? - new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); - - protected CropsTickingMethod() { - - } - - public static void register() { - // Calls the static initializer which registers the callback. - } - - public static void tick(LevelChunk levelChunk, int tickSpeed) { - INSTANCE.doTick(levelChunk, tickSpeed); - } - - protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); - - private static void onSettingsUpdate() { - CROPS_TO_GROW_CACHE = new HashSet<>(); - plugin.getSettings().getCropsToGrow().forEach(cropName -> { - Key key = Keys.ofMaterialAndData(cropName); - if (key instanceof MaterialKey materialKey) { - Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); - if (block != null && block.defaultBlockState().isRandomlyTicking()) - CROPS_TO_GROW_CACHE.add(block); - } - }); - } - - private static class PaperCropsTickingMethod extends CropsTickingMethod { - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - ServerLevel serverLevel = levelChunk.level; - LevelChunkSection[] sections = levelChunk.getSections(); - - int minSection = serverLevel.getMinSectionY(); - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - RandomSource simpleRandom = SERVER_LEVEL_SIMPLE_RANDOM.get(serverLevel); - - for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - ca.spottedleaf.moonrise.common.list.ShortList tickList = - levelChunkSection.moonrise$getTickingBlockList(); - int tickingBlocks = tickList.size(); - if (tickingBlocks <= 0) { - continue; - } - - PalettedContainer states = levelChunkSection.states; - - int offsetY = (sectionIndex + minSection) << 4; - - for (int i = 0; i < tickSpeed; ++i) { - int index = simpleRandom.nextInt() & 0xFFF; - - if (index >= tickingBlocks) { - continue; - } - - int location = (int) tickList.getRaw(index) & 0xFFFF; - BlockState blockState = states.get(location); - if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) - continue; - - // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! - BlockPos blockPos = new BlockPos((location & 15) | chunkOffsetX, - ((location >>> 8) & 15) | offsetY, - ((location >>> 4) & 15) | chunkOffsetZ); - - blockState.randomTick(serverLevel, blockPos, simpleRandom); - } - } - - } - - } - - private static class SpigotCropsTickingMethod extends CropsTickingMethod { - - private static int random = ThreadLocalRandom.current().nextInt(); - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - LevelChunkSection[] sections = levelChunk.getSections(); - ServerLevel serverLevel = levelChunk.level; - - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - - for (int i = 0; i < tickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { - BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); - blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); - } - } - } - } - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/DragonUtils.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/DragonUtils.java deleted file mode 100644 index 499296e9d3..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/DragonUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon; - -import com.bgsoftware.common.reflection.ReflectField; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; - -import java.lang.reflect.Modifier; - -public class DragonUtils { - - private static final ReflectField END_PODIUM_LOCATION = new ReflectField( - EndPodiumFeature.class, BlockPos.class, - Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static BlockPos currentPodiumPosition = BlockPos.ZERO; - - private DragonUtils() { - - } - - public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { - try { - END_PODIUM_LOCATION.set(null, podiumPosition); - currentPodiumPosition = podiumPosition; - runnable.run(); - } finally { - END_PODIUM_LOCATION.set(null, BlockPos.ZERO); - currentPodiumPosition = BlockPos.ZERO; - } - } - - public static BlockPos getCurrentPodiumPosition() { - return currentPodiumPosition; - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndWorldEndDragonFightHandler.java deleted file mode 100644 index dfe908e641..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndWorldEndDragonFightHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; -import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.dimension.end.EndDragonFight; - -import java.util.LinkedList; -import java.util.List; - -public class EndWorldEndDragonFightHandler extends EndDragonFight { - - private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); - - private final List worldDragonFightsList = new LinkedList<>(); - - public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); - } - - @Override - public void tick() { - this.worldDragonFightsList.forEach(EndDragonFight::tick); - } - - public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); - if (oldDragonFight != null) - this.worldDragonFightsList.remove(oldDragonFight); - this.worldDragonFightsList.add(endDragonFight); - } - - @Nullable - public IslandEndDragonFight getDragonFight(IslandCache islandCache) { - return islandCache.get(CACHE_KEY); - } - - @Nullable - public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { - IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); - if (endDragonFight != null) - this.worldDragonFightsList.remove(endDragonFight); - return endDragonFight; - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEndDragonFight.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEndDragonFight.java deleted file mode 100644 index e5e1cc7778..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEndDragonFight.java +++ /dev/null @@ -1,211 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; -import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import net.minecraft.world.level.block.state.pattern.BlockPattern; -import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; -import net.minecraft.world.level.block.state.predicate.BlockPredicate; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -public class IslandEndDragonFight extends EndDragonFight { - - private static final ReflectField DRAGON_BATTLE = new ReflectField( - EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 4); - private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); - - private static final ReflectField TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>( - EndDragonFight.class, int.class, Modifier.PRIVATE, 4); - private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( - DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); - - private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") - .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") - .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) - .build(); - - private final Island island; - private final BlockPos islandBlockPos; - private final Vec3 islandBlockVectored; - private final ServerLevel serverLevel; - private final IslandEntityEnderDragon entityEnderDragon; - - private byte currentTick = 0; - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { - this(island, serverLevel, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), null); - } - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, - @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); - - this.island = island; - this.islandBlockPos = islandBlockPos; - this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); - this.serverLevel = serverLevel; - this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; - - SCAN_FOR_LEGACY_PORTALS.set(this, false); - WAS_DRAGON_KILLED.set(this, false); - DRAGON_BATTLE.set(this.entityEnderDragon, this); - - TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); - } - - @Override - public void tick() { - // doServerTick - - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); - - DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); - if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { - LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); - } - - if (++currentTick >= 20) { - updateBattlePlayers(); - currentTick = 0; - TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); - } - } - - @Nullable - @Override - public BlockPattern.BlockPatternMatch findExitPortal() { - int chunkX = this.islandBlockPos.getX() >> 4; - int chunkZ = this.islandBlockPos.getZ() >> 4; - - for (int x = -8; x <= 8; ++x) { - for (int z = -8; z <= 8; ++z) { - LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); - - for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { - if (blockEntity instanceof TheEndPortalBlockEntity) { - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( - this.serverLevel, blockEntity.getBlockPos()); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - } - } - - int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); - currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); - for (int y = highestBlock; y >= this.serverLevel.getMinY(); --y) { - currentPosition.setY(y); - - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - - return null; - } - - @Override - public void resetSpikeCrystals() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); - } - - public void removeBattlePlayers() { - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - for (ServerPlayer serverPlayer : dragonEventPlayers) - this.dragonEvent.removePlayer(serverPlayer); - } - - public IslandEntityEnderDragon getEnderDragon() { - return this.entityEnderDragon; - } - - private void updateBattlePlayers() { - Set nearbyPlayers = new HashSet<>(); - - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - Player bukkitPlayer = superiorPlayer.asPlayer(); - if (bukkitPlayer != null) { - ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); - if (serverPlayer.serverLevel().equals(this.serverLevel)) { - this.dragonEvent.addPlayer(serverPlayer); - nearbyPlayers.add(serverPlayer.getUUID()); - } - } - } - - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - - dragonEventPlayers.stream() - .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) - .forEach(this.dragonEvent::removePlayer); - } - - private IslandEntityEnderDragon spawnEnderDragon() { - IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); - - entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); - entityEnderDragon.absMoveTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), - this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); - - this.serverLevel.addFreshEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); - - this.dragonUUID = entityEnderDragon.getUUID(); - this.resetSpikeCrystals(); - - return entityEnderDragon; - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java index 2a10d46c3e..1b7cf541ec 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/IslandEntityEnderDragon.java @@ -2,59 +2,34 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.config.SettingsManager; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntitySpawnReason; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; -import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftEnderDragon; -public class IslandEntityEnderDragon extends EnderDragon { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - @NotNull - public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { - return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : - new EnderDragon(entityTypes, level); - } - - private final ServerLevel serverLevel; - private final Dimension dimension; - private BlockPos islandBlockPos; +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { - this(level); - this.islandBlockPos = islandBlockPos; + super(level, islandBlockPos); } - private IslandEntityEnderDragon(Level level) { - super(EntityType.ENDER_DRAGON, level); - this.serverLevel = (ServerLevel) level; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + public IslandEntityEnderDragon(Level level) { + super(level); } @Nullable @Override - public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, - @Nullable SpawnGroupData spawnGroupData) { + @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); - return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override @@ -64,40 +39,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { finalizeIslandEnderDragon(); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - - private void finalizeIslandEnderDragon() { - if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) - return; - - Island island; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); - } - - if (island == null) - return; - - Location middleBlock = island.getCenter(dimension); - - SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); - if (dimensionConfig instanceof SettingsManager.Worlds.End) { - middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); - } - - this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); - - IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); - } - } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/SpikesCache.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/SpikesCache.java deleted file mode 100644 index dd10c18103..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/SpikesCache.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon; - - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.common.annotations.Nullable; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.CacheStats; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public class SpikesCache implements LoadingCache> { - - private static final SpikesCache INSTANCE = new SpikesCache(); - - private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() - .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); - - private long worldSeed; - - public static SpikesCache getInstance() { - return INSTANCE; - } - - private SpikesCache() { - - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - List getUnchecked(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public List apply(@NotNull Long worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void refresh(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ConcurrentMap> asMap() { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Nullable - @Override - public List getIfPresent(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed, - @NotNull Callable> loader) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAllPresent(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void put(@NotNull Long worldSeed, @NotNull List spikes) { - try { - this.worldSeed = worldSeed; - cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); - } finally { - this.worldSeed = 0; - } - } - - @Override - public void putAll(Map> spikesMap) { - spikesMap.forEach(this::put); - } - - @Override - public void invalidate(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll() { - this.cachedSpikes.invalidateAll(); - } - - @Override - public long size() { - return this.cachedSpikes.size(); - } - - @Override - public @NotNull - CacheStats stats() { - return this.cachedSpikes.stats(); - } - - @Override - public void cleanUp() { - this.cachedSpikes.cleanUp(); - } - - private class InternalCacheLoader extends CacheLoader> { - - @Override - public @NotNull - List load(@NotNull BlockPos blockPos) { - List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); - - Collections.shuffle(list, new Random(worldSeed)); - List spikesList = Lists.newArrayList(); - - for (int i = 0; i < 10; ++i) { - int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int l = list.get(i); - int radius = 2 + l / 3; - int height = 76 + l * 3; - boolean guarded = l == 1 || l == 2; - - spikesList.add(new SpikeFeature.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded)); - } - - return spikesList; - } - - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/generator/IslandsGeneratorImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/generator/IslandsGeneratorImpl.java deleted file mode 100644 index e5b7722082..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/generator/IslandsGeneratorImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.generator; - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; -import org.bukkit.generator.WorldInfo; - -import java.util.Collections; -import java.util.List; -import java.util.Random; - -@SuppressWarnings({"unused", "NullableProblems"}) -public class IslandsGeneratorImpl extends IslandsGenerator { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private final Dimension dimension; - - public IslandsGeneratorImpl(Dimension dimension) { - this.dimension = dimension; - } - - @Override - public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, - @NotNull ChunkData chunkData) { - if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { - chunkData.setBlock(0, 99, 0, Material.BEDROCK); - } - } - - @Override - public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { - return new BiomeProvider() { - @Override - public @NotNull - Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { - return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension); - } - - @Override - public @NotNull - List getBiomes(@NotNull WorldInfo worldInfo) { - return IslandUtils.getDefaultWorldBiomes(); - } - - }; - } - - @Override - public List getDefaultPopulators(World world) { - return Collections.emptyList(); - } - - @Override - public Location getFixedSpawnLocation(World world, Random random) { - return new Location(world, 0, 100, 0); - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/hologram/EntityHologram.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/hologram/EntityHologram.java new file mode 100644 index 0000000000..c17b157278 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/hologram/EntityHologram.java @@ -0,0 +1,39 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.hologram; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_3.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuBrewingStandBlockEntity.java deleted file mode 100644 index beaf44850e..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuBrewingStandBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { - - private final InventoryHolder holder; - - public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuDispenserBlockEntity.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuDispenserBlockEntity.java deleted file mode 100644 index f4ae61e8f8..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuDispenserBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.DispenserBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuDispenserBlockEntity extends DispenserBlockEntity { - - private final InventoryHolder holder; - - public MenuDispenserBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuFurnaceBlockEntity.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuFurnaceBlockEntity.java deleted file mode 100644 index dd967845a1..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuFurnaceBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.FurnaceBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { - - private final InventoryHolder holder; - - public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuHopperBlockEntity.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuHopperBlockEntity.java deleted file mode 100644 index 45729b238b..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/menu/MenuHopperBlockEntity.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.HopperBlock; -import net.minecraft.world.level.block.entity.HopperBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuHopperBlockEntity extends HopperBlockEntity { - - private final InventoryHolder holder; - - public MenuHopperBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.HOPPER.defaultBlockState().setValue(HopperBlock.FACING, Direction.DOWN)); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/player/OfflinePlayerDataImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/player/OfflinePlayerDataImpl.java deleted file mode 100644 index bcfed6d315..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/player/OfflinePlayerDataImpl.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.player; - -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.level.Level; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; - -import java.util.Optional; - -public class OfflinePlayerDataImpl implements OfflinePlayerData { - - private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); - - private Player fakePlayer; - - public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { - return POOL.obtain().initialize(offlinePlayer); - } - - private OfflinePlayerDataImpl() { - - } - - private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), - Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return null; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - this.fakePlayer = serverPlayer.getBukkitEntity(); - this.fakePlayer.loadData(); - - return this; - } - - @Override - public Player getFakeOnlinePlayer() { - return this.fakePlayer; - } - - @Override - public void setLocation(Location location) { - ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); - serverPlayer.setLevel(((CraftWorld) location.getWorld()).getHandle()); - serverPlayer.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - } - - @Override - public void applyChanges() { - this.fakePlayer.saveData(); - } - - @Override - public void release() { - this.fakePlayer = null; - POOL.release(this); - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/spawners/TickingSpawnerBlockEntityNotifier.java deleted file mode 100644 index b579de04cb..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/spawners/TickingSpawnerBlockEntityNotifier.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.spawners; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BaseSpawner; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -import java.util.function.IntFunction; - -public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { - - private final SpawnerBlockEntity spawnerBlockEntity; - private final TickingBlockEntity tickingBlockEntity; - private final IntFunction delayChangeCallback; - - public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, - IntFunction delayChangeCallback) { - this.spawnerBlockEntity = spawnerBlockEntity; - this.tickingBlockEntity = tickingBlockEntity; - this.delayChangeCallback = delayChangeCallback; - updateDelay(); - } - - @Override - public void tick() { - BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); - int startDelay = baseSpawner.spawnDelay; - try { - tickingBlockEntity.tick(); - } finally { - int newDelay = baseSpawner.spawnDelay; - if (newDelay > startDelay) - updateDelay(); - } - } - - @Override - public boolean isRemoved() { - return tickingBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return tickingBlockEntity.getPos(); - } - - @Override - public String getType() { - return tickingBlockEntity.getType(); - } - - public void updateDelay() { - BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); - baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..20332e7811 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java @@ -0,0 +1,375 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.utils; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.utils.TickingBlockList; +import com.google.common.base.Suppliers; +import com.google.gson.JsonParseException; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +public class NMSUtilsVersioned { + + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( + EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { + return chunkMap.read(chunkPos).join().orElse(null); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { + return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), + chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { + chunkMap.write(chunkPos, () -> chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } else { + return BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + MoonriseRegionFileIO.RegionDataController regionDataController = + serverLevel.moonrise$getEntityChunkDataController(); + int chunkX = chunkPosition.getX(); + int chunkZ = chunkPosition.getZ(); + MoonriseRegionFileIO.RegionDataController.ReadData readData = + regionDataController.readData(chunkX, chunkZ); + if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { + net.minecraft.nbt.CompoundTag entityData = readData.syncRead(); + if (entityData != null) { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + return; + } + } + + chunkCallback.onChunkNotExist(chunkPosition); + } catch (IOException error) { + countDownLatch.countDown(); + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.liquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess()); + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + applySignTextLines(compoundTag, "front_text"); + applySignTextLines(compoundTag, "back_text"); + convertLegacySignTextLines(compoundTag); + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + + Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + + chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); + + // Unsafe: we do not provide chunks cache, even tho it is required. + // Should be fine in normal flow, as the only method that access the chunks cache + // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 + WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); + + customChunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + } + + public static CompoundTag saveEntity(Entity entity) { + CompoundTag compoundTag = new CompoundTag(); + entity.save(compoundTag); + return compoundTag; + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.moonrise$getTickingBlockList().size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + public static String getPropertyValue(Property property) { + return property.value(); + } + + public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.getDragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absMoveTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSectionY(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinY(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxY(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.markUnsaved(); + } + + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { + if (blockEntityCompound.contains(key)) { + CompoundTag frontText = blockEntityCompound.getCompound(key); + ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); + List textLines = new ArrayList<>(); + for (net.minecraft.nbt.Tag lineTag : messages) { + try { + textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); + } catch (JsonParseException error) { + textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); + } + } + + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); + } + } + + private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockEntityCache.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockEntityCache.java deleted file mode 100644 index 2fc27effc2..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockEntityCache.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class BlockEntityCache { - - private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); - - private BlockEntityCache() { - - } - - public static String getBlockEntityId(BlockState blockState) { - return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { - for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - if (blockEntityType.isValid(blockState)) { - ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); - if (resourceLocation != null) - return resourceLocation.toString(); - } - } - - return ""; - }); - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java deleted file mode 100644 index 398de5a92a..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/ChunkReaderImpl.java +++ /dev/null @@ -1,243 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.block.CraftBlockType; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.InventoryHolder; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class ChunkReaderImpl implements ChunkReader { - - private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - private static final byte[] FULL_LIGHT = new byte[2048]; - private static final byte[] EMPTY_LIGHT = new byte[2048]; - - static { - Arrays.fill(FULL_LIGHT, (byte) 0xFF); - } - - private final ServerLevel serverLevel; - private final int x; - private final int z; - - private final Map blockEntities = new HashMap<>(); - private final List entities = new LinkedList<>(); - private final PalettedContainerRO[] blockids; - private final byte[][] skylight; - private final byte[][] emitlight; - - public ChunkReaderImpl(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - - this.serverLevel = levelChunk.level; - ChunkPos chunkPos = levelChunk.getPos(); - this.x = chunkPos.x; - this.z = chunkPos.z; - - LevelChunkSection[] levelChunkSections = levelChunk.getSections(); - this.blockids = new PalettedContainerRO[levelChunkSections.length]; - this.skylight = new byte[levelChunkSections.length][]; - this.emitlight = new byte[levelChunkSections.length][]; - - LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); - - for (int i = 0; i < this.blockids.length; ++i) { - LevelChunkSection levelChunkSection = levelChunkSections[i]; - - this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); - - DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (skyLightArray == null) { - this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; - } else { - this.skylight[i] = new byte[2048]; - System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); - } - - DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (emitLightArray == null) { - this.emitlight[i] = EMPTY_LIGHT; - } else { - this.emitlight[i] = new byte[2048]; - System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); - } - } - - levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - InventoryHolder inventoryHolder = blockEntity.getOwner(); - if (inventoryHolder != null) - compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); - - blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); - }); - - for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) - entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); - } - - @Override - public int getX() { - return this.x; - } - - @Override - public int getZ() { - return this.z; - } - - @Override - public Material getType(int x, int y, int z) { - return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); - } - - @Override - public short getData(int x, int y, int z) { - return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); - } - - @Override - @Nullable - public CompoundTag getTileEntity(int x, int y, int z) { - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); - return this.blockEntities.get(blockPos); - } - } - - @Override - @Nullable - public CompoundTag readBlockStates(int x, int y, int z) { - BlockState blockState = getBlockState(x, y, z); - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = CompoundTag.of(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(int x, int y, int z) { - int off = (y & 15) << 7 | z << 3 | x >> 1; - int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; - } - - @Override - public void forEachEntity(EntityConsumer consumer) { - if (entities.isEmpty()) - return; - - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = wrapper.getHandle(); - for (CachedEntity cachedEntity : entities) { - location.setX(cachedEntity.x); - location.setY(cachedEntity.y); - location.setZ(cachedEntity.z); - location.setYaw(cachedEntity.yaw); - location.setPitch(cachedEntity.pitch); - consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); - } - } - } - - private BlockState getBlockState(int x, int y, int z) { - return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); - } - - private int getSectionIndex(int y) { - int sectionIndex = SectionPos.blockToSectionCoord(y); - return sectionIndex - this.serverLevel.getMinSectionY(); - } - - private int getSectionYFromSectionIndex(int index) { - return index + this.serverLevel.getMinSectionY(); - } - - private static class CachedEntity { - - private final double x; - private final double y; - private final double z; - private final float yaw; - private final float pitch; - private final EntityType entityType; - private final CompoundTag entityTag; - - CachedEntity(Entity entity) { - this.x = entity.getX(); - this.y = entity.getY(); - this.z = entity.getZ(); - this.yaw = entity.getBukkitYaw(); - this.pitch = entity.getXRot(); - this.entityType = entity.getBukkitEntity().getType(); - - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - - this.entityTag = CompoundTag.fromNBT(compoundTag); - } - - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/KeyBlocksCache.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/KeyBlocksCache.java deleted file mode 100644 index 4fa1124aac..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/KeyBlocksCache.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; - -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.level.block.Block; -import org.bukkit.Material; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class KeyBlocksCache { - - private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); - - private KeyBlocksCache() { - - } - - public static Key getBlockKey(Block block) { - return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { - Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); - }); - } - - public static void cacheAllBlocks() { - BuiltInRegistries.BLOCK.forEach(KeyBlocksCache::getBlockKey); - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/PropertiesMapper.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/PropertiesMapper.java deleted file mode 100644 index aa8e9fe54d..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/PropertiesMapper.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; - -import com.bgsoftware.superiorskyblock.core.logging.Log; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.Property; - -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; - -public class PropertiesMapper { - - private static final Map> nameToProperty = new HashMap<>(); - private static final Map, String> propertyToName = new HashMap<>(); - - static { - Map fieldsToNames = new IdentityHashMap<>(); - - fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); - fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); - fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); - fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); - fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); - fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); - fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); - fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); - fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); - fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); - fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); - fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); - fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); - fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); - fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); - fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); - fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); - fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); - fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); - fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); - fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); - fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); - fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); - fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); - fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); - fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); - fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); - fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); - - try { - for (Field field : BlockStateProperties.class.getFields()) { - field.setAccessible(true); - Object value = field.get(null); - if (value instanceof Property) { - Property property = (Property) value; - register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); - } - } - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while loading properties mapper:"); - } - - } - - private static void register(String key, String fieldName, Property property) { - if (nameToProperty.containsKey(key)) { - Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); - } else { - nameToProperty.put(key, property); - propertyToName.put(property, key); - } - } - - public static Property getProperty(String name) { - return nameToProperty.get(name); - } - - public static String getPropertyName(Property property) { - return propertyToName.get(property); - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/PropertiesMapperVersioned.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..d6dc1c9bf5 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/PropertiesMapperVersioned.java @@ -0,0 +1,17 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; + +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionDataImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionDataImpl.java deleted file mode 100644 index 5ed73c252e..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionDataImpl.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; - -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionDataImpl implements WorldEditSession.Data { - - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private final List> chunks = new LinkedList<>(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); - - public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, - List> blocksToUpdate, - List> blockEntities, - Set lightenChunks) { - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // Convert chunk data - Iterator> chunksIterator = chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); - int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); - WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); - - List> lights; - if (isStarLightInterface || chunkData.lights().isEmpty()) { - lights = Collections.emptyList(); - } else { - lights = new LinkedList<>(); - chunkData.lights().forEach(lightPosition -> { - lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, - lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, - null)); - }); - } - - PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), - chunkData.heightmaps(), lights); - - this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, - currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); - } - - // Convert blocksToUpdate - blocksToUpdate.forEach(blockToUpdate -> { - BlockPos blockPos = blockToUpdate.getKey(); - this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockToUpdate.getValue())); - }); - - // Convert blockEntities - blockEntities.forEach(blockEntity -> { - BlockPos blockPos = blockEntity.getKey(); - this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockEntity.getValue())); - }); - - // Convert lights - lightenChunks.forEach(lightPosition -> { - this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, - lightPosition.z - baseChunkPosZAxis, null)); - }); - } - - public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, - int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, - Long2ObjectMapView chunks) { - this.chunks.forEach(chunkDataPositioned -> { - long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, - baseChunkPosZAxis + chunkDataPositioned.zOffset); - - List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - chunkDataPositioned.object.lights.forEach(lightPositioned -> { - lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, - baseBlockPosYAxis + lightPositioned.yOffset, - baseBlockPosZAxis + lightPositioned.zOffset)); - }); - - chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, - chunkDataPositioned.object.heightmaps, lights)); - }); - } - - public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { - this.blocksToUpdate.forEach(blockToUpdatePositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, - baseBlockPosYAxis + blockToUpdatePositioned.yOffset, - baseBlockPosZAxis + blockToUpdatePositioned.zOffset); - blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); - }); - } - - public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { - this.blockEntities.forEach(blockEntityPositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, - baseBlockPosYAxis + blockEntityPositioned.yOffset, - baseBlockPosZAxis + blockEntityPositioned.zOffset); - blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); - }); - } - - public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { - this.lightenChunks.forEach(lightPositioned -> { - ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, - baseChunkPosZAxis + lightPositioned.zOffset); - lightenChunks.add(newPos); - }); - } - - private static class PositionedObject { - - private final int xOffset; - private final int yOffset; - private final int zOffset; - private final V object; - - PositionedObject(int xOffset, int zOffset, V object) { - this(xOffset, 0, zOffset, object); - } - - PositionedObject(int xOffset, int yOffset, int zOffset, V object) { - this.xOffset = xOffset; - this.yOffset = yOffset; - this.zOffset = zOffset; - this.object = object; - } - - } - - private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, - List> lights) { - } - -} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java deleted file mode 100644 index 21c4372495..0000000000 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/WorldEditSessionImpl.java +++ /dev/null @@ -1,479 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.google.common.base.Preconditions; -import com.google.gson.JsonParseException; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.SignText; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.ticks.ProtoChunkTicks; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.generator.ChunkGenerator; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionImpl implements WorldEditSession { - - private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; - - private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - - private Dimension dimension; - private LevelHeightAccessor levelHeightAccessor; - - @Nullable - private ServerLevel serverLevel; - - public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { - return POOL.obtain().initialize(serverLevel); - } - - public static WorldEditSessionImpl obtain(Dimension dimension) { - return POOL.obtain().initialize(dimension); - } - - private WorldEditSessionImpl() { - } - - private WorldEditSessionImpl initialize(ServerLevel serverLevel) { - this.serverLevel = serverLevel; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); - this.levelHeightAccessor = serverLevel; - return this; - } - - private WorldEditSessionImpl initialize(Dimension dimension) { - DimensionType dimensionType = getDimensionTypeFromDimension(dimension); - this.serverLevel = null; - this.dimension = dimension; - this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); - return this; - } - - @Override - public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, - @Nullable CompoundTag blockEntityData) { - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - if (!isValidPosition(blockPos)) - return; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - blocksToUpdate.add(new Pair<>(blockPos, blockState)); - return; - } - - ChunkPos chunkPos = new ChunkPos(blockPos); - - if (blockEntityData != null) - blockEntities.add(new Pair<>(blockPos, blockEntityData)); - - ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); - - if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) - chunkData.lights.add(blockPos); - - LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - } - - @Override - public List getAffectedChunks() { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); - - if (chunks.isEmpty()) - return Collections.emptyList(); - - List chunkPositions = new LinkedList<>(); - World bukkitWorld = serverLevel.getWorld(); - LongIterator iterator = chunks.keyIterator(); - while (iterator.hasNext()) { - long chunkKey = iterator.next(); - int chunkX = (int) chunkKey; - int chunkZ = (int) (chunkKey >> 32); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); - } - return chunkPositions; - } - - @Override - public void applyBlocks(Chunk bukkitChunk) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); - - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); - ChunkPos chunkPos = levelChunk.getPos(); - - long chunkKey = chunkPos.toLong(); - ChunkData chunkData = this.chunks.remove(chunkKey); - - if (chunkData == null) - return; - - int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); - for (int i = 0; i < chunkSectionsCount; ++i) { - levelChunk.getSections()[i] = chunkData.chunkSections[i]; - } - - chunkData.heightmaps.forEach(((type, heightmap) -> { - levelChunk.setHeightmap(type, heightmap.getRawData()); - })); - - if (plugin.getSettings().isLightsUpdate()) { - if (isStarLightInterface) { - this.lightenChunks.add(chunkPos); - } else { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); - // Queues chunk light for this chunk. - threadedLevelLightEngine.lightChunk(levelChunk, false); - } - } - - levelChunk.markUnsaved(); - } - - @Override - public void finish(Island island) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); - - // Update blocks - blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); - - // Update block entities - blockEntities.forEach(data -> { - net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); - if (blockEntityCompound != null) { - BlockPos blockPos = data.getKey(); - blockEntityCompound.putInt("x", blockPos.getX()); - blockEntityCompound.putInt("y", blockPos.getY()); - blockEntityCompound.putInt("z", blockPos.getZ()); - - applySignTextLines(blockEntityCompound, "front_text"); - applySignTextLines(blockEntityCompound, "back_text"); - convertLegacySignTextLines(blockEntityCompound); - - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.loadWithComponents(blockEntityCompound, MinecraftServer.getServer().registryAccess()); - } - }); - - if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - threadedLevelLightEngine.starlight$serverRelightChunks(lightenChunks, chunkCallback -> { - }, completeCallback -> { - }); - this.lightenChunks.clear(); - } - - release(); - } - - @Override - public Data readData(Location baseLocation) { - return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); - } - - @Override - public void applyData(Data data, Location baseLocation) { - WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // We need to transform all data to the new base location values - - dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, - baseBlockPosZAxis, this, this.chunks); - dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); - dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); - dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); - } - - @Override - public void release() { - this.chunks.clear(); - this.blocksToUpdate.clear(); - this.blockEntities.clear(); - this.lightenChunks.clear(); - this.serverLevel = null; - this.dimension = null; - this.levelHeightAccessor = null; - POOL.release(this); - } - - public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - return new ChunkData(chunkSections, heightmaps, lights); - } - - private boolean isValidPosition(BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - !this.levelHeightAccessor.isOutsideBuildHeight(blockPos.getY()); - } - - private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { - if (blockEntityCompound.contains(key)) { - net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); - ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); - List textLines = new ArrayList<>(); - for (net.minecraft.nbt.Tag lineTag : messages) { - try { - textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); - } catch (JsonParseException error) { - textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); - } - } - - while (textLines.size() < 4) - textLines.add(Component.empty()); - - Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); - - SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); - } - } - - private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { - Component[] signLines = new Component[4]; - Arrays.fill(signLines, Component.empty()); - boolean hasAnySignLines = false; - // We try to convert old text sign lines - for (int i = 1; i <= 4; ++i) { - if (blockEntityCompound.contains("SSB.Text" + i)) { - String signLine = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; - hasAnySignLines = true; - } - } else { - String signLine = blockEntityCompound.getString("Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromJSON(signLine); - hasAnySignLines = true; - } - } - } - - if (hasAnySignLines) { - SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); - } - } - - private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { - ResourceKey resourceKey; - switch (dimension.getEnvironment()) { - case NETHER -> resourceKey = LevelStem.NETHER; - case THE_END -> resourceKey = LevelStem.END; - default -> resourceKey = LevelStem.OVERWORLD; - } - Registry registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); - return registry.getValue(resourceKey).type().value(); - } - - public class ChunkData { - - private final LevelChunkSection[] chunkSections; - private final Map heightmaps; - private final List lights; - - private ChunkData(long chunkKey) { - this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), - isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); - - ChunkPos chunkPos = new ChunkPos(chunkKey); - - Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); - - createChunkSections(biomesRegistry); - - ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); - - createHeightmaps(tempChunk); - if (serverLevel != null) - runCustomWorldGenerator(tempChunk); - } - - private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - this.chunkSections = chunkSections; - this.heightmaps = heightmaps; - this.lights = lights; - } - - public LevelChunkSection[] chunkSections() { - return this.chunkSections; - } - - public Map heightmaps() { - return this.heightmaps; - } - - public List lights() { - return this.lights; - } - - private void createChunkSections(Registry biomesRegistry) { - Holder biome = CraftBiome.bukkitToMinecraftHolder( - IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); - - for (int i = 0; i < this.chunkSections.length; ++i) { - PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), - biome, PalettedContainer.Strategy.SECTION_BIOMES); - PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - - this.chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); - } - } - - private void runCustomWorldGenerator(ProtoChunk tempChunk) { - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - - if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) - return; - - NMSUtils.buildSurfaceForChunk(serverLevel, tempChunk); - - // We want to copy the level chunk sections back - LevelChunkSection[] tempChunkSections = tempChunk.getSections(); - for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { - LevelChunkSection chunkSection = tempChunkSections[i]; - if (chunkSection != null) - this.chunkSections[i] = chunkSection; - } - } - - private void createHeightmaps(ProtoChunk tempChunk) { - for (Heightmap.Types heightmapType : Heightmap.Types.values()) { - if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { - this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); - } - } - } - - } - - -} diff --git a/NMS/v1_21_4/properties b/NMS/v1_21_4/properties new file mode 100644 index 0000000000..4a9b3b888d --- /dev/null +++ b/NMS/v1_21_4/properties @@ -0,0 +1,7 @@ +NMS_VERSION=v1_21_4 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index dd873f3275..bcffab4825 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -1,221 +1,30 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_4; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; -import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; -import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuBrewingStandBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuDispenserBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuFurnaceBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.menu.MenuHopperBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.BlockEntityCache; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; -import com.google.common.collect.Multimap; -import com.google.common.collect.MultimapBuilder; -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.TextReplacementConfig; -import net.minecraft.SharedConstants; -import net.minecraft.core.BlockPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.Container; -import net.minecraft.world.entity.item.FallingBlockEntity; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.attribute.Attribute; -import org.bukkit.attribute.AttributeModifier; -import org.bukkit.block.Biome; -import org.bukkit.block.data.Ageable; -import org.bukkit.block.data.BlockData; -import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftFallingBlock; -import org.bukkit.craftbukkit.entity.CraftMinecart; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; -import org.bukkit.potion.PotionEffect; -import org.jetbrains.annotations.NotNull; -import java.util.EnumMap; import java.util.Locale; import java.util.Objects; -import java.util.Optional; -import java.util.function.BiFunction; -public class NMSAlgorithmsImpl implements NMSAlgorithms { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Multimap EMPTY_ATTRIBUTES_MAP = - MultimapBuilder.hashKeys().hashSetValues().build(); - - private static final EnumBridge BIOME_ENUM_BRIDGE = new EnumBridge<>() { - @Override - public Biome[] getValues() { - return Biome.values(); - } - - @Override - public String getName(Biome enumValue) { - return enumValue.name(); - } - }; - - private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); - - static { - MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); - } - - private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { - @Override - public byte[] processClass(byte[] classBytes, String path) { - return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); - } - }; - - @Override - public void registerCommand(BukkitCommand command) { - ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); - } +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms { @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); } - @Override - public int getCombinedId(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return 0; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(wrapper.getHandle()); - } - return Block.getId(blockState); - } - - @Override - public int getCombinedId(Material material, byte data) { - BlockState blockState; - - if (data == 0) { - Block block = CraftMagicNumbers.getBlock(material); - if (block == null) - return -1; - blockState = block.defaultBlockState(); - } else { - blockState = CraftMagicNumbers.getBlock(material, data); - } - - return blockState == null ? -1 : Block.getId(blockState); - } - - @Override - public Optional getTileEntityIdFromCombinedId(int combinedId) { - BlockState blockState = Block.stateById(combinedId); - - if (!blockState.hasBlockEntity()) - return Optional.empty(); - - String id = BlockEntityCache.getBlockEntityId(blockState); - - return Text.isBlank(id) ? Optional.empty() : Optional.of(id); - } - - @Override - public int compareMaterials(Material o1, Material o2) { - int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); - int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); - return Integer.compare(firstMaterial, secondMaterial); - } - - @Override - public short getBlockDataValue(org.bukkit.block.BlockState blockState) { - BlockData blockData = blockState.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getBlockDataValue(org.bukkit.block.Block block) { - BlockData blockData = block.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getMaxBlockDataValue(Material material) { - if (!material.isBlock()) - return 0; - - BlockData blockData = Bukkit.createBlockData(material); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); - } - - @Override - public Key getBlockKey(int combinedId) { - Block block = Block.stateById(combinedId).getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { - AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); - Block block = minecart.getDisplayBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { - FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); - Block block = fallingBlock.getBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public void setCustomModel(ItemMeta itemMeta, int customModel) { - itemMeta.setCustomModelData(customModel); - } - @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); @@ -244,13 +53,6 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } - @Override - public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { - if (!potionMeta.hasCustomEffects()) - potionMeta.setColor(potionEffect.getType().getColor()); - potionMeta.addCustomEffect(potionEffect, true); - } - @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); @@ -261,93 +63,4 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } - @Nullable - @Override - public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { - MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); - return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); - } - - @Override - public int getMaxWorldSize() { - return Bukkit.getMaxWorldSize(); - } - - @Override - public double getCurrentTps() { - try { - return MinecraftServer.getServer().tps1.getAverage(); - } catch (Throwable error) { - //noinspection removal - return MinecraftServer.getServer().recentTps[0]; - } - } - - @Override - public int getDataVersion() { - return SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - } - - @Override - public ClassProcessor getClassProcessor() { - return CLASS_PROCESSOR; - } - - @Override - public void handlePaperChatRenderer(Object event) { - if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) - return; - - ChatRenderer originalRenderer = asyncChatEvent.renderer(); - asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); - } - - @Override - public void hideAttributes(ItemMeta itemMeta) { - itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); - } - - @Override - public EnumBridge getBiomeBridge() { - return BIOME_ENUM_BRIDGE; - } - - private interface MenuCreator extends BiFunction { - } - - private static class ChatRendererWrapper { - - private static final String MESSAGE_PLACEHOLDER = "{message}"; - private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = - net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); - - private final ChatRenderer renderer = new ChatRenderer() { - @Override - public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, - net.kyori.adventure.text.@NotNull Component sourceDisplayName, - net.kyori.adventure.text.@NotNull Component message, - @NotNull Audience viewer) { - String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer - .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); - Island island = superiorPlayer.getIsland(); - - return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( - Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) - .replaceText(TextReplacementConfig.builder() - .matchLiteral(MESSAGE_PLACEHOLDER) - .replacement(message) - .build()); - } - }; - - private final ChatRenderer originalRenderer; - - public ChatRendererWrapper(ChatRenderer originalRenderer) { - this.originalRenderer = originalRenderer; - } - - } - } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java index b7df630172..1ca8e7cb71 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -1,25 +1,17 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_4; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; -import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.crops.CropsBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.crops.CropsTickingMethod; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -38,21 +30,15 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.BitStorage; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -60,48 +46,30 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import net.minecraft.world.phys.AABB; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.entity.CraftEntityType; import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; -import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; -import java.util.Objects; import java.util.concurrent.CompletableFuture; -public class NMSChunksImpl implements NMSChunks { - - private final SuperiorSkyblockPlugin plugin; +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - KeyBlocksCache.cacheAllBlocks(); - CropsTickingMethod.register(); + super(plugin); } @Override - public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, - Collection playersToUpdate) { - if (chunkPositions.isEmpty()) - return; - - Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.SET_BIOME, false) { + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); @@ -119,7 +87,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null); + levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); @@ -130,9 +98,11 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), @@ -145,7 +115,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("biomes", biomesCompound); @@ -155,19 +125,12 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { // Do nothing. } - }); + }; } @Override - public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { - if (chunkPositions.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), - chunkPosition.getX(), chunkPosition.getZ(), false)); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.DELETE_CHUNK, false) { + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); @@ -184,6 +147,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( @@ -194,8 +158,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - unloadedChunkCompound.setEntities(new ListTag()); - unloadedChunkCompound.setBlockEntities(tileEntities); + chunkCompound.put("entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, @@ -203,18 +167,19 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).put("block_states", blockStatesCompound); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { - NMSUtils.buildSurfaceForChunk(serverLevel, protoChunk); + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), @@ -260,7 +225,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound tileEntities.add(blockEntityCompound); } - unloadedChunkCompound.setSections(sectionsList); + chunkCompound.put("sections", sectionsList); } } @@ -269,34 +234,14 @@ public void onFinish() { if (onFinish != null) onFinish.run(); } - }); + }; } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); - List chunkPositionsToCalculate = new LinkedList<>(); - - Iterator chunkPositionsIterator = chunkPositions.iterator(); - while (chunkPositionsIterator.hasNext()) { - ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); - if (cachedCalculatedChunk != null) { - allCalculatedChunks.add(cachedCalculatedChunk); - chunkPositionsIterator.remove(); - } else { - chunkPositionsToCalculate.add(chunkPosition); - } - } - - if (chunkPositions.isEmpty()) - return CompletableFuture.completedFuture(allCalculatedChunks); - - CompletableFuture> completableFuture = new CompletableFuture<>(); - - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( - ChunkLoadReason.BLOCKS_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -310,6 +255,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( @@ -327,36 +273,36 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getList("sections", 10); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompound(i); byte yPosition = sectionCompound.getByte("Y"); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { - PalettedContainer blocksDataPalette; + PalettedContainer blocksPalettedContainer; if (sectionCompound.contains("block_states", 10)) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("block_states")).promotePartial((sx) -> { }); - blocksDataPalette = dataResult.getOrThrow(); + blocksPalettedContainer = dataResult.getOrThrow(); } else { - blocksDataPalette = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } - PalettedContainer> biomesDataPalette; + PalettedContainer> biomesPalettedContainer; if (sectionCompound.contains("biomes", 10)) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, sectionCompound.getCompound("biomes")).promotePartial((sx) -> { }); - biomesDataPalette = dataResult.getOrThrow(); + biomesPalettedContainer = dataResult.getOrThrow(); } else { - biomesDataPalette = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } - chunkSections[sectionIndex] = new LevelChunkSection(blocksDataPalette, biomesDataPalette); + chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } @@ -372,20 +318,14 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { completableFuture.complete(allCalculatedChunks); } - }); - - return completableFuture; + }; } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); - - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - List unloadedChunkCompounds = new LinkedList<>(); - - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( - ChunkLoadReason.ENTITIES_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { @@ -408,8 +348,9 @@ public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - for (Tag entityTag : unloadedChunkCompound.getEntities()) { + for (Tag entityTag : chunkCompound.getList("entities", 10)) { EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); if (entityType == null) continue; @@ -421,7 +362,9 @@ public void onFinish() { continue; } - Key entityKey = Keys.of(CraftEntityType.minecraftToBukkit(entityType)); + Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( + CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); + chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); } } @@ -429,161 +372,17 @@ public void onFinish() { completableFuture.complete(chunkEntities); }); } - }); - - return completableFuture; - } - - @Override - public void injectChunkSections(Chunk chunk) { - // No implementation - } - - @Override - public boolean isChunkEmpty(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> - chunkSection == null || chunkSection.hasOnlyAir()); - } - - @Override - public Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); - return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; - } - - @Override - public void startTickingChunk(Island island, Chunk chunk, boolean stop) { - if (plugin.getSettings().getCropsInterval() <= 0) - return; - - if (stop) { - CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); - if (cropsBlockEntity != null) - cropsBlockEntity.remove(); - } else { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - CropsBlockEntity.create(island, levelChunk); - } - } - - @Override - public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { - if (chunkPositions.isEmpty()) return; - CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> - cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); - } - - @Override - public void shutdown() { - List> pendingTasks = NMSUtils.getPendingChunkActions(); - - if (pendingTasks.isEmpty()) - return; - - Log.info("Waiting for chunk tasks to complete."); - - CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); - } - - @Override - public List getBlockEntities(Chunk chunk) { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - List blockEntities = new LinkedList<>(); - - World bukkitWorld = chunk.getWorld(); - - levelChunk.getBlockEntities().keySet().forEach(blockPos -> - blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); - - return blockEntities; - } - - private static final ReflectField PALETTED_CONTAINER_DATA = new ReflectField<>( - PalettedContainer.class, Object.class, "d"); - - private static final ReflectField PALETTED_CONTAINER_DATA_STORAGE = new ReflectField<>( - PalettedContainer.class, BitStorage.class, "b"); - - private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { - KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); - List spawnersLocations = new LinkedList<>(); - - for (int i = 0; i < chunkSections.length; ++i) { - LevelChunkSection levelChunkSection = chunkSections[i]; - if (levelChunkSection != null && !levelChunkSection.hasOnlyAir()) { - int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4; - for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { - BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, - sectionBottomY, blockCounts, spawnersLocations); - } - } - } - - return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); - } - - private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, - int sectionBottomY, KeyMap blockCounts, - List spawnersLocations) { - Block block = blockState.getBlock(); - - if (block == Blocks.AIR) - return; - - Location location = new Location(chunkPosition.getWorld(), - (chunkPosition.getX() << 4) + x, - sectionBottomY + y, - (chunkPosition.getZ() << 4) + z); - - int blockAmount = 1; - - if (NMSUtils.isDoubleBlock(block, blockState)) { - blockAmount = 2; - blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); - } - - Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); - blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); - if (block == Blocks.SPAWNER) { - spawnersLocations.add(location); - } - } - - private static void removeEntities(ChunkAccess chunk) { - ChunkPos chunkPos = chunk.getPos(); - ServerLevel serverLevel = ((LevelChunk) chunk).level; - - int chunkWorldCoordX = chunkPos.x << 4; - int chunkWorldCoordZ = chunkPos.z << 4; - - AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinY(), chunkWorldCoordZ, - chunkWorldCoordX + 15, serverLevel.getMaxY(), chunkWorldCoordZ + 15); - - List worldEntities = new LinkedList<>(); - serverLevel.getEntities().get(chunkBounds, worldEntities::add); - - worldEntities.forEach(nmsEntity -> { - if (!(nmsEntity instanceof Player)) - nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); - }); - } - - private static void removeBlockEntities(ChunkAccess chunk) { - chunk.blockEntities.values().forEach(BlockEntity::setRemoved); - chunk.blockEntities.clear(); + }; } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { - NMSUtils.buildSurfaceForChunk(serverLevel, chunk); - } + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; + + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSDragonFightImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSDragonFightImpl.java deleted file mode 100644 index 6efec4868e..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSDragonFightImpl.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.EndWorldEndDragonFightHandler; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.IslandEndDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.IslandEntityEnderDragon; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.SpikesCache; -import com.google.common.cache.LoadingCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.advancement.Advancement; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.entity.Player; - -import java.lang.reflect.Modifier; -import java.util.List; - -public class NMSDragonFightImpl implements NMSDragonFight { - - private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( - EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField<>( - ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE, 1); - - private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( - SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static boolean firstWorldPreparation = true; - - static { - ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); - } - - @Override - public void prepareEndWorld(World bukkitWorld) { - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); - - if (firstWorldPreparation) { - firstWorldPreparation = false; - SPIKE_CACHE.set(null, SpikesCache.getInstance()); - } - } - - @Nullable - @Override - public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return null; - - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); - return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); - } - - @Override - public void startDragonBattle(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); - } - - @Override - public void removeDragonBattle(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); - - if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { - islandEndDragonFight.removeBattlePlayers(); - islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); - } - } - - @Override - public void awardTheEndAchievement(Player player) { - Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); - if (advancement != null) - player.getAdvancementProgress(advancement).awardCriteria(""); - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java index 35f6fdba88..dd11192078 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSEntitiesImpl.java @@ -1,50 +1,22 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_4; -import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; -import org.bukkit.Material; -import org.bukkit.craftbukkit.entity.CraftAnimals; -import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; -import org.bukkit.entity.Animals; import org.bukkit.entity.minecart.PoweredMinecart; -import org.bukkit.inventory.EntityEquipment; -import org.bukkit.inventory.ItemStack; -public class NMSEntitiesImpl implements NMSEntities { +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSEntities { @Override - public ItemStack[] getEquipment(EntityEquipment entityEquipment) { - ItemStack[] itemStacks = new ItemStack[7]; - - itemStacks[0] = new ItemStack(Material.ARMOR_STAND); - itemStacks[1] = entityEquipment.getItemInMainHand(); - itemStacks[2] = entityEquipment.getItemInOffHand(); - itemStacks[3] = entityEquipment.getHelmet(); - itemStacks[4] = entityEquipment.getChestplate(); - itemStacks[5] = entityEquipment.getLeggings(); - itemStacks[6] = entityEquipment.getBoots(); - - return itemStacks; - } - - @Override - public boolean isAnimalFood(ItemStack itemStack, Animals animals) { - return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); - } - - @Override - public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); } @Override - public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); + protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSHologramsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSHologramsImpl.java deleted file mode 100644 index 58ec1f184d..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSHologramsImpl.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4; - -import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; -import com.bgsoftware.superiorskyblock.nms.NMSHolograms; -import com.google.common.base.Preconditions; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftArmorStand; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.entity.Entity; - -@SuppressWarnings("unused") -public class NMSHologramsImpl implements NMSHolograms { - - @Override - public Hologram createHologram(Location location) { - Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); - serverLevel.addFreshEntity(entityHologram); - return entityHologram; - } - - @Override - public boolean isHologram(Entity entity) { - return ((CraftEntity) entity).getHandle() instanceof Hologram; - } - - public static class EntityHologram extends ArmorStand implements Hologram { - - private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); - - private CraftEntity bukkitEntity; - - EntityHologram(ServerLevel serverLevel, double x, double y, double z) { - super(serverLevel, x, y, z); - - setInvisible(true); - setSmall(true); - setShowArms(false); - setNoGravity(true); - setNoBasePlate(true); - setMarker(true); - forceSetBoundingBox(EMPTY_BOUND); - - super.collides = false; - super.setCustomNameVisible(true); - } - - @Override - public void setHologramName(String name) { - super.setCustomName(CraftChatMessage.fromStringOrNull(name)); - } - - @Override - public void removeHologram() { - super.remove(RemovalReason.DISCARDED); - } - - @Override - public org.bukkit.entity.ArmorStand getHandle() { - return this.getBukkitEntity(); - } - - @Override - public void inactiveTick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - @Override - public boolean repositionEntityAfterLoad() { - return false; - } - - @Override - public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { - // Prevent stand being equipped - } - - @Override - public void addAdditionalSaveData(CompoundTag compoundTag) { - // Do not save NBT. - } - - @Override - public void readAdditionalSaveData(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { - // Prevent stand being equipped - return InteractionResult.PASS; - } - - @Override - public void tick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - public void forceSetBoundingBox(AABB boundingBox) { - super.setBoundingBox(boundingBox); - } - - @Override - public CraftArmorStand getBukkitEntity() { - if (bukkitEntity == null) { - bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); - } - return (CraftArmorStand) bukkitEntity; - } - - @Override - public void remove(RemovalReason removalReason) { - // Prevent being killed. - } - - @Override - public void playSound(SoundEvent soundEvent, float volume, float pitch) { - // Remove sounds. - } - - @Override - public boolean saveAsPassenger(CompoundTag compoundTag) { - // Do not save NBT. - return false; - } - - @Override - public CompoundTag saveWithoutId(CompoundTag compoundTag) { - // Do not save NBT. - return compoundTag; - } - - @Override - public void load(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public boolean isInvulnerableTo(ServerLevel serverLevel, DamageSource damageSource) { - /* - * The field Entity.invulnerable is private. - * It's only used while saving NBTTags, but since the entity would be killed - * on chunk unload, we prefer to override isInvulnerable(). - */ - return true; - } - - @Override - public void setCustomName(Component component) { - // Locks the custom name. - } - - @Override - public void setCustomNameVisible(boolean isCustomNameVisible) { - // Locks the custom name. - } - - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java deleted file mode 100644 index 3859b38630..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSPlayersImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.nms.NMSPlayers; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.player.OfflinePlayerDataImpl; -import com.bgsoftware.superiorskyblock.player.PlayerLocales; -import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.level.ServerPlayer; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Item; -import org.bukkit.entity.Player; - -import java.util.Locale; - -public class NMSPlayersImpl implements NMSPlayers { - - private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - - @Override - public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { - return OfflinePlayerDataImpl.create(offlinePlayer); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer) { - Player player = superiorPlayer.asPlayer(); - - if (player == null) - return; - - ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() - .ifPresent(property -> setSkinTexture(superiorPlayer, property)); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { - superiorPlayer.setTextureValue(property.value()); - } - - @SuppressWarnings("deprecation") - @Override - public void sendActionBar(Player player, String message) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); - } - - @Override - public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { - BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); - bossBar.addPlayer(player); - return bossBar; - } - - @SuppressWarnings("deprecation") - @Override - public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { - player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); - } - - @Override - public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { - return superiorPlayer.getUniqueId().equals(item.getThrower()); - } - - @Nullable - @Override - public Locale getPlayerLocale(Player player) { - if (PLAYER_LOCALE.isValid()) { - return player.locale(); - } else try { - //noinspection deprecation - return PlayerLocales.getLocale(player.getLocale()); - } catch (IllegalArgumentException error) { - return null; - } - } - - private static class BossBarImpl implements BossBar { - - private final org.bukkit.boss.BossBar bossBar; - private final BossBarTask bossBarTask; - - public BossBarImpl(String message, BarColor color, double ticksToRun) { - bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); - this.bossBarTask = BossBarTask.create(this, ticksToRun); - } - - @Override - public void addPlayer(Player player) { - this.bossBar.addPlayer(player); - this.bossBarTask.registerTask(player); - } - - @Override - public void removeAll() { - this.bossBar.removeAll(); - this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); - } - - @Override - public void setProgress(double progress) { - this.bossBar.setProgress(progress); - } - - @Override - public double getProgress() { - return this.bossBar.getProgress(); - } - - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java index c2ea3b884b..140da89bb1 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java @@ -1,86 +1,28 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_4; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.ListTag; -import com.bgsoftware.superiorskyblock.tag.Tag; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; -import com.mojang.serialization.Dynamic; -import net.minecraft.SharedConstants; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; -import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.util.Optional; import java.util.Set; -@SuppressWarnings({"unused"}) -public class NMSTagsImpl implements NMSTags { - - @Override - public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) - itemStack.save(MinecraftServer.getServer().registryAccess()); - tagCompound.putInt("DataVersion", SharedConstants.getCurrentVersion().getDataVersion().getVersion()); - - return CompoundTag.fromNBT(tagCompound); - } - - @Override - public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { - if (compoundTag.containsKey("NBT")) { - // Old compound version, deserialize it accordingly - return deserializeItemOld(compoundTag); - } - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); - - int currentVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - int itemVersion = tagCompound.getInt("DataVersion"); - if (itemVersion < currentVersion) { - tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, - new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); - } - - ItemStack itemStack = ItemStack.parse(MinecraftServer.getServer().registryAccess(), tagCompound).orElseThrow(); - - return CraftItemStack.asCraftMirror(itemStack); - } - - private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); - Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount").orElse(0); - short data = (short) compoundTag.getShort("data").orElse(0); - CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); - - org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - if (nbtData != null) - itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); - - return CraftItemStack.asCraftMirror(itemStack); - } +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSTags { @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { @@ -97,18 +39,30 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I } @Override - @SuppressWarnings("ConstantConditions") - public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { - net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) + itemStack.save(MinecraftServer.getServer().registryAccess()); + tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + return CompoundTag.fromNBT(tagCompound); + } + + @Override + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.contains(key, 3) ? compoundTag.getInt(key) : def; + } - if (compoundTag == null) - compoundTag = new net.minecraft.nbt.CompoundTag(); + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow(); + } - if (!compoundTag.contains("id")) - //noinspection deprecation - compoundTag.putString("id", entityType.getName()); + @Override + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); + } - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { entity.absMoveTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; @@ -170,29 +124,4 @@ public String getNBTStringValue(Object object) { return ((StringTag) object).getAsString(); } - @Override - public Object parseList(ListTag listTag) { - net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); - - for (Tag tag : listTag) - nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); - - return nbtTagList; - } - - @Override - public Object getNBTCompoundTag(Object object, String key) { - return ((net.minecraft.nbt.CompoundTag) object).get(key); - } - - @Override - public void setNBTCompoundTagValue(Object object, String key, Object value) { - ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); - } - - @Override - public int getNBTTagListSize(Object object) { - return ((net.minecraft.nbt.ListTag) object).size(); - } - } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java deleted file mode 100644 index b2a65d2fbb..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSUtils.java +++ /dev/null @@ -1,535 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4; - -import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.PropertiesMapper; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; -import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; -import com.google.common.base.Suppliers; -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkPyramid; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.chunk.status.ChunkStep; -import net.minecraft.world.level.chunk.storage.EntityStorage; -import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.generator.CustomChunkGenerator; - -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; - -public class NMSUtils { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( - ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); - private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( - ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); - private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( - EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); - - private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); - - public static final ObjectsPool> BLOCK_POS_POOL = - ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); - - private NMSUtils() { - - } - - @Nullable - public static T getBlockEntityAt(Location location, Class type) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); - } - } - - public static void runActionOnEntityChunks(Collection chunksCoords, - ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); - } - - public static void runActionOnChunks(Collection chunksCoords, - boolean saveChunks, ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); - } - - private static void runActionOnChunksInternal(Collection chunksCoords, - ChunkCallback chunkCallback, - Consumer> onUnloadChunkAction) { - List unloadedChunks = new LinkedList<>(); - List loadedChunks = new LinkedList<>(); - - chunksCoords.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - ChunkAccess chunkAccess; - - try { - chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); - } catch (Throwable ex) { - chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); - } - - if (chunkAccess instanceof LevelChunk levelChunk) { - loadedChunks.add(levelChunk); - } else { - unloadedChunks.add(chunkPosition.copy()); - } - }); - - boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); - - if (!loadedChunks.isEmpty()) - runActionOnLoadedChunks(loadedChunks, chunkCallback); - - if (hasUnloadedChunks) { - onUnloadChunkAction.accept(unloadedChunks); - } else { - chunkCallback.onFinish(); - } - } - - private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { - chunks.forEach(chunkCallback::onLoadedChunk); - } - - private static void runActionOnUnloadedChunks(Collection chunks, - boolean saveChunks, ChunkCallback chunkCallback) { - if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { - Iterator chunksIterator = chunks.iterator(); - while (chunksIterator.hasNext()) { - ChunkPosition chunkPosition = chunksIterator.next(); - - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( - chunkPosition.getX(), chunkPosition.getZ()); - - if (cachedUnloadedChunk != null) { - chunkCallback.onLoadedChunk(cachedUnloadedChunk); - chunksIterator.remove(); - } - } - - if (chunks.isEmpty()) { - chunkCallback.onFinish(); - return; - } - } - - CompletableFuture pendingTask = new CompletableFuture<>(); - PENDING_CHUNK_ACTIONS.add(pendingTask); - - BukkitExecutor.createTask().runAsync(v -> { - CountDownLatch countDownLatch; - if (chunkCallback.isWaitForChunkLoad) { - countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - } else { - countDownLatch = null; - } - - List chunkCompounds = new LinkedList<>(); - - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - boolean calledCountdown = false; - try { - net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); - - if (chunkCompound == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), - Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, - Optional.empty(), chunkPos, serverLevel); - - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - calledCountdown = true; - - if (saveChunks) - chunkCompounds.add(unloadedChunkCompound); - } catch (Exception error) { - if (!calledCountdown && countDownLatch != null) - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - if (countDownLatch != null) { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - } - - return chunkCompounds; - }).runSync(chunkCompounds -> { - chunkCompounds.forEach(unloadedChunkCompound -> { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = unloadedChunkCompound.chunkPos(); - - try { - chunkMap.write(chunkPos, () -> unloadedChunkCompound.chunkCompound); - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); - } - }); - - chunkCallback.onFinish(); - - pendingTask.complete(null); - PENDING_CHUNK_ACTIONS.remove(pendingTask); - }); - } - - private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); - SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { - if (error != null) { - countDownLatch.countDown(); - throw new RuntimeException(error); - } else { - net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - } else { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } - } - }); - }); - - BukkitExecutor.createTask().runAsync(v -> { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } else { - BukkitExecutor.createTask().runAsync(v -> { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - try { - MoonriseRegionFileIO.RegionDataController regionDataController = - serverLevel.moonrise$getEntityChunkDataController(); - int chunkX = chunkPosition.getX(); - int chunkZ = chunkPosition.getZ(); - MoonriseRegionFileIO.RegionDataController.ReadData readData = - regionDataController.readData(chunkX, chunkZ); - if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { - net.minecraft.nbt.CompoundTag entityData = readData.syncRead(); - if (entityData != null) { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - return; - } - } - - chunkCallback.onChunkNotExist(chunkPosition); - } catch (IOException error) { - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } - } - - public static List> getPendingChunkActions() { - return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); - } - - public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { - return new ProtoChunk(chunkPos, - UpgradeData.EMPTY, - serverLevel, - serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), - null); - } - - public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { - ServerLevel serverLevel = levelChunk.level; - - if (!isValidPosition(serverLevel, blockPos)) - return null; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - serverLevel.setBlock(blockPos, blockState, 3); - return blockState; - } - - int indexY = serverLevel.getSectionIndex(blockPos.getY()); - - LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - boolean isOriginallyChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - - levelChunk.markUnsaved(); - - boolean isChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) - serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); - - serverLevel.getLightEngine().checkBlock(blockPos); - - if (tileEntity != null) { - net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); - if (tileEntityCompound != null) { - tileEntityCompound.putInt("x", blockPos.getX()); - tileEntityCompound.putInt("y", blockPos.getY()); - tileEntityCompound.putInt("z", blockPos.getZ()); - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.loadWithComponents(tileEntityCompound, MinecraftServer.getServer().registryAccess()); - } - } - - return blockState; - } - - public static boolean isDoubleBlock(Block block, BlockState blockState) { - return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && - blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; - } - - @Nullable - public static LevelChunk getCraftChunkHandle(CraftChunk craftChunk) { - ServerLevel serverLevel = craftChunk.getCraftWorld().getHandle(); - LevelChunk loadedChunk = serverLevel.getChunkIfLoaded(craftChunk.getX(), craftChunk.getZ()); - if (loadedChunk != null) - return loadedChunk; - - return (LevelChunk) serverLevel.getChunk(craftChunk.getX(), craftChunk.getZ(), ChunkStatus.FULL, true); - } - - public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkAccess chunkAccess) { - CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), serverLevel.generator); - - ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); - - // Unsafe: we do not provide chunks cache, even tho it is required. - // Should be fine in normal flow, as the only method that access the chunsk cache - // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: - // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 - WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); - - customChunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - chunkAccess); - } - - public record UnloadedChunkCompound(ChunkPosition chunkPosition, - net.minecraft.nbt.CompoundTag chunkCompound) { - - public ListTag getSections() { - return chunkCompound.getList("sections", 10); - } - - public ListTag getEntities() { - return chunkCompound.getList("Entities", 10); - } - - public void setSections(ListTag sectionsList) { - chunkCompound.put("sections", sectionsList); - } - - public void setEntities(ListTag entitiesList) { - chunkCompound.put("entities", entitiesList); - } - - public void setBlockEntities(ListTag blockEntitiesList) { - chunkCompound.put("block_entities", blockEntitiesList); - } - - public ServerLevel serverLevel() { - return ((CraftWorld) chunkPosition.getWorld()).getHandle(); - } - - public ChunkPos chunkPos() { - return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - } - - } - - private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); - } - - public static abstract class ChunkCallback { - - private final ChunkLoadReason chunkLoadReason; - private final boolean isWaitForChunkLoad; - - @Nullable - protected CountDownLatch chunkLoadLatch; - - public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { - this.chunkLoadReason = chunkLoadReason; - this.isWaitForChunkLoad = isWaitForChunkLoad; - } - - public abstract void onLoadedChunk(LevelChunk levelChunk); - - public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - - public abstract void onFinish(); - - protected final void latchCountDown() { - if (this.chunkLoadLatch != null) - this.chunkLoadLatch.countDown(); - } - - public final void onChunkNotExist(ChunkPosition chunkPosition) { - if (!plugin.getProviders().hasCustomWorldsSupport()) - return; - - ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { - LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); - }); - } - - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index 64534b2702..996cd0738e 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -3,131 +3,57 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; -import com.bgsoftware.superiorskyblock.nms.ICachedBlock; -import com.bgsoftware.superiorskyblock.nms.NMSWorld; -import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.generator.IslandsGeneratorImpl; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_4.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_4.vibration.IslandVibrationUser; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.ChunkReaderImpl; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.WorldEditSessionImpl; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import io.papermc.paper.antixray.ChunkPacketBlockController; -import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.BubbleColumn; import org.bukkit.block.data.type.HangingSign; -import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.WallHangingSign; -import org.bukkit.block.data.type.WallSign; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.block.CraftBlock; -import org.bukkit.craftbukkit.block.CraftBlockState; -import org.bukkit.craftbukkit.block.CraftSign; -import org.bukkit.craftbukkit.block.data.CraftBlockData; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.function.IntFunction; -public class NMSWorldImpl implements NMSWorld { +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); - private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, - Object.class, "chunkPacketBlockController") - .removeFinal(); - - private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); } @Override - public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { - Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); - Location location = new Location( - Bukkit.getWorld(chunkSnapshot.getWorldName()), - (chunkSnapshot.getX() << 4) + x, - y, - (chunkSnapshot.getZ() << 4) + z - ); - - return Keys.of(KeyBlocksCache.getBlockKey(block), location); + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); } @Override - public void listenSpawner(Location location, IntFunction delayChangeCallback) { - SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); - if (spawnerBlockEntity == null) + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; - ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - - List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? - LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; - - Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new LinkedList<>(); - - while (blockEntityTickersIterator.hasNext()) { - TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && - !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { - blockEntityTickersIterator.remove(); - tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); - } - } + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } - if (!tickersToAdd.isEmpty()) - blockEntityTickers.addAll(tickersToAdd); + @Override + public SignType getSignType(Object sign) { + if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return super.getSignType(sign); } @Override @@ -174,263 +100,4 @@ public void replaceTrialBlockPlayerDetector(Island island, Location location) { } } - @Override - public void replaceSculkSensorListener(Island island, Location location) { - SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); - if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) - return; - - SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); - } - - @Override - public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { - if (!plugin.getSettings().isWorldBorders()) - return; - - Player player = superiorPlayer.asPlayer(); - World world = superiorPlayer.getWorld(); - - if (world == null || player == null) - return; - - int islandSize = island == null ? 0 : island.getIslandSize(); - - boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; - - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - - WorldBorder worldBorder; - - if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { - worldBorder = serverLevel.getWorldBorder(); - } else { - Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); - if (dimension == null) - return; - - Location center = island.getCenter(dimension); - - worldBorder = new WorldBorder(); - worldBorder.world = serverLevel; - worldBorder.setWarningBlocks(0); - worldBorder.setCenter(center.getX(), center.getZ()); - - switch (superiorPlayer.getBorderColor()) { - case BLUE -> { - worldBorder.setSize((islandSize * 2) + 1D); - } - case GREEN -> { - worldBorder.setSize((islandSize * 2) + 1.001D); - worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); - } - case RED -> { - worldBorder.setSize((islandSize * 2) + 1D); - worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); - } - } - } - - ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); - ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); - } - - @Override - public Object getBlockData(org.bukkit.block.Block block) { - return block.getBlockData(); - } - - @Override - public void setBlock(Location location, int combinedId) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - BlockState blockState = - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - - if (blockState != null) { - serverLevel.getChunkSource().blockChanged(blockPos); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); - } - } - } - } - - @Override - public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return NMSCachedBlock.obtain(block); - } - - @Override - public boolean isWaterLogged(org.bukkit.block.Block block) { - if (Materials.isWater(block.getType())) - return true; - - BlockData blockData = block.getBlockData(); - - return blockData instanceof BubbleColumn || - (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); - } - - @Override - public SignType getSignType(Object sign) { - if (sign instanceof WallSign) - return SignType.WALL_SIGN; - else if (sign instanceof Sign) - return SignType.STANDING_SIGN; - else if (sign instanceof HangingSign) - return SignType.HANGING_SIGN; - else if (sign instanceof WallHangingSign) - return SignType.HANGING_WALL_SIGN; - else - return SignType.UNKNOWN; - } - - @Override - public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { - BlockState blockState = ((CraftBlock) block).getNMS(); - return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; - } - - @Override - public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { - return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); - } - - @Override - public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { - return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); - } - - private int getDefaultAmount(BlockState blockState) { - Block block = blockState.getBlock(); - return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; - } - - @Override - public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { - return !bukkitBlock.isPassable(); - } - - @Override - public void placeSign(Island island, Location location) { - SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); - if (signBlockEntity == null) - return; - - String[] lines = new String[4]; - Component[] messages = signBlockEntity.getFrontText().getMessages(false); - System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - Component[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } - - System.arraycopy(newLines, 0, messages, 0, 4); - } - - @Override - public void playGeneratorSound(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); - } - } - - @Override - public void playBreakAnimation(org.bukkit.block.Block block) { - ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); - } - } - - @Override - public void playPlaceSound(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); - } - } - - @Override - public int getMinHeight(World world) { - return world.getMinHeight(); - } - - @Override - public void removeAntiXray(org.bukkit.World bukkitWorld) { - if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); - } - - @Override - public IslandsGenerator createGenerator(Dimension dimension) { - return new IslandsGeneratorImpl(dimension); - } - - @Override - public WorldEditSession createEditSession(World world) { - return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); - } - - @Override - public WorldEditSession createPartialEditSession(Dimension dimension) { - return WorldEditSessionImpl.obtain(dimension); - } - - @Override - public ChunkReader createChunkReader(Chunk chunk) { - return new ChunkReaderImpl(chunk); - } - - private static ReflectField> initializeLevelBlockEntityTickersField() { - ReflectField> field = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - - if (!field.isValid()) - field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); - - return field; - } - } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsBlockEntity.java deleted file mode 100644 index 42d50d74aa..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsBlockEntity.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.crops; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.function.Consumer; - -public class CropsBlockEntity extends BlockEntity { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - - private final WeakReference island; - private final WeakReference chunk; - - private int currentTick = 0; - - private double cachedCropGrowthMultiplier; - - private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(levelChunk); - setLevel(levelChunk.level); - levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; - } - - public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); - return new CropsBlockEntity(island, levelChunk, blockPos); - }); - } - - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); - } - - public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { - if (tickingChunks.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> { - long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); - if (cropsBlockEntity != null) - cropsBlockEntityConsumer.accept(cropsBlockEntity); - }); - } - - @Override - public boolean isValidBlockState(BlockState state) { - return true; - } - - public void remove() { - this.remove = true; - } - - public void tick() { - if (++currentTick <= plugin.getSettings().getCropsInterval()) - return; - - LevelChunk levelChunk = this.chunk.get(); - Island island = this.island.get(); - ServerLevel serverLevel = (ServerLevel) getLevel(); - - if (levelChunk == null || island == null || serverLevel == null) { - remove(); - return; - } - - currentTick = 0; - - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - if (chunkRandomTickSpeed > 0) - CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); - } - - public void setCropGrowthMultiplier(double cropGrowthMultiplier) { - this.cachedCropGrowthMultiplier = cropGrowthMultiplier; - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingBlockEntity.java deleted file mode 100644 index 265928a203..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/crops/CropsTickingBlockEntity.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.crops; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { - - - @Override - public void tick() { - cropsBlockEntity.tick(); - } - - @Override - public boolean isRemoved() { - return cropsBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return cropsBlockEntity.getBlockPos(); - } - - @Override - public String getType() { - return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/DragonUtils.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/DragonUtils.java deleted file mode 100644 index ce1e97f4b0..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/DragonUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; - -import com.bgsoftware.common.reflection.ReflectField; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; - -import java.lang.reflect.Modifier; - -public class DragonUtils { - - private static final ReflectField END_PODIUM_LOCATION = new ReflectField( - EndPodiumFeature.class, BlockPos.class, - Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static BlockPos currentPodiumPosition = BlockPos.ZERO; - - private DragonUtils() { - - } - - public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { - try { - END_PODIUM_LOCATION.set(null, podiumPosition); - currentPodiumPosition = podiumPosition; - runnable.run(); - } finally { - END_PODIUM_LOCATION.set(null, BlockPos.ZERO); - currentPodiumPosition = BlockPos.ZERO; - } - } - - public static BlockPos getCurrentPodiumPosition() { - return currentPodiumPosition; - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndWorldEndDragonFightHandler.java deleted file mode 100644 index 3c3370d29e..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndWorldEndDragonFightHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; -import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.dimension.end.EndDragonFight; - -import java.util.LinkedList; -import java.util.List; - -public class EndWorldEndDragonFightHandler extends EndDragonFight { - - private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); - - private final List worldDragonFightsList = new LinkedList<>(); - - public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); - } - - @Override - public void tick() { - this.worldDragonFightsList.forEach(EndDragonFight::tick); - } - - public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); - if (oldDragonFight != null) - this.worldDragonFightsList.remove(oldDragonFight); - this.worldDragonFightsList.add(endDragonFight); - } - - @Nullable - public IslandEndDragonFight getDragonFight(IslandCache islandCache) { - return islandCache.get(CACHE_KEY); - } - - @Nullable - public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { - IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); - if (endDragonFight != null) - this.worldDragonFightsList.remove(endDragonFight); - return endDragonFight; - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEndDragonFight.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEndDragonFight.java deleted file mode 100644 index da25050468..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEndDragonFight.java +++ /dev/null @@ -1,211 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; -import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import net.minecraft.world.level.block.state.pattern.BlockPattern; -import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; -import net.minecraft.world.level.block.state.predicate.BlockPredicate; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -public class IslandEndDragonFight extends EndDragonFight { - - private static final ReflectField DRAGON_BATTLE = new ReflectField( - EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 4); - private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); - - private static final ReflectField TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>( - EndDragonFight.class, int.class, Modifier.PRIVATE, 4); - private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( - DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); - - private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") - .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") - .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) - .build(); - - private final Island island; - private final BlockPos islandBlockPos; - private final Vec3 islandBlockVectored; - private final ServerLevel serverLevel; - private final IslandEntityEnderDragon entityEnderDragon; - - private byte currentTick = 0; - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { - this(island, serverLevel, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), null); - } - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, - @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); - - this.island = island; - this.islandBlockPos = islandBlockPos; - this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); - this.serverLevel = serverLevel; - this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; - - SCAN_FOR_LEGACY_PORTALS.set(this, false); - WAS_DRAGON_KILLED.set(this, false); - DRAGON_BATTLE.set(this.entityEnderDragon, this); - - TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); - } - - @Override - public void tick() { - // doServerTick - - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); - - DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); - if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { - LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); - } - - if (++currentTick >= 20) { - updateBattlePlayers(); - currentTick = 0; - TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); - } - } - - @Nullable - @Override - public BlockPattern.BlockPatternMatch findExitPortal() { - int chunkX = this.islandBlockPos.getX() >> 4; - int chunkZ = this.islandBlockPos.getZ() >> 4; - - for (int x = -8; x <= 8; ++x) { - for (int z = -8; z <= 8; ++z) { - LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); - - for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { - if (blockEntity instanceof TheEndPortalBlockEntity) { - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( - this.serverLevel, blockEntity.getBlockPos()); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - } - } - - int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); - currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); - for (int y = highestBlock; y >= this.serverLevel.getMinY(); --y) { - currentPosition.setY(y); - - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - - return null; - } - - @Override - public void resetSpikeCrystals() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); - } - - public void removeBattlePlayers() { - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - for (ServerPlayer serverPlayer : dragonEventPlayers) - this.dragonEvent.removePlayer(serverPlayer); - } - - public IslandEntityEnderDragon getEnderDragon() { - return this.entityEnderDragon; - } - - private void updateBattlePlayers() { - Set nearbyPlayers = new HashSet<>(); - - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - Player bukkitPlayer = superiorPlayer.asPlayer(); - if (bukkitPlayer != null) { - ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); - if (serverPlayer.serverLevel().equals(this.serverLevel)) { - this.dragonEvent.addPlayer(serverPlayer); - nearbyPlayers.add(serverPlayer.getUUID()); - } - } - } - - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - - dragonEventPlayers.stream() - .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) - .forEach(this.dragonEvent::removePlayer); - } - - private IslandEntityEnderDragon spawnEnderDragon() { - IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); - - entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); - entityEnderDragon.absMoveTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), - this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); - - this.serverLevel.addFreshEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); - - this.dragonUUID = entityEnderDragon.getUUID(); - this.resetSpikeCrystals(); - - return entityEnderDragon; - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java index 54ab5dcf9e..e3d1893522 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/IslandEntityEnderDragon.java @@ -2,59 +2,34 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.config.SettingsManager; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntitySpawnReason; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; -import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftEnderDragon; -public class IslandEntityEnderDragon extends EnderDragon { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - @NotNull - public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { - return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : - new EnderDragon(entityTypes, level); - } - - private final ServerLevel serverLevel; - private final Dimension dimension; - private BlockPos islandBlockPos; +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { - this(level); - this.islandBlockPos = islandBlockPos; + super(level, islandBlockPos); } - private IslandEntityEnderDragon(Level level) { - super(EntityType.ENDER_DRAGON, level); - this.serverLevel = (ServerLevel) level; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + public IslandEntityEnderDragon(Level level) { + super(level); } @Nullable @Override - public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, - @Nullable SpawnGroupData spawnGroupData) { + @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); - return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override @@ -64,40 +39,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { finalizeIslandEnderDragon(); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - - private void finalizeIslandEnderDragon() { - if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) - return; - - Island island; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); - } - - if (island == null) - return; - - Location middleBlock = island.getCenter(dimension); - - SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); - if (dimensionConfig instanceof SettingsManager.Worlds.End) { - middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); - } - - this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); - - IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); - } - } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/SpikesCache.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/SpikesCache.java deleted file mode 100644 index 1e3108407b..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/SpikesCache.java +++ /dev/null @@ -1,189 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; - - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.common.annotations.Nullable; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.CacheStats; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public class SpikesCache implements LoadingCache> { - - private static final SpikesCache INSTANCE = new SpikesCache(); - - private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() - .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); - - private long worldSeed; - - public static SpikesCache getInstance() { - return INSTANCE; - } - - private SpikesCache() { - - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - List getUnchecked(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public List apply(@NotNull Long worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void refresh(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ConcurrentMap> asMap() { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Nullable - @Override - public List getIfPresent(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed, - @NotNull Callable> loader) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAllPresent(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void put(@NotNull Long worldSeed, @NotNull List spikes) { - try { - this.worldSeed = worldSeed; - cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); - } finally { - this.worldSeed = 0; - } - } - - @Override - public void putAll(Map> spikesMap) { - spikesMap.forEach(this::put); - } - - @Override - public void invalidate(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll() { - this.cachedSpikes.invalidateAll(); - } - - @Override - public long size() { - return this.cachedSpikes.size(); - } - - @Override - public @NotNull - CacheStats stats() { - return this.cachedSpikes.stats(); - } - - @Override - public void cleanUp() { - this.cachedSpikes.cleanUp(); - } - - private class InternalCacheLoader extends CacheLoader> { - - @Override - public @NotNull - List load(@NotNull BlockPos blockPos) { - List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); - - Collections.shuffle(list, new Random(worldSeed)); - List spikesList = Lists.newArrayList(); - - for (int i = 0; i < 10; ++i) { - int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int l = list.get(i); - int radius = 2 + l / 3; - int height = 76 + l * 3; - boolean guarded = l == 1 || l == 2; - - spikesList.add(new SpikeFeature.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded)); - } - - return spikesList; - } - - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/generator/IslandsGeneratorImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/generator/IslandsGeneratorImpl.java deleted file mode 100644 index c896500ee1..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/generator/IslandsGeneratorImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.generator; - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; -import org.bukkit.generator.WorldInfo; - -import java.util.Collections; -import java.util.List; -import java.util.Random; - -@SuppressWarnings({"unused", "NullableProblems"}) -public class IslandsGeneratorImpl extends IslandsGenerator { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private final Dimension dimension; - - public IslandsGeneratorImpl(Dimension dimension) { - this.dimension = dimension; - } - - @Override - public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, - @NotNull ChunkData chunkData) { - if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { - chunkData.setBlock(0, 99, 0, Material.BEDROCK); - } - } - - @Override - public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { - return new BiomeProvider() { - @Override - public @NotNull - Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { - return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension); - } - - @Override - public @NotNull - List getBiomes(@NotNull WorldInfo worldInfo) { - return IslandUtils.getDefaultWorldBiomes(); - } - - }; - } - - @Override - public List getDefaultPopulators(World world) { - return Collections.emptyList(); - } - - @Override - public Location getFixedSpawnLocation(World world, Random random) { - return new Location(world, 0, 100, 0); - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/hologram/EntityHologram.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/hologram/EntityHologram.java new file mode 100644 index 0000000000..aac6edff5d --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/hologram/EntityHologram.java @@ -0,0 +1,39 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.hologram; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_4.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuBrewingStandBlockEntity.java deleted file mode 100644 index 04d3a730f6..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuBrewingStandBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { - - private final InventoryHolder holder; - - public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuDispenserBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuDispenserBlockEntity.java deleted file mode 100644 index bbf1632899..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuDispenserBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.DispenserBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuDispenserBlockEntity extends DispenserBlockEntity { - - private final InventoryHolder holder; - - public MenuDispenserBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuFurnaceBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuFurnaceBlockEntity.java deleted file mode 100644 index 77a85ea54d..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuFurnaceBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.FurnaceBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { - - private final InventoryHolder holder; - - public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuHopperBlockEntity.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuHopperBlockEntity.java deleted file mode 100644 index 4f02ec085e..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/menu/MenuHopperBlockEntity.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.HopperBlock; -import net.minecraft.world.level.block.entity.HopperBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuHopperBlockEntity extends HopperBlockEntity { - - private final InventoryHolder holder; - - public MenuHopperBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.HOPPER.defaultBlockState().setValue(HopperBlock.FACING, Direction.DOWN)); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/spawners/TickingSpawnerBlockEntityNotifier.java deleted file mode 100644 index 31fd354396..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/spawners/TickingSpawnerBlockEntityNotifier.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.spawners; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BaseSpawner; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -import java.util.function.IntFunction; - -public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { - - private final SpawnerBlockEntity spawnerBlockEntity; - private final TickingBlockEntity tickingBlockEntity; - private final IntFunction delayChangeCallback; - - public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, - IntFunction delayChangeCallback) { - this.spawnerBlockEntity = spawnerBlockEntity; - this.tickingBlockEntity = tickingBlockEntity; - this.delayChangeCallback = delayChangeCallback; - updateDelay(); - } - - @Override - public void tick() { - BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); - int startDelay = baseSpawner.spawnDelay; - try { - tickingBlockEntity.tick(); - } finally { - int newDelay = baseSpawner.spawnDelay; - if (newDelay > startDelay) - updateDelay(); - } - } - - @Override - public boolean isRemoved() { - return tickingBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return tickingBlockEntity.getPos(); - } - - @Override - public String getType() { - return tickingBlockEntity.getType(); - } - - public void updateDelay() { - BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); - baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..98a0f4a3f2 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java @@ -0,0 +1,375 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.utils; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.utils.TickingBlockList; +import com.google.common.base.Suppliers; +import com.google.gson.JsonParseException; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +public class NMSUtilsVersioned { + + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( + EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { + return chunkMap.read(chunkPos).join().orElse(null); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { + return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), + chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { + chunkMap.write(chunkPos, () -> chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } else { + return BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + MoonriseRegionFileIO.RegionDataController regionDataController = + serverLevel.moonrise$getEntityChunkDataController(); + int chunkX = chunkPosition.getX(); + int chunkZ = chunkPosition.getZ(); + MoonriseRegionFileIO.RegionDataController.ReadData readData = + regionDataController.readData(chunkX, chunkZ); + if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { + CompoundTag entityData = readData.syncRead(); + if (entityData != null) { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + return; + } + } + + chunkCallback.onChunkNotExist(chunkPosition); + } catch (IOException error) { + countDownLatch.countDown(); + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.liquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess()); + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + applySignTextLines(compoundTag, "front_text"); + applySignTextLines(compoundTag, "back_text"); + convertLegacySignTextLines(compoundTag); + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + + Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + + chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); + + // Unsafe: we do not provide chunks cache, even tho it is required. + // Should be fine in normal flow, as the only method that access the chunks cache + // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 + WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); + + customChunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + } + + public static CompoundTag saveEntity(Entity entity) { + CompoundTag compoundTag = new CompoundTag(); + entity.save(compoundTag); + return compoundTag; + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.moonrise$getTickingBlockList().size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + public static String getPropertyValue(Property property) { + return property.value(); + } + + public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.getDragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absMoveTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSectionY(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinY(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxY(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.markUnsaved(); + } + + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { + if (blockEntityCompound.contains(key)) { + CompoundTag frontText = blockEntityCompound.getCompound(key); + ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); + List textLines = new ArrayList<>(); + for (net.minecraft.nbt.Tag lineTag : messages) { + try { + textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); + } catch (JsonParseException error) { + textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); + } + } + + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); + } + } + + private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockEntityCache.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockEntityCache.java deleted file mode 100644 index 5cc780bf72..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockEntityCache.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class BlockEntityCache { - - private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); - - private BlockEntityCache() { - - } - - public static String getBlockEntityId(BlockState blockState) { - return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { - for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - if (blockEntityType.isValid(blockState)) { - ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); - if (resourceLocation != null) - return resourceLocation.toString(); - } - } - - return ""; - }); - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java deleted file mode 100644 index 77a0b094da..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/ChunkReaderImpl.java +++ /dev/null @@ -1,243 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.block.CraftBlockType; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.InventoryHolder; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class ChunkReaderImpl implements ChunkReader { - - private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - private static final byte[] FULL_LIGHT = new byte[2048]; - private static final byte[] EMPTY_LIGHT = new byte[2048]; - - static { - Arrays.fill(FULL_LIGHT, (byte) 0xFF); - } - - private final ServerLevel serverLevel; - private final int x; - private final int z; - - private final Map blockEntities = new HashMap<>(); - private final List entities = new LinkedList<>(); - private final PalettedContainerRO[] blockids; - private final byte[][] skylight; - private final byte[][] emitlight; - - public ChunkReaderImpl(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - - this.serverLevel = levelChunk.level; - ChunkPos chunkPos = levelChunk.getPos(); - this.x = chunkPos.x; - this.z = chunkPos.z; - - LevelChunkSection[] levelChunkSections = levelChunk.getSections(); - this.blockids = new PalettedContainerRO[levelChunkSections.length]; - this.skylight = new byte[levelChunkSections.length][]; - this.emitlight = new byte[levelChunkSections.length][]; - - LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); - - for (int i = 0; i < this.blockids.length; ++i) { - LevelChunkSection levelChunkSection = levelChunkSections[i]; - - this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); - - DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (skyLightArray == null) { - this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; - } else { - this.skylight[i] = new byte[2048]; - System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); - } - - DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (emitLightArray == null) { - this.emitlight[i] = EMPTY_LIGHT; - } else { - this.emitlight[i] = new byte[2048]; - System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); - } - } - - levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - InventoryHolder inventoryHolder = blockEntity.getOwner(); - if (inventoryHolder != null) - compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); - - blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); - }); - - for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) - entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); - } - - @Override - public int getX() { - return this.x; - } - - @Override - public int getZ() { - return this.z; - } - - @Override - public Material getType(int x, int y, int z) { - return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); - } - - @Override - public short getData(int x, int y, int z) { - return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); - } - - @Override - @Nullable - public CompoundTag getTileEntity(int x, int y, int z) { - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); - return this.blockEntities.get(blockPos); - } - } - - @Override - @Nullable - public CompoundTag readBlockStates(int x, int y, int z) { - BlockState blockState = getBlockState(x, y, z); - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = CompoundTag.of(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(int x, int y, int z) { - int off = (y & 15) << 7 | z << 3 | x >> 1; - int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; - } - - @Override - public void forEachEntity(EntityConsumer consumer) { - if (entities.isEmpty()) - return; - - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = wrapper.getHandle(); - for (CachedEntity cachedEntity : entities) { - location.setX(cachedEntity.x); - location.setY(cachedEntity.y); - location.setZ(cachedEntity.z); - location.setYaw(cachedEntity.yaw); - location.setPitch(cachedEntity.pitch); - consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); - } - } - } - - private BlockState getBlockState(int x, int y, int z) { - return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); - } - - private int getSectionIndex(int y) { - int sectionIndex = SectionPos.blockToSectionCoord(y); - return sectionIndex - this.serverLevel.getMinSectionY(); - } - - private int getSectionYFromSectionIndex(int index) { - return index + this.serverLevel.getMinSectionY(); - } - - private static class CachedEntity { - - private final double x; - private final double y; - private final double z; - private final float yaw; - private final float pitch; - private final EntityType entityType; - private final CompoundTag entityTag; - - CachedEntity(Entity entity) { - this.x = entity.getX(); - this.y = entity.getY(); - this.z = entity.getZ(); - this.yaw = entity.getBukkitYaw(); - this.pitch = entity.getXRot(); - this.entityType = entity.getBukkitEntity().getType(); - - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - - this.entityTag = CompoundTag.fromNBT(compoundTag); - } - - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java deleted file mode 100644 index c9eeb0ea83..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/KeyBlocksCache.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; - -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.level.block.Block; -import org.bukkit.Material; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class KeyBlocksCache { - - private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); - - private KeyBlocksCache() { - - } - - public static Key getBlockKey(Block block) { - return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { - Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); - }); - } - - public static void cacheAllBlocks() { - BuiltInRegistries.BLOCK.forEach(KeyBlocksCache::getBlockKey); - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapper.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapper.java deleted file mode 100644 index b614485ebc..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapper.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; - -import com.bgsoftware.superiorskyblock.core.logging.Log; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.Property; - -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; - -public class PropertiesMapper { - - private static final Map> nameToProperty = new HashMap<>(); - private static final Map, String> propertyToName = new HashMap<>(); - - static { - Map fieldsToNames = new IdentityHashMap<>(); - - fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); - fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); - fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); - fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); - fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); - fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); - fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); - fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); - fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); - fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); - fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); - fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); - fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); - fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); - fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); - fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); - fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); - fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); - fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); - fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); - fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); - fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); - fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); - fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); - fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); - fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); - fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); - fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); - - try { - for (Field field : BlockStateProperties.class.getFields()) { - field.setAccessible(true); - Object value = field.get(null); - if (value instanceof Property) { - Property property = (Property) value; - register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); - } - } - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while loading properties mapper:"); - } - - } - - private static void register(String key, String fieldName, Property property) { - if (nameToProperty.containsKey(key)) { - Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); - } else { - nameToProperty.put(key, property); - propertyToName.put(property, key); - } - } - - public static Property getProperty(String name) { - return nameToProperty.get(name); - } - - public static String getPropertyName(Property property) { - return propertyToName.get(property); - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapperVersioned.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..0bc18de650 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/PropertiesMapperVersioned.java @@ -0,0 +1,17 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; + +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionDataImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionDataImpl.java deleted file mode 100644 index f106d6dab6..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionDataImpl.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; - -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionDataImpl implements WorldEditSession.Data { - - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private final List> chunks = new LinkedList<>(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); - - public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, - List> blocksToUpdate, - List> blockEntities, - Set lightenChunks) { - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // Convert chunk data - Iterator> chunksIterator = chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); - int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); - WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); - - List> lights; - if (isStarLightInterface || chunkData.lights().isEmpty()) { - lights = Collections.emptyList(); - } else { - lights = new LinkedList<>(); - chunkData.lights().forEach(lightPosition -> { - lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, - lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, - null)); - }); - } - - PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), - chunkData.heightmaps(), lights); - - this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, - currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); - } - - // Convert blocksToUpdate - blocksToUpdate.forEach(blockToUpdate -> { - BlockPos blockPos = blockToUpdate.getKey(); - this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockToUpdate.getValue())); - }); - - // Convert blockEntities - blockEntities.forEach(blockEntity -> { - BlockPos blockPos = blockEntity.getKey(); - this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockEntity.getValue())); - }); - - // Convert lights - lightenChunks.forEach(lightPosition -> { - this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, - lightPosition.z - baseChunkPosZAxis, null)); - }); - } - - public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, - int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, - Long2ObjectMapView chunks) { - this.chunks.forEach(chunkDataPositioned -> { - long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, - baseChunkPosZAxis + chunkDataPositioned.zOffset); - - List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - chunkDataPositioned.object.lights.forEach(lightPositioned -> { - lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, - baseBlockPosYAxis + lightPositioned.yOffset, - baseBlockPosZAxis + lightPositioned.zOffset)); - }); - - chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, - chunkDataPositioned.object.heightmaps, lights)); - }); - } - - public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { - this.blocksToUpdate.forEach(blockToUpdatePositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, - baseBlockPosYAxis + blockToUpdatePositioned.yOffset, - baseBlockPosZAxis + blockToUpdatePositioned.zOffset); - blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); - }); - } - - public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { - this.blockEntities.forEach(blockEntityPositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, - baseBlockPosYAxis + blockEntityPositioned.yOffset, - baseBlockPosZAxis + blockEntityPositioned.zOffset); - blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); - }); - } - - public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { - this.lightenChunks.forEach(lightPositioned -> { - ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, - baseChunkPosZAxis + lightPositioned.zOffset); - lightenChunks.add(newPos); - }); - } - - private static class PositionedObject { - - private final int xOffset; - private final int yOffset; - private final int zOffset; - private final V object; - - PositionedObject(int xOffset, int zOffset, V object) { - this(xOffset, 0, zOffset, object); - } - - PositionedObject(int xOffset, int yOffset, int zOffset, V object) { - this.xOffset = xOffset; - this.yOffset = yOffset; - this.zOffset = zOffset; - this.object = object; - } - - } - - private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, - List> lights) { - } - -} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java deleted file mode 100644 index 018203c6a3..0000000000 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/WorldEditSessionImpl.java +++ /dev/null @@ -1,478 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.google.common.base.Preconditions; -import com.google.gson.JsonParseException; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.SignText; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.ticks.ProtoChunkTicks; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.generator.ChunkGenerator; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionImpl implements WorldEditSession { - - private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; - - private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - - private Dimension dimension; - private LevelHeightAccessor levelHeightAccessor; - - @Nullable - private ServerLevel serverLevel; - - public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { - return POOL.obtain().initialize(serverLevel); - } - - public static WorldEditSessionImpl obtain(Dimension dimension) { - return POOL.obtain().initialize(dimension); - } - - private WorldEditSessionImpl() { - } - - private WorldEditSessionImpl initialize(ServerLevel serverLevel) { - this.serverLevel = serverLevel; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); - this.levelHeightAccessor = serverLevel; - return this; - } - - private WorldEditSessionImpl initialize(Dimension dimension) { - DimensionType dimensionType = getDimensionTypeFromDimension(dimension); - this.serverLevel = null; - this.dimension = dimension; - this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); - return this; - } - - @Override - public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, - @Nullable CompoundTag blockEntityData) { - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - if (!isValidPosition(blockPos)) - return; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - blocksToUpdate.add(new Pair<>(blockPos, blockState)); - return; - } - - ChunkPos chunkPos = new ChunkPos(blockPos); - - if (blockEntityData != null) - blockEntities.add(new Pair<>(blockPos, blockEntityData)); - - ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); - - if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) - chunkData.lights.add(blockPos); - - LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - } - - @Override - public List getAffectedChunks() { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); - - if (chunks.isEmpty()) - return Collections.emptyList(); - - List chunkPositions = new LinkedList<>(); - World bukkitWorld = serverLevel.getWorld(); - LongIterator iterator = chunks.keyIterator(); - while (iterator.hasNext()) { - long chunkKey = iterator.next(); - int chunkX = (int) chunkKey; - int chunkZ = (int) (chunkKey >> 32); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); - } - return chunkPositions; - } - - @Override - public void applyBlocks(Chunk bukkitChunk) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); - - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); - ChunkPos chunkPos = levelChunk.getPos(); - - long chunkKey = chunkPos.toLong(); - ChunkData chunkData = this.chunks.remove(chunkKey); - - if (chunkData == null) - return; - - int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); - for (int i = 0; i < chunkSectionsCount; ++i) { - levelChunk.getSections()[i] = chunkData.chunkSections[i]; - } - - chunkData.heightmaps.forEach(((type, heightmap) -> { - levelChunk.setHeightmap(type, heightmap.getRawData()); - })); - - if (plugin.getSettings().isLightsUpdate()) { - if (isStarLightInterface) { - this.lightenChunks.add(chunkPos); - } else { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); - // Queues chunk light for this chunk. - threadedLevelLightEngine.lightChunk(levelChunk, false); - } - } - - levelChunk.markUnsaved(); - } - - @Override - public void finish(Island island) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); - - // Update blocks - blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); - - // Update block entities - blockEntities.forEach(data -> { - net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); - if (blockEntityCompound != null) { - BlockPos blockPos = data.getKey(); - blockEntityCompound.putInt("x", blockPos.getX()); - blockEntityCompound.putInt("y", blockPos.getY()); - blockEntityCompound.putInt("z", blockPos.getZ()); - - applySignTextLines(blockEntityCompound, "front_text"); - applySignTextLines(blockEntityCompound, "back_text"); - convertLegacySignTextLines(blockEntityCompound); - - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.loadWithComponents(blockEntityCompound, MinecraftServer.getServer().registryAccess()); - } - }); - - if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - threadedLevelLightEngine.starlight$serverRelightChunks(lightenChunks, chunkCallback -> { - }, completeCallback -> { - }); - this.lightenChunks.clear(); - } - - release(); - } - - @Override - public Data readData(Location baseLocation) { - return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); - } - - @Override - public void applyData(Data data, Location baseLocation) { - WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // We need to transform all data to the new base location values - - dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, - baseBlockPosZAxis, this, this.chunks); - dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); - dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); - dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); - } - - @Override - public void release() { - this.chunks.clear(); - this.blocksToUpdate.clear(); - this.blockEntities.clear(); - this.lightenChunks.clear(); - this.serverLevel = null; - this.dimension = null; - this.levelHeightAccessor = null; - POOL.release(this); - } - - public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - return new ChunkData(chunkSections, heightmaps, lights); - } - - private boolean isValidPosition(BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - this.levelHeightAccessor.isInsideBuildHeight(blockPos.getY()); - } - - private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { - if (blockEntityCompound.contains(key)) { - net.minecraft.nbt.CompoundTag frontText = blockEntityCompound.getCompound(key); - ListTag messages = frontText.getList("messages", net.minecraft.nbt.Tag.TAG_STRING); - List textLines = new ArrayList<>(); - for (net.minecraft.nbt.Tag lineTag : messages) { - try { - textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); - } catch (JsonParseException error) { - textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); - } - } - - while (textLines.size() < 4) - textLines.add(Component.empty()); - - Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); - - SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); - } - } - - private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { - Component[] signLines = new Component[4]; - Arrays.fill(signLines, Component.empty()); - boolean hasAnySignLines = false; - // We try to convert old text sign lines - for (int i = 1; i <= 4; ++i) { - if (blockEntityCompound.contains("SSB.Text" + i)) { - String signLine = blockEntityCompound.getString("SSB.Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; - hasAnySignLines = true; - } - } else { - String signLine = blockEntityCompound.getString("Text" + i); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromJSON(signLine); - hasAnySignLines = true; - } - } - } - - if (hasAnySignLines) { - SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); - } - } - - private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { - ResourceKey resourceKey; - switch (dimension.getEnvironment()) { - case NETHER -> resourceKey = LevelStem.NETHER; - case THE_END -> resourceKey = LevelStem.END; - default -> resourceKey = LevelStem.OVERWORLD; - } - Registry registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); - return registry.getValue(resourceKey).type().value(); - } - - public class ChunkData { - - private final LevelChunkSection[] chunkSections; - private final Map heightmaps; - private final List lights; - - private ChunkData(long chunkKey) { - this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), - isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); - ChunkPos chunkPos = new ChunkPos(chunkKey); - - Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); - - createChunkSections(biomesRegistry); - - ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); - - createHeightmaps(tempChunk); - if (serverLevel != null) - runCustomWorldGenerator(tempChunk); - } - - private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - this.chunkSections = chunkSections; - this.heightmaps = heightmaps; - this.lights = lights; - } - - public LevelChunkSection[] chunkSections() { - return this.chunkSections; - } - - public Map heightmaps() { - return this.heightmaps; - } - - public List lights() { - return this.lights; - } - - private void createChunkSections(Registry biomesRegistry) { - Holder biome = CraftBiome.bukkitToMinecraftHolder( - IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); - - for (int i = 0; i < this.chunkSections.length; ++i) { - PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), - biome, PalettedContainer.Strategy.SECTION_BIOMES); - PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - - this.chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); - } - } - - private void runCustomWorldGenerator(ProtoChunk tempChunk) { - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - - if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) - return; - - NMSUtils.buildSurfaceForChunk(serverLevel, tempChunk); - - // We want to copy the level chunk sections back - LevelChunkSection[] tempChunkSections = tempChunk.getSections(); - for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { - LevelChunkSection chunkSection = tempChunkSections[i]; - if (chunkSection != null) - this.chunkSections[i] = chunkSection; - } - } - - private void createHeightmaps(ProtoChunk tempChunk) { - for (Heightmap.Types heightmapType : Heightmap.Types.values()) { - if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { - this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); - } - } - } - - } - - -} diff --git a/NMS/v1_21_5/properties b/NMS/v1_21_5/properties new file mode 100644 index 0000000000..b3e920e518 --- /dev/null +++ b/NMS/v1_21_5/properties @@ -0,0 +1,7 @@ +NMS_VERSION=v1_21_5 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java index a6cdfbe5ec..d010f85506 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java @@ -1,221 +1,30 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_5; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; -import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; -import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.menu.MenuBrewingStandBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.menu.MenuDispenserBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.menu.MenuFurnaceBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.menu.MenuHopperBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.BlockEntityCache; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.KeyBlocksCache; -import com.google.common.collect.Multimap; -import com.google.common.collect.MultimapBuilder; -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.TextReplacementConfig; -import net.minecraft.SharedConstants; -import net.minecraft.core.BlockPos; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.Container; -import net.minecraft.world.entity.item.FallingBlockEntity; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.attribute.Attribute; -import org.bukkit.attribute.AttributeModifier; -import org.bukkit.block.Biome; -import org.bukkit.block.data.Ageable; -import org.bukkit.block.data.BlockData; -import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftFallingBlock; -import org.bukkit.craftbukkit.entity.CraftMinecart; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; -import org.bukkit.potion.PotionEffect; -import org.jetbrains.annotations.NotNull; -import java.util.EnumMap; import java.util.Locale; import java.util.Objects; -import java.util.Optional; -import java.util.function.BiFunction; -public class NMSAlgorithmsImpl implements NMSAlgorithms { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Multimap EMPTY_ATTRIBUTES_MAP = - MultimapBuilder.hashKeys().hashSetValues().build(); - - private static final EnumBridge BIOME_ENUM_BRIDGE = new EnumBridge<>() { - @Override - public Biome[] getValues() { - return Biome.values(); - } - - @Override - public String getName(Biome enumValue) { - return enumValue.name(); - } - }; - - private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); - - static { - MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); - } - - private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { - @Override - public byte[] processClass(byte[] classBytes, String path) { - return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); - } - }; - - @Override - public void registerCommand(BukkitCommand command) { - ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); - } +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms { @Override public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); } - @Override - public int getCombinedId(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return 0; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(wrapper.getHandle()); - } - return Block.getId(blockState); - } - - @Override - public int getCombinedId(Material material, byte data) { - BlockState blockState; - - if (data == 0) { - Block block = CraftMagicNumbers.getBlock(material); - if (block == null) - return -1; - blockState = block.defaultBlockState(); - } else { - blockState = CraftMagicNumbers.getBlock(material, data); - } - - return blockState == null ? -1 : Block.getId(blockState); - } - - @Override - public Optional getTileEntityIdFromCombinedId(int combinedId) { - BlockState blockState = Block.stateById(combinedId); - - if (!blockState.hasBlockEntity()) - return Optional.empty(); - - String id = BlockEntityCache.getBlockEntityId(blockState); - - return Text.isBlank(id) ? Optional.empty() : Optional.of(id); - } - - @Override - public int compareMaterials(Material o1, Material o2) { - int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); - int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); - return Integer.compare(firstMaterial, secondMaterial); - } - - @Override - public short getBlockDataValue(org.bukkit.block.BlockState blockState) { - BlockData blockData = blockState.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getBlockDataValue(org.bukkit.block.Block block) { - BlockData blockData = block.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getMaxBlockDataValue(Material material) { - if (!material.isBlock()) - return 0; - - BlockData blockData = Bukkit.createBlockData(material); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); - } - - @Override - public Key getBlockKey(int combinedId) { - Block block = Block.stateById(combinedId).getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { - AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); - Block block = minecart.getDisplayBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { - FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); - Block block = fallingBlock.getBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public void setCustomModel(ItemMeta itemMeta, int customModel) { - itemMeta.setCustomModelData(customModel); - } - @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); @@ -244,13 +53,6 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } - @Override - public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { - if (!potionMeta.hasCustomEffects()) - potionMeta.setColor(potionEffect.getType().getColor()); - potionMeta.addCustomEffect(potionEffect, true); - } - @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); @@ -261,93 +63,4 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } - @Nullable - @Override - public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { - MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); - return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); - } - - @Override - public int getMaxWorldSize() { - return Bukkit.getMaxWorldSize(); - } - - @Override - public double getCurrentTps() { - try { - return MinecraftServer.getServer().tps1.getAverage(); - } catch (Throwable error) { - //noinspection removal - return MinecraftServer.getServer().recentTps[0]; - } - } - - @Override - public int getDataVersion() { - return SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - } - - @Override - public ClassProcessor getClassProcessor() { - return CLASS_PROCESSOR; - } - - @Override - public void handlePaperChatRenderer(Object event) { - if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) - return; - - ChatRenderer originalRenderer = asyncChatEvent.renderer(); - asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); - } - - @Override - public void hideAttributes(ItemMeta itemMeta) { - itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); - } - - @Override - public EnumBridge getBiomeBridge() { - return BIOME_ENUM_BRIDGE; - } - - private interface MenuCreator extends BiFunction { - } - - private static class ChatRendererWrapper { - - private static final String MESSAGE_PLACEHOLDER = "{message}"; - private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = - net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); - - private final ChatRenderer renderer = new ChatRenderer() { - @Override - public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, - net.kyori.adventure.text.@NotNull Component sourceDisplayName, - net.kyori.adventure.text.@NotNull Component message, - @NotNull Audience viewer) { - String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer - .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); - Island island = superiorPlayer.getIsland(); - - return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( - Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) - .replaceText(TextReplacementConfig.builder() - .matchLiteral(MESSAGE_PLACEHOLDER) - .replacement(message) - .build()); - } - }; - - private final ChatRenderer originalRenderer; - - public ChatRendererWrapper(ChatRenderer originalRenderer) { - this.originalRenderer = originalRenderer; - } - - } - } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java index eff5fa3cd2..62c59994e5 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java @@ -1,25 +1,17 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_5; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; -import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.crops.CropsBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.crops.CropsTickingMethod; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -38,21 +30,15 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.BitStorage; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -60,49 +46,31 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import net.minecraft.world.phys.AABB; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.entity.CraftEntityType; import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; -import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; -public class NMSChunksImpl implements NMSChunks { - - private final SuperiorSkyblockPlugin plugin; +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSChunks { public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - KeyBlocksCache.cacheAllBlocks(); - CropsTickingMethod.register(); + super(plugin); } @Override - public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, - Collection playersToUpdate) { - if (chunkPositions.isEmpty()) - return; - - Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.SET_BIOME, false) { + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); @@ -120,7 +88,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null); + levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); @@ -131,9 +99,11 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), @@ -146,7 +116,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); @@ -156,19 +126,12 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { // Do nothing. } - }); + }; } @Override - public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { - if (chunkPositions.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), - chunkPosition.getX(), chunkPosition.getZ(), false)); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.DELETE_CHUNK, false) { + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); @@ -185,6 +148,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( @@ -195,8 +159,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - unloadedChunkCompound.setEntities(new ListTag()); - unloadedChunkCompound.setBlockEntities(tileEntities); + chunkCompound.put("entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, @@ -204,18 +168,19 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { - NMSUtils.buildSurfaceForChunk(serverLevel, protoChunk); + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), @@ -261,7 +226,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound tileEntities.add(blockEntityCompound); } - unloadedChunkCompound.setSections(sectionsList); + chunkCompound.put("sections", sectionsList); } } @@ -270,34 +235,14 @@ public void onFinish() { if (onFinish != null) onFinish.run(); } - }); + }; } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); - List chunkPositionsToCalculate = new LinkedList<>(); - - Iterator chunkPositionsIterator = chunkPositions.iterator(); - while (chunkPositionsIterator.hasNext()) { - ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); - if (cachedCalculatedChunk != null) { - allCalculatedChunks.add(cachedCalculatedChunk); - chunkPositionsIterator.remove(); - } else { - chunkPositionsToCalculate.add(chunkPosition); - } - } - - if (chunkPositions.isEmpty()) - return CompletableFuture.completedFuture(allCalculatedChunks); - - CompletableFuture> completableFuture = new CompletableFuture<>(); - - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( - ChunkLoadReason.BLOCKS_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -311,6 +256,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( @@ -328,38 +274,38 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { - PalettedContainer blocksDataPalette; + PalettedContainer blocksPalettedContainer; Optional blockStatesCompound = sectionCompound.getCompound("block_states"); if (blockStatesCompound.isPresent()) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, blockStatesCompound.get()).promotePartial((sx) -> { }); - blocksDataPalette = dataResult.getOrThrow(); + blocksPalettedContainer = dataResult.getOrThrow(); } else { - blocksDataPalette = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } - PalettedContainer> biomesDataPalette; + PalettedContainer> biomesPalettedContainer; Optional biomesCompound = sectionCompound.getCompound("biomes"); if (biomesCompound.isPresent()) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, biomesCompound.get()).promotePartial((sx) -> { }); - biomesDataPalette = dataResult.getOrThrow(); + biomesPalettedContainer = dataResult.getOrThrow(); } else { - biomesDataPalette = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } - chunkSections[sectionIndex] = new LevelChunkSection(blocksDataPalette, biomesDataPalette); + chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } @@ -375,20 +321,14 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { completableFuture.complete(allCalculatedChunks); } - }); - - return completableFuture; + }; } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); - - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - List unloadedChunkCompounds = new LinkedList<>(); - - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( - ChunkLoadReason.ENTITIES_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { @@ -411,8 +351,9 @@ public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - for (Tag entityTag : unloadedChunkCompound.getEntities()) { + for (Tag entityTag : chunkCompound.getListOrEmpty("entities")) { EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); if (entityType == null) continue; @@ -424,7 +365,9 @@ public void onFinish() { continue; } - Key entityKey = Keys.of(CraftEntityType.minecraftToBukkit(entityType)); + Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( + CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); + chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); } } @@ -432,161 +375,17 @@ public void onFinish() { completableFuture.complete(chunkEntities); }); } - }); - - return completableFuture; - } - - @Override - public void injectChunkSections(Chunk chunk) { - // No implementation - } - - @Override - public boolean isChunkEmpty(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> - chunkSection == null || chunkSection.hasOnlyAir()); - } - - @Override - public Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); - return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; - } - - @Override - public void startTickingChunk(Island island, Chunk chunk, boolean stop) { - if (plugin.getSettings().getCropsInterval() <= 0) - return; - - if (stop) { - CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); - if (cropsBlockEntity != null) - cropsBlockEntity.remove(); - } else { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - CropsBlockEntity.create(island, levelChunk); - } - } - - @Override - public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { - if (chunkPositions.isEmpty()) return; - CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> - cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); - } - - @Override - public void shutdown() { - List> pendingTasks = NMSUtils.getPendingChunkActions(); - - if (pendingTasks.isEmpty()) - return; - - Log.info("Waiting for chunk tasks to complete."); - - CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); - } - - @Override - public List getBlockEntities(Chunk chunk) { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - List blockEntities = new LinkedList<>(); - - World bukkitWorld = chunk.getWorld(); - - levelChunk.getBlockEntities().keySet().forEach(blockPos -> - blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); - - return blockEntities; - } - - private static final ReflectField PALETTED_CONTAINER_DATA = new ReflectField<>( - PalettedContainer.class, Object.class, "d"); - - private static final ReflectField PALETTED_CONTAINER_DATA_STORAGE = new ReflectField<>( - PalettedContainer.class, BitStorage.class, "b"); - - private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { - KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); - List spawnersLocations = new LinkedList<>(); - - for (int i = 0; i < chunkSections.length; ++i) { - LevelChunkSection levelChunkSection = chunkSections[i]; - if (levelChunkSection != null && !levelChunkSection.hasOnlyAir()) { - int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4; - for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { - BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, - sectionBottomY, blockCounts, spawnersLocations); - } - } - } - - return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); - } - - private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, - int sectionBottomY, KeyMap blockCounts, - List spawnersLocations) { - Block block = blockState.getBlock(); - - if (block == Blocks.AIR) - return; - - Location location = new Location(chunkPosition.getWorld(), - (chunkPosition.getX() << 4) + x, - sectionBottomY + y, - (chunkPosition.getZ() << 4) + z); - - int blockAmount = 1; - - if (NMSUtils.isDoubleBlock(block, blockState)) { - blockAmount = 2; - blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); - } - - Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); - blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); - if (block == Blocks.SPAWNER) { - spawnersLocations.add(location); - } - } - - private static void removeEntities(ChunkAccess chunk) { - ChunkPos chunkPos = chunk.getPos(); - ServerLevel serverLevel = ((LevelChunk) chunk).level; - - int chunkWorldCoordX = chunkPos.x << 4; - int chunkWorldCoordZ = chunkPos.z << 4; - - AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinY(), chunkWorldCoordZ, - chunkWorldCoordX + 15, serverLevel.getMaxY(), chunkWorldCoordZ + 15); - - List worldEntities = new LinkedList<>(); - serverLevel.getEntities().get(chunkBounds, worldEntities::add); - - worldEntities.forEach(nmsEntity -> { - if (!(nmsEntity instanceof Player)) - nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); - }); - } - - private static void removeBlockEntities(ChunkAccess chunk) { - chunk.blockEntities.values().forEach(BlockEntity::setRemoved); - chunk.blockEntities.clear(); + }; } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { - NMSUtils.buildSurfaceForChunk(serverLevel, chunk); - } + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; + + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSDragonFightImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSDragonFightImpl.java deleted file mode 100644 index 9ecfa5c8a5..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSDragonFightImpl.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.EndWorldEndDragonFightHandler; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.IslandEndDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.IslandEntityEnderDragon; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.SpikesCache; -import com.google.common.cache.LoadingCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.advancement.Advancement; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.entity.Player; - -import java.lang.reflect.Modifier; -import java.util.List; - -public class NMSDragonFightImpl implements NMSDragonFight { - - private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( - EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField<>( - ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE, 1); - - private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( - SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static boolean firstWorldPreparation = true; - - static { - ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); - } - - @Override - public void prepareEndWorld(World bukkitWorld) { - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); - - if (firstWorldPreparation) { - firstWorldPreparation = false; - SPIKE_CACHE.set(null, SpikesCache.getInstance()); - } - } - - @Nullable - @Override - public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return null; - - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); - return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); - } - - @Override - public void startDragonBattle(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); - } - - @Override - public void removeDragonBattle(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); - - if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { - islandEndDragonFight.removeBattlePlayers(); - islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); - } - } - - @Override - public void awardTheEndAchievement(Player player) { - Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); - if (advancement != null) - player.getAdvancementProgress(advancement).awardCriteria(""); - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSEntitiesImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSEntitiesImpl.java index cb26e74060..41c4a287b9 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSEntitiesImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSEntitiesImpl.java @@ -1,50 +1,22 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_5; -import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; -import org.bukkit.Material; -import org.bukkit.craftbukkit.entity.CraftAnimals; -import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; -import org.bukkit.entity.Animals; import org.bukkit.entity.minecart.PoweredMinecart; -import org.bukkit.inventory.EntityEquipment; -import org.bukkit.inventory.ItemStack; -public class NMSEntitiesImpl implements NMSEntities { +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSEntities { @Override - public ItemStack[] getEquipment(EntityEquipment entityEquipment) { - ItemStack[] itemStacks = new ItemStack[7]; - - itemStacks[0] = new ItemStack(Material.ARMOR_STAND); - itemStacks[1] = entityEquipment.getItemInMainHand(); - itemStacks[2] = entityEquipment.getItemInOffHand(); - itemStacks[3] = entityEquipment.getHelmet(); - itemStacks[4] = entityEquipment.getChestplate(); - itemStacks[5] = entityEquipment.getLeggings(); - itemStacks[6] = entityEquipment.getBoots(); - - return itemStacks; - } - - @Override - public boolean isAnimalFood(ItemStack itemStack, Animals animals) { - return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); - } - - @Override - public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); } @Override - public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); + protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSHologramsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSHologramsImpl.java deleted file mode 100644 index 557fe89731..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSHologramsImpl.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5; - -import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; -import com.bgsoftware.superiorskyblock.nms.NMSHolograms; -import com.google.common.base.Preconditions; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftArmorStand; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.entity.Entity; - -@SuppressWarnings("unused") -public class NMSHologramsImpl implements NMSHolograms { - - @Override - public Hologram createHologram(Location location) { - Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); - serverLevel.addFreshEntity(entityHologram); - return entityHologram; - } - - @Override - public boolean isHologram(Entity entity) { - return ((CraftEntity) entity).getHandle() instanceof Hologram; - } - - public static class EntityHologram extends ArmorStand implements Hologram { - - private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); - - private CraftEntity bukkitEntity; - - EntityHologram(ServerLevel serverLevel, double x, double y, double z) { - super(serverLevel, x, y, z); - - setInvisible(true); - setSmall(true); - setShowArms(false); - setNoGravity(true); - setNoBasePlate(true); - setMarker(true); - forceSetBoundingBox(EMPTY_BOUND); - - super.collides = false; - super.setCustomNameVisible(true); - } - - @Override - public void setHologramName(String name) { - super.setCustomName(CraftChatMessage.fromStringOrNull(name)); - } - - @Override - public void removeHologram() { - super.remove(RemovalReason.DISCARDED); - } - - @Override - public org.bukkit.entity.ArmorStand getHandle() { - return this.getBukkitEntity(); - } - - @Override - public void inactiveTick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - @Override - public boolean repositionEntityAfterLoad() { - return false; - } - - @Override - public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { - // Prevent stand being equipped - } - - @Override - public void addAdditionalSaveData(CompoundTag compoundTag) { - // Do not save NBT. - } - - @Override - public void readAdditionalSaveData(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { - // Prevent stand being equipped - return InteractionResult.PASS; - } - - @Override - public void tick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - public void forceSetBoundingBox(AABB boundingBox) { - super.setBoundingBox(boundingBox); - } - - @Override - public CraftArmorStand getBukkitEntity() { - if (bukkitEntity == null) { - bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); - } - return (CraftArmorStand) bukkitEntity; - } - - @Override - public void remove(RemovalReason removalReason) { - // Prevent being killed. - } - - @Override - public void playSound(SoundEvent soundEvent, float volume, float pitch) { - // Remove sounds. - } - - @Override - public boolean saveAsPassenger(CompoundTag compoundTag) { - // Do not save NBT. - return false; - } - - @Override - public CompoundTag saveWithoutId(CompoundTag compoundTag) { - // Do not save NBT. - return compoundTag; - } - - @Override - public void load(CompoundTag compoundTag) { - // Do not load NBT. - } - - @Override - public boolean isInvulnerableTo(ServerLevel serverLevel, DamageSource damageSource) { - /* - * The field Entity.invulnerable is private. - * It's only used while saving NBTTags, but since the entity would be killed - * on chunk unload, we prefer to override isInvulnerable(). - */ - return true; - } - - @Override - public void setCustomName(Component component) { - // Locks the custom name. - } - - @Override - public void setCustomNameVisible(boolean isCustomNameVisible) { - // Locks the custom name. - } - - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSPlayersImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSPlayersImpl.java deleted file mode 100644 index e9e6c5bf04..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSPlayersImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.nms.NMSPlayers; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.player.OfflinePlayerDataImpl; -import com.bgsoftware.superiorskyblock.player.PlayerLocales; -import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.level.ServerPlayer; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Item; -import org.bukkit.entity.Player; - -import java.util.Locale; - -public class NMSPlayersImpl implements NMSPlayers { - - private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - - @Override - public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { - return OfflinePlayerDataImpl.create(offlinePlayer); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer) { - Player player = superiorPlayer.asPlayer(); - - if (player == null) - return; - - ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() - .ifPresent(property -> setSkinTexture(superiorPlayer, property)); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { - superiorPlayer.setTextureValue(property.value()); - } - - @SuppressWarnings("deprecation") - @Override - public void sendActionBar(Player player, String message) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); - } - - @Override - public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { - BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); - bossBar.addPlayer(player); - return bossBar; - } - - @SuppressWarnings("deprecation") - @Override - public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { - player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); - } - - @Override - public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { - return superiorPlayer.getUniqueId().equals(item.getThrower()); - } - - @Nullable - @Override - public Locale getPlayerLocale(Player player) { - if (PLAYER_LOCALE.isValid()) { - return player.locale(); - } else try { - //noinspection deprecation - return PlayerLocales.getLocale(player.getLocale()); - } catch (IllegalArgumentException error) { - return null; - } - } - - private static class BossBarImpl implements BossBar { - - private final org.bukkit.boss.BossBar bossBar; - private final BossBarTask bossBarTask; - - public BossBarImpl(String message, BarColor color, double ticksToRun) { - bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); - this.bossBarTask = BossBarTask.create(this, ticksToRun); - } - - @Override - public void addPlayer(Player player) { - this.bossBar.addPlayer(player); - this.bossBarTask.registerTask(player); - } - - @Override - public void removeAll() { - this.bossBar.removeAll(); - this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); - } - - @Override - public void setProgress(double progress) { - this.bossBar.setProgress(progress); - } - - @Override - public double getProgress() { - return this.bossBar.getProgress(); - } - - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java index 8b98b0402d..f4d4e0f8e6 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java @@ -1,86 +1,28 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_5; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.ListTag; -import com.bgsoftware.superiorskyblock.tag.Tag; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; -import com.mojang.serialization.Dynamic; -import net.minecraft.SharedConstants; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; -import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; import java.util.Optional; import java.util.Set; -@SuppressWarnings({"unused"}) -public class NMSTagsImpl implements NMSTags { - - @Override - public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) - itemStack.save(MinecraftServer.getServer().registryAccess()); - tagCompound.putInt("DataVersion", SharedConstants.getCurrentVersion().getDataVersion().getVersion()); - - return CompoundTag.fromNBT(tagCompound); - } - - @Override - public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { - if (compoundTag.containsKey("NBT")) { - // Old compound version, deserialize it accordingly - return deserializeItemOld(compoundTag); - } - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); - - int currentVersion = SharedConstants.getCurrentVersion().getDataVersion().getVersion(); - int itemVersion = tagCompound.getIntOr("DataVersion", 0); - if (itemVersion < currentVersion) { - tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, - new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); - } - - ItemStack itemStack = ItemStack.parse(MinecraftServer.getServer().registryAccess(), tagCompound).orElseThrow(); - - return CraftItemStack.asCraftMirror(itemStack); - } - - private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); - Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount").orElse(0); - short data = (short) compoundTag.getShort("data").orElse(0); - CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); - - org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - if (nbtData != null) - itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); - - return CraftItemStack.asCraftMirror(itemStack); - } +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSTags { @Override public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { @@ -97,18 +39,30 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I } @Override - @SuppressWarnings("ConstantConditions") - public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { - net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) + itemStack.save(MinecraftServer.getServer().registryAccess()); + tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + return CompoundTag.fromNBT(tagCompound); + } + + @Override + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.getIntOr(key, def); + } - if (compoundTag == null) - compoundTag = new net.minecraft.nbt.CompoundTag(); + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + return ItemStack.parse(MinecraftServer.getServer().registryAccess(), compoundTag).orElseThrow(); + } - if (!compoundTag.contains("id")) - //noinspection deprecation - compoundTag.putString("id", entityType.getName()); + @Override + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); + } - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; @@ -170,29 +124,4 @@ public String getNBTStringValue(Object object) { return ((StringTag) object).value(); } - @Override - public Object parseList(ListTag listTag) { - net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); - - for (Tag tag : listTag) - nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); - - return nbtTagList; - } - - @Override - public Object getNBTCompoundTag(Object object, String key) { - return ((net.minecraft.nbt.CompoundTag) object).get(key); - } - - @Override - public void setNBTCompoundTagValue(Object object, String key, Object value) { - ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); - } - - @Override - public int getNBTTagListSize(Object object) { - return ((net.minecraft.nbt.ListTag) object).size(); - } - } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java deleted file mode 100644 index 607a6a293c..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSUtils.java +++ /dev/null @@ -1,534 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5; - -import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.PropertiesMapper; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; -import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; -import com.google.common.base.Suppliers; -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.tags.BlockTags; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkPyramid; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.chunk.status.ChunkStep; -import net.minecraft.world.level.chunk.storage.EntityStorage; -import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.generator.CustomChunkGenerator; - -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; - -public class NMSUtils { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( - ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); - private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( - ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); - private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( - EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); - - private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); - - public static final ObjectsPool> BLOCK_POS_POOL = - ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); - - private NMSUtils() { - - } - - @Nullable - public static T getBlockEntityAt(Location location, Class type) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); - } - } - - public static void runActionOnEntityChunks(Collection chunksCoords, - ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); - } - - public static void runActionOnChunks(Collection chunksCoords, - boolean saveChunks, ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); - } - - private static void runActionOnChunksInternal(Collection chunksCoords, - ChunkCallback chunkCallback, - Consumer> onUnloadChunkAction) { - List unloadedChunks = new LinkedList<>(); - List loadedChunks = new LinkedList<>(); - - chunksCoords.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - ChunkAccess chunkAccess; - - try { - chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); - } catch (Throwable ex) { - chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); - } - - if (chunkAccess instanceof LevelChunk levelChunk) { - loadedChunks.add(levelChunk); - } else { - unloadedChunks.add(chunkPosition.copy()); - } - }); - - boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); - - if (!loadedChunks.isEmpty()) - runActionOnLoadedChunks(loadedChunks, chunkCallback); - - if (hasUnloadedChunks) { - onUnloadChunkAction.accept(unloadedChunks); - } else { - chunkCallback.onFinish(); - } - } - - private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { - chunks.forEach(chunkCallback::onLoadedChunk); - } - - private static void runActionOnUnloadedChunks(Collection chunks, - boolean saveChunks, ChunkCallback chunkCallback) { - if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { - Iterator chunksIterator = chunks.iterator(); - while (chunksIterator.hasNext()) { - ChunkPosition chunkPosition = chunksIterator.next(); - - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( - chunkPosition.getX(), chunkPosition.getZ()); - - if (cachedUnloadedChunk != null) { - chunkCallback.onLoadedChunk(cachedUnloadedChunk); - chunksIterator.remove(); - } - } - - if (chunks.isEmpty()) { - chunkCallback.onFinish(); - return; - } - } - - CompletableFuture pendingTask = new CompletableFuture<>(); - PENDING_CHUNK_ACTIONS.add(pendingTask); - - BukkitExecutor.createTask().runAsync(v -> { - CountDownLatch countDownLatch; - if (chunkCallback.isWaitForChunkLoad) { - countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - } else { - countDownLatch = null; - } - - List chunkCompounds = new LinkedList<>(); - - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - boolean calledCountdown = false; - try { - net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); - - if (chunkCompound == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), - Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, - Optional.empty(), chunkPos, serverLevel); - - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - calledCountdown = true; - - if (saveChunks) - chunkCompounds.add(unloadedChunkCompound); - } catch (Exception error) { - if (!calledCountdown && countDownLatch != null) - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - if (countDownLatch != null) { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - } - - return chunkCompounds; - }).runSync(chunkCompounds -> { - chunkCompounds.forEach(unloadedChunkCompound -> { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = unloadedChunkCompound.chunkPos(); - - try { - chunkMap.write(chunkPos, () -> unloadedChunkCompound.chunkCompound); - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); - } - }); - - chunkCallback.onFinish(); - - pendingTask.complete(null); - PENDING_CHUNK_ACTIONS.remove(pendingTask); - }); - } - - private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); - SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { - if (error != null) { - countDownLatch.countDown(); - throw new RuntimeException(error); - } else { - net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - } else { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } - } - }); - }); - - BukkitExecutor.createTask().runAsync(v -> { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } else { - BukkitExecutor.createTask().runAsync(v -> { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - try { - MoonriseRegionFileIO.RegionDataController regionDataController = - serverLevel.moonrise$getEntityChunkDataController(); - int chunkX = chunkPosition.getX(); - int chunkZ = chunkPosition.getZ(); - MoonriseRegionFileIO.RegionDataController.ReadData readData = - regionDataController.readData(chunkX, chunkZ); - if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { - net.minecraft.nbt.CompoundTag entityData = readData.syncRead(); - if (entityData != null) { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } - } - - chunkCallback.onChunkNotExist(chunkPosition); - } catch (IOException error) { - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } - } - - public static List> getPendingChunkActions() { - return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); - } - - public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { - return new ProtoChunk(chunkPos, - UpgradeData.EMPTY, - serverLevel, - serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), - null); - } - - public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { - ServerLevel serverLevel = levelChunk.level; - - if (!isValidPosition(serverLevel, blockPos)) - return null; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - serverLevel.setBlock(blockPos, blockState, 3); - return blockState; - } - - int indexY = serverLevel.getSectionIndex(blockPos.getY()); - - LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - boolean isOriginallyChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - - levelChunk.markUnsaved(); - - boolean isChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) - serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); - - serverLevel.getLightEngine().checkBlock(blockPos); - - if (tileEntity != null) { - net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); - if (tileEntityCompound != null) { - tileEntityCompound.putInt("x", blockPos.getX()); - tileEntityCompound.putInt("y", blockPos.getY()); - tileEntityCompound.putInt("z", blockPos.getZ()); - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.loadWithComponents(tileEntityCompound, MinecraftServer.getServer().registryAccess()); - } - } - - return blockState; - } - - public static boolean isDoubleBlock(Block block, BlockState blockState) { - return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && - blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; - } - - @Nullable - public static LevelChunk getCraftChunkHandle(CraftChunk craftChunk) { - ServerLevel serverLevel = craftChunk.getCraftWorld().getHandle(); - LevelChunk loadedChunk = serverLevel.getChunkIfLoaded(craftChunk.getX(), craftChunk.getZ()); - if (loadedChunk != null) - return loadedChunk; - - return (LevelChunk) serverLevel.getChunk(craftChunk.getX(), craftChunk.getZ(), ChunkStatus.FULL, true); - } - - public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkAccess chunkAccess) { - CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), serverLevel.generator); - - ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); - - // Unsafe: we do not provide chunks cache, even tho it is required. - // Should be fine in normal flow, as the only method that access the chunsk cache - // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: - // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 - WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); - - customChunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - chunkAccess); - } - - public record UnloadedChunkCompound(ChunkPosition chunkPosition, - net.minecraft.nbt.CompoundTag chunkCompound) { - - public ListTag getSections() { - return chunkCompound.getListOrEmpty("sections"); - } - - public ListTag getEntities() { - return chunkCompound.getListOrEmpty("Entities"); - } - - public void setSections(ListTag sectionsList) { - chunkCompound.put("sections", sectionsList); - } - - public void setEntities(ListTag entitiesList) { - chunkCompound.put("entities", entitiesList); - } - - public void setBlockEntities(ListTag blockEntitiesList) { - chunkCompound.put("block_entities", blockEntitiesList); - } - - public ServerLevel serverLevel() { - return ((CraftWorld) chunkPosition.getWorld()).getHandle(); - } - - public ChunkPos chunkPos() { - return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - } - - } - - private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); - } - - public static abstract class ChunkCallback { - - private final ChunkLoadReason chunkLoadReason; - private final boolean isWaitForChunkLoad; - - @Nullable - protected CountDownLatch chunkLoadLatch; - - public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { - this.chunkLoadReason = chunkLoadReason; - this.isWaitForChunkLoad = isWaitForChunkLoad; - } - - public abstract void onLoadedChunk(LevelChunk levelChunk); - - public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - - public abstract void onFinish(); - - protected final void latchCountDown() { - if (this.chunkLoadLatch != null) - this.chunkLoadLatch.countDown(); - } - - public final void onChunkNotExist(ChunkPosition chunkPosition) { - if (!plugin.getProviders().hasCustomWorldsSupport()) - return; - - ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { - LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); - }); - } - - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java index 7a2f4c2c8b..2a9cd9f852 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java @@ -3,131 +3,57 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; -import com.bgsoftware.superiorskyblock.nms.ICachedBlock; -import com.bgsoftware.superiorskyblock.nms.NMSWorld; -import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.generator.IslandsGeneratorImpl; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_5.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_5.vibration.IslandVibrationUser; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.ChunkReaderImpl; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.WorldEditSessionImpl; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; import com.bgsoftware.superiorskyblock.world.SignType; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import io.papermc.paper.antixray.ChunkPacketBlockController; -import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.BubbleColumn; import org.bukkit.block.data.type.HangingSign; -import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.WallHangingSign; -import org.bukkit.block.data.type.WallSign; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.block.CraftBlock; -import org.bukkit.craftbukkit.block.CraftBlockState; -import org.bukkit.craftbukkit.block.CraftSign; -import org.bukkit.craftbukkit.block.data.CraftBlockData; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.function.IntFunction; -public class NMSWorldImpl implements NMSWorld { +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); - private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, - Object.class, "chunkPacketBlockController") - .removeFinal(); - - private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; + super(plugin); } @Override - public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { - Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); - Location location = new Location( - Bukkit.getWorld(chunkSnapshot.getWorldName()), - (chunkSnapshot.getX() << 4) + x, - y, - (chunkSnapshot.getZ() << 4) + z - ); - - return Keys.of(KeyBlocksCache.getBlockKey(block), location); + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); } @Override - public void listenSpawner(Location location, IntFunction delayChangeCallback) { - SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); - if (spawnerBlockEntity == null) + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) return; - ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - - List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? - LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; - - Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new LinkedList<>(); - - while (blockEntityTickersIterator.hasNext()) { - TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && - !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { - blockEntityTickersIterator.remove(); - tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); - } - } + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } - if (!tickersToAdd.isEmpty()) - blockEntityTickers.addAll(tickersToAdd); + @Override + public SignType getSignType(Object sign) { + if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return super.getSignType(sign); } @Override @@ -174,263 +100,4 @@ public void replaceTrialBlockPlayerDetector(Island island, Location location) { } } - @Override - public void replaceSculkSensorListener(Island island, Location location) { - SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); - if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) - return; - - SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); - } - - @Override - public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { - if (!plugin.getSettings().isWorldBorders()) - return; - - Player player = superiorPlayer.asPlayer(); - World world = superiorPlayer.getWorld(); - - if (world == null || player == null) - return; - - int islandSize = island == null ? 0 : island.getIslandSize(); - - boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; - - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - - WorldBorder worldBorder; - - if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { - worldBorder = serverLevel.getWorldBorder(); - } else { - Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); - if (dimension == null) - return; - - Location center = island.getCenter(dimension); - - worldBorder = new WorldBorder(); - worldBorder.world = serverLevel; - worldBorder.setWarningBlocks(0); - worldBorder.setCenter(center.getX(), center.getZ()); - - switch (superiorPlayer.getBorderColor()) { - case BLUE -> { - worldBorder.setSize((islandSize * 2) + 1D); - } - case GREEN -> { - worldBorder.setSize((islandSize * 2) + 1.001D); - worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); - } - case RED -> { - worldBorder.setSize((islandSize * 2) + 1D); - worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); - } - } - } - - ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); - ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); - } - - @Override - public Object getBlockData(org.bukkit.block.Block block) { - return block.getBlockData(); - } - - @Override - public void setBlock(Location location, int combinedId) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - BlockState blockState = - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - - if (blockState != null) { - serverLevel.getChunkSource().blockChanged(blockPos); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); - } - } - } - } - - @Override - public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return NMSCachedBlock.obtain(block); - } - - @Override - public boolean isWaterLogged(org.bukkit.block.Block block) { - if (Materials.isWater(block.getType())) - return true; - - BlockData blockData = block.getBlockData(); - - return blockData instanceof BubbleColumn || - (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); - } - - @Override - public SignType getSignType(Object sign) { - if (sign instanceof WallSign) - return SignType.WALL_SIGN; - else if (sign instanceof Sign) - return SignType.STANDING_SIGN; - else if (sign instanceof HangingSign) - return SignType.HANGING_SIGN; - else if (sign instanceof WallHangingSign) - return SignType.HANGING_WALL_SIGN; - else - return SignType.UNKNOWN; - } - - @Override - public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { - BlockState blockState = ((CraftBlock) block).getNMS(); - return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; - } - - @Override - public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { - return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); - } - - @Override - public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { - return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); - } - - private int getDefaultAmount(BlockState blockState) { - Block block = blockState.getBlock(); - return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; - } - - @Override - public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { - return !bukkitBlock.isPassable(); - } - - @Override - public void placeSign(Island island, Location location) { - SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); - if (signBlockEntity == null) - return; - - String[] lines = new String[4]; - Component[] messages = signBlockEntity.getFrontText().getMessages(false); - System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - Component[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } - - System.arraycopy(newLines, 0, messages, 0, 4); - } - - @Override - public void playGeneratorSound(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); - } - } - - @Override - public void playBreakAnimation(org.bukkit.block.Block block) { - ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); - } - } - - @Override - public void playPlaceSound(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); - } - } - - @Override - public int getMinHeight(World world) { - return world.getMinHeight(); - } - - @Override - public void removeAntiXray(org.bukkit.World bukkitWorld) { - if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); - } - - @Override - public IslandsGenerator createGenerator(Dimension dimension) { - return new IslandsGeneratorImpl(dimension); - } - - @Override - public WorldEditSession createEditSession(World world) { - return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); - } - - @Override - public WorldEditSession createPartialEditSession(Dimension dimension) { - return WorldEditSessionImpl.obtain(dimension); - } - - @Override - public ChunkReader createChunkReader(Chunk chunk) { - return new ChunkReaderImpl(chunk); - } - - private static ReflectField> initializeLevelBlockEntityTickersField() { - ReflectField> field = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - - if (!field.isValid()) - field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); - - return field; - } - } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsBlockEntity.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsBlockEntity.java deleted file mode 100644 index 229f511543..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsBlockEntity.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.crops; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.function.Consumer; - -public class CropsBlockEntity extends BlockEntity { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - - private final WeakReference island; - private final WeakReference chunk; - - private int currentTick = 0; - - private double cachedCropGrowthMultiplier; - - private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(levelChunk); - setLevel(levelChunk.level); - levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; - } - - public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); - return new CropsBlockEntity(island, levelChunk, blockPos); - }); - } - - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); - } - - public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { - if (tickingChunks.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> { - long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); - if (cropsBlockEntity != null) - cropsBlockEntityConsumer.accept(cropsBlockEntity); - }); - } - - @Override - public boolean isValidBlockState(BlockState state) { - return true; - } - - public void remove() { - this.remove = true; - } - - public void tick() { - if (++currentTick <= plugin.getSettings().getCropsInterval()) - return; - - LevelChunk levelChunk = this.chunk.get(); - Island island = this.island.get(); - ServerLevel serverLevel = (ServerLevel) getLevel(); - - if (levelChunk == null || island == null || serverLevel == null) { - remove(); - return; - } - - currentTick = 0; - - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - if (chunkRandomTickSpeed > 0) - CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); - } - - public void setCropGrowthMultiplier(double cropGrowthMultiplier) { - this.cachedCropGrowthMultiplier = cropGrowthMultiplier; - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingBlockEntity.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingBlockEntity.java deleted file mode 100644 index 12e6b7afd2..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingBlockEntity.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.crops; - -import com.bgsoftware.superiorskyblock.nms.v1_21_5.crops.CropsBlockEntity; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { - - - @Override - public void tick() { - cropsBlockEntity.tick(); - } - - @Override - public boolean isRemoved() { - return cropsBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return cropsBlockEntity.getBlockPos(); - } - - @Override - public String getType() { - return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingMethod.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingMethod.java deleted file mode 100644 index 5a776d6190..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/crops/CropsTickingMethod.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.crops; - -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; - -public abstract class CropsTickingMethod { - - private static final ReflectField SERVER_LEVEL_SIMPLE_RANDOM = new ReflectField<>( - ServerLevel.class, RandomSource.class, "simpleRandom"); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_SIMPLE_RANDOM.isValid() ? - new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); - - private static Set CROPS_TO_GROW_CACHE; - - static { - plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); - } - - protected CropsTickingMethod() { - - } - - public static void register() { - // Calls the static initializer which registers the callback. - } - - public static void tick(LevelChunk levelChunk, int tickSpeed) { - INSTANCE.doTick(levelChunk, tickSpeed); - } - - protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); - - private static void onSettingsUpdate() { - CROPS_TO_GROW_CACHE = new HashSet<>(); - plugin.getSettings().getCropsToGrow().forEach(cropName -> { - Key key = Keys.ofMaterialAndData(cropName); - if (key instanceof MaterialKey materialKey) { - Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); - if (block != null && block.defaultBlockState().isRandomlyTicking()) - CROPS_TO_GROW_CACHE.add(block); - } - }); - } - - private static class PaperCropsTickingMethod extends CropsTickingMethod { - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - ServerLevel serverLevel = levelChunk.level; - LevelChunkSection[] sections = levelChunk.getSections(); - - int minSection = serverLevel.getMinSectionY(); - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - RandomSource simpleRandom = SERVER_LEVEL_SIMPLE_RANDOM.get(serverLevel); - - for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - ca.spottedleaf.moonrise.common.list.ShortList tickList = - levelChunkSection.moonrise$getTickingBlockList(); - int tickingBlocks = tickList.size(); - if (tickingBlocks <= 0) { - continue; - } - - PalettedContainer states = levelChunkSection.states; - - int offsetY = (sectionIndex + minSection) << 4; - - for (int i = 0; i < tickSpeed; ++i) { - int index = simpleRandom.nextInt() & 0xFFF; - - if (index >= tickingBlocks) { - continue; - } - - int location = (int) tickList.getRaw(index) & 0xFFFF; - BlockState blockState = states.get(location); - if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) - continue; - - // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! - BlockPos blockPos = new BlockPos((location & 15) | chunkOffsetX, - ((location >>> 8) & 15) | offsetY, - ((location >>> 4) & 15) | chunkOffsetZ); - - blockState.randomTick(serverLevel, blockPos, simpleRandom); - } - } - - } - - } - - private static class SpigotCropsTickingMethod extends CropsTickingMethod { - - private static int random = ThreadLocalRandom.current().nextInt(); - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - LevelChunkSection[] sections = levelChunk.getSections(); - ServerLevel serverLevel = levelChunk.level; - - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - - for (int i = 0; i < tickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { - BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); - blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); - } - } - } - } - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/DragonUtils.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/DragonUtils.java deleted file mode 100644 index 406cecc167..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/DragonUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; - -import com.bgsoftware.common.reflection.ReflectField; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; - -import java.lang.reflect.Modifier; - -public class DragonUtils { - - private static final ReflectField END_PODIUM_LOCATION = new ReflectField( - EndPodiumFeature.class, BlockPos.class, - Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static BlockPos currentPodiumPosition = BlockPos.ZERO; - - private DragonUtils() { - - } - - public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { - try { - END_PODIUM_LOCATION.set(null, podiumPosition); - currentPodiumPosition = podiumPosition; - runnable.run(); - } finally { - END_PODIUM_LOCATION.set(null, BlockPos.ZERO); - currentPodiumPosition = BlockPos.ZERO; - } - } - - public static BlockPos getCurrentPodiumPosition() { - return currentPodiumPosition; - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndWorldEndDragonFightHandler.java deleted file mode 100644 index 286e82fa7f..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndWorldEndDragonFightHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; -import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.dimension.end.EndDragonFight; - -import java.util.LinkedList; -import java.util.List; - -public class EndWorldEndDragonFightHandler extends EndDragonFight { - - private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); - - private final List worldDragonFightsList = new LinkedList<>(); - - public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); - } - - @Override - public void tick() { - this.worldDragonFightsList.forEach(EndDragonFight::tick); - } - - public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); - if (oldDragonFight != null) - this.worldDragonFightsList.remove(oldDragonFight); - this.worldDragonFightsList.add(endDragonFight); - } - - @Nullable - public IslandEndDragonFight getDragonFight(IslandCache islandCache) { - return islandCache.get(CACHE_KEY); - } - - @Nullable - public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { - IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); - if (endDragonFight != null) - this.worldDragonFightsList.remove(endDragonFight); - return endDragonFight; - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEndDragonFight.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEndDragonFight.java deleted file mode 100644 index df043b3d27..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEndDragonFight.java +++ /dev/null @@ -1,212 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.IslandEntityEnderDragon; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; -import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import net.minecraft.world.level.block.state.pattern.BlockPattern; -import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; -import net.minecraft.world.level.block.state.predicate.BlockPredicate; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -public class IslandEndDragonFight extends EndDragonFight { - - private static final ReflectField DRAGON_BATTLE = new ReflectField( - EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 4); - private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); - - private static final ReflectField TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>( - EndDragonFight.class, int.class, Modifier.PRIVATE, 4); - private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( - DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); - - private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") - .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") - .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) - .build(); - - private final Island island; - private final BlockPos islandBlockPos; - private final Vec3 islandBlockVectored; - private final ServerLevel serverLevel; - private final IslandEntityEnderDragon entityEnderDragon; - - private byte currentTick = 0; - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { - this(island, serverLevel, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), null); - } - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, - @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); - - this.island = island; - this.islandBlockPos = islandBlockPos; - this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); - this.serverLevel = serverLevel; - this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; - - SCAN_FOR_LEGACY_PORTALS.set(this, false); - WAS_DRAGON_KILLED.set(this, false); - DRAGON_BATTLE.set(this.entityEnderDragon, this); - - TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); - } - - @Override - public void tick() { - // doServerTick - - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); - - DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); - if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { - LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); - } - - if (++currentTick >= 20) { - updateBattlePlayers(); - currentTick = 0; - TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); - } - } - - @Nullable - @Override - public BlockPattern.BlockPatternMatch findExitPortal() { - int chunkX = this.islandBlockPos.getX() >> 4; - int chunkZ = this.islandBlockPos.getZ() >> 4; - - for (int x = -8; x <= 8; ++x) { - for (int z = -8; z <= 8; ++z) { - LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); - - for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { - if (blockEntity instanceof TheEndPortalBlockEntity) { - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( - this.serverLevel, blockEntity.getBlockPos()); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - } - } - - int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); - currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); - for (int y = highestBlock; y >= this.serverLevel.getMinY(); --y) { - currentPosition.setY(y); - - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - - return null; - } - - @Override - public void resetSpikeCrystals() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); - } - - public void removeBattlePlayers() { - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - for (ServerPlayer serverPlayer : dragonEventPlayers) - this.dragonEvent.removePlayer(serverPlayer); - } - - public IslandEntityEnderDragon getEnderDragon() { - return this.entityEnderDragon; - } - - private void updateBattlePlayers() { - Set nearbyPlayers = new HashSet<>(); - - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - Player bukkitPlayer = superiorPlayer.asPlayer(); - if (bukkitPlayer != null) { - ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); - if (serverPlayer.serverLevel().equals(this.serverLevel)) { - this.dragonEvent.addPlayer(serverPlayer); - nearbyPlayers.add(serverPlayer.getUUID()); - } - } - } - - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - - dragonEventPlayers.stream() - .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) - .forEach(this.dragonEvent::removePlayer); - } - - private IslandEntityEnderDragon spawnEnderDragon() { - IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); - - entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); - entityEnderDragon.absSnapTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), - this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); - - this.serverLevel.addFreshEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); - - this.dragonUUID = entityEnderDragon.getUUID(); - this.resetSpikeCrystals(); - - return entityEnderDragon; - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java index de857b5881..c8be9c1bd7 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/IslandEntityEnderDragon.java @@ -2,59 +2,34 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.config.SettingsManager; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntitySpawnReason; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; -import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftEnderDragon; -public class IslandEntityEnderDragon extends EnderDragon { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - @NotNull - public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { - return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : - new EnderDragon(entityTypes, level); - } - - private final ServerLevel serverLevel; - private final Dimension dimension; - private BlockPos islandBlockPos; +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { - this(level); - this.islandBlockPos = islandBlockPos; + super(level, islandBlockPos); } - private IslandEntityEnderDragon(Level level) { - super(EntityType.ENDER_DRAGON, level); - this.serverLevel = (ServerLevel) level; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + public IslandEntityEnderDragon(Level level) { + super(level); } @Nullable @Override - public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, - @Nullable SpawnGroupData spawnGroupData) { + @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); - return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override @@ -64,40 +39,4 @@ public void readAdditionalSaveData(@NotNull CompoundTag compoundTag) { finalizeIslandEnderDragon(); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - - private void finalizeIslandEnderDragon() { - if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) - return; - - Island island; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); - } - - if (island == null) - return; - - Location middleBlock = island.getCenter(dimension); - - SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); - if (dimensionConfig instanceof SettingsManager.Worlds.End) { - middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); - } - - this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); - - IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); - } - } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/SpikesCache.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/SpikesCache.java deleted file mode 100644 index 03b4ed71e2..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/SpikesCache.java +++ /dev/null @@ -1,190 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; - - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.DragonUtils; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.CacheStats; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public class SpikesCache implements LoadingCache> { - - private static final SpikesCache INSTANCE = new SpikesCache(); - - private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() - .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); - - private long worldSeed; - - public static SpikesCache getInstance() { - return INSTANCE; - } - - private SpikesCache() { - - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - List getUnchecked(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public List apply(@NotNull Long worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void refresh(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ConcurrentMap> asMap() { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Nullable - @Override - public List getIfPresent(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed, - @NotNull Callable> loader) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAllPresent(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void put(@NotNull Long worldSeed, @NotNull List spikes) { - try { - this.worldSeed = worldSeed; - cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); - } finally { - this.worldSeed = 0; - } - } - - @Override - public void putAll(Map> spikesMap) { - spikesMap.forEach(this::put); - } - - @Override - public void invalidate(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll() { - this.cachedSpikes.invalidateAll(); - } - - @Override - public long size() { - return this.cachedSpikes.size(); - } - - @Override - public @NotNull - CacheStats stats() { - return this.cachedSpikes.stats(); - } - - @Override - public void cleanUp() { - this.cachedSpikes.cleanUp(); - } - - private class InternalCacheLoader extends CacheLoader> { - - @Override - public @NotNull - List load(@NotNull BlockPos blockPos) { - List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); - - Collections.shuffle(list, new Random(worldSeed)); - List spikesList = Lists.newArrayList(); - - for (int i = 0; i < 10; ++i) { - int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int l = list.get(i); - int radius = 2 + l / 3; - int height = 76 + l * 3; - boolean guarded = l == 1 || l == 2; - - spikesList.add(new SpikeFeature.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded)); - } - - return spikesList; - } - - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/generator/IslandsGeneratorImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/generator/IslandsGeneratorImpl.java deleted file mode 100644 index fe20e4d555..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/generator/IslandsGeneratorImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.generator; - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; -import org.bukkit.generator.WorldInfo; - -import java.util.Collections; -import java.util.List; -import java.util.Random; - -@SuppressWarnings({"unused", "NullableProblems"}) -public class IslandsGeneratorImpl extends IslandsGenerator { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private final Dimension dimension; - - public IslandsGeneratorImpl(Dimension dimension) { - this.dimension = dimension; - } - - @Override - public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, - @NotNull ChunkData chunkData) { - if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { - chunkData.setBlock(0, 99, 0, Material.BEDROCK); - } - } - - @Override - public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { - return new BiomeProvider() { - @Override - public @NotNull - Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { - return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension); - } - - @Override - public @NotNull - List getBiomes(@NotNull WorldInfo worldInfo) { - return IslandUtils.getDefaultWorldBiomes(); - } - - }; - } - - @Override - public List getDefaultPopulators(World world) { - return Collections.emptyList(); - } - - @Override - public Location getFixedSpawnLocation(World world, Random random) { - return new Location(world, 0, 100, 0); - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/hologram/EntityHologram.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/hologram/EntityHologram.java new file mode 100644 index 0000000000..9ed5be439c --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/hologram/EntityHologram.java @@ -0,0 +1,39 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.hologram; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_5.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + public void addAdditionalSaveData(CompoundTag compoundTag) { + // Do not save NBT. + } + + @Override + public void readAdditionalSaveData(CompoundTag compoundTag) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(CompoundTag compoundTag) { + // Do not save NBT. + return false; + } + + @Override + public CompoundTag saveWithoutId(CompoundTag compoundTag) { + // Do not save NBT. + return compoundTag; + } + + @Override + public void load(CompoundTag compoundTag) { + // Do not load NBT. + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuBrewingStandBlockEntity.java deleted file mode 100644 index 7d57cc07f0..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuBrewingStandBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { - - private final InventoryHolder holder; - - public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuDispenserBlockEntity.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuDispenserBlockEntity.java deleted file mode 100644 index ec1ae009b0..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuDispenserBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.DispenserBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuDispenserBlockEntity extends DispenserBlockEntity { - - private final InventoryHolder holder; - - public MenuDispenserBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuFurnaceBlockEntity.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuFurnaceBlockEntity.java deleted file mode 100644 index d8bfab24fa..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuFurnaceBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.FurnaceBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { - - private final InventoryHolder holder; - - public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuHopperBlockEntity.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuHopperBlockEntity.java deleted file mode 100644 index 1a40fb8664..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/menu/MenuHopperBlockEntity.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.HopperBlock; -import net.minecraft.world.level.block.entity.HopperBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuHopperBlockEntity extends HopperBlockEntity { - - private final InventoryHolder holder; - - public MenuHopperBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.HOPPER.defaultBlockState().setValue(HopperBlock.FACING, Direction.DOWN)); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/player/OfflinePlayerDataImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/player/OfflinePlayerDataImpl.java deleted file mode 100644 index 12102f601d..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/player/OfflinePlayerDataImpl.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.player; - -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; - -import java.util.Optional; - -public class OfflinePlayerDataImpl implements OfflinePlayerData { - - private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); - private static final ReflectMethod ENTITY_SET_LEVEL = new ReflectMethod<>(Entity.class, 1, Level.class); - - private Player fakePlayer; - - public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { - return POOL.obtain().initialize(offlinePlayer); - } - - private OfflinePlayerDataImpl() { - - } - - private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), - Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return null; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - this.fakePlayer = serverPlayer.getBukkitEntity(); - this.fakePlayer.loadData(); - - return this; - } - - @Override - public Player getFakeOnlinePlayer() { - return this.fakePlayer; - } - - @Override - public void setLocation(Location location) { - ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); - serverPlayer.absSnapTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - } - - @Override - public void applyChanges() { - this.fakePlayer.saveData(); - } - - @Override - public void release() { - this.fakePlayer = null; - POOL.release(this); - } - -} \ No newline at end of file diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/spawners/TickingSpawnerBlockEntityNotifier.java deleted file mode 100644 index f6b3135db5..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/spawners/TickingSpawnerBlockEntityNotifier.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.spawners; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BaseSpawner; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -import java.util.function.IntFunction; - -public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { - - private final SpawnerBlockEntity spawnerBlockEntity; - private final TickingBlockEntity tickingBlockEntity; - private final IntFunction delayChangeCallback; - - public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, - IntFunction delayChangeCallback) { - this.spawnerBlockEntity = spawnerBlockEntity; - this.tickingBlockEntity = tickingBlockEntity; - this.delayChangeCallback = delayChangeCallback; - updateDelay(); - } - - @Override - public void tick() { - BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); - int startDelay = baseSpawner.spawnDelay; - try { - tickingBlockEntity.tick(); - } finally { - int newDelay = baseSpawner.spawnDelay; - if (newDelay > startDelay) - updateDelay(); - } - } - - @Override - public boolean isRemoved() { - return tickingBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return tickingBlockEntity.getPos(); - } - - @Override - public String getType() { - return tickingBlockEntity.getType(); - } - - public void updateDelay() { - BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); - baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..d3d3ff0923 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java @@ -0,0 +1,374 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.utils; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.utils.TickingBlockList; +import com.google.common.base.Suppliers; +import com.google.gson.JsonParseException; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +public class NMSUtilsVersioned { + + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( + EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { + return chunkMap.read(chunkPos).join().orElse(null); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { + return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), + chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { + chunkMap.write(chunkPos, () -> chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } else { + return BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + MoonriseRegionFileIO.RegionDataController regionDataController = + serverLevel.moonrise$getEntityChunkDataController(); + int chunkX = chunkPosition.getX(); + int chunkZ = chunkPosition.getZ(); + MoonriseRegionFileIO.RegionDataController.ReadData readData = + regionDataController.readData(chunkX, chunkZ); + if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { + CompoundTag entityData = readData.syncRead(); + if (entityData != null) { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + return; + } + } + + chunkCallback.onChunkNotExist(chunkPosition); + } catch (IOException error) { + countDownLatch.countDown(); + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.liquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + blockEntity.loadWithComponents(compoundTag, MinecraftServer.getServer().registryAccess()); + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + applySignTextLines(compoundTag, "front_text"); + applySignTextLines(compoundTag, "back_text"); + convertLegacySignTextLines(compoundTag); + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + + Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + + chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); + + // Unsafe: we do not provide chunks cache, even tho it is required. + // Should be fine in normal flow, as the only method that access the chunks cache + // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 + WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); + + customChunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + } + + public static CompoundTag saveEntity(Entity entity) { + CompoundTag compoundTag = new CompoundTag(); + entity.save(compoundTag); + return compoundTag; + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.moonrise$getTickingBlockList().size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + public static String getPropertyValue(Property property) { + return property.value(); + } + + public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.getDragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absSnapTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSectionY(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinY(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxY(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.markUnsaved(); + } + + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { + blockEntityCompound.getCompound(key).ifPresent(textCompound -> { + ListTag messages = textCompound.getListOrEmpty("messages"); + List textLines = new ArrayList<>(); + for (net.minecraft.nbt.Tag lineTag : messages) { + try { + textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); + } catch (JsonParseException error) { + textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); + } + } + + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); + }); + } + + private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockEntityCache.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockEntityCache.java deleted file mode 100644 index f968fb4245..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockEntityCache.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class BlockEntityCache { - - private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); - - private BlockEntityCache() { - - } - - public static String getBlockEntityId(BlockState blockState) { - return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { - for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - if (blockEntityType.isValid(blockState)) { - ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); - if (resourceLocation != null) - return resourceLocation.toString(); - } - } - - return ""; - }); - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java deleted file mode 100644 index c63a16970e..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/ChunkReaderImpl.java +++ /dev/null @@ -1,243 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.block.CraftBlockType; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.InventoryHolder; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class ChunkReaderImpl implements ChunkReader { - - private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - private static final byte[] FULL_LIGHT = new byte[2048]; - private static final byte[] EMPTY_LIGHT = new byte[2048]; - - static { - Arrays.fill(FULL_LIGHT, (byte) 0xFF); - } - - private final ServerLevel serverLevel; - private final int x; - private final int z; - - private final Map blockEntities = new HashMap<>(); - private final List entities = new LinkedList<>(); - private final PalettedContainerRO[] blockids; - private final byte[][] skylight; - private final byte[][] emitlight; - - public ChunkReaderImpl(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - - this.serverLevel = levelChunk.level; - ChunkPos chunkPos = levelChunk.getPos(); - this.x = chunkPos.x; - this.z = chunkPos.z; - - LevelChunkSection[] levelChunkSections = levelChunk.getSections(); - this.blockids = new PalettedContainerRO[levelChunkSections.length]; - this.skylight = new byte[levelChunkSections.length][]; - this.emitlight = new byte[levelChunkSections.length][]; - - LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); - - for (int i = 0; i < this.blockids.length; ++i) { - LevelChunkSection levelChunkSection = levelChunkSections[i]; - - this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); - - DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (skyLightArray == null) { - this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; - } else { - this.skylight[i] = new byte[2048]; - System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); - } - - DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (emitLightArray == null) { - this.emitlight[i] = EMPTY_LIGHT; - } else { - this.emitlight[i] = new byte[2048]; - System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); - } - } - - levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - InventoryHolder inventoryHolder = blockEntity.getOwner(); - if (inventoryHolder != null) - compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); - - blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); - }); - - for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) - entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); - } - - @Override - public int getX() { - return this.x; - } - - @Override - public int getZ() { - return this.z; - } - - @Override - public Material getType(int x, int y, int z) { - return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); - } - - @Override - public short getData(int x, int y, int z) { - return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); - } - - @Override - @Nullable - public CompoundTag getTileEntity(int x, int y, int z) { - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); - return this.blockEntities.get(blockPos); - } - } - - @Override - @Nullable - public CompoundTag readBlockStates(int x, int y, int z) { - BlockState blockState = getBlockState(x, y, z); - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = CompoundTag.of(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(int x, int y, int z) { - int off = (y & 15) << 7 | z << 3 | x >> 1; - int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; - } - - @Override - public void forEachEntity(EntityConsumer consumer) { - if (entities.isEmpty()) - return; - - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = wrapper.getHandle(); - for (CachedEntity cachedEntity : entities) { - location.setX(cachedEntity.x); - location.setY(cachedEntity.y); - location.setZ(cachedEntity.z); - location.setYaw(cachedEntity.yaw); - location.setPitch(cachedEntity.pitch); - consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); - } - } - } - - private BlockState getBlockState(int x, int y, int z) { - return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); - } - - private int getSectionIndex(int y) { - int sectionIndex = SectionPos.blockToSectionCoord(y); - return sectionIndex - this.serverLevel.getMinSectionY(); - } - - private int getSectionYFromSectionIndex(int index) { - return index + this.serverLevel.getMinSectionY(); - } - - private static class CachedEntity { - - private final double x; - private final double y; - private final double z; - private final float yaw; - private final float pitch; - private final EntityType entityType; - private final CompoundTag entityTag; - - CachedEntity(Entity entity) { - this.x = entity.getX(); - this.y = entity.getY(); - this.z = entity.getZ(); - this.yaw = entity.getBukkitYaw(); - this.pitch = entity.getXRot(); - this.entityType = entity.getBukkitEntity().getType(); - - net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag(); - entity.save(compoundTag); - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - - this.entityTag = CompoundTag.fromNBT(compoundTag); - } - - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java deleted file mode 100644 index 671c6f9800..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/KeyBlocksCache.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; - -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.level.block.Block; -import org.bukkit.Material; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class KeyBlocksCache { - - private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); - - private KeyBlocksCache() { - - } - - public static Key getBlockKey(Block block) { - return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { - Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); - }); - } - - public static void cacheAllBlocks() { - BuiltInRegistries.BLOCK.forEach(KeyBlocksCache::getBlockKey); - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java deleted file mode 100644 index 50339bb510..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapper.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; - -import com.bgsoftware.superiorskyblock.core.logging.Log; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.Property; - -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; - -public class PropertiesMapper { - - private static final Map> nameToProperty = new HashMap<>(); - private static final Map, String> propertyToName = new HashMap<>(); - - static { - Map fieldsToNames = new IdentityHashMap<>(); - - fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); - fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); - fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); - fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); - fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); - fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); - fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); - fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); - fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); - fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); - fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); - fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); - fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); - fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); - fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); - fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); - fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); - fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); - fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); - fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); - fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); - fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); - fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); - fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); - fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); - fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); - fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); - fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); - fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); - - try { - for (Field field : BlockStateProperties.class.getFields()) { - field.setAccessible(true); - Object value = field.get(null); - if (value instanceof Property) { - Property property = (Property) value; - register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); - } - } - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while loading properties mapper:"); - } - - } - - private static void register(String key, String fieldName, Property property) { - if (nameToProperty.containsKey(key)) { - Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); - } else { - nameToProperty.put(key, property); - propertyToName.put(property, key); - } - } - - public static Property getProperty(String name) { - return nameToProperty.get(name); - } - - public static String getPropertyName(Property property) { - return propertyToName.get(property); - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapperVersioned.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..40d8887245 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/PropertiesMapperVersioned.java @@ -0,0 +1,18 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; + +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionDataImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionDataImpl.java deleted file mode 100644 index ff6bd9d987..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionDataImpl.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; - -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionDataImpl implements WorldEditSession.Data { - - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private final List> chunks = new LinkedList<>(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); - - public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, - List> blocksToUpdate, - List> blockEntities, - Set lightenChunks) { - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // Convert chunk data - Iterator> chunksIterator = chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); - int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); - WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); - - List> lights; - if (isStarLightInterface || chunkData.lights().isEmpty()) { - lights = Collections.emptyList(); - } else { - lights = new LinkedList<>(); - chunkData.lights().forEach(lightPosition -> { - lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, - lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, - null)); - }); - } - - PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), - chunkData.heightmaps(), lights); - - this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, - currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); - } - - // Convert blocksToUpdate - blocksToUpdate.forEach(blockToUpdate -> { - BlockPos blockPos = blockToUpdate.getKey(); - this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockToUpdate.getValue())); - }); - - // Convert blockEntities - blockEntities.forEach(blockEntity -> { - BlockPos blockPos = blockEntity.getKey(); - this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockEntity.getValue())); - }); - - // Convert lights - lightenChunks.forEach(lightPosition -> { - this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, - lightPosition.z - baseChunkPosZAxis, null)); - }); - } - - public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, - int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, - Long2ObjectMapView chunks) { - this.chunks.forEach(chunkDataPositioned -> { - long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, - baseChunkPosZAxis + chunkDataPositioned.zOffset); - - List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - chunkDataPositioned.object.lights.forEach(lightPositioned -> { - lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, - baseBlockPosYAxis + lightPositioned.yOffset, - baseBlockPosZAxis + lightPositioned.zOffset)); - }); - - chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, - chunkDataPositioned.object.heightmaps, lights)); - }); - } - - public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { - this.blocksToUpdate.forEach(blockToUpdatePositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, - baseBlockPosYAxis + blockToUpdatePositioned.yOffset, - baseBlockPosZAxis + blockToUpdatePositioned.zOffset); - blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); - }); - } - - public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { - this.blockEntities.forEach(blockEntityPositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, - baseBlockPosYAxis + blockEntityPositioned.yOffset, - baseBlockPosZAxis + blockEntityPositioned.zOffset); - blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); - }); - } - - public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { - this.lightenChunks.forEach(lightPositioned -> { - ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, - baseChunkPosZAxis + lightPositioned.zOffset); - lightenChunks.add(newPos); - }); - } - - private static class PositionedObject { - - private final int xOffset; - private final int yOffset; - private final int zOffset; - private final V object; - - PositionedObject(int xOffset, int zOffset, V object) { - this(xOffset, 0, zOffset, object); - } - - PositionedObject(int xOffset, int yOffset, int zOffset, V object) { - this.xOffset = xOffset; - this.yOffset = yOffset; - this.zOffset = zOffset; - this.object = object; - } - - } - - private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, - List> lights) { - } - -} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java deleted file mode 100644 index ba05a35f7e..0000000000 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/WorldEditSessionImpl.java +++ /dev/null @@ -1,477 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.google.common.base.Preconditions; -import com.google.gson.JsonParseException; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.SignText; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.ticks.ProtoChunkTicks; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.generator.ChunkGenerator; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionImpl implements WorldEditSession { - - private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; - - private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - - private Dimension dimension; - private LevelHeightAccessor levelHeightAccessor; - - @Nullable - private ServerLevel serverLevel; - - public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { - return POOL.obtain().initialize(serverLevel); - } - - public static WorldEditSessionImpl obtain(Dimension dimension) { - return POOL.obtain().initialize(dimension); - } - - private WorldEditSessionImpl() { - } - - private WorldEditSessionImpl initialize(ServerLevel serverLevel) { - this.serverLevel = serverLevel; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); - this.levelHeightAccessor = serverLevel; - return this; - } - - private WorldEditSessionImpl initialize(Dimension dimension) { - DimensionType dimensionType = getDimensionTypeFromDimension(dimension); - this.serverLevel = null; - this.dimension = dimension; - this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); - return this; - } - - @Override - public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, - @Nullable CompoundTag blockEntityData) { - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - if (!isValidPosition(blockPos)) - return; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - blocksToUpdate.add(new Pair<>(blockPos, blockState)); - return; - } - - ChunkPos chunkPos = new ChunkPos(blockPos); - - if (blockEntityData != null) - blockEntities.add(new Pair<>(blockPos, blockEntityData)); - - ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); - - if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) - chunkData.lights.add(blockPos); - - LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - } - - @Override - public List getAffectedChunks() { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); - - if (chunks.isEmpty()) - return Collections.emptyList(); - - List chunkPositions = new LinkedList<>(); - World bukkitWorld = serverLevel.getWorld(); - LongIterator iterator = chunks.keyIterator(); - while (iterator.hasNext()) { - long chunkKey = iterator.next(); - int chunkX = (int) chunkKey; - int chunkZ = (int) (chunkKey >> 32); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); - } - return chunkPositions; - } - - @Override - public void applyBlocks(Chunk bukkitChunk) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); - - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); - ChunkPos chunkPos = levelChunk.getPos(); - - long chunkKey = chunkPos.toLong(); - ChunkData chunkData = this.chunks.remove(chunkKey); - - if (chunkData == null) - return; - - int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); - for (int i = 0; i < chunkSectionsCount; ++i) { - levelChunk.getSections()[i] = chunkData.chunkSections[i]; - } - - chunkData.heightmaps.forEach(((type, heightmap) -> { - levelChunk.setHeightmap(type, heightmap.getRawData()); - })); - - if (plugin.getSettings().isLightsUpdate()) { - if (isStarLightInterface) { - this.lightenChunks.add(chunkPos); - } else { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); - // Queues chunk light for this chunk. - threadedLevelLightEngine.lightChunk(levelChunk, false); - } - } - - levelChunk.markUnsaved(); - } - - @Override - public void finish(Island island) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); - - // Update blocks - blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); - - // Update block entities - blockEntities.forEach(data -> { - net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); - if (blockEntityCompound != null) { - BlockPos blockPos = data.getKey(); - blockEntityCompound.putInt("x", blockPos.getX()); - blockEntityCompound.putInt("y", blockPos.getY()); - blockEntityCompound.putInt("z", blockPos.getZ()); - - applySignTextLines(blockEntityCompound, "front_text"); - applySignTextLines(blockEntityCompound, "back_text"); - convertLegacySignTextLines(blockEntityCompound); - - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) - worldBlockEntity.loadWithComponents(blockEntityCompound, MinecraftServer.getServer().registryAccess()); - } - }); - - if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - threadedLevelLightEngine.starlight$serverRelightChunks(lightenChunks, chunkCallback -> { - }, completeCallback -> { - }); - this.lightenChunks.clear(); - } - - release(); - } - - @Override - public Data readData(Location baseLocation) { - return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); - } - - @Override - public void applyData(Data data, Location baseLocation) { - WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // We need to transform all data to the new base location values - - dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, - baseBlockPosZAxis, this, this.chunks); - dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); - dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); - dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); - } - - @Override - public void release() { - this.chunks.clear(); - this.blocksToUpdate.clear(); - this.blockEntities.clear(); - this.lightenChunks.clear(); - this.serverLevel = null; - this.dimension = null; - this.levelHeightAccessor = null; - POOL.release(this); - } - - public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - return new ChunkData(chunkSections, heightmaps, lights); - } - - private boolean isValidPosition(BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - this.levelHeightAccessor.isInsideBuildHeight(blockPos.getY()); - } - - private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { - blockEntityCompound.getCompound(key).ifPresent(textCompound -> { - ListTag messages = textCompound.getListOrEmpty("messages"); - List textLines = new ArrayList<>(); - for (net.minecraft.nbt.Tag lineTag : messages) { - try { - textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); - } catch (JsonParseException error) { - textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); - } - } - - while (textLines.size() < 4) - textLines.add(Component.empty()); - - Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); - - SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); - }); - } - - private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { - Component[] signLines = new Component[4]; - Arrays.fill(signLines, Component.empty()); - boolean hasAnySignLines = false; - // We try to convert old text sign lines - for (int i = 1; i <= 4; ++i) { - if (blockEntityCompound.contains("SSB.Text" + i)) { - String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; - hasAnySignLines = true; - } - } else { - String signLine = blockEntityCompound.getString("Text" + i).orElse(null); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromJSON(signLine); - hasAnySignLines = true; - } - } - } - - if (hasAnySignLines) { - SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); - } - } - - private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { - ResourceKey resourceKey; - switch (dimension.getEnvironment()) { - case NETHER -> resourceKey = LevelStem.NETHER; - case THE_END -> resourceKey = LevelStem.END; - default -> resourceKey = LevelStem.OVERWORLD; - } - Registry registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); - return registry.getValue(resourceKey).type().value(); - } - - public class ChunkData { - - private final LevelChunkSection[] chunkSections; - private final Map heightmaps; - private final List lights; - - private ChunkData(long chunkKey) { - this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), - isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); - ChunkPos chunkPos = new ChunkPos(chunkKey); - - Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); - - createChunkSections(biomesRegistry); - - ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); - - createHeightmaps(tempChunk); - if (serverLevel != null) - runCustomWorldGenerator(tempChunk); - } - - private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - this.chunkSections = chunkSections; - this.heightmaps = heightmaps; - this.lights = lights; - } - - public LevelChunkSection[] chunkSections() { - return this.chunkSections; - } - - public Map heightmaps() { - return this.heightmaps; - } - - public List lights() { - return this.lights; - } - - private void createChunkSections(Registry biomesRegistry) { - Holder biome = CraftBiome.bukkitToMinecraftHolder( - IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); - - for (int i = 0; i < this.chunkSections.length; ++i) { - PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), - biome, PalettedContainer.Strategy.SECTION_BIOMES); - PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - - this.chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); - } - } - - private void runCustomWorldGenerator(ProtoChunk tempChunk) { - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - - if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) - return; - - NMSUtils.buildSurfaceForChunk(serverLevel, tempChunk); - - // We want to copy the level chunk sections back - LevelChunkSection[] tempChunkSections = tempChunk.getSections(); - for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { - LevelChunkSection chunkSection = tempChunkSections[i]; - if (chunkSection != null) - this.chunkSections[i] = chunkSection; - } - } - - private void createHeightmaps(ProtoChunk tempChunk) { - for (Heightmap.Types heightmapType : Heightmap.Types.values()) { - if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { - this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); - } - } - } - - } - - -} diff --git a/NMS/v1_21_7/properties b/NMS/v1_21_7/properties new file mode 100644 index 0000000000..9c939718b7 --- /dev/null +++ b/NMS/v1_21_7/properties @@ -0,0 +1,7 @@ +NMS_VERSION=v1_21_7 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java index ebdcafd0ed..50fcac1df5 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java @@ -1,127 +1,34 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_7; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; -import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; -import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.menu.MenuBrewingStandBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.menu.MenuDispenserBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.menu.MenuFurnaceBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.menu.MenuHopperBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.BlockEntityCache; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.KeyBlocksCache; -import com.google.common.collect.Multimap; -import com.google.common.collect.MultimapBuilder; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonParseException; import com.mojang.serialization.JsonOps; -import io.papermc.paper.chat.ChatRenderer; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.text.TextReplacementConfig; -import net.minecraft.SharedConstants; -import net.minecraft.core.BlockPos; import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentSerialization; import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.Container; -import net.minecraft.world.entity.item.FallingBlockEntity; -import net.minecraft.world.entity.vehicle.AbstractMinecart; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.NamespacedKey; -import org.bukkit.attribute.Attribute; -import org.bukkit.attribute.AttributeModifier; -import org.bukkit.block.Biome; -import org.bukkit.block.data.Ageable; -import org.bukkit.block.data.BlockData; -import org.bukkit.command.defaults.BukkitCommand; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftFallingBlock; -import org.bukkit.craftbukkit.entity.CraftMinecart; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.FallingBlock; -import org.bukkit.entity.Player; -import org.bukkit.event.inventory.InventoryType; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.PotionMeta; import org.bukkit.inventory.meta.trim.ArmorTrim; import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; -import org.bukkit.potion.PotionEffect; -import org.jetbrains.annotations.NotNull; -import java.util.EnumMap; import java.util.Locale; import java.util.Objects; -import java.util.Optional; -import java.util.function.BiFunction; -public class NMSAlgorithmsImpl implements NMSAlgorithms { +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms { private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create(); - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Multimap EMPTY_ATTRIBUTES_MAP = - MultimapBuilder.hashKeys().hashSetValues().build(); - - private static final EnumBridge BIOME_ENUM_BRIDGE = new EnumBridge<>() { - @Override - public Biome[] getValues() { - return Biome.values(); - } - - @Override - public String getName(Biome enumValue) { - return enumValue.name(); - } - }; - - private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); - - static { - MENUS_HOLDER_CREATORS.put(InventoryType.DISPENSER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.DROPPER, MenuDispenserBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BREWING, MenuBrewingStandBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.HOPPER, MenuHopperBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.BLAST_FURNACE, MenuFurnaceBlockEntity::new); - MENUS_HOLDER_CREATORS.put(InventoryType.SMOKER, MenuFurnaceBlockEntity::new); - } - - private final ClassProcessor CLASS_PROCESSOR = new ClassProcessor() { - @Override - public byte[] processClass(byte[] classBytes, String path) { - return Bukkit.getUnsafe().processClass(plugin.getDescription(), path, classBytes); - } - }; - - @Override - public void registerCommand(BukkitCommand command) { - ((CraftServer) plugin.getServer()).getCommandMap().register("superiorskyblock2", command); - } - @Override public String parseSignLine(String original) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE); @@ -130,103 +37,6 @@ public String parseSignLine(String original) { return COMPONENT_GSON.toJson(jsonElement); } - @Override - public int getCombinedId(Location location) { - org.bukkit.World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return 0; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - BlockState blockState; - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - wrapper.getHandle().set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - blockState = serverLevel.getBlockState(wrapper.getHandle()); - } - return Block.getId(blockState); - } - - @Override - public int getCombinedId(Material material, byte data) { - BlockState blockState; - - if (data == 0) { - Block block = CraftMagicNumbers.getBlock(material); - if (block == null) - return -1; - blockState = block.defaultBlockState(); - } else { - blockState = CraftMagicNumbers.getBlock(material, data); - } - - return blockState == null ? -1 : Block.getId(blockState); - } - - @Override - public Optional getTileEntityIdFromCombinedId(int combinedId) { - BlockState blockState = Block.stateById(combinedId); - - if (!blockState.hasBlockEntity()) - return Optional.empty(); - - String id = BlockEntityCache.getBlockEntityId(blockState); - - return Text.isBlank(id) ? Optional.empty() : Optional.of(id); - } - - @Override - public int compareMaterials(Material o1, Material o2) { - int firstMaterial = o1.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o1).defaultBlockState()) : o1.ordinal(); - int secondMaterial = o2.isBlock() ? Block.getId(CraftMagicNumbers.getBlock(o2).defaultBlockState()) : o2.ordinal(); - return Integer.compare(firstMaterial, secondMaterial); - } - - @Override - public short getBlockDataValue(org.bukkit.block.BlockState blockState) { - BlockData blockData = blockState.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getBlockDataValue(org.bukkit.block.Block block) { - BlockData blockData = block.getBlockData(); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0); - } - - @Override - public short getMaxBlockDataValue(Material material) { - if (!material.isBlock()) - return 0; - - BlockData blockData = Bukkit.createBlockData(material); - return (short) (blockData instanceof Ageable ? ((Ageable) blockData).getMaximumAge() : 0); - } - - @Override - public Key getBlockKey(int combinedId) { - Block block = Block.stateById(combinedId).getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getMinecartBlock(org.bukkit.entity.Minecart bukkitMinecart) { - AbstractMinecart minecart = ((CraftMinecart) bukkitMinecart).getHandle(); - Block block = minecart.getDisplayBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public Key getFallingBlockType(FallingBlock bukkitFallingBlock) { - FallingBlockEntity fallingBlock = ((CraftFallingBlock) bukkitFallingBlock).getHandle(); - Block block = fallingBlock.getBlockState().getBlock(); - return KeyBlocksCache.getBlockKey(block); - } - - @Override - public void setCustomModel(ItemMeta itemMeta, int customModel) { - itemMeta.setCustomModelData(customModel); - } - @Override public void setItemModel(ItemMeta itemMeta, String itemModel) { itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); @@ -255,13 +65,6 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } - @Override - public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { - if (!potionMeta.hasCustomEffects()) - potionMeta.setColor(potionEffect.getType().getColor()); - potionMeta.addCustomEffect(potionEffect, true); - } - @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); @@ -272,93 +75,4 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } - @Nullable - @Override - public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHolder defaultHolder, String title) { - MenuCreator menuCreator = MENUS_HOLDER_CREATORS.get(inventoryType); - return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); - } - - @Override - public int getMaxWorldSize() { - return Bukkit.getMaxWorldSize(); - } - - @Override - public double getCurrentTps() { - try { - return MinecraftServer.getServer().tps1.getAverage(); - } catch (Throwable error) { - //noinspection removal - return MinecraftServer.getServer().recentTps[0]; - } - } - - @Override - public int getDataVersion() { - return SharedConstants.getCurrentVersion().dataVersion().version(); - } - - @Override - public ClassProcessor getClassProcessor() { - return CLASS_PROCESSOR; - } - - @Override - public void handlePaperChatRenderer(Object event) { - if (!(event instanceof io.papermc.paper.event.player.AsyncChatEvent asyncChatEvent)) - return; - - ChatRenderer originalRenderer = asyncChatEvent.renderer(); - asyncChatEvent.renderer(new ChatRendererWrapper(originalRenderer).renderer); - } - - @Override - public void hideAttributes(ItemMeta itemMeta) { - itemMeta.setAttributeModifiers(EMPTY_ATTRIBUTES_MAP); - } - - @Override - public EnumBridge getBiomeBridge() { - return BIOME_ENUM_BRIDGE; - } - - private interface MenuCreator extends BiFunction { - } - - private static class ChatRendererWrapper { - - private static final String MESSAGE_PLACEHOLDER = "{message}"; - private static final net.kyori.adventure.text.Component MESSAGE_PLACEHOLDER_COMPONENT = - net.kyori.adventure.text.Component.text(MESSAGE_PLACEHOLDER); - - private final ChatRenderer renderer = new ChatRenderer() { - @Override - public net.kyori.adventure.text.@NotNull Component render(@NotNull Player source, - net.kyori.adventure.text.@NotNull Component sourceDisplayName, - net.kyori.adventure.text.@NotNull Component message, - @NotNull Audience viewer) { - String originalFormat = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer - .legacyAmpersand().serialize(originalRenderer.render(source, sourceDisplayName, MESSAGE_PLACEHOLDER_COMPONENT, viewer)); - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(source); - Island island = superiorPlayer.getIsland(); - - return net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().deserialize( - Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(originalFormat, superiorPlayer, island))) - .replaceText(TextReplacementConfig.builder() - .matchLiteral(MESSAGE_PLACEHOLDER) - .replacement(message) - .build()); - } - }; - - private final ChatRenderer originalRenderer; - - public ChatRendererWrapper(ChatRenderer originalRenderer) { - this.originalRenderer = originalRenderer; - } - - } - } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java index 3c1739e6c4..28d7c4debc 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java @@ -1,25 +1,17 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_7; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; -import com.bgsoftware.superiorskyblock.nms.NMSChunks; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.crops.CropsBlockEntity; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.crops.CropsTickingMethod; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; @@ -39,22 +31,16 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.util.BitStorage; import net.minecraft.util.ProblemReporter; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.Level; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -64,52 +50,35 @@ import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.ValueInput; -import net.minecraft.world.phys.AABB; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftEntityType; import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import org.slf4j.Logger; -import java.util.Arrays; import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.CompletableFuture; -public class NMSChunksImpl implements NMSChunks { +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSChunks { private static final Logger LOGGER = LogUtils.getLogger(); - private final SuperiorSkyblockPlugin plugin; - public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - KeyBlocksCache.cacheAllBlocks(); - CropsTickingMethod.register(); + super(plugin); } @Override - public void setBiome(List chunkPositions, org.bukkit.block.Biome bukkitBiome, - Collection playersToUpdate) { - if (chunkPositions.isEmpty()) - return; - - Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.SET_BIOME, false) { + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); ChunkPos chunkPos = levelChunk.getPos(); @@ -127,7 +96,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null); + levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); @@ -138,9 +107,11 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); Codec>> biomesCodec = PalettedContainer.codecRW( biomesRegistry.asHolderIdMap(), @@ -153,7 +124,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound DataResult dataResult = biomesCodec.encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); @@ -163,19 +134,12 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { // Do nothing. } - }); + }; } @Override - public void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish) { - if (chunkPositions.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> island.markChunkEmpty(chunkPosition.getWorld(), - chunkPosition.getX(), chunkPosition.getZ(), false)); - - NMSUtils.runActionOnChunks(chunkPositions, true, new NMSUtils.ChunkCallback( - ChunkLoadReason.DELETE_CHUNK, false) { + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { @Override public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); @@ -192,6 +156,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { @Override public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); Codec> blocksCodec = PalettedContainer.codecRW( @@ -202,8 +167,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - unloadedChunkCompound.setEntities(new ListTag()); - unloadedChunkCompound.setBlockEntities(tileEntities); + chunkCompound.put("entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, @@ -211,18 +176,19 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound DataResult dataResult = blocksCodec.encodeStart(NbtOps.INSTANCE, statesContainer); Tag blockStatesCompound = dataResult.getOrThrow(); - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); } else { ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); try { - NMSUtils.buildSurfaceForChunk(serverLevel, protoChunk); + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); } catch (Exception ignored) { } Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); + Codec>> biomesCodec = PalettedContainer.codecRO( biomesRegistry.asHolderIdMap(), biomesRegistry.holderByNameCodec(), @@ -268,7 +234,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound tileEntities.add(blockEntityCompound); } - unloadedChunkCompound.setSections(sectionsList); + chunkCompound.put("sections", sectionsList); } } @@ -277,34 +243,14 @@ public void onFinish() { if (onFinish != null) onFinish.run(); } - }); + }; } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); - List chunkPositionsToCalculate = new LinkedList<>(); - - Iterator chunkPositionsIterator = chunkPositions.iterator(); - while (chunkPositionsIterator.hasNext()) { - ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); - if (cachedCalculatedChunk != null) { - allCalculatedChunks.add(cachedCalculatedChunk); - chunkPositionsIterator.remove(); - } else { - chunkPositionsToCalculate.add(chunkPosition); - } - } - - if (chunkPositions.isEmpty()) - return CompletableFuture.completedFuture(allCalculatedChunks); - - CompletableFuture> completableFuture = new CompletableFuture<>(); - - NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( - ChunkLoadReason.BLOCKS_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { ChunkPos chunkPos = levelChunk.getPos(); @@ -318,6 +264,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); Registry biomesRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.BIOME); Codec> blocksCodec = PalettedContainer.codecRW( @@ -335,38 +282,38 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; - ListTag sectionsList = unloadedChunkCompound.getSections(); + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); for (int i = 0; i < sectionsList.size(); ++i) { CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { - PalettedContainer blocksDataPalette; + PalettedContainer blocksPalettedContainer; Optional blockStatesCompound = sectionCompound.getCompound("block_states"); if (blockStatesCompound.isPresent()) { DataResult> dataResult = blocksCodec.parse(NbtOps.INSTANCE, blockStatesCompound.get()).promotePartial((sx) -> { }); - blocksDataPalette = dataResult.getOrThrow(); + blocksPalettedContainer = dataResult.getOrThrow(); } else { - blocksDataPalette = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + blocksPalettedContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); } - PalettedContainer> biomesDataPalette; + PalettedContainer> biomesPalettedContainer; Optional biomesCompound = sectionCompound.getCompound("biomes"); if (biomesCompound.isPresent()) { DataResult>> dataResult = biomesCodec.parse(NbtOps.INSTANCE, biomesCompound.get()).promotePartial((sx) -> { }); - biomesDataPalette = dataResult.getOrThrow(); + biomesPalettedContainer = dataResult.getOrThrow(); } else { - biomesDataPalette = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biomesPalettedContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), biomesRegistry.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); } - chunkSections[sectionIndex] = new LevelChunkSection(blocksDataPalette, biomesDataPalette); + chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); } } @@ -382,20 +329,14 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { completableFuture.complete(allCalculatedChunks); } - }); - - return completableFuture; + }; } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); - - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - List unloadedChunkCompounds = new LinkedList<>(); - - NMSUtils.runActionOnEntityChunks(chunkPositions, new NMSUtils.ChunkCallback( - ChunkLoadReason.ENTITIES_RECALCULATE, true) { + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { @@ -418,8 +359,9 @@ public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - for (Tag entityTag : unloadedChunkCompound.getEntities()) { + for (Tag entityTag : chunkCompound.getListOrEmpty("entities")) { Entity fakeEntity; EntityType entityType; try (ProblemReporter.ScopedCollector scopedCollector = @@ -447,161 +389,17 @@ public void onFinish() { completableFuture.complete(chunkEntities); }); } - }); - - return completableFuture; - } - - @Override - public void injectChunkSections(Chunk chunk) { - // No implementation - } - - @Override - public boolean isChunkEmpty(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - return levelChunk != null && Arrays.stream(levelChunk.getSections()).allMatch(chunkSection -> - chunkSection == null || chunkSection.hasOnlyAir()); - } - - @Override - public Chunk getChunkIfLoaded(ChunkPosition chunkPosition) { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkAccess chunkAccess = serverLevel.getChunkSource().getChunk(chunkPosition.getX(), chunkPosition.getZ(), false); - return chunkAccess instanceof LevelChunk levelChunk ? new CraftChunk(levelChunk) : null; - } - - @Override - public void startTickingChunk(Island island, Chunk chunk, boolean stop) { - if (plugin.getSettings().getCropsInterval() <= 0) - return; - - if (stop) { - CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); - if (cropsBlockEntity != null) - cropsBlockEntity.remove(); - } else { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - CropsBlockEntity.create(island, levelChunk); - } - } - - @Override - public void updateCropsTicker(List chunkPositions, double newCropGrowthMultiplier) { - if (chunkPositions.isEmpty()) return; - CropsBlockEntity.forEachChunk(chunkPositions, cropsBlockEntity -> - cropsBlockEntity.setCropGrowthMultiplier(newCropGrowthMultiplier)); - } - - @Override - public void shutdown() { - List> pendingTasks = NMSUtils.getPendingChunkActions(); - - if (pendingTasks.isEmpty()) - return; - - Log.info("Waiting for chunk tasks to complete."); - - CompletableFuture.allOf(pendingTasks.toArray(new CompletableFuture[0])).join(); - } - - @Override - public List getBlockEntities(Chunk chunk) { - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) chunk)); - List blockEntities = new LinkedList<>(); - - World bukkitWorld = chunk.getWorld(); - - levelChunk.getBlockEntities().keySet().forEach(blockPos -> - blockEntities.add(new Location(bukkitWorld, blockPos.getX(), blockPos.getY(), blockPos.getZ()))); - - return blockEntities; - } - - private static final ReflectField PALETTED_CONTAINER_DATA = new ReflectField<>( - PalettedContainer.class, Object.class, "d"); - - private static final ReflectField PALETTED_CONTAINER_DATA_STORAGE = new ReflectField<>( - PalettedContainer.class, BitStorage.class, "b"); - - private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { - KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); - List spawnersLocations = new LinkedList<>(); - - for (int i = 0; i < chunkSections.length; ++i) { - LevelChunkSection levelChunkSection = chunkSections[i]; - if (levelChunkSection != null && !levelChunkSection.hasOnlyAir()) { - int sectionBottomY = level.getSectionYFromSectionIndex(i) << 4; - for (BlockPos blockPos : BlockPos.betweenClosed(0, 0, 0, 15, 15, 15)) { - BlockState blockState = levelChunkSection.getBlockState(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - calculateChunkInternal(blockState, blockPos.getX(), blockPos.getY(), blockPos.getZ(), chunkPosition, - sectionBottomY, blockCounts, spawnersLocations); - } - } - } - - return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); - } - - private static void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, - int sectionBottomY, KeyMap blockCounts, - List spawnersLocations) { - Block block = blockState.getBlock(); - - if (block == Blocks.AIR) - return; - - Location location = new Location(chunkPosition.getWorld(), - (chunkPosition.getX() << 4) + x, - sectionBottomY + y, - (chunkPosition.getZ() << 4) + z); - - int blockAmount = 1; - - if (NMSUtils.isDoubleBlock(block, blockState)) { - blockAmount = 2; - blockState = blockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM); - } - - Key blockKey = Keys.of(KeyBlocksCache.getBlockKey(blockState.getBlock()), location); - blockCounts.computeIfAbsent(blockKey, b -> new Counter(0)).inc(blockAmount); - if (block == Blocks.SPAWNER) { - spawnersLocations.add(location); - } - } - - private static void removeEntities(ChunkAccess chunk) { - ChunkPos chunkPos = chunk.getPos(); - ServerLevel serverLevel = ((LevelChunk) chunk).level; - - int chunkWorldCoordX = chunkPos.x << 4; - int chunkWorldCoordZ = chunkPos.z << 4; - - AABB chunkBounds = new AABB(chunkWorldCoordX, serverLevel.getMinY(), chunkWorldCoordZ, - chunkWorldCoordX + 15, serverLevel.getMaxY(), chunkWorldCoordZ + 15); - - List worldEntities = new LinkedList<>(); - serverLevel.getEntities().get(chunkBounds, worldEntities::add); - - worldEntities.forEach(nmsEntity -> { - if (!(nmsEntity instanceof Player)) - nmsEntity.setRemoved(Entity.RemovalReason.DISCARDED); - }); - } - - private static void removeBlockEntities(ChunkAccess chunk) { - chunk.blockEntities.values().forEach(BlockEntity::setRemoved); - chunk.blockEntities.clear(); + }; } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - if (bukkitGenerator != null && !(bukkitGenerator instanceof IslandsGenerator)) { - NMSUtils.buildSurfaceForChunk(serverLevel, chunk); - } + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; + + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSDragonFightImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSDragonFightImpl.java deleted file mode 100644 index 1a1e7c5e41..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSDragonFightImpl.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.EndWorldEndDragonFightHandler; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.IslandEndDragonFight; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.IslandEntityEnderDragon; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.SpikesCache; -import com.google.common.cache.LoadingCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.NamespacedKey; -import org.bukkit.World; -import org.bukkit.advancement.Advancement; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.entity.Player; - -import java.lang.reflect.Modifier; -import java.util.List; - -public class NMSDragonFightImpl implements NMSDragonFight { - - private static final ReflectField> ENTITY_TYPES_BUILDER = new ReflectField>( - EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - - private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField<>( - ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE, 1); - - private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( - SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static boolean firstWorldPreparation = true; - - static { - ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); - } - - @Override - public void prepareEndWorld(World bukkitWorld) { - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); - - if (firstWorldPreparation) { - firstWorldPreparation = false; - SPIKE_CACHE.set(null, SpikesCache.getInstance()); - } - } - - @Nullable - @Override - public org.bukkit.entity.EnderDragon getEnderDragon(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return null; - - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); - return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); - } - - @Override - public void startDragonBattle(Island island, Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); - } - - @Override - public void removeDragonBattle(Island island, Dimension dimension) { - World bukkitWorld = island.getCenter(dimension).getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - if (!(serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonFightHandler)) - return; - - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); - - if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { - islandEndDragonFight.removeBattlePlayers(); - islandEndDragonFight.getEnderDragon().getBukkitEntity().remove(); - } - } - - @Override - public void awardTheEndAchievement(Player player) { - Advancement advancement = Bukkit.getAdvancement(NamespacedKey.minecraft("end/root")); - if (advancement != null) - player.getAdvancementProgress(advancement).awardCriteria(""); - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java index f119931de5..bc83ad6763 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSEntitiesImpl.java @@ -1,57 +1,24 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_7; -import com.bgsoftware.superiorskyblock.nms.NMSEntities; import net.minecraft.tags.ItemTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.PortalProcessor; -import org.bukkit.Material; -import org.bukkit.craftbukkit.entity.CraftAnimals; -import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; import org.bukkit.craftbukkit.inventory.CraftItemStack; -import org.bukkit.entity.Animals; -import org.bukkit.entity.Steerable; import org.bukkit.entity.minecart.PoweredMinecart; -import org.bukkit.inventory.EntityEquipment; -import org.bukkit.inventory.ItemStack; -public class NMSEntitiesImpl implements NMSEntities { +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSEntities { @Override - public ItemStack[] getEquipment(EntityEquipment entityEquipment) { - ItemStack[] itemStacks = new ItemStack[7]; - - itemStacks[0] = new ItemStack(Material.ARMOR_STAND); - itemStacks[1] = entityEquipment.getItemInMainHand(); - itemStacks[2] = entityEquipment.getItemInOffHand(); - itemStacks[3] = entityEquipment.getHelmet(); - itemStacks[4] = entityEquipment.getChestplate(); - itemStacks[5] = entityEquipment.getLeggings(); - itemStacks[6] = entityEquipment.getBoots(); - - return itemStacks; - } - - @Override - public boolean isAnimalFood(ItemStack itemStack, Animals animals) { - return ((CraftAnimals) animals).getHandle().isFood(CraftItemStack.asNMSCopy(itemStack)); - } - - @Override - public boolean isMinecartFuel(ItemStack bukkitItem, PoweredMinecart minecart) { + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); } @Override - public int getPortalTicks(org.bukkit.entity.Entity bukkitEntity) { - Entity entity = ((CraftEntity) bukkitEntity).getHandle(); + protected int getPortalTicks(Entity entity) { PortalProcessor portalProcessor = entity.portalProcess; return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); } - @Override - public boolean canShearSaddleFromEntity(org.bukkit.entity.Entity entity) { - return entity instanceof Steerable steerable && steerable.hasSaddle(); - } } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSHologramsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSHologramsImpl.java deleted file mode 100644 index 6c7aa11144..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSHologramsImpl.java +++ /dev/null @@ -1,204 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7; - -import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; -import com.bgsoftware.superiorskyblock.nms.NMSHolograms; -import com.google.common.base.Preconditions; -import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvent; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.damagesource.DamageSource; -import net.minecraft.world.entity.EquipmentSlot; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.storage.ValueInput; -import net.minecraft.world.level.storage.ValueOutput; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftArmorStand; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.entity.Entity; - -@SuppressWarnings("unused") -public class NMSHologramsImpl implements NMSHolograms { - - @Override - public Hologram createHologram(Location location) { - Preconditions.checkNotNull(location.getWorld(), "Cannot create hologram in null worlds."); - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - EntityHologram entityHologram = new EntityHologram(serverLevel, location.getX(), location.getY(), location.getZ()); - serverLevel.addFreshEntity(entityHologram); - return entityHologram; - } - - @Override - public boolean isHologram(Entity entity) { - return ((CraftEntity) entity).getHandle() instanceof Hologram; - } - - public static class EntityHologram extends ArmorStand implements Hologram { - - private static final AABB EMPTY_BOUND = new AABB(0D, 0D, 0D, 0D, 0D, 0D); - - private CraftEntity bukkitEntity; - - EntityHologram(ServerLevel serverLevel, double x, double y, double z) { - super(serverLevel, x, y, z); - - setInvisible(true); - setSmall(true); - setShowArms(false); - setNoGravity(true); - setNoBasePlate(true); - setMarker(true); - forceSetBoundingBox(EMPTY_BOUND); - - super.collides = false; - super.setCustomNameVisible(true); - } - - @Override - public void setHologramName(String name) { - super.setCustomName(CraftChatMessage.fromStringOrNull(name)); - } - - @Override - public void removeHologram() { - super.remove(RemovalReason.DISCARDED); - } - - @Override - public org.bukkit.entity.ArmorStand getHandle() { - return this.getBukkitEntity(); - } - - @Override - public void inactiveTick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - @Override - public boolean repositionEntityAfterLoad() { - return false; - } - - @Override - public void setItemSlot(EquipmentSlot equipmentSlot, ItemStack itemStack, boolean silence) { - // Prevent stand being equipped - } - - @Override - protected void addAdditionalSaveData(ValueOutput output) { - // Do not save NBT. - } - - @Override - protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) { - // Do not save NBT. - } - - @Override - protected void readAdditionalSaveData(ValueInput input) { - // Do not load NBT. - } - - @Override - public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { - // Prevent stand being equipped - return InteractionResult.PASS; - } - - @Override - public void tick() { - // Disable normal ticking for this entity. - - // Workaround to force EntityTrackerEntry to send a teleport packet immediately after spawning this entity. - if (this.onGround) { - this.onGround = false; - } - } - - public void forceSetBoundingBox(AABB boundingBox) { - super.setBoundingBox(boundingBox); - } - - @Override - public CraftArmorStand getBukkitEntity() { - if (bukkitEntity == null) { - bukkitEntity = new CraftArmorStand((CraftServer) Bukkit.getServer(), this); - } - return (CraftArmorStand) bukkitEntity; - } - - @Override - public void remove(RemovalReason removalReason) { - // Prevent being killed. - } - - @Override - public void playSound(SoundEvent soundEvent, float volume, float pitch) { - // Remove sounds. - } - - @Override - public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { - // Do not save NBT. - return false; - } - - @Override - public boolean saveAsPassenger(ValueOutput output) { - // Do not save NBT. - return false; - } - - @Override - public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { - // Do not save NBT. - } - - @Override - public void saveWithoutId(ValueOutput output) { - // Do not save NBT. - } - - @Override - public void load(ValueInput input) { - // Do not load NBT. - } - - @Override - public boolean isInvulnerableTo(ServerLevel serverLevel, DamageSource damageSource) { - /* - * The field Entity.invulnerable is private. - * It's only used while saving NBTTags, but since the entity would be killed - * on chunk unload, we prefer to override isInvulnerable(). - */ - return true; - } - - @Override - public void setCustomName(Component component) { - // Locks the custom name. - } - - @Override - public void setCustomNameVisible(boolean isCustomNameVisible) { - // Locks the custom name. - } - - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSPlayersImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSPlayersImpl.java deleted file mode 100644 index 102bd279c5..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSPlayersImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.api.service.bossbar.BossBar; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.nms.NMSPlayers; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.player.OfflinePlayerDataImpl; -import com.bgsoftware.superiorskyblock.player.PlayerLocales; -import com.bgsoftware.superiorskyblock.service.bossbar.BossBarTask; -import com.mojang.authlib.properties.Property; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; -import net.minecraft.server.level.ServerPlayer; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Item; -import org.bukkit.entity.Player; - -import java.util.Locale; - -public class NMSPlayersImpl implements NMSPlayers { - - private static final ReflectMethod PLAYER_LOCALE = new ReflectMethod<>(ServerPlayer.class, "locale"); - - @Override - public OfflinePlayerData createOfflinePlayerData(OfflinePlayer offlinePlayer) { - return OfflinePlayerDataImpl.create(offlinePlayer); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer) { - Player player = superiorPlayer.asPlayer(); - - if (player == null) - return; - - ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() - .ifPresent(property -> setSkinTexture(superiorPlayer, property)); - } - - @Override - public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { - superiorPlayer.setTextureValue(property.value()); - } - - @SuppressWarnings("deprecation") - @Override - public void sendActionBar(Player player, String message) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); - } - - @Override - public BossBar createBossBar(Player player, String message, BossBar.Color color, double ticksToRun) { - BossBarImpl bossBar = new BossBarImpl(message, BarColor.valueOf(color.name()), ticksToRun); - bossBar.addPlayer(player); - return bossBar; - } - - @SuppressWarnings("deprecation") - @Override - public void sendTitle(Player player, String title, String subtitle, int fadeIn, int duration, int fadeOut) { - player.sendTitle(title, subtitle, fadeIn, duration, fadeOut); - } - - @Override - public boolean wasThrownByPlayer(Item item, SuperiorPlayer superiorPlayer) { - return superiorPlayer.getUniqueId().equals(item.getThrower()); - } - - @Nullable - @Override - public Locale getPlayerLocale(Player player) { - if (PLAYER_LOCALE.isValid()) { - return player.locale(); - } else try { - //noinspection deprecation - return PlayerLocales.getLocale(player.getLocale()); - } catch (IllegalArgumentException error) { - return null; - } - } - - private static class BossBarImpl implements BossBar { - - private final org.bukkit.boss.BossBar bossBar; - private final BossBarTask bossBarTask; - - public BossBarImpl(String message, BarColor color, double ticksToRun) { - bossBar = Bukkit.createBossBar(message, color, BarStyle.SOLID); - this.bossBarTask = BossBarTask.create(this, ticksToRun); - } - - @Override - public void addPlayer(Player player) { - this.bossBar.addPlayer(player); - this.bossBarTask.registerTask(player); - } - - @Override - public void removeAll() { - this.bossBar.removeAll(); - this.bossBar.getPlayers().forEach(this.bossBarTask::unregisterTask); - } - - @Override - public void setProgress(double progress) { - this.bossBar.setProgress(progress); - } - - @Override - public double getProgress() { - return this.bossBar.getProgress(); - } - - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java index 5e6de56260..5949341885 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java @@ -1,127 +1,83 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_7; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.ListTag; -import com.bgsoftware.superiorskyblock.tag.Tag; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; -import com.mojang.serialization.Dynamic; -import net.minecraft.SharedConstants; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NumericTag; import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.datafix.DataFixers; -import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.slf4j.Logger; import java.util.Optional; import java.util.Set; -@SuppressWarnings({"unused"}) -public class NMSTagsImpl implements NMSTags { +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSTags { private static final Logger LOGGER = LogUtils.getLogger(); @Override - public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { + public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - RegistryOps context = - MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); + PropertyMap propertyMap = new PropertyMap(); + propertyMap.put("textures", new Property("textures", texture)); + + ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap); + + itemStack.set(DataComponents.PROFILE, resolvableProfile); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { + RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow(); - tagCompound.putInt("DataVersion", SharedConstants.getCurrentVersion().dataVersion().version()); + tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); return CompoundTag.fromNBT(tagCompound); } @Override - public org.bukkit.inventory.ItemStack deserializeItem(CompoundTag compoundTag) { - if (compoundTag.containsKey("NBT")) { - // Old compound version, deserialize it accordingly - return deserializeItemOld(compoundTag); - } - - net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); - - int currentVersion = SharedConstants.getCurrentVersion().dataVersion().version(); - int itemVersion = tagCompound.getIntOr("DataVersion", 0); - if (itemVersion < currentVersion) { - tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, - new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); - } + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.getIntOr(key, def); + } + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); - ItemStack itemStack = ItemStack.CODEC.parse(context, tagCompound) + return ItemStack.CODEC.parse(context, compoundTag) .resultOrPartial((itemId) -> LOGGER.error("Tried to load invalid item: '{}'", itemId)) .orElseThrow(); - - return CraftItemStack.asCraftMirror(itemStack); - } - - private static org.bukkit.inventory.ItemStack deserializeItemOld(CompoundTag compoundTag) { - String typeName = Materials.patchOldMaterialName(compoundTag.getString("type").orElse(null)); - Material type = Material.valueOf(typeName); - int amount = compoundTag.getInt("amount").orElse(0); - short data = (short) compoundTag.getShort("data").orElse(0); - CompoundTag nbtData = compoundTag.getCompound("NBT").orElse(null); - - org.bukkit.inventory.ItemStack bukkitItem = new org.bukkit.inventory.ItemStack(type, amount, data); - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - if (nbtData != null) - itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of((net.minecraft.nbt.CompoundTag) nbtData.toNBT())); - - return CraftItemStack.asCraftMirror(itemStack); } @Override - public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { - ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - - PropertyMap propertyMap = new PropertyMap(); - propertyMap.put("textures", new Property("textures", texture)); - - ResolvableProfile resolvableProfile = new ResolvableProfile(Optional.empty(), Optional.empty(), propertyMap); - - itemStack.set(DataComponents.PROFILE, resolvableProfile); - - return CraftItemStack.asBukkitCopy(itemStack); + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); } @Override - @SuppressWarnings("ConstantConditions") - public void spawnEntity(org.bukkit.entity.EntityType entityType, Location location, CompoundTag entityTag) { - net.minecraft.nbt.CompoundTag compoundTag = (net.minecraft.nbt.CompoundTag) entityTag.toNBT(); - - if (compoundTag == null) - compoundTag = new net.minecraft.nbt.CompoundTag(); - - if (!compoundTag.contains("id")) - //noinspection deprecation - compoundTag.putString("id", entityType.getName()); - - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); return !serverLevel.addWithUUID(entity) ? null : entity; @@ -183,29 +139,4 @@ public String getNBTStringValue(Object object) { return ((StringTag) object).value(); } - @Override - public Object parseList(ListTag listTag) { - net.minecraft.nbt.ListTag nbtTagList = new net.minecraft.nbt.ListTag(); - - for (Tag tag : listTag) - nbtTagList.add((net.minecraft.nbt.Tag) tag.toNBT()); - - return nbtTagList; - } - - @Override - public Object getNBTCompoundTag(Object object, String key) { - return ((net.minecraft.nbt.CompoundTag) object).get(key); - } - - @Override - public void setNBTCompoundTagValue(Object object, String key, Object value) { - ((net.minecraft.nbt.CompoundTag) object).put(key, (net.minecraft.nbt.Tag) value); - } - - @Override - public int getNBTTagListSize(Object object) { - return ((net.minecraft.nbt.ListTag) object).size(); - } - } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java deleted file mode 100644 index ee2dcf8a71..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSUtils.java +++ /dev/null @@ -1,546 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7; - -import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.PropertiesMapper; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; -import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; -import com.google.common.base.Suppliers; -import com.mojang.logging.LogUtils; -import net.minecraft.core.BlockPos; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.ServerChunkCache; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.WorldGenRegion; -import net.minecraft.tags.BlockTags; -import net.minecraft.util.ProblemReporter; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SlabBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.block.state.properties.SlabType; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkPyramid; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.chunk.status.ChunkStep; -import net.minecraft.world.level.chunk.storage.EntityStorage; -import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; -import net.minecraft.world.level.entity.PersistentEntitySectionManager; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.storage.TagValueInput; -import net.minecraft.world.level.storage.ValueInput; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.generator.CustomChunkGenerator; -import org.slf4j.Logger; - -import java.io.IOException; -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; -import java.util.function.Consumer; - -public class NMSUtils { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Logger LOGGER = LogUtils.getLogger(); - - private static final ReflectMethod CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED = new ReflectMethod<>( - ServerChunkCache.class, "getChunkAtIfCachedImmediately", int.class, int.class); - private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( - ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); - private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( - EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); - - private static final List> PENDING_CHUNK_ACTIONS = new LinkedList<>(); - - public static final ObjectsPool> BLOCK_POS_POOL = - ObjectsPools.createNewPool(() -> new BlockPos.MutableBlockPos(0, 0, 0)); - - private NMSUtils() { - - } - - @Nullable - public static T getBlockEntityAt(Location location, Class type) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return null; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos); - return !type.isInstance(blockEntity) ? null : type.cast(blockEntity); - } - } - - public static void runActionOnEntityChunks(Collection chunksCoords, - ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedEntityChunks(unloadedChunks, chunkCallback)); - } - - public static void runActionOnChunks(Collection chunksCoords, - boolean saveChunks, ChunkCallback chunkCallback) { - runActionOnChunksInternal(chunksCoords, chunkCallback, unloadedChunks -> - runActionOnUnloadedChunks(unloadedChunks, saveChunks, chunkCallback)); - } - - private static void runActionOnChunksInternal(Collection chunksCoords, - ChunkCallback chunkCallback, - Consumer> onUnloadChunkAction) { - List unloadedChunks = new LinkedList<>(); - List loadedChunks = new LinkedList<>(); - - chunksCoords.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - ChunkAccess chunkAccess; - - try { - chunkAccess = serverLevel.getChunkIfLoadedImmediately(chunkPosition.getX(), chunkPosition.getZ()); - } catch (Throwable ex) { - chunkAccess = serverLevel.getChunkIfLoaded(chunkPosition.getX(), chunkPosition.getZ()); - } - - if (chunkAccess instanceof LevelChunk levelChunk) { - loadedChunks.add(levelChunk); - } else { - unloadedChunks.add(chunkPosition.copy()); - } - }); - - boolean hasUnloadedChunks = !unloadedChunks.isEmpty(); - - if (!loadedChunks.isEmpty()) - runActionOnLoadedChunks(loadedChunks, chunkCallback); - - if (hasUnloadedChunks) { - onUnloadChunkAction.accept(unloadedChunks); - } else { - chunkCallback.onFinish(); - } - } - - private static void runActionOnLoadedChunks(Collection chunks, ChunkCallback chunkCallback) { - chunks.forEach(chunkCallback::onLoadedChunk); - } - - private static void runActionOnUnloadedChunks(Collection chunks, - boolean saveChunks, ChunkCallback chunkCallback) { - if (CHUNK_CACHE_SERVER_GET_CHUNK_IF_CACHED.isValid()) { - Iterator chunksIterator = chunks.iterator(); - while (chunksIterator.hasNext()) { - ChunkPosition chunkPosition = chunksIterator.next(); - - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - LevelChunk cachedUnloadedChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately( - chunkPosition.getX(), chunkPosition.getZ()); - - if (cachedUnloadedChunk != null) { - chunkCallback.onLoadedChunk(cachedUnloadedChunk); - chunksIterator.remove(); - } - } - - if (chunks.isEmpty()) { - chunkCallback.onFinish(); - return; - } - } - - CompletableFuture pendingTask = new CompletableFuture<>(); - PENDING_CHUNK_ACTIONS.add(pendingTask); - - BukkitExecutor.createTask().runAsync(v -> { - CountDownLatch countDownLatch; - if (chunkCallback.isWaitForChunkLoad) { - countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - } else { - countDownLatch = null; - } - - List chunkCompounds = new LinkedList<>(); - - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - boolean calledCountdown = false; - try { - net.minecraft.nbt.CompoundTag chunkCompound = chunkMap.read(chunkPos).join().orElse(null); - - if (chunkCompound == null) { - chunkCallback.onChunkNotExist(chunkPosition); - return; - } - - net.minecraft.nbt.CompoundTag chunkDataCompound = chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), - Suppliers.ofInstance(serverLevel.getDataStorage()), chunkCompound, - Optional.empty(), chunkPos, serverLevel); - - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, chunkDataCompound); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - calledCountdown = true; - - if (saveChunks) - chunkCompounds.add(unloadedChunkCompound); - } catch (Exception error) { - if (!calledCountdown && countDownLatch != null) - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - if (countDownLatch != null) { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - } - - return chunkCompounds; - }).runSync(chunkCompounds -> { - chunkCompounds.forEach(unloadedChunkCompound -> { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - ChunkMap chunkMap = serverLevel.getChunkSource().chunkMap; - - ChunkPos chunkPos = unloadedChunkCompound.chunkPos(); - - try { - chunkMap.write(chunkPos, () -> unloadedChunkCompound.chunkCompound); - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while saving unloaded chunk ", unloadedChunkCompound.chunkPosition, ":"); - } - }); - - chunkCallback.onFinish(); - - pendingTask.complete(null); - PENDING_CHUNK_ACTIONS.remove(pendingTask); - }); - } - - private static void runActionOnUnloadedEntityChunks(Collection chunks, ChunkCallback chunkCallback) { - CountDownLatch countDownLatch = chunkCallback.chunkLoadLatch = new CountDownLatch(chunks.size()); - - if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); - SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); - - ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - - regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { - if (error != null) { - countDownLatch.countDown(); - throw new RuntimeException(error); - } else { - net.minecraft.nbt.CompoundTag entityData = entityDataOptional.orElse(null); - if (entityData == null) { - chunkCallback.onChunkNotExist(chunkPosition); - } else { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - } - } - }); - }); - - BukkitExecutor.createTask().runAsync(v -> { - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } else { - BukkitExecutor.createTask().runAsync(v -> { - chunks.forEach(chunkPosition -> { - ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - - try { - MoonriseRegionFileIO.RegionDataController regionDataController = - serverLevel.moonrise$getEntityChunkDataController(); - int chunkX = chunkPosition.getX(); - int chunkZ = chunkPosition.getZ(); - MoonriseRegionFileIO.RegionDataController.ReadData readData = - regionDataController.readData(chunkX, chunkZ); - if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { - net.minecraft.nbt.CompoundTag entityData = readData.syncRead(); - if (entityData != null) { - UnloadedChunkCompound unloadedChunkCompound = new UnloadedChunkCompound(chunkPosition, entityData); - chunkCallback.onUnloadedChunk(unloadedChunkCompound); - return; - } - } - - chunkCallback.onChunkNotExist(chunkPosition); - } catch (IOException error) { - countDownLatch.countDown(); - Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); - } - }); - - try { - countDownLatch.await(); - } catch (InterruptedException error) { - throw new RuntimeException(error); - } - }).runSync(v -> { - chunkCallback.onFinish(); - }); - } - } - - public static List> getPendingChunkActions() { - return Collections.unmodifiableList(PENDING_CHUNK_ACTIONS); - } - - public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { - return new ProtoChunk(chunkPos, - UpgradeData.EMPTY, - serverLevel, - serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), - null); - } - - public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, - CompoundTag statesTag, CompoundTag tileEntity) { - ServerLevel serverLevel = levelChunk.level; - - if (!isValidPosition(serverLevel, blockPos)) - return null; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - serverLevel.setBlock(blockPos, blockState, 3); - return blockState; - } - - int indexY = serverLevel.getSectionIndex(blockPos.getY()); - - LevelChunkSection levelChunkSection = levelChunk.getSections()[indexY]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - boolean isOriginallyChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - levelChunk.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - - levelChunk.markUnsaved(); - - boolean isChunkSectionEmpty = levelChunkSection.hasOnlyAir(); - - if (isOriginallyChunkSectionEmpty != isChunkSectionEmpty) - serverLevel.getLightEngine().updateSectionStatus(blockPos, isChunkSectionEmpty); - - serverLevel.getLightEngine().checkBlock(blockPos); - - if (tileEntity != null) { - net.minecraft.nbt.CompoundTag tileEntityCompound = (net.minecraft.nbt.CompoundTag) tileEntity.toNBT(); - if (tileEntityCompound != null) { - tileEntityCompound.putInt("x", blockPos.getX()); - tileEntityCompound.putInt("y", blockPos.getY()); - tileEntityCompound.putInt("z", blockPos.getZ()); - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) { - try (ProblemReporter.ScopedCollector scopedCollector = - new ProblemReporter.ScopedCollector(() -> "setblock@" + blockPos, LOGGER)) { - ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), tileEntityCompound); - worldBlockEntity.loadWithComponents(valueInput); - } - } - } - } - - return blockState; - } - - public static boolean isDoubleBlock(Block block, BlockState blockState) { - return (block.defaultBlockState().is(BlockTags.SLABS) || block.defaultBlockState().is(BlockTags.WOODEN_SLABS)) && - blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; - } - - @Nullable - public static LevelChunk getCraftChunkHandle(CraftChunk craftChunk) { - ServerLevel serverLevel = craftChunk.getCraftWorld().getHandle(); - LevelChunk loadedChunk = serverLevel.getChunkIfLoaded(craftChunk.getX(), craftChunk.getZ()); - if (loadedChunk != null) - return loadedChunk; - - return (LevelChunk) serverLevel.getChunk(craftChunk.getX(), craftChunk.getZ(), ChunkStatus.FULL, true); - } - - public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkAccess chunkAccess) { - CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, - serverLevel.getChunkSource().getGenerator(), serverLevel.generator); - - ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); - - // Unsafe: we do not provide chunks cache, even tho it is required. - // Should be fine in normal flow, as the only method that access the chunsk cache - // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: - // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 - WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); - - customChunkGenerator.buildSurface(region, - serverLevel.structureManager().forWorldGenRegion(region), - serverLevel.getChunkSource().randomState(), - chunkAccess); - } - - public record UnloadedChunkCompound(ChunkPosition chunkPosition, - net.minecraft.nbt.CompoundTag chunkCompound) { - - public ListTag getSections() { - return chunkCompound.getListOrEmpty("sections"); - } - - public ListTag getEntities() { - return chunkCompound.getListOrEmpty("Entities"); - } - - public void setSections(ListTag sectionsList) { - chunkCompound.put("sections", sectionsList); - } - - public void setEntities(ListTag entitiesList) { - chunkCompound.put("entities", entitiesList); - } - - public void setBlockEntities(ListTag blockEntitiesList) { - chunkCompound.put("block_entities", blockEntitiesList); - } - - public ServerLevel serverLevel() { - return ((CraftWorld) chunkPosition.getWorld()).getHandle(); - } - - public ChunkPos chunkPos() { - return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); - } - - } - - private static boolean isValidPosition(ServerLevel serverLevel, BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - blockPos.getY() >= serverLevel.getMinY() && blockPos.getY() < serverLevel.getMaxY(); - } - - public static abstract class ChunkCallback { - - private final ChunkLoadReason chunkLoadReason; - private final boolean isWaitForChunkLoad; - - @Nullable - protected CountDownLatch chunkLoadLatch; - - public ChunkCallback(ChunkLoadReason chunkLoadReason, boolean isWaitForChunkLoad) { - this.chunkLoadReason = chunkLoadReason; - this.isWaitForChunkLoad = isWaitForChunkLoad; - } - - public abstract void onLoadedChunk(LevelChunk levelChunk); - - public abstract void onUnloadedChunk(UnloadedChunkCompound unloadedChunkCompound); - - public abstract void onFinish(); - - protected final void latchCountDown() { - if (this.chunkLoadLatch != null) - this.chunkLoadLatch.countDown(); - } - - public final void onChunkNotExist(ChunkPosition chunkPosition) { - if (!plugin.getProviders().hasCustomWorldsSupport()) - return; - - ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { - LevelChunk levelChunk = getCraftChunkHandle((CraftChunk) bukkitChunk); - BukkitExecutor.ensureMain(() -> onLoadedChunk(levelChunk)); - }); - } - - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java index 23b74156e0..c494b6d483 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java @@ -2,133 +2,34 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.enums.BorderColor; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.Materials; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; -import com.bgsoftware.superiorskyblock.nms.ICachedBlock; -import com.bgsoftware.superiorskyblock.nms.NMSWorld; -import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; -import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.NMSCachedBlock; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.generator.IslandsGeneratorImpl; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.spawners.TickingSpawnerBlockEntityNotifier; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.trial.IslandPlayerDetector; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_7.vibration.IslandVibrationUser; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.ChunkReaderImpl; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.WorldEditSessionImpl; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.world.SignType; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import io.papermc.paper.antixray.ChunkPacketBlockController; -import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; -import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.ChunkSnapshot; import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.BubbleColumn; import org.bukkit.block.data.type.HangingSign; -import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.WallHangingSign; -import org.bukkit.block.data.type.WallSign; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.block.CraftBlock; -import org.bukkit.craftbukkit.block.CraftBlockState; -import org.bukkit.craftbukkit.block.CraftSign; -import org.bukkit.craftbukkit.block.data.CraftBlockData; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; import java.lang.reflect.Modifier; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.function.IntFunction; -public class NMSWorldImpl implements NMSWorld { +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSWorld { - private static final ReflectField> LEVEL_BLOCK_ENTITY_TICKERS = initializeLevelBlockEntityTickersField(); private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); - private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, - Object.class, "chunkPacketBlockController") - .removeFinal(); - - private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { - this.plugin = plugin; - } - - @Override - public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { - Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); - Location location = new Location( - Bukkit.getWorld(chunkSnapshot.getWorldName()), - (chunkSnapshot.getX() << 4) + x, - y, - (chunkSnapshot.getZ() << 4) + z - ); - - return Keys.of(KeyBlocksCache.getBlockKey(block), location); - } - - @Override - public void listenSpawner(Location location, IntFunction delayChangeCallback) { - SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); - if (spawnerBlockEntity == null) - return; - - ServerLevel serverLevel = (ServerLevel) spawnerBlockEntity.getLevel(); - - List blockEntityTickers = LEVEL_BLOCK_ENTITY_TICKERS.isValid() ? - LEVEL_BLOCK_ENTITY_TICKERS.get(serverLevel) : serverLevel.blockEntityTickers; - - Iterator blockEntityTickersIterator = blockEntityTickers.iterator(); - List tickersToAdd = new LinkedList<>(); - - while (blockEntityTickersIterator.hasNext()) { - TickingBlockEntity tickingBlockEntity = blockEntityTickersIterator.next(); - if (tickingBlockEntity.getPos().equals(spawnerBlockEntity.getBlockPos()) && - !(tickingBlockEntity instanceof TickingSpawnerBlockEntityNotifier)) { - blockEntityTickersIterator.remove(); - tickersToAdd.add(new TickingSpawnerBlockEntityNotifier(spawnerBlockEntity, tickingBlockEntity, delayChangeCallback)); - } - } - - if (!tickersToAdd.isEmpty()) - blockEntityTickers.addAll(tickersToAdd); + super(plugin); } @Override @@ -175,254 +76,19 @@ public void replaceSculkSensorListener(Island island, Location location) { SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); } - @Override - public void setWorldBorder(SuperiorPlayer superiorPlayer, Island island) { - if (!plugin.getSettings().isWorldBorders()) - return; - - Player player = superiorPlayer.asPlayer(); - World world = superiorPlayer.getWorld(); - - if (world == null || player == null) - return; - - int islandSize = island == null ? 0 : island.getIslandSize(); - - boolean disabled = !superiorPlayer.hasWorldBorderEnabled() || islandSize < 0; - - ServerLevel serverLevel = ((CraftWorld) world).getHandle(); - - WorldBorder worldBorder; - - if (disabled || island == null || (!plugin.getSettings().getSpawn().isWorldBorder() && island.isSpawn())) { - worldBorder = serverLevel.getWorldBorder(); - } else { - Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); - if (dimension == null) - return; - - Location center = island.getCenter(dimension); - - worldBorder = new WorldBorder(); - worldBorder.world = serverLevel; - worldBorder.setWarningBlocks(0); - worldBorder.setCenter(center.getX(), center.getZ()); - - switch (superiorPlayer.getBorderColor()) { - case BorderColor.BLUE -> { - worldBorder.setSize((islandSize * 2) + 1D); - } - case BorderColor.GREEN -> { - worldBorder.setSize((islandSize * 2) + 1.001D); - worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); - } - case BorderColor.RED -> { - worldBorder.setSize((islandSize * 2) + 1D); - worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); - } - } - } - - ClientboundInitializeBorderPacket initializeBorderPacket = new ClientboundInitializeBorderPacket(worldBorder); - ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); - } - - @Override - public Object getBlockData(org.bukkit.block.Block block) { - return block.getBlockData(); - } - - @Override - public void setBlock(Location location, int combinedId) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - BlockState blockState = - NMSUtils.setBlock(serverLevel.getChunkAt(blockPos), blockPos, combinedId, null, null); - - if (blockState != null) { - serverLevel.getChunkSource().blockChanged(blockPos); - if (CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) { - serverLevel.chunkPacketBlockController.onBlockChange(serverLevel, blockPos, blockState, Blocks.AIR.defaultBlockState(), 530, 512); - } - } - } - } - - @Override - public ICachedBlock cacheBlock(org.bukkit.block.Block block) { - return NMSCachedBlock.obtain(block); - } - - @Override - public boolean isWaterLogged(org.bukkit.block.Block block) { - if (Materials.isWater(block.getType())) - return true; - - BlockData blockData = block.getBlockData(); - - return blockData instanceof BubbleColumn || - (blockData instanceof Waterlogged && ((Waterlogged) blockData).isWaterlogged()); - } - @Override public SignType getSignType(Object sign) { - if (sign instanceof WallSign) - return SignType.WALL_SIGN; - else if (sign instanceof Sign) - return SignType.STANDING_SIGN; - else if (sign instanceof HangingSign) + if (sign instanceof HangingSign) return SignType.HANGING_SIGN; else if (sign instanceof WallHangingSign) return SignType.HANGING_WALL_SIGN; else - return SignType.UNKNOWN; + return super.getSignType(sign); } @Override - public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { - BlockState blockState = ((CraftBlock) block).getNMS(); - return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; - } - - @Override - public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { - return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); - } - - @Override - public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { - return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); - } - - private int getDefaultAmount(BlockState blockState) { - Block block = blockState.getBlock(); - return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; - } - - @Override - public boolean canPlayerSuffocate(org.bukkit.block.Block bukkitBlock) { - return !bukkitBlock.isPassable(); - } - - @Override - public void placeSign(Island island, Location location) { - SignBlockEntity signBlockEntity = NMSUtils.getBlockEntityAt(location, SignBlockEntity.class); - if (signBlockEntity == null) - return; - - String[] lines = new String[4]; - Component[] messages = signBlockEntity.getFrontText().getMessages(false); - System.arraycopy(CraftSign.revertComponents(messages), 0, lines, 0, lines.length); - String[] strippedLines = new String[4]; - for (int i = 0; i < 4; i++) - strippedLines[i] = Formatters.STRIP_COLOR_FORMATTER.format(lines[i]); - - Component[] newLines; - - IslandSigns.Result result = IslandSigns.handleSignPlace(island.getOwner(), location, strippedLines, false); - if (result.isCancelEvent()) { - newLines = CraftSign.sanitizeLines(strippedLines); - } else { - newLines = CraftSign.sanitizeLines(lines); - } - - System.arraycopy(newLines, 0, messages, 0, 4); - } - - @Override - public void playGeneratorSound(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - serverLevel.levelEvent(1501, blockPos, 0); - } - } - - @Override - public void playBreakAnimation(org.bukkit.block.Block block) { - ServerLevel serverLevel = ((CraftWorld) block.getWorld()).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(block.getX(), block.getY(), block.getZ()); - serverLevel.levelEvent(null, 2001, blockPos, Block.getId(serverLevel.getBlockState(blockPos))); - } - } - - @Override - public void playPlaceSound(Location location) { - World bukkitWorld = location.getWorld(); - - if (bukkitWorld == null) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - SoundType soundType = serverLevel.getBlockState(blockPos).getSoundType(); - - serverLevel.playSound(null, blockPos, soundType.getPlaceSound(), SoundSource.BLOCKS, - (soundType.getVolume() + 1.0F) / 2.0F, soundType.getPitch() * 0.8F); - } - } - - @Override - public int getMinHeight(World world) { - return world.getMinHeight(); - } - - @Override - public void removeAntiXray(org.bukkit.World bukkitWorld) { - if (!CHUNK_PACKET_BLOCK_CONTROLLER.isValid()) - return; - - ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ChunkPacketBlockController.NO_OPERATION_INSTANCE); - } - - @Override - public IslandsGenerator createGenerator(Dimension dimension) { - return new IslandsGeneratorImpl(dimension); - } - - @Override - public WorldEditSession createEditSession(World world) { - return WorldEditSessionImpl.obtain(((CraftWorld) world).getHandle()); - } - - @Override - public WorldEditSession createPartialEditSession(Dimension dimension) { - return WorldEditSessionImpl.obtain(dimension); - } - - @Override - public ChunkReader createChunkReader(Chunk chunk) { - return new ChunkReaderImpl(chunk); - } - - private static ReflectField> initializeLevelBlockEntityTickersField() { - ReflectField> field = new ReflectField<>( - Level.class, List.class, Modifier.PROTECTED | Modifier.FINAL, 1); - - if (!field.isValid()) - field = new ReflectField<>(Level.class, List.class, Modifier.PUBLIC | Modifier.FINAL, 1); - - return field; + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); } } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsBlockEntity.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsBlockEntity.java deleted file mode 100644 index cf5f97410f..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsBlockEntity.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.crops; - -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; - -import java.lang.ref.WeakReference; -import java.util.List; -import java.util.function.Consumer; - -public class CropsBlockEntity extends BlockEntity { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); - - private final WeakReference island; - private final WeakReference chunk; - - private int currentTick = 0; - - private double cachedCropGrowthMultiplier; - - private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); - this.island = new WeakReference<>(island); - this.chunk = new WeakReference<>(levelChunk); - setLevel(levelChunk.level); - levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); - this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; - } - - public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); - return new CropsBlockEntity(island, levelChunk, blockPos); - }); - } - - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); - } - - public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { - if (tickingChunks.isEmpty()) - return; - - chunkPositions.forEach(chunkPosition -> { - long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); - if (cropsBlockEntity != null) - cropsBlockEntityConsumer.accept(cropsBlockEntity); - }); - } - - @Override - public boolean isValidBlockState(BlockState state) { - return true; - } - - public void remove() { - this.remove = true; - } - - public void tick() { - if (++currentTick <= plugin.getSettings().getCropsInterval()) - return; - - LevelChunk levelChunk = this.chunk.get(); - Island island = this.island.get(); - ServerLevel serverLevel = (ServerLevel) getLevel(); - - if (levelChunk == null || island == null || serverLevel == null) { - remove(); - return; - } - - currentTick = 0; - - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); - if (chunkRandomTickSpeed > 0) - CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); - } - - public void setCropGrowthMultiplier(double cropGrowthMultiplier) { - this.cachedCropGrowthMultiplier = cropGrowthMultiplier; - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingBlockEntity.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingBlockEntity.java deleted file mode 100644 index bc3066a417..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingBlockEntity.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.crops; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { - - - @Override - public void tick() { - cropsBlockEntity.tick(); - } - - @Override - public boolean isRemoved() { - return cropsBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return cropsBlockEntity.getBlockPos(); - } - - @Override - public String getType() { - return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingMethod.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingMethod.java deleted file mode 100644 index fc978c0761..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/crops/CropsTickingMethod.java +++ /dev/null @@ -1,159 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.crops; - -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; - -public abstract class CropsTickingMethod { - - private static final ReflectField SERVER_LEVEL_SIMPLE_RANDOM = new ReflectField<>( - ServerLevel.class, RandomSource.class, "simpleRandom"); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final CropsTickingMethod INSTANCE = SERVER_LEVEL_SIMPLE_RANDOM.isValid() ? - new PaperCropsTickingMethod() : new SpigotCropsTickingMethod(); - - private static Set CROPS_TO_GROW_CACHE; - - static { - plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingMethod::onSettingsUpdate); - } - - protected CropsTickingMethod() { - - } - - public static void register() { - // Calls the static initializer which registers the callback. - } - - public static void tick(LevelChunk levelChunk, int tickSpeed) { - INSTANCE.doTick(levelChunk, tickSpeed); - } - - protected abstract void doTick(LevelChunk levelChunk, int tickSpeed); - - private static void onSettingsUpdate() { - CROPS_TO_GROW_CACHE = new HashSet<>(); - plugin.getSettings().getCropsToGrow().forEach(cropName -> { - Key key = Keys.ofMaterialAndData(cropName); - if (key instanceof MaterialKey materialKey) { - Block block = CraftMagicNumbers.getBlock(materialKey.getMaterial()); - if (block != null && block.defaultBlockState().isRandomlyTicking()) - CROPS_TO_GROW_CACHE.add(block); - } - }); - } - - private static class PaperCropsTickingMethod extends CropsTickingMethod { - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - ServerLevel serverLevel = levelChunk.level; - LevelChunkSection[] sections = levelChunk.getSections(); - - int minSection = serverLevel.getMinSectionY(); - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - RandomSource simpleRandom = SERVER_LEVEL_SIMPLE_RANDOM.get(serverLevel); - - for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - ca.spottedleaf.moonrise.common.list.ShortList tickList = - levelChunkSection.moonrise$getTickingBlockList(); - int tickingBlocks = tickList.size(); - if (tickingBlocks <= 0) { - continue; - } - - PalettedContainer states = levelChunkSection.states; - - int offsetY = (sectionIndex + minSection) << 4; - - for (int i = 0; i < tickSpeed; ++i) { - int index = simpleRandom.nextInt() & 0xFFF; - - if (index >= tickingBlocks) { - continue; - } - - int location = (int) tickList.getRaw(index) & 0xFFFF; - BlockState blockState = states.get(location); - if (!CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) - continue; - - // do not use a mutable pos, as some random tick implementations store the input without calling immutable()! - BlockPos blockPos = new BlockPos((location & 15) | chunkOffsetX, - ((location >>> 8) & 15) | offsetY, - ((location >>> 4) & 15) | chunkOffsetZ); - - blockState.randomTick(serverLevel, blockPos, simpleRandom); - } - } - - } - - } - - private static class SpigotCropsTickingMethod extends CropsTickingMethod { - - private static int random = ThreadLocalRandom.current().nextInt(); - - @Override - protected void doTick(LevelChunk levelChunk, int tickSpeed) { - LevelChunkSection[] sections = levelChunk.getSections(); - ServerLevel serverLevel = levelChunk.level; - - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; - - for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { - LevelChunkSection levelChunkSection = sections[sectionIndex]; - if (levelChunkSection == null || !levelChunkSection.isRandomlyTickingBlocks()) { - continue; - } - - int sectionBottomY = serverLevel.getSectionYFromSectionIndex(sectionIndex) << 4; - - for (int i = 0; i < tickSpeed; i++) { - random = random * 3 + 1013904223; - int factor = random >> 2; - int x = factor & 15; - int z = factor >> 8 & 15; - int y = factor >> 16 & 15; - BlockState blockState = levelChunkSection.getBlockState(x, y, z); - if (blockState.isRandomlyTicking() && CROPS_TO_GROW_CACHE.contains(blockState.getBlock())) { - BlockPos blockPos = new BlockPos(x + chunkOffsetX, y + sectionBottomY, z + chunkOffsetZ); - blockState.randomTick(serverLevel, blockPos, serverLevel.getRandom()); - } - } - } - } - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/DragonUtils.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/DragonUtils.java deleted file mode 100644 index 3dc973554b..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/DragonUtils.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; - -import com.bgsoftware.common.reflection.ReflectField; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.levelgen.feature.EndPodiumFeature; - -import java.lang.reflect.Modifier; - -public class DragonUtils { - - private static final ReflectField END_PODIUM_LOCATION = new ReflectField( - EndPodiumFeature.class, BlockPos.class, - Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, 1) - .removeFinal(); - - private static BlockPos currentPodiumPosition = BlockPos.ZERO; - - private DragonUtils() { - - } - - public static void runWithPodiumPosition(BlockPos podiumPosition, Runnable runnable) { - try { - END_PODIUM_LOCATION.set(null, podiumPosition); - currentPodiumPosition = podiumPosition; - runnable.run(); - } finally { - END_PODIUM_LOCATION.set(null, BlockPos.ZERO); - currentPodiumPosition = BlockPos.ZERO; - } - } - - public static BlockPos getCurrentPodiumPosition() { - return currentPodiumPosition; - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndWorldEndDragonFightHandler.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndWorldEndDragonFightHandler.java deleted file mode 100644 index 342e6edd6c..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndWorldEndDragonFightHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; -import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; -import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.dimension.end.EndDragonFight; - -import java.util.LinkedList; -import java.util.List; - -public class EndWorldEndDragonFightHandler extends EndDragonFight { - - private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); - - private final List worldDragonFightsList = new LinkedList<>(); - - public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); - } - - @Override - public void tick() { - this.worldDragonFightsList.forEach(EndDragonFight::tick); - } - - public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { - IslandEndDragonFight oldDragonFight = islandCache.store(CACHE_KEY, endDragonFight); - if (oldDragonFight != null) - this.worldDragonFightsList.remove(oldDragonFight); - this.worldDragonFightsList.add(endDragonFight); - } - - @Nullable - public IslandEndDragonFight getDragonFight(IslandCache islandCache) { - return islandCache.get(CACHE_KEY); - } - - @Nullable - public IslandEndDragonFight removeDragonFight(IslandCache islandCache) { - IslandEndDragonFight endDragonFight = islandCache.remove(CACHE_KEY); - if (endDragonFight != null) - this.worldDragonFightsList.remove(endDragonFight); - return endDragonFight; - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEndDragonFight.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEndDragonFight.java deleted file mode 100644 index f6806ce8ae..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEndDragonFight.java +++ /dev/null @@ -1,211 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonLandingPhase; -import net.minecraft.world.entity.boss.enderdragon.phases.DragonPhaseInstance; -import net.minecraft.world.entity.boss.enderdragon.phases.EnderDragonPhase; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.TheEndPortalBlockEntity; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import net.minecraft.world.level.block.state.pattern.BlockPattern; -import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; -import net.minecraft.world.level.block.state.predicate.BlockPredicate; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.phys.Vec3; -import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; -import org.bukkit.event.entity.CreatureSpawnEvent; - -import java.lang.reflect.Modifier; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; - -public class IslandEndDragonFight extends EndDragonFight { - - private static final ReflectField DRAGON_BATTLE = new ReflectField( - EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); - private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 4); - private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); - - private static final ReflectField TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>( - EndDragonFight.class, int.class, Modifier.PRIVATE, 4); - private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( - DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); - - private static final BlockPattern EXIT_PORTAL_PATTERN = BlockPatternBuilder.start() - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ", " ", " ", " # ", " ", " ", " ") - .aisle(" ### ", " # # ", "# #", "# # #", "# #", " # # ", " ### ") - .aisle(" ", " ### ", " ##### ", " ##### ", " ##### ", " ### ", " ") - .where('#', BlockInWorld.hasState(BlockPredicate.forBlock(Blocks.BEDROCK))) - .build(); - - private final Island island; - private final BlockPos islandBlockPos; - private final Vec3 islandBlockVectored; - private final ServerLevel serverLevel; - private final IslandEntityEnderDragon entityEnderDragon; - - private byte currentTick = 0; - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, Location location) { - this(island, serverLevel, new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()), null); - } - - public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, - @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); - - this.island = island; - this.islandBlockPos = islandBlockPos; - this.islandBlockVectored = Vec3.atBottomCenterOf(islandBlockPos); - this.serverLevel = serverLevel; - this.entityEnderDragon = islandEntityEnderDragon == null ? spawnEnderDragon() : islandEntityEnderDragon; - - SCAN_FOR_LEGACY_PORTALS.set(this, false); - WAS_DRAGON_KILLED.set(this, false); - DRAGON_BATTLE.set(this.entityEnderDragon, this); - - TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); - } - - @Override - public void tick() { - // doServerTick - - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::tick); - - DragonPhaseInstance currentPhase = this.entityEnderDragon.getPhaseManager().getCurrentPhase(); - if (currentPhase instanceof DragonLandingPhase && !this.islandBlockVectored.equals(currentPhase.getFlyTargetLocation())) { - LANDING_TARGET_POSITION.set(currentPhase, this.islandBlockVectored); - } - - if (++currentTick >= 20) { - updateBattlePlayers(); - currentTick = 0; - TICKS_SINCE_LAST_PLAYER_SCAN.set(this, Integer.MIN_VALUE); - } - } - - @Nullable - @Override - public BlockPattern.BlockPatternMatch findExitPortal() { - int chunkX = this.islandBlockPos.getX() >> 4; - int chunkZ = this.islandBlockPos.getZ() >> 4; - - for (int x = -8; x <= 8; ++x) { - for (int z = -8; z <= 8; ++z) { - LevelChunk levelChunk = this.serverLevel.getChunk(chunkX + x, chunkZ + z); - - for (BlockEntity blockEntity : levelChunk.getBlockEntities().values()) { - if (blockEntity instanceof TheEndPortalBlockEntity) { - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find( - this.serverLevel, blockEntity.getBlockPos()); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - } - } - - int highestBlock = this.serverLevel.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, this.islandBlockPos).getY(); - - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos currentPosition = wrapper.getHandle(); - currentPosition.set(this.islandBlockPos.getX(), 0, this.islandBlockPos.getZ()); - for (int y = highestBlock; y >= this.serverLevel.getMinY(); --y) { - currentPosition.setY(y); - - BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); - - if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); - - return blockPatternMatch; - } - } - } - - return null; - } - - @Override - public void resetSpikeCrystals() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::resetSpikeCrystals); - } - - public void removeBattlePlayers() { - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - for (ServerPlayer serverPlayer : dragonEventPlayers) - this.dragonEvent.removePlayer(serverPlayer); - } - - public IslandEntityEnderDragon getEnderDragon() { - return this.entityEnderDragon; - } - - private void updateBattlePlayers() { - Set nearbyPlayers = new HashSet<>(); - - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - Player bukkitPlayer = superiorPlayer.asPlayer(); - if (bukkitPlayer != null) { - ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); - if (serverPlayer.level().equals(this.serverLevel)) { - this.dragonEvent.addPlayer(serverPlayer); - nearbyPlayers.add(serverPlayer.getUUID()); - } - } - } - - List dragonEventPlayers = new SequentialListBuilder() - .build(this.dragonEvent.getPlayers()); - - dragonEventPlayers.stream() - .filter(entityPlayer -> !nearbyPlayers.contains(entityPlayer.getUUID())) - .forEach(this.dragonEvent::removePlayer); - } - - private IslandEntityEnderDragon spawnEnderDragon() { - IslandEntityEnderDragon entityEnderDragon = new IslandEntityEnderDragon(this.serverLevel, this.islandBlockPos); - - entityEnderDragon.getPhaseManager().setPhase(EnderDragonPhase.HOLDING_PATTERN); - entityEnderDragon.absSnapTo(this.islandBlockPos.getX(), 128, this.islandBlockPos.getZ(), - this.serverLevel.getRandom().nextFloat() * 360.0F, 0.0F); - - this.serverLevel.addFreshEntity(entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); - - this.dragonUUID = entityEnderDragon.getUUID(); - this.resetSpikeCrystals(); - - return entityEnderDragon; - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java index c96a14d756..007a7f7015 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/IslandEntityEnderDragon.java @@ -2,102 +2,41 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.config.SettingsManager; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; +import net.minecraft.nbt.CompoundTag; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.EntitySpawnReason; -import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.SpawnGroupData; -import net.minecraft.world.entity.boss.enderdragon.EnderDragon; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.storage.ValueInput; -import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftEnderDragon; -public class IslandEntityEnderDragon extends EnderDragon { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - @NotNull - public static EnderDragon fromEntityTypes(EntityType entityTypes, Level level) { - return plugin.getGrid().isIslandsWorld(level.getWorld()) ? new IslandEntityEnderDragon(level) : - new EnderDragon(entityTypes, level); - } - - private final ServerLevel serverLevel; - private final Dimension dimension; - private BlockPos islandBlockPos; +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.AbstractIslandEntityEnderDragon { public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { - this(level); - this.islandBlockPos = islandBlockPos; + super(level, islandBlockPos); } - private IslandEntityEnderDragon(Level level) { - super(EntityType.ENDER_DRAGON, level); - this.serverLevel = (ServerLevel) level; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); + public IslandEntityEnderDragon(Level level) { + super(level); } @Nullable @Override - public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, EntitySpawnReason spawnReason, - @Nullable SpawnGroupData spawnGroupData) { + @Nullable SpawnGroupData entityData) { if (this.islandBlockPos == null) finalizeIslandEnderDragon(); - return super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + return super.finalizeSpawn(world, difficulty, spawnReason, entityData); } @Override protected void readAdditionalSaveData(ValueInput input) { - // loadData super.readAdditionalSaveData(input); finalizeIslandEnderDragon(); } - @Override - public void aiStep() { - DragonUtils.runWithPodiumPosition(this.islandBlockPos, super::aiStep); - } - - @Override - @NotNull - public CraftEnderDragon getBukkitEntity() { - return (CraftEnderDragon) super.getBukkitEntity(); - } - - private void finalizeIslandEnderDragon() { - if (!(this.serverLevel.getDragonFight() instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) - return; - - Island island; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - island = plugin.getGrid().getIslandAt(getBukkitEntity().getLocation(wrapper.getHandle())); - } - - if (island == null) - return; - - Location middleBlock = island.getCenter(dimension); - - SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); - if (dimensionConfig instanceof SettingsManager.Worlds.End) { - middleBlock = ((SettingsManager.Worlds.End) dimensionConfig).getPortalOffset().applyToLocation(middleBlock); - } - - this.islandBlockPos = new BlockPos(middleBlock.getBlockX(), middleBlock.getBlockY(), middleBlock.getBlockZ()); - - IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, this); - dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); - } - } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/SpikesCache.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/SpikesCache.java deleted file mode 100644 index e3226b1a0e..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/SpikesCache.java +++ /dev/null @@ -1,190 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; - - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.DragonUtils; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.CacheStats; -import com.google.common.cache.LoadingCache; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import net.minecraft.core.BlockPos; -import net.minecraft.util.Mth; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -public class SpikesCache implements LoadingCache> { - - private static final SpikesCache INSTANCE = new SpikesCache(); - - private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() - .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); - - private long worldSeed; - - public static SpikesCache getInstance() { - return INSTANCE; - } - - private SpikesCache() { - - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - List getUnchecked(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public List apply(@NotNull Long worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void refresh(@NotNull Long worldSeed) { - try { - this.worldSeed = worldSeed; - cachedSpikes.refresh(DragonUtils.getCurrentPodiumPosition()); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ConcurrentMap> asMap() { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Nullable - @Override - public List getIfPresent(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public @NotNull - List get(@NotNull Long worldSeed, - @NotNull Callable> loader) throws ExecutionException { - try { - this.worldSeed = worldSeed; - return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); - } finally { - this.worldSeed = 0; - } - } - - @Override - public @NotNull - ImmutableMap> getAllPresent(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void put(@NotNull Long worldSeed, @NotNull List spikes) { - try { - this.worldSeed = worldSeed; - cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); - } finally { - this.worldSeed = 0; - } - } - - @Override - public void putAll(Map> spikesMap) { - spikesMap.forEach(this::put); - } - - @Override - public void invalidate(@NotNull Object worldSeed) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll(@NotNull Iterable keys) { - throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); - } - - @Override - public void invalidateAll() { - this.cachedSpikes.invalidateAll(); - } - - @Override - public long size() { - return this.cachedSpikes.size(); - } - - @Override - public @NotNull - CacheStats stats() { - return this.cachedSpikes.stats(); - } - - @Override - public void cleanUp() { - this.cachedSpikes.cleanUp(); - } - - private class InternalCacheLoader extends CacheLoader> { - - @Override - public @NotNull - List load(@NotNull BlockPos blockPos) { - List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); - - Collections.shuffle(list, new Random(worldSeed)); - List spikesList = Lists.newArrayList(); - - for (int i = 0; i < 10; ++i) { - int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int spikeZ = Mth.floor(42.0D * Math.sin(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); - int l = list.get(i); - int radius = 2 + l / 3; - int height = 76 + l * 3; - boolean guarded = l == 1 || l == 2; - - spikesList.add(new SpikeFeature.EndSpike(spikeX + blockPos.getX(), spikeZ + blockPos.getZ(), radius, height, guarded)); - } - - return spikesList; - } - - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/generator/IslandsGeneratorImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/generator/IslandsGeneratorImpl.java deleted file mode 100644 index 4b7239985b..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/generator/IslandsGeneratorImpl.java +++ /dev/null @@ -1,67 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.generator; - -import com.bgsoftware.common.annotations.NotNull; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.generator.BiomeProvider; -import org.bukkit.generator.BlockPopulator; -import org.bukkit.generator.WorldInfo; - -import java.util.Collections; -import java.util.List; -import java.util.Random; - -@SuppressWarnings({"unused", "NullableProblems"}) -public class IslandsGeneratorImpl extends IslandsGenerator { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private final Dimension dimension; - - public IslandsGeneratorImpl(Dimension dimension) { - this.dimension = dimension; - } - - @Override - public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ, - @NotNull ChunkData chunkData) { - if (chunkX == 0 && chunkZ == 0 && this.dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) { - chunkData.setBlock(0, 99, 0, Material.BEDROCK); - } - } - - @Override - public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) { - return new BiomeProvider() { - @Override - public @NotNull - Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) { - return IslandUtils.getDefaultWorldBiome(IslandsGeneratorImpl.this.dimension); - } - - @Override - public @NotNull - List getBiomes(@NotNull WorldInfo worldInfo) { - return IslandUtils.getDefaultWorldBiomes(); - } - - }; - } - - @Override - public List getDefaultPopulators(World world) { - return Collections.emptyList(); - } - - @Override - public Location getFixedSpawnLocation(World world, Random random) { - return new Location(world, 0, 100, 0); - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/hologram/EntityHologram.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/hologram/EntityHologram.java new file mode 100644 index 0000000000..06bbd73f8c --- /dev/null +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/hologram/EntityHologram.java @@ -0,0 +1,56 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_7.hologram; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.level.storage.ValueOutput; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_7.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + protected void addAdditionalSaveData(ValueOutput output) { + // Do not save NBT. + } + + @Override + protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) { + // Do not save NBT. + } + + @Override + protected void readAdditionalSaveData(ValueInput input) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { + // Do not save NBT. + return false; + } + + @Override + public boolean saveAsPassenger(ValueOutput output) { + // Do not save NBT. + return false; + } + + @Override + public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { + // Do not save NBT. + } + + @Override + public void saveWithoutId(ValueOutput output) { + // Do not save NBT. + } + + @Override + public void load(ValueInput input) { + // Do not load NBT. + } + +} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuBrewingStandBlockEntity.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuBrewingStandBlockEntity.java deleted file mode 100644 index 6eb85a5af8..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuBrewingStandBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuBrewingStandBlockEntity extends BrewingStandBlockEntity { - - private final InventoryHolder holder; - - public MenuBrewingStandBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuDispenserBlockEntity.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuDispenserBlockEntity.java deleted file mode 100644 index 00095c3346..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuDispenserBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.DispenserBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuDispenserBlockEntity extends DispenserBlockEntity { - - private final InventoryHolder holder; - - public MenuDispenserBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuFurnaceBlockEntity.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuFurnaceBlockEntity.java deleted file mode 100644 index 47a6e1a49d..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuFurnaceBlockEntity.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.FurnaceBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuFurnaceBlockEntity extends FurnaceBlockEntity { - - private final InventoryHolder holder; - - public MenuFurnaceBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.AIR.defaultBlockState()); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuHopperBlockEntity.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuHopperBlockEntity.java deleted file mode 100644 index 1dc946fa3e..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/menu/MenuHopperBlockEntity.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.menu; - -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.network.chat.Component; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.HopperBlock; -import net.minecraft.world.level.block.entity.HopperBlockEntity; -import org.bukkit.inventory.InventoryHolder; - -public class MenuHopperBlockEntity extends HopperBlockEntity { - - private final InventoryHolder holder; - - public MenuHopperBlockEntity(InventoryHolder holder, String title) { - super(BlockPos.ZERO, Blocks.HOPPER.defaultBlockState().setValue(HopperBlock.FACING, Direction.DOWN)); - this.holder = holder; - this.name = Component.nullToEmpty(title); - } - - @Override - public InventoryHolder getOwner() { - return holder; - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/player/OfflinePlayerDataImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/player/OfflinePlayerDataImpl.java deleted file mode 100644 index b86d5b0d9a..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/player/OfflinePlayerDataImpl.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.player; - -import com.bgsoftware.common.reflection.ReflectMethod; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.mojang.authlib.GameProfile; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ClientInformation; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.OfflinePlayer; -import org.bukkit.craftbukkit.CraftServer; -import org.bukkit.craftbukkit.CraftWorld; -import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.entity.Player; - -import java.util.Optional; - -public class OfflinePlayerDataImpl implements OfflinePlayerData { - - private static final ObjectsPool POOL = new ObjectsPool<>(OfflinePlayerDataImpl::new); - private static final ReflectMethod ENTITY_SET_LEVEL = new ReflectMethod<>(Entity.class, 1, Level.class); - - private Player fakePlayer; - - public static OfflinePlayerDataImpl create(OfflinePlayer offlinePlayer) { - return POOL.obtain().initialize(offlinePlayer); - } - - private OfflinePlayerDataImpl() { - - } - - private OfflinePlayerDataImpl initialize(OfflinePlayer offlinePlayer) { - GameProfile profile = new GameProfile(offlinePlayer.getUniqueId(), - Optional.ofNullable(offlinePlayer.getName()).orElse("")); - - MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); - ServerLevel serverLevel = server.getLevel(Level.OVERWORLD); - - if (serverLevel == null) - return null; - - ServerPlayer serverPlayer = new ServerPlayer(server, serverLevel, profile, ClientInformation.createDefault()); - this.fakePlayer = serverPlayer.getBukkitEntity(); - this.fakePlayer.loadData(); - - return this; - } - - @Override - public Player getFakeOnlinePlayer() { - return this.fakePlayer; - } - - @Override - public void setLocation(Location location) { - ServerPlayer serverPlayer = ((CraftPlayer) this.fakePlayer).getHandle(); - ServerLevel serverLevel = ((CraftWorld) location.getWorld()).getHandle(); - ENTITY_SET_LEVEL.invoke(serverPlayer, serverLevel); - serverPlayer.absSnapTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - } - - @Override - public void applyChanges() { - this.fakePlayer.saveData(); - } - - @Override - public void release() { - this.fakePlayer = null; - POOL.release(this); - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/spawners/TickingSpawnerBlockEntityNotifier.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/spawners/TickingSpawnerBlockEntityNotifier.java deleted file mode 100644 index 44758ded5e..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/spawners/TickingSpawnerBlockEntityNotifier.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.spawners; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.BaseSpawner; -import net.minecraft.world.level.block.entity.SpawnerBlockEntity; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -import java.util.function.IntFunction; - -public class TickingSpawnerBlockEntityNotifier implements TickingBlockEntity { - - private final SpawnerBlockEntity spawnerBlockEntity; - private final TickingBlockEntity tickingBlockEntity; - private final IntFunction delayChangeCallback; - - public TickingSpawnerBlockEntityNotifier(SpawnerBlockEntity spawnerBlockEntity, TickingBlockEntity tickingBlockEntity, - IntFunction delayChangeCallback) { - this.spawnerBlockEntity = spawnerBlockEntity; - this.tickingBlockEntity = tickingBlockEntity; - this.delayChangeCallback = delayChangeCallback; - updateDelay(); - } - - @Override - public void tick() { - BaseSpawner baseSpawner = this.spawnerBlockEntity.getSpawner(); - int startDelay = baseSpawner.spawnDelay; - try { - tickingBlockEntity.tick(); - } finally { - int newDelay = baseSpawner.spawnDelay; - if (newDelay > startDelay) - updateDelay(); - } - } - - @Override - public boolean isRemoved() { - return tickingBlockEntity.isRemoved(); - } - - @Override - public BlockPos getPos() { - return tickingBlockEntity.getPos(); - } - - @Override - public String getType() { - return tickingBlockEntity.getType(); - } - - public void updateDelay() { - BaseSpawner baseSpawner = spawnerBlockEntity.getSpawner(); - baseSpawner.spawnDelay = delayChangeCallback.apply(baseSpawner.spawnDelay); - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..dc5d123d60 --- /dev/null +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java @@ -0,0 +1,389 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_7.utils; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.utils.TickingBlockList; +import com.google.common.base.Suppliers; +import com.google.gson.JsonParseException; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.logging.LogUtils; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.util.ProblemReporter; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.TagValueOutput; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; +import org.slf4j.Logger; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +public class NMSUtilsVersioned { + + private static final Logger LOGGER = LogUtils.getLogger(); + + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( + EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { + return chunkMap.read(chunkPos).join().orElse(null); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { + return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), + chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { + chunkMap.write(chunkPos, () -> chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } else { + return BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + MoonriseRegionFileIO.RegionDataController regionDataController = + serverLevel.moonrise$getEntityChunkDataController(); + int chunkX = chunkPosition.getX(); + int chunkZ = chunkPosition.getZ(); + MoonriseRegionFileIO.RegionDataController.ReadData readData = + regionDataController.readData(chunkX, chunkZ); + if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { + CompoundTag entityData = readData.syncRead(); + if (entityData != null) { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + return; + } + } + + chunkCallback.onChunkNotExist(chunkPosition); + } catch (IOException error) { + countDownLatch.countDown(); + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + serverLevel.registryAccess().lookupOrThrow(Registries.BIOME), + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, + new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.liquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "block_entity@" + blockEntity.getBlockPos(), LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag); + blockEntity.loadWithComponents(valueInput); + } + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + applySignTextLines(compoundTag, "front_text"); + applySignTextLines(compoundTag, "back_text"); + convertLegacySignTextLines(compoundTag); + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + + Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), + biome, PalettedContainer.Strategy.SECTION_BIOMES); + PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, + Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + + chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); + + // Unsafe: we do not provide chunks cache, even tho it is required. + // Should be fine in normal flow, as the only method that access the chunks cache + // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 + WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); + + customChunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), + PalettedContainer.Strategy.SECTION_STATES); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + } + + public static CompoundTag saveEntity(Entity entity) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "cached_entity@" + entity.getUUID(), LOGGER)) { + TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess()); + entity.save(valueOutput); + return valueOutput.buildResult(); + } + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.moonrise$getTickingBlockList().size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + public static String getPropertyValue(Property property) { + return property.value(); + } + + public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.getDragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absSnapTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSectionY(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinY(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxY(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.markUnsaved(); + } + + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { + blockEntityCompound.getCompound(key).ifPresent(textCompound -> { + ListTag messages = textCompound.getListOrEmpty("messages"); + List textLines = new ArrayList<>(); + for (net.minecraft.nbt.Tag lineTag : messages) { + try { + textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); + } catch (JsonParseException error) { + textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); + } + } + + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); + }); + } + + private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockEntityCache.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockEntityCache.java deleted file mode 100644 index 98e89479c0..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockEntityCache.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; - -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class BlockEntityCache { - - private static final Map BLOCK_TO_ID = new IdentityHashMap<>(); - - private BlockEntityCache() { - - } - - public static String getBlockEntityId(BlockState blockState) { - return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { - for (BlockEntityType blockEntityType : BuiltInRegistries.BLOCK_ENTITY_TYPE) { - if (blockEntityType.isValid(blockState)) { - ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); - if (resourceLocation != null) - return resourceLocation.toString(); - } - } - - return ""; - }); - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/ChunkReaderImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/ChunkReaderImpl.java deleted file mode 100644 index 48f216ac92..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/ChunkReaderImpl.java +++ /dev/null @@ -1,255 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.ChunkReader; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.mojang.logging.LogUtils; -import net.minecraft.core.BlockPos; -import net.minecraft.core.SectionPos; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.ProblemReporter; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LightLayer; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.BooleanProperty; -import net.minecraft.world.level.block.state.properties.EnumProperty; -import net.minecraft.world.level.block.state.properties.IntegerProperty; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; -import net.minecraft.world.level.lighting.LevelLightEngine; -import net.minecraft.world.level.storage.TagValueOutput; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.block.CraftBlockType; -import org.bukkit.craftbukkit.entity.CraftEntity; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; -import org.bukkit.entity.EntityType; -import org.bukkit.inventory.InventoryHolder; -import org.slf4j.Logger; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -public class ChunkReaderImpl implements ChunkReader { - - private static final Logger LOGGER = LogUtils.getLogger(); - - private static final PalettedContainer EMPTY_STATES = new PalettedContainer<>( - Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - private static final byte[] FULL_LIGHT = new byte[2048]; - private static final byte[] EMPTY_LIGHT = new byte[2048]; - - static { - Arrays.fill(FULL_LIGHT, (byte) 0xFF); - } - - private final ServerLevel serverLevel; - private final int x; - private final int z; - - private final Map blockEntities = new HashMap<>(); - private final List entities = new LinkedList<>(); - private final PalettedContainerRO[] blockids; - private final byte[][] skylight; - private final byte[][] emitlight; - - public ChunkReaderImpl(Chunk bukkitChunk) { - LevelChunk levelChunk = NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk); - - this.serverLevel = levelChunk.level; - ChunkPos chunkPos = levelChunk.getPos(); - this.x = chunkPos.x; - this.z = chunkPos.z; - - LevelChunkSection[] levelChunkSections = levelChunk.getSections(); - this.blockids = new PalettedContainerRO[levelChunkSections.length]; - this.skylight = new byte[levelChunkSections.length][]; - this.emitlight = new byte[levelChunkSections.length][]; - - LevelLightEngine lightEngine = this.serverLevel.getLightEngine(); - - for (int i = 0; i < this.blockids.length; ++i) { - LevelChunkSection levelChunkSection = levelChunkSections[i]; - - this.blockids[i] = levelChunkSection.hasOnlyAir() ? EMPTY_STATES : levelChunkSection.getStates().copy(); - - DataLayer skyLightArray = lightEngine.getLayerListener(LightLayer.SKY) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (skyLightArray == null) { - this.skylight[i] = serverLevel.dimensionType().hasSkyLight() ? FULL_LIGHT : EMPTY_LIGHT; - } else { - this.skylight[i] = new byte[2048]; - System.arraycopy(skyLightArray.getData(), 0, this.skylight[i], 0, 2048); - } - - DataLayer emitLightArray = lightEngine.getLayerListener(LightLayer.BLOCK) - .getDataLayerData(SectionPos.of(this.x, getSectionYFromSectionIndex(i), this.z)); - if (emitLightArray == null) { - this.emitlight[i] = EMPTY_LIGHT; - } else { - this.emitlight[i] = new byte[2048]; - System.arraycopy(emitLightArray.getData(), 0, this.emitlight[i], 0, 2048); - } - } - - levelChunk.getBlockEntities().forEach((blockPos, blockEntity) -> { - net.minecraft.nbt.CompoundTag compoundTag = blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); - - compoundTag.remove("x"); - compoundTag.remove("y"); - compoundTag.remove("z"); - - InventoryHolder inventoryHolder = blockEntity.getOwner(); - if (inventoryHolder != null) - compoundTag.putString("inventoryType", inventoryHolder.getInventory().getType().name()); - - blockEntities.put(blockPos, CompoundTag.fromNBT(compoundTag)); - }); - - for (org.bukkit.entity.Entity entity : bukkitChunk.getEntities()) - entities.add(new CachedEntity(((CraftEntity) entity).getHandle())); - } - - @Override - public int getX() { - return this.x; - } - - @Override - public int getZ() { - return this.z; - } - - @Override - public Material getType(int x, int y, int z) { - return CraftBlockType.minecraftToBukkit(getBlockState(x, y, z).getBlock()); - } - - @Override - public short getData(int x, int y, int z) { - return CraftMagicNumbers.toLegacyData(getBlockState(x, y, z)); - } - - @Override - @Nullable - public CompoundTag getTileEntity(int x, int y, int z) { - try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { - BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); - blockPos.set((this.x << 4) + x, y, (this.z << 4) + z); - return this.blockEntities.get(blockPos); - } - } - - @Override - @Nullable - public CompoundTag readBlockStates(int x, int y, int z) { - BlockState blockState = getBlockState(x, y, z); - - if (blockState.getValues().isEmpty()) - return null; - - CompoundTag compoundTag = CompoundTag.of(); - - blockState.getValues().forEach((property, value) -> { - String name = PropertiesMapper.getPropertyName(property); - - if (property instanceof BooleanProperty) { - compoundTag.setByte(name, (Boolean) value ? (byte) 1 : 0); - } else if (property instanceof IntegerProperty integerProperty) { - compoundTag.setIntArray(name, new int[]{(Integer) value, integerProperty.min, integerProperty.max}); - } else if (property instanceof EnumProperty) { - compoundTag.setString(name, ((Enum) value).name()); - } - }); - - return compoundTag; - } - - @Override - public byte[] getLightLevels(int x, int y, int z) { - int off = (y & 15) << 7 | z << 3 | x >> 1; - int skyLightLevel = this.skylight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - int emitLightLevel = this.emitlight[this.getSectionIndex(y)][off] >> ((x & 1) << 2) & 15; - return new byte[]{(byte) skyLightLevel, (byte) emitLightLevel}; - } - - @Override - public void forEachEntity(EntityConsumer consumer) { - if (entities.isEmpty()) - return; - - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = wrapper.getHandle(); - for (CachedEntity cachedEntity : entities) { - location.setX(cachedEntity.x); - location.setY(cachedEntity.y); - location.setZ(cachedEntity.z); - location.setYaw(cachedEntity.yaw); - location.setPitch(cachedEntity.pitch); - consumer.apply(cachedEntity.entityType, cachedEntity.entityTag, location); - } - } - } - - private BlockState getBlockState(int x, int y, int z) { - return this.blockids[this.getSectionIndex(y)].get(x, y & 15, z); - } - - private int getSectionIndex(int y) { - int sectionIndex = SectionPos.blockToSectionCoord(y); - return sectionIndex - this.serverLevel.getMinSectionY(); - } - - private int getSectionYFromSectionIndex(int index) { - return index + this.serverLevel.getMinSectionY(); - } - - private static class CachedEntity { - - private final double x; - private final double y; - private final double z; - private final float yaw; - private final float pitch; - private final EntityType entityType; - private final CompoundTag entityTag; - - CachedEntity(Entity entity) { - this.x = entity.getX(); - this.y = entity.getY(); - this.z = entity.getZ(); - this.yaw = entity.getBukkitYaw(); - this.pitch = entity.getXRot(); - this.entityType = entity.getBukkitEntity().getType(); - - net.minecraft.nbt.CompoundTag compoundTag; - try (ProblemReporter.ScopedCollector scopedCollector = - new ProblemReporter.ScopedCollector(() -> "cached_entity@" + entity.getUUID(), LOGGER)) { - TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess()); - entity.save(valueOutput); - compoundTag = valueOutput.buildResult(); - } - - compoundTag.putFloat("Yaw", entity.getYRot()); - compoundTag.putFloat("Pitch", entity.getXRot()); - - this.entityTag = CompoundTag.fromNBT(compoundTag); - } - - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/KeyBlocksCache.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/KeyBlocksCache.java deleted file mode 100644 index 035ea48438..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/KeyBlocksCache.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; - -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.level.block.Block; -import org.bukkit.Material; -import org.bukkit.craftbukkit.util.CraftMagicNumbers; - -import java.util.IdentityHashMap; -import java.util.Map; - -public class KeyBlocksCache { - - private static final Map BLOCK_TO_KEY = new IdentityHashMap<>(); - - private KeyBlocksCache() { - - } - - public static Key getBlockKey(Block block) { - return BLOCK_TO_KEY.computeIfAbsent(block, unused -> { - Material blockType = CraftMagicNumbers.getMaterial(block); - return blockType == null ? null : blockType.isItem() ? Keys.of(blockType, (short) 0) : Keys.of(blockType); - }); - } - - public static void cacheAllBlocks() { - BuiltInRegistries.BLOCK.forEach(KeyBlocksCache::getBlockKey); - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapper.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapper.java deleted file mode 100644 index 84dc898dd0..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapper.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; - -import com.bgsoftware.superiorskyblock.core.logging.Log; -import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.Property; - -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; - -public class PropertiesMapper { - - private static final Map> nameToProperty = new HashMap<>(); - private static final Map, String> propertyToName = new HashMap<>(); - - static { - Map fieldsToNames = new IdentityHashMap<>(); - - fieldsToNames.put(BlockStateProperties.AXIS, "axis-empty"); - fieldsToNames.put(BlockStateProperties.FACING_HOPPER, "facing-notup"); - fieldsToNames.put(BlockStateProperties.HORIZONTAL_FACING, "facing-horizontal"); - fieldsToNames.put(BlockStateProperties.EAST_WALL, "wall-east"); - fieldsToNames.put(BlockStateProperties.NORTH_WALL, "wall-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_WALL, "wall-south"); - fieldsToNames.put(BlockStateProperties.WEST_WALL, "wall-west"); - fieldsToNames.put(BlockStateProperties.EAST_REDSTONE, "redstone-east"); - fieldsToNames.put(BlockStateProperties.NORTH_REDSTONE, "redstone-north"); - fieldsToNames.put(BlockStateProperties.SOUTH_REDSTONE, "redstone-south"); - fieldsToNames.put(BlockStateProperties.WEST_REDSTONE, "redstone-west"); - fieldsToNames.put(BlockStateProperties.DOUBLE_BLOCK_HALF, "double-half"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE, "track-shape-empty"); - fieldsToNames.put(BlockStateProperties.RAIL_SHAPE_STRAIGHT, "track-shape"); - fieldsToNames.put(BlockStateProperties.AGE_1, "age1"); - fieldsToNames.put(BlockStateProperties.AGE_2, "age2"); - fieldsToNames.put(BlockStateProperties.AGE_3, "age3"); - fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); - fieldsToNames.put(BlockStateProperties.AGE_5, "age5"); - fieldsToNames.put(BlockStateProperties.AGE_7, "age7"); - fieldsToNames.put(BlockStateProperties.AGE_15, "age15"); - fieldsToNames.put(BlockStateProperties.AGE_25, "age25"); - fieldsToNames.put(BlockStateProperties.LEVEL_CAULDRON, "level3"); - fieldsToNames.put(BlockStateProperties.LEVEL_COMPOSTER, "level8"); - fieldsToNames.put(BlockStateProperties.LEVEL_FLOWING, "level1-8"); - fieldsToNames.put(BlockStateProperties.LEVEL, "level15"); - fieldsToNames.put(BlockStateProperties.DISTANCE, "distance1-7"); - fieldsToNames.put(BlockStateProperties.STABILITY_DISTANCE, "distance7"); - fieldsToNames.put(BlockStateProperties.CHEST_TYPE, "chest-type"); - fieldsToNames.put(BlockStateProperties.MODE_COMPARATOR, "comparator-mode"); - fieldsToNames.put(BlockStateProperties.PISTON_TYPE, "piston-type"); - fieldsToNames.put(BlockStateProperties.SLAB_TYPE, "slab-type"); - fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); - - try { - for (Field field : BlockStateProperties.class.getFields()) { - field.setAccessible(true); - Object value = field.get(null); - if (value instanceof Property) { - Property property = (Property) value; - register(fieldsToNames.getOrDefault(field.get(null), property.getName()), field.getName(), property); - } - } - } catch (Exception error) { - Log.error(error, "An unexpected error occurred while loading properties mapper:"); - } - - } - - private static void register(String key, String fieldName, Property property) { - if (nameToProperty.containsKey(key)) { - Log.error("Block state ", key, "(", fieldName, ") already exists. Contact Ome_R!"); - } else { - nameToProperty.put(key, property); - propertyToName.put(property, key); - } - } - - public static Property getProperty(String name) { - return nameToProperty.get(name); - } - - public static String getPropertyName(Property property) { - return propertyToName.get(property); - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapperVersioned.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..ffc8e3beab --- /dev/null +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/PropertiesMapperVersioned.java @@ -0,0 +1,18 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; + +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionDataImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionDataImpl.java deleted file mode 100644 index b103f02cbd..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionDataImpl.java +++ /dev/null @@ -1,167 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; - -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.levelgen.Heightmap; -import org.bukkit.Location; - -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionDataImpl implements WorldEditSession.Data { - - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private final List> chunks = new LinkedList<>(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final List> lightenChunks = isStarLightInterface ? new LinkedList<>() : Collections.emptyList(); - - public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, - List> blocksToUpdate, - List> blockEntities, - Set lightenChunks) { - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // Convert chunk data - Iterator> chunksIterator = chunks.entryIterator(); - while (chunksIterator.hasNext()) { - Long2ObjectMapView.Entry entry = chunksIterator.next(); - int currChunkPosXAxis = ChunkPos.getX(entry.getKey()); - int currChunkPosZAxis = ChunkPos.getZ(entry.getKey()); - WorldEditSessionImpl.ChunkData chunkData = entry.getValue(); - - List> lights; - if (isStarLightInterface || chunkData.lights().isEmpty()) { - lights = Collections.emptyList(); - } else { - lights = new LinkedList<>(); - chunkData.lights().forEach(lightPosition -> { - lights.add(new PositionedObject<>(lightPosition.getX() - baseBlockPosXAxis, - lightPosition.getY() - baseBlockPosYAxis, lightPosition.getZ() - baseBlockPosZAxis, - null)); - }); - } - - PositionedChunkData positionedChunkData = new PositionedChunkData(chunkData.chunkSections(), - chunkData.heightmaps(), lights); - - this.chunks.add(new PositionedObject<>(currChunkPosXAxis - baseChunkPosXAxis, - currChunkPosZAxis - baseChunkPosZAxis, positionedChunkData)); - } - - // Convert blocksToUpdate - blocksToUpdate.forEach(blockToUpdate -> { - BlockPos blockPos = blockToUpdate.getKey(); - this.blocksToUpdate.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockToUpdate.getValue())); - }); - - // Convert blockEntities - blockEntities.forEach(blockEntity -> { - BlockPos blockPos = blockEntity.getKey(); - this.blockEntities.add(new PositionedObject<>(blockPos.getX() - baseBlockPosXAxis, - blockPos.getY() - baseBlockPosYAxis, blockPos.getZ() - baseBlockPosZAxis, - blockEntity.getValue())); - }); - - // Convert lights - lightenChunks.forEach(lightPosition -> { - this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, - lightPosition.z - baseChunkPosZAxis, null)); - }); - } - - public void readChunks(int baseChunkPosXAxis, int baseChunkPosZAxis, int baseBlockPosXAxis, int baseBlockPosYAxis, - int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, - Long2ObjectMapView chunks) { - this.chunks.forEach(chunkDataPositioned -> { - long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, - baseChunkPosZAxis + chunkDataPositioned.zOffset); - - List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); - chunkDataPositioned.object.lights.forEach(lightPositioned -> { - lights.add(new BlockPos(baseBlockPosXAxis + lightPositioned.xOffset, - baseBlockPosYAxis + lightPositioned.yOffset, - baseBlockPosZAxis + lightPositioned.zOffset)); - }); - - chunks.put(newPos, worldEditSession.createChunkData(chunkDataPositioned.object.chunkSections, - chunkDataPositioned.object.heightmaps, lights)); - }); - } - - public void readBlocksToUpdate(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blocksToUpdate) { - this.blocksToUpdate.forEach(blockToUpdatePositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockToUpdatePositioned.xOffset, - baseBlockPosYAxis + blockToUpdatePositioned.yOffset, - baseBlockPosZAxis + blockToUpdatePositioned.zOffset); - blocksToUpdate.add(new Pair<>(newPos, blockToUpdatePositioned.object)); - }); - } - - public void readBlockEntities(int baseBlockPosXAxis, int baseBlockPosYAxis, int baseBlockPosZAxis, List> blockEntities) { - this.blockEntities.forEach(blockEntityPositioned -> { - BlockPos newPos = new BlockPos(baseBlockPosXAxis + blockEntityPositioned.xOffset, - baseBlockPosYAxis + blockEntityPositioned.yOffset, - baseBlockPosZAxis + blockEntityPositioned.zOffset); - blockEntities.add(new Pair<>(newPos, blockEntityPositioned.object)); - }); - } - - public void readLights(int baseChunkPosXAxis, int baseChunkPosZAxis, Set lightenChunks) { - this.lightenChunks.forEach(lightPositioned -> { - ChunkPos newPos = new ChunkPos(baseChunkPosXAxis + lightPositioned.xOffset, - baseChunkPosZAxis + lightPositioned.zOffset); - lightenChunks.add(newPos); - }); - } - - private static class PositionedObject { - - private final int xOffset; - private final int yOffset; - private final int zOffset; - private final V object; - - PositionedObject(int xOffset, int zOffset, V object) { - this(xOffset, 0, zOffset, object); - } - - PositionedObject(int xOffset, int yOffset, int zOffset, V object) { - this.xOffset = xOffset; - this.yOffset = yOffset; - this.zOffset = zOffset; - this.object = object; - } - - } - - private record PositionedChunkData(LevelChunkSection[] chunkSections, Map heightmaps, - List> lights) { - } - -} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java deleted file mode 100644 index 5aa9151d4c..0000000000 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/WorldEditSessionImpl.java +++ /dev/null @@ -1,492 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.ObjectsPool; -import com.bgsoftware.superiorskyblock.core.Text; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.collections.view.LongIterator; -import com.bgsoftware.superiorskyblock.island.IslandUtils; -import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; -import com.bgsoftware.superiorskyblock.tag.ByteTag; -import com.bgsoftware.superiorskyblock.tag.CompoundTag; -import com.bgsoftware.superiorskyblock.tag.IntArrayTag; -import com.bgsoftware.superiorskyblock.tag.StringTag; -import com.bgsoftware.superiorskyblock.tag.Tag; -import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; -import com.google.common.base.Preconditions; -import com.google.gson.JsonParseException; -import com.mojang.logging.LogUtils; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.NbtOps; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceKey; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ThreadedLevelLightEngine; -import net.minecraft.util.ProblemReporter; -import net.minecraft.world.item.DyeColor; -import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.LevelHeightAccessor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.block.BedBlock; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.SignText; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; -import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.UpgradeData; -import net.minecraft.world.level.chunk.status.ChunkStatus; -import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.Heightmap; -import net.minecraft.world.level.storage.TagValueInput; -import net.minecraft.world.level.storage.ValueInput; -import net.minecraft.world.ticks.ProtoChunkTicks; -import org.bukkit.Chunk; -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.craftbukkit.CraftChunk; -import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.util.CraftChatMessage; -import org.bukkit.generator.ChunkGenerator; -import org.slf4j.Logger; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Supplier; - -public class WorldEditSessionImpl implements WorldEditSession { - - private static final Logger LOGGER = LogUtils.getLogger(); - - private static final ObjectsPool POOL = new ObjectsPool<>(WorldEditSessionImpl::new); - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final boolean isStarLightInterface = ((Supplier) () -> { - try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); - return true; - } catch (ClassNotFoundException error) { - return false; - } - }).get(); - - private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; - - private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); - private final List> blocksToUpdate = new LinkedList<>(); - private final List> blockEntities = new LinkedList<>(); - private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); - - private Dimension dimension; - private LevelHeightAccessor levelHeightAccessor; - - @Nullable - private ServerLevel serverLevel; - - public static WorldEditSessionImpl obtain(ServerLevel serverLevel) { - return POOL.obtain().initialize(serverLevel); - } - - public static WorldEditSessionImpl obtain(Dimension dimension) { - return POOL.obtain().initialize(dimension); - } - - private WorldEditSessionImpl() { - } - - private WorldEditSessionImpl initialize(ServerLevel serverLevel) { - this.serverLevel = serverLevel; - this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(serverLevel.getWorld()); - this.levelHeightAccessor = serverLevel; - return this; - } - - private WorldEditSessionImpl initialize(Dimension dimension) { - DimensionType dimensionType = getDimensionTypeFromDimension(dimension); - this.serverLevel = null; - this.dimension = dimension; - this.levelHeightAccessor = LevelHeightAccessor.create(dimensionType.minY(), dimensionType.height()); - return this; - } - - @Override - public void setBlock(Location location, int combinedId, @Nullable CompoundTag statesTag, - @Nullable CompoundTag blockEntityData) { - BlockPos blockPos = new BlockPos(location.getBlockX(), location.getBlockY(), location.getBlockZ()); - - if (!isValidPosition(blockPos)) - return; - - BlockState blockState = Block.stateById(combinedId); - - if (statesTag != null) { - for (Map.Entry> entry : statesTag.entrySet()) { - try { - // noinspection rawtypes - Property property = PropertiesMapper.getProperty(entry.getKey()); - if (property != null) { - if (entry.getValue() instanceof ByteTag) { - // noinspection unchecked - blockState = blockState.setValue(property, ((ByteTag) entry.getValue()).getValue() == 1); - } else if (entry.getValue() instanceof IntArrayTag) { - int[] data = ((IntArrayTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, data[0]); - } else if (entry.getValue() instanceof StringTag) { - String data = ((StringTag) entry.getValue()).getValue(); - // noinspection unchecked - blockState = blockState.setValue(property, Enum.valueOf(property.getValueClass(), data)); - } - } - } catch (Exception ignored) { - } - } - } - - if ((blockState.liquid() && plugin.getSettings().isLiquidUpdate()) || - blockState.getBlock() instanceof BedBlock) { - blocksToUpdate.add(new Pair<>(blockPos, blockState)); - return; - } - - ChunkPos chunkPos = new ChunkPos(blockPos); - - if (blockEntityData != null) - blockEntities.add(new Pair<>(blockPos, blockEntityData)); - - ChunkData chunkData = this.chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); - - if (plugin.getSettings().isLightsUpdate() && !isStarLightInterface && blockState.getLightEmission() > 0) - chunkData.lights.add(blockPos); - - LevelChunkSection levelChunkSection = chunkData.chunkSections[this.levelHeightAccessor.getSectionIndex(blockPos.getY())]; - - int blockX = blockPos.getX() & 15; - int blockY = blockPos.getY(); - int blockZ = blockPos.getZ() & 15; - - levelChunkSection.setBlockState(blockX, blockY & 15, blockZ, blockState, false); - - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(blockX, blockY, blockZ, blockState); - chunkData.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(blockX, blockY, blockZ, blockState); - } - - @Override - public List getAffectedChunks() { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#getAffectedChunks on partial initialized session"); - - if (chunks.isEmpty()) - return Collections.emptyList(); - - List chunkPositions = new LinkedList<>(); - World bukkitWorld = serverLevel.getWorld(); - LongIterator iterator = chunks.keyIterator(); - while (iterator.hasNext()) { - long chunkKey = iterator.next(); - int chunkX = (int) chunkKey; - int chunkZ = (int) (chunkKey >> 32); - chunkPositions.add(ChunkPosition.of(bukkitWorld, chunkX, chunkZ, false)); - } - return chunkPositions; - } - - @Override - public void applyBlocks(Chunk bukkitChunk) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); - - LevelChunk levelChunk = Objects.requireNonNull(NMSUtils.getCraftChunkHandle((CraftChunk) bukkitChunk)); - ChunkPos chunkPos = levelChunk.getPos(); - - long chunkKey = chunkPos.toLong(); - ChunkData chunkData = this.chunks.remove(chunkKey); - - if (chunkData == null) - return; - - int chunkSectionsCount = Math.min(chunkData.chunkSections.length, levelChunk.getSections().length); - for (int i = 0; i < chunkSectionsCount; ++i) { - levelChunk.getSections()[i] = chunkData.chunkSections[i]; - } - - chunkData.heightmaps.forEach(((type, heightmap) -> { - levelChunk.setHeightmap(type, heightmap.getRawData()); - })); - - if (plugin.getSettings().isLightsUpdate()) { - if (isStarLightInterface) { - this.lightenChunks.add(chunkPos); - } else { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); - // Queues chunk light for this chunk. - threadedLevelLightEngine.lightChunk(levelChunk, false); - } - } - - levelChunk.markUnsaved(); - } - - @Override - public void finish(Island island) { - Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#finish on partial initialized session"); - - // Update blocks - blocksToUpdate.forEach(data -> serverLevel.setBlock(data.getKey(), data.getValue(), 3)); - - // Update block entities - blockEntities.forEach(data -> { - net.minecraft.nbt.CompoundTag blockEntityCompound = (net.minecraft.nbt.CompoundTag) data.getValue().toNBT(); - if (blockEntityCompound != null) { - BlockPos blockPos = data.getKey(); - blockEntityCompound.putInt("x", blockPos.getX()); - blockEntityCompound.putInt("y", blockPos.getY()); - blockEntityCompound.putInt("z", blockPos.getZ()); - - applySignTextLines(blockEntityCompound, "front_text"); - applySignTextLines(blockEntityCompound, "back_text"); - convertLegacySignTextLines(blockEntityCompound); - - BlockEntity worldBlockEntity = serverLevel.getBlockEntity(blockPos); - if (worldBlockEntity != null) { - try (ProblemReporter.ScopedCollector scopedCollector = - new ProblemReporter.ScopedCollector(() -> "block_entity@" + blockPos, LOGGER)) { - ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), blockEntityCompound); - worldBlockEntity.loadWithComponents(valueInput); - } - } - } - }); - - if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { - ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - threadedLevelLightEngine.starlight$serverRelightChunks(lightenChunks, chunkCallback -> { - }, completeCallback -> { - }); - this.lightenChunks.clear(); - } - - release(); - } - - @Override - public Data readData(Location baseLocation) { - return new WorldEditSessionDataImpl(baseLocation, this.chunks, this.blocksToUpdate, this.blockEntities, this.lightenChunks); - } - - @Override - public void applyData(Data data, Location baseLocation) { - WorldEditSessionDataImpl dataImpl = (WorldEditSessionDataImpl) data; - - int baseBlockPosXAxis = baseLocation.getBlockX(); - int baseBlockPosYAxis = baseLocation.getBlockY(); - int baseBlockPosZAxis = baseLocation.getBlockZ(); - int baseChunkPosXAxis = baseBlockPosXAxis >> 4; - int baseChunkPosZAxis = baseBlockPosZAxis >> 4; - - // We need to transform all data to the new base location values - - dataImpl.readChunks(baseChunkPosXAxis, baseChunkPosZAxis, baseBlockPosXAxis, baseBlockPosYAxis, - baseBlockPosZAxis, this, this.chunks); - dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); - dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); - dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); - } - - @Override - public void release() { - this.chunks.clear(); - this.blocksToUpdate.clear(); - this.blockEntities.clear(); - this.lightenChunks.clear(); - this.serverLevel = null; - this.dimension = null; - this.levelHeightAccessor = null; - POOL.release(this); - } - - public ChunkData createChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - return new ChunkData(chunkSections, heightmaps, lights); - } - - private boolean isValidPosition(BlockPos blockPos) { - return blockPos.getX() >= -30000000 && blockPos.getZ() >= -30000000 && - blockPos.getX() < 30000000 && blockPos.getZ() < 30000000 && - this.levelHeightAccessor.isInsideBuildHeight(blockPos.getY()); - } - - private static void applySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound, String key) { - blockEntityCompound.getCompound(key).ifPresent(textCompound -> { - ListTag messages = textCompound.getListOrEmpty("messages"); - List textLines = new ArrayList<>(); - for (net.minecraft.nbt.Tag lineTag : messages) { - try { - textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); - } catch (JsonParseException error) { - textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); - } - } - - for (int i = 0; i < 4; i++) { - if (textLines.get(i) == null) - textLines.set(i, Component.empty()); - } - - Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); - - SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); - }); - } - - private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blockEntityCompound) { - Component[] signLines = new Component[4]; - Arrays.fill(signLines, Component.empty()); - boolean hasAnySignLines = false; - // We try to convert old text sign lines - for (int i = 1; i <= 4; ++i) { - if (blockEntityCompound.contains("SSB.Text" + i)) { - String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; - hasAnySignLines = true; - } - } else { - String signLine = blockEntityCompound.getString("Text" + i).orElse(null); - if (!Text.isBlank(signLine)) { - signLines[i - 1] = CraftChatMessage.fromJSON(signLine); - hasAnySignLines = true; - } - } - } - - if (hasAnySignLines) { - SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); - SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() - .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); - } - } - - private static DimensionType getDimensionTypeFromDimension(Dimension dimension) { - ResourceKey resourceKey; - switch (dimension.getEnvironment()) { - case NETHER -> resourceKey = LevelStem.NETHER; - case THE_END -> resourceKey = LevelStem.END; - default -> resourceKey = LevelStem.OVERWORLD; - } - Registry registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); - return registry.getValue(resourceKey).type().value(); - } - - public class ChunkData { - - private final LevelChunkSection[] chunkSections; - private final Map heightmaps; - private final List lights; - - private ChunkData(long chunkKey) { - this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), - isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); - - ChunkPos chunkPos = new ChunkPos(chunkKey); - - Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); - - createChunkSections(biomesRegistry); - - ProtoChunk tempChunk = new ProtoChunk(chunkPos, UpgradeData.EMPTY, this.chunkSections, - new ProtoChunkTicks<>(), new ProtoChunkTicks<>(), levelHeightAccessor, biomesRegistry, null); - - createHeightmaps(tempChunk); - if (serverLevel != null) - runCustomWorldGenerator(tempChunk); - } - - private ChunkData(LevelChunkSection[] chunkSections, Map heightmaps, List lights) { - this.chunkSections = chunkSections; - this.heightmaps = heightmaps; - this.lights = lights; - } - - public LevelChunkSection[] chunkSections() { - return this.chunkSections; - } - - public Map heightmaps() { - return this.heightmaps; - } - - public List lights() { - return this.lights; - } - - private void createChunkSections(Registry biomesRegistry) { - Holder biome = CraftBiome.bukkitToMinecraftHolder( - IslandUtils.getDefaultWorldBiome(WorldEditSessionImpl.this.dimension)); - - for (int i = 0; i < this.chunkSections.length; ++i) { - PalettedContainer> biomesContainer = new PalettedContainer<>(biomesRegistry.asHolderIdMap(), - biome, PalettedContainer.Strategy.SECTION_BIOMES); - PalettedContainer statesContainer = new PalettedContainer<>(Block.BLOCK_STATE_REGISTRY, - Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - - this.chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); - } - } - - private void runCustomWorldGenerator(ProtoChunk tempChunk) { - ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); - - if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) - return; - - NMSUtils.buildSurfaceForChunk(serverLevel, tempChunk); - - // We want to copy the level chunk sections back - LevelChunkSection[] tempChunkSections = tempChunk.getSections(); - for (int i = 0; i < Math.min(this.chunkSections.length, tempChunkSections.length); ++i) { - LevelChunkSection chunkSection = tempChunkSections[i]; - if (chunkSection != null) - this.chunkSections[i] = chunkSection; - } - } - - private void createHeightmaps(ProtoChunk tempChunk) { - for (Heightmap.Types heightmapType : Heightmap.Types.values()) { - if (ChunkStatus.FULL.heightmapsAfter().contains(heightmapType)) { - this.heightmaps.put(heightmapType, new Heightmap(tempChunk, heightmapType)); - } - } - } - - } - - -} From 43f2e7676f52f87504be8aef1350b428b1d87fde Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 4 Oct 2025 20:28:24 +0300 Subject: [PATCH 357/600] Adds support to 1.21.9 (Paper only) --- .../templates/NMSPlayersImpl.java.template | 2 +- .../nms/v1_17/utils/NMSUtilsVersioned.java | 5 + .../nms/v1_18/utils/NMSUtilsVersioned.java | 5 + .../nms/v1_19/utils/NMSUtilsVersioned.java | 5 + .../nms/v1_20_3/utils/NMSUtilsVersioned.java | 5 + .../nms/v1_20_4/utils/NMSUtilsVersioned.java | 5 + .../nms/v1_21/utils/NMSUtilsVersioned.java | 5 + .../nms/v1_21_3/utils/NMSUtilsVersioned.java | 5 + .../nms/v1_21_4/utils/NMSUtilsVersioned.java | 5 + .../nms/v1_21_5/utils/NMSUtilsVersioned.java | 5 + .../nms/v1_21_7/utils/NMSUtilsVersioned.java | 5 + NMS/v1_21_9/build.gradle | 23 + NMS/v1_21_9/properties | 7 + .../nms/v1_21_9/NMSAlgorithmsImpl.java | 77 ++++ .../nms/v1_21_9/NMSChunksImpl.java | 365 ++++++++++++++++ .../nms/v1_21_9/NMSEntitiesImpl.java | 24 ++ .../nms/v1_21_9/NMSTagsImpl.java | 149 +++++++ .../nms/v1_21_9/NMSWorldImpl.java | 94 ++++ .../dragon/IslandEntityEnderDragon.java | 40 ++ .../nms/v1_21_9/hologram/EntityHologram.java | 55 +++ .../v1_21_9/trial/IslandPlayerDetector.java | 53 +++ .../nms/v1_21_9/utils/NMSUtilsVersioned.java | 406 ++++++++++++++++++ .../vibration/IslandVibrationUser.java | 90 ++++ .../world/PropertiesMapperVersioned.java | 18 + build.gradle | 2 +- settings.gradle | 3 +- .../superiorskyblock/tag/ByteArrayTag.java | 3 +- .../superiorskyblock/tag/ByteTag.java | 3 +- .../superiorskyblock/tag/CompoundTag.java | 2 +- .../superiorskyblock/tag/DoubleTag.java | 3 +- .../superiorskyblock/tag/EndTag.java | 2 +- .../superiorskyblock/tag/FloatTag.java | 3 +- .../superiorskyblock/tag/IntArrayTag.java | 3 +- .../superiorskyblock/tag/IntTag.java | 3 +- .../superiorskyblock/tag/ListTag.java | 2 +- .../superiorskyblock/tag/LongTag.java | 3 +- .../superiorskyblock/tag/NMSTagConverter.java | 52 ++- .../superiorskyblock/tag/ShortTag.java | 3 +- .../superiorskyblock/tag/StringTag.java | 3 +- 39 files changed, 1522 insertions(+), 21 deletions(-) create mode 100644 NMS/v1_21_9/build.gradle create mode 100644 NMS/v1_21_9/properties create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSEntitiesImpl.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/IslandEntityEnderDragon.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/hologram/EntityHologram.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/vibration/IslandVibrationUser.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/PropertiesMapperVersioned.java diff --git a/NMS/src/main/templates/NMSPlayersImpl.java.template b/NMS/src/main/templates/NMSPlayersImpl.java.template index e6920c7918..97513c5af0 100644 --- a/NMS/src/main/templates/NMSPlayersImpl.java.template +++ b/NMS/src/main/templates/NMSPlayersImpl.java.template @@ -41,7 +41,7 @@ public class NMSPlayersImpl implements NMSPlayers { return; ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.getGameProfile().getProperties().get("textures").stream().findFirst() + NMSUtilsVersioned.getProfileProperties(serverPlayer.getGameProfile()).get("textures").stream().findFirst() .ifPresent(property -> setSkinTexture(superiorPlayer, property)); } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java index b13d38659d..33a62e6a2d 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java @@ -14,6 +14,7 @@ import com.google.common.base.Suppliers; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; @@ -253,6 +254,10 @@ public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpa serverLevel.addEntity(entity, spawnReason); } + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.getProperties(); + } + public static String getPropertyValue(Property property) { return property.getValue(); } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java index 60a2c97dd6..ad7afbd43b 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java @@ -13,6 +13,7 @@ import com.google.common.base.Suppliers; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; @@ -244,6 +245,10 @@ public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpa serverLevel.addFreshEntity(entity, spawnReason); } + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.getProperties(); + } + public static String getPropertyValue(Property property) { return property.getValue(); } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java index c7b074641c..b41b9707ba 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java @@ -14,6 +14,7 @@ import com.google.common.base.Suppliers; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; @@ -275,6 +276,10 @@ public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpa serverLevel.addFreshEntity(entity, spawnReason); } + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.getProperties(); + } + public static String getPropertyValue(Property property) { return property.getValue(); } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java index 063a1be085..40bbf797f9 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java @@ -13,6 +13,7 @@ import com.google.common.base.Suppliers; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; @@ -272,6 +273,10 @@ public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpa serverLevel.addFreshEntity(entity, spawnReason); } + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.getProperties(); + } + public static String getPropertyValue(Property property) { return property.value(); } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java index 7bf65fe9b3..bd90957f3c 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java @@ -14,6 +14,7 @@ import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; @@ -326,6 +327,10 @@ private static void convertLegacySignTextLines(net.minecraft.nbt.CompoundTag blo } } + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.getProperties(); + } + public static String getPropertyValue(Property property) { return property.value(); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java index 9bf0fd70f1..3dea5f1635 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java @@ -14,6 +14,7 @@ import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; @@ -283,6 +284,10 @@ public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpa serverLevel.addFreshEntity(entity, spawnReason); } + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.getProperties(); + } + public static String getPropertyValue(Property property) { return property.value(); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java index 20332e7811..0f8f5b6ad9 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java @@ -15,6 +15,7 @@ import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; @@ -288,6 +289,10 @@ public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpa serverLevel.addFreshEntity(entity, spawnReason); } + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.getProperties(); + } + public static String getPropertyValue(Property property) { return property.value(); } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java index 98a0f4a3f2..cd461926c7 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java @@ -15,6 +15,7 @@ import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; @@ -288,6 +289,10 @@ public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpa serverLevel.addFreshEntity(entity, spawnReason); } + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.getProperties(); + } + public static String getPropertyValue(Property property) { return property.value(); } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java index d3d3ff0923..1750ea4a2c 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java @@ -15,6 +15,7 @@ import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.Registry; @@ -288,6 +289,10 @@ public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpa serverLevel.addFreshEntity(entity, spawnReason); } + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.getProperties(); + } + public static String getPropertyValue(Property property) { return property.value(); } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java index dc5d123d60..8340410458 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java @@ -15,6 +15,7 @@ import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; @@ -303,6 +304,10 @@ public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpa serverLevel.addFreshEntity(entity, spawnReason); } + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.getProperties(); + } + public static String getPropertyValue(Property property) { return property.value(); } diff --git a/NMS/v1_21_9/build.gradle b/NMS/v1_21_9/build.gradle new file mode 100644 index 0000000000..7f628e113f --- /dev/null +++ b/NMS/v1_21_9/build.gradle @@ -0,0 +1,23 @@ +plugins { + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } +} + +group 'NMS:v1_21_9' + +dependencies { + paperweight.paperDevBundle("1.21.9-R0.1-SNAPSHOT") + compileOnly project(":NMS:Spigot-1_20_3") + compileOnly project(":NMS:Paper-1_20_3") + compileOnly project(":API") + compileOnly rootProject +} + +if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/NMS/v1_21_9/properties b/NMS/v1_21_9/properties new file mode 100644 index 0000000000..928a628a97 --- /dev/null +++ b/NMS/v1_21_9/properties @@ -0,0 +1,7 @@ +NMS_VERSION=v1_21_9 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java new file mode 100644 index 0000000000..97e26635c9 --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java @@ -0,0 +1,77 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.mojang.serialization.JsonOps; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.ComponentSerialization; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.inventory.ItemRarity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; + +import java.util.Locale; +import java.util.Objects; + +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms { + + private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create(); + + @Override + public String parseSignLine(String original) { + RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE); + JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0]) + .getOrThrow(JsonParseException::new); + return COMPONENT_GSON.toJson(jsonElement); + } + + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + itemMeta.setRarity(ItemRarity.valueOf(rarity)); + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + + @Override + public String getMinecraftKey(ItemStack itemStack) { + return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); + } + + @Override + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.setEnchantmentGlintOverride(true); + } + +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java new file mode 100644 index 0000000000..c2bb2aa19e --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java @@ -0,0 +1,365 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.core.CalculatedChunk; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Counter; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.bgsoftware.superiorskyblock.nms.v1_21_9.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_9.utils.NMSUtilsVersioned; +import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.mojang.logging.LogUtils; +import com.mojang.serialization.DataResult; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; +import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.ProblemReporter; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerFactory; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.Strategy; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.ValueInput; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.entity.CraftEntityType; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.generator.ChunkGenerator; +import org.slf4j.Logger; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import static com.bgsoftware.superiorskyblock.nms.v1_21_9.utils.NMSUtilsVersioned.DEFAULT_PALETTED_CONTAINER_FACTORY; + +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSChunks { + + private static final Logger LOGGER = LogUtils.getLogger(); + + + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { + super(plugin); + } + + @Override + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); + + ChunkPos chunkPos = levelChunk.getPos(); + + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + LevelChunkSection currentSection = chunkSections[i]; + if (currentSection != null) { + PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); + chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); + } + } + + levelChunk.markUnsaved(); + + ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); + ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( + levelChunk, levelChunk.level.getLightEngine(), null, null, true); + + playersToUpdate.forEach(player -> { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + serverPlayer.connection.send(forgetLevelChunkPacket); + serverPlayer.connection.send(mapChunkPacket); + }); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); + + PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerRWCodec() + .encodeStart(NbtOps.INSTANCE, biomesContainer); + Tag biomesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); + + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); + } + + @Override + public void onFinish() { + // Do nothing. + } + }; + } + + @Override + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + chunkSections[i] = new LevelChunkSection(DEFAULT_PALETTED_CONTAINER_FACTORY); + } + + removeEntities(levelChunk); + removeBlockEntities(levelChunk); + removeBlocks(levelChunk); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + ListTag tileEntities = new ListTag(); + + chunkCompound.put("entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); + + if (serverLevel.generator instanceof IslandsGenerator) { + PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() + .encodeStart(NbtOps.INSTANCE, statesContainer); + Tag blockStatesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); + } else { + ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); + + try { + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); + } catch (Exception ignored) { + } + + LevelLightEngine lightEngine = serverLevel.getLightEngine(); + LevelChunkSection[] chunkSections = protoChunk.getSections(); + + ListTag sectionsList = new ListTag(); + + // Save blocks + for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { + int chunkSectionIndex = serverLevel.getSectionIndex(i); + + CompoundTag sectionCompound = new CompoundTag(); + + if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { + LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; + + { + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() + .encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); + sectionCompound.put("block_states", dataResult.getOrThrow()); + } + + { + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerCodec() + .encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); + sectionCompound.put("biomes", dataResult.getOrThrow()); + } + } + + if (!sectionCompound.isEmpty()) { + sectionCompound.putByte("Y", (byte) i); + sectionsList.add(sectionCompound); + } + } + + for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { + CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, + MinecraftServer.getServer().registryAccess()); + if (blockEntityCompound != null) + tileEntities.add(blockEntityCompound); + } + + chunkCompound.put("sections", sectionsList); + } + } + + @Override + public void onFinish() { + if (onFinish != null) + onFinish.run(); + } + }; + } + + @Override + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + + latchCountDown(); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + + LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; + + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); + for (int i = 0; i < sectionsList.size(); ++i) { + CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); + byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); + int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); + + if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { + PalettedContainer blocksPalettedContainer; + Optional blockStatesCompound = sectionCompound.getCompound("block_states"); + if (blockStatesCompound.isPresent()) { + DataResult> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY + .blockStatesContainerCodec().parse(NbtOps.INSTANCE, blockStatesCompound.get()) + .promotePartial((sx) -> { + }); + blocksPalettedContainer = dataResult.getOrThrow(); + } else { + blocksPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + } + + PalettedContainer> biomesPalettedContainer; + Optional biomesCompound = sectionCompound.getCompound("biomes"); + if (biomesCompound.isPresent()) { + DataResult>> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY + .biomeContainerRWCodec().parse(NbtOps.INSTANCE, biomesCompound.get()) + .promotePartial((sx) -> { + }); + biomesPalettedContainer = dataResult.getOrThrow(); + } else { + biomesPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBiomes(); + } + + chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); + } + + } + + CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + allCalculatedChunks.add(calculatedChunk); + unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + latchCountDown(); + } + + @Override + public void onFinish() { + completableFuture.complete(allCalculatedChunks); + } + }; + } + + @Override + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { + if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) + chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); + } + + latchCountDown(); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + unloadedChunkCompounds.add(unloadedChunkCompound); + + latchCountDown(); + } + + @Override + public void onFinish() { + BukkitExecutor.ensureMain(() -> { + for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + + for (Tag entityTag : chunkCompound.getListOrEmpty("entities")) { + Entity fakeEntity; + EntityType entityType; + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(entityTag::toString, LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), (CompoundTag) entityTag); + + entityType = EntityType.by(valueInput).orElse(null); + if (entityType == null) + continue; + + fakeEntity = EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL).orElse(null); + } + + if (fakeEntity != null) { + fakeEntity.valid = false; + if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) + continue; + } + + Key entityKey = Keys.of(CraftEntityType.minecraftToBukkit(entityType)); + chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); + } + } + + completableFuture.complete(chunkEntities); + }); + } + }; + } + + private static void removeBlocks(ChunkAccess chunk) { + ServerLevel serverLevel = ((LevelChunk) chunk).level; + ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); + + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; + + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); + } + +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSEntitiesImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSEntitiesImpl.java new file mode 100644 index 0000000000..be91f780c6 --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSEntitiesImpl.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9; + +import net.minecraft.tags.ItemTags; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PortalProcessor; +import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.minecart.PoweredMinecart; + +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSEntities { + + @Override + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); + } + + @Override + protected int getPortalTicks(Entity entity) { + PortalProcessor portalProcessor = entity.portalProcess; + return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); + } + +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java new file mode 100644 index 0000000000..4810d897a2 --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java @@ -0,0 +1,149 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9; + +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.datafixers.util.Either; +import com.mojang.logging.LogUtils; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.ByteArrayTag; +import net.minecraft.nbt.IntArrayTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.NumericTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.PlayerSkin; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ResolvableProfile; +import org.bukkit.Location; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.slf4j.Logger; + +import java.util.Optional; +import java.util.Set; + +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSTags { + + private static final Logger LOGGER = LogUtils.getLogger(); + + @Override + public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + Multimap properties = HashMultimap.create(); + properties.put("textures", new Property("textures", texture)); + + ResolvableProfile.Partial partialProfile = new ResolvableProfile.Partial( + Optional.empty(), Optional.empty(), new PropertyMap(properties)); + + ResolvableProfile resolvableProfile = new ResolvableProfile.Static(Either.right(partialProfile), PlayerSkin.Patch.EMPTY); + + itemStack.set(DataComponents.PROFILE, resolvableProfile); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { + RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); + + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) + ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow(); + tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + + return CompoundTag.fromNBT(tagCompound); + } + + @Override + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.getIntOr(key, def); + } + + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + RegistryOps context = + MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); + + return ItemStack.CODEC.parse(context, compoundTag) + .resultOrPartial((itemId) -> LOGGER.error("Tried to load invalid item: '{}'", itemId)) + .orElseThrow(); + } + + @Override + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); + } + + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { + EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { + entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); + return !serverLevel.addWithUUID(entity) ? null : entity; + }); + } + + @Override + public byte[] getNBTByteArrayValue(Object object) { + return ((ByteArrayTag) object).getAsByteArray(); + } + + @Override + public byte getNBTByteValue(Object object) { + return ((NumericTag) object).byteValue(); + } + + @Override + public Set getNBTCompoundValue(Object object) { + return ((net.minecraft.nbt.CompoundTag) object).keySet(); + } + + @Override + public double getNBTDoubleValue(Object object) { + return ((NumericTag) object).doubleValue(); + } + + @Override + public float getNBTFloatValue(Object object) { + return ((NumericTag) object).floatValue(); + } + + @Override + public int[] getNBTIntArrayValue(Object object) { + return ((IntArrayTag) object).getAsIntArray(); + } + + @Override + public int getNBTIntValue(Object object) { + return ((NumericTag) object).intValue(); + } + + @Override + public Object getNBTListIndexValue(Object object, int index) { + return ((net.minecraft.nbt.ListTag) object).get(index); + } + + @Override + public long getNBTLongValue(Object object) { + return ((NumericTag) object).longValue(); + } + + @Override + public short getNBTShortValue(Object object) { + return ((NumericTag) object).shortValue(); + } + + @Override + public String getNBTStringValue(Object object) { + return ((StringTag) object).value(); + } + +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java new file mode 100644 index 0000000000..dd072e9c03 --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java @@ -0,0 +1,94 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.nms.v1_21_9.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_9.trial.IslandPlayerDetector; +import com.bgsoftware.superiorskyblock.nms.v1_21_9.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.world.SignType; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; +import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; +import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import org.bukkit.Location; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.WallHangingSign; + +import java.lang.reflect.Modifier; + +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSWorld { + + private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( + SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + + public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { + super(plugin); + } + + @Override + public void replaceTrialBlockPlayerDetector(Island island, Location location) { + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); + if (blockEntity == null) + return; + + if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { + VaultConfig vaultConfig = vaultBlockEntity.getConfig(); + + PlayerDetector playerDetector = vaultConfig.playerDetector(); + if (playerDetector instanceof IslandPlayerDetector) + return; + + VaultConfig newConfig = new VaultConfig( + vaultConfig.lootTable(), + vaultConfig.activationRange(), + vaultConfig.deactivationRange(), + vaultConfig.keyItem(), + vaultConfig.overrideLootTableToDisplay(), + IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), + vaultConfig.entitySelector() + ); + + vaultBlockEntity.setConfig(newConfig); + } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { + TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); + PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); + + if (playerDetector instanceof IslandPlayerDetector) + return; + + trialSpawnerBlockEntity.trialSpawner.setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector)); + } + } + + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) + return; + + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } + + @Override + public SignType getSignType(Object sign) { + if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return super.getSignType(sign); + } + + @Override + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); + } + +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/IslandEntityEnderDragon.java new file mode 100644 index 0000000000..efb357f2c5 --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/IslandEntityEnderDragon.java @@ -0,0 +1,40 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9.dragon; + +import com.bgsoftware.common.annotations.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.SpawnGroupData; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; +import net.minecraft.world.level.storage.ValueInput; + +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_9.dragon.AbstractIslandEntityEnderDragon { + + public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { + super(level, islandBlockPos); + } + + public IslandEntityEnderDragon(Level level) { + super(level); + } + + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, + DifficultyInstance difficulty, + EntitySpawnReason spawnReason, + @Nullable SpawnGroupData entityData) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(world, difficulty, spawnReason, entityData); + } + + @Override + protected void readAdditionalSaveData(ValueInput input) { + super.readAdditionalSaveData(input); + finalizeIslandEnderDragon(); + } + +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/hologram/EntityHologram.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/hologram/EntityHologram.java new file mode 100644 index 0000000000..d6f9034d08 --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/hologram/EntityHologram.java @@ -0,0 +1,55 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9.hologram; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.level.storage.ValueOutput; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_9.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + protected void addAdditionalSaveData(ValueOutput output) { + // Do not save NBT. + } + + @Override + protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) { + // Do not save NBT. + } + + @Override + protected void readAdditionalSaveData(ValueInput input) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { + // Do not save NBT. + return false; + } + + @Override + public boolean saveAsPassenger(ValueOutput output) { + // Do not save NBT. + return false; + } + + @Override + public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { + // Do not save NBT. + } + + @Override + public void saveWithoutId(ValueOutput output) { + // Do not save NBT. + } + + @Override + public void load(ValueInput input) { + // Do not load NBT. + } + +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java new file mode 100644 index 0000000000..8b84361071 --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java @@ -0,0 +1,53 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9.trial; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +public class IslandPlayerDetector implements PlayerDetector { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final PlayerDetector original; + private final IslandPrivilege requiredPrivilege; + + public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + } + + public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + } + + private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + this.island = island; + this.original = original; + this.requiredPrivilege = requiredPrivilege; + } + + @Override + public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { + List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); + if (!players.isEmpty()) { + players = new LinkedList<>(players); + players.removeIf(uuid -> { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); + return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + }); + players = Collections.unmodifiableList(players); + } + return players; + } + +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..3852fb8c99 --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java @@ -0,0 +1,406 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9.utils; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_9.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_9.utils.TickingBlockList; +import com.google.common.base.Suppliers; +import com.google.gson.JsonParseException; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.logging.LogUtils; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.util.ProblemReporter; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerFactory; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.Strategy; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.TagValueOutput; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; +import org.slf4j.Logger; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +public class NMSUtilsVersioned { + + private static final Logger LOGGER = LogUtils.getLogger(); + + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( + EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + public static final PalettedContainerFactory DEFAULT_PALETTED_CONTAINER_FACTORY = PalettedContainerFactory.create( + MinecraftServer.getServer().registryAccess()); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { + return chunkMap.read(chunkPos).join().orElse(null); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { + return chunkMap.upgradeChunkTag(serverLevel.getTypeKey(), Suppliers.ofInstance(serverLevel.getDataStorage()), + chunkCompoundTag, Optional.empty(), chunkPos, serverLevel); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { + chunkMap.write(chunkPos, () -> chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } else { + return BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + MoonriseRegionFileIO.RegionDataController regionDataController = + serverLevel.moonrise$getEntityChunkDataController(); + int chunkX = chunkPosition.getX(); + int chunkZ = chunkPosition.getZ(); + MoonriseRegionFileIO.RegionDataController.ReadData readData = + regionDataController.readData(chunkX, chunkZ); + if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { + CompoundTag entityData = readData.syncRead(); + if (entityData != null) { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + return; + } + } + + chunkCallback.onChunkNotExist(chunkPosition); + } catch (IOException error) { + countDownLatch.countDown(); + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + DEFAULT_PALETTED_CONTAINER_FACTORY, + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), + new ProtoChunkTicks<>(), levelHeightAccessor, DEFAULT_PALETTED_CONTAINER_FACTORY, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.liquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "block_entity@" + blockEntity.getBlockPos(), LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag); + blockEntity.loadWithComponents(valueInput); + } + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + applySignTextLines(compoundTag, "front_text"); + applySignTextLines(compoundTag, "back_text"); + convertLegacySignTextLines(compoundTag); + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + PalettedContainer> biomesContainer = createBiomesContainer(biome); + PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); + + // Unsafe: we do not provide chunks cache, even tho it is required. + // Should be fine in normal flow, as the only method that access the chunks cache + // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 + WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); + + customChunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + } + + public static CompoundTag saveEntity(Entity entity) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "cached_entity@" + entity.getUUID(), LOGGER)) { + TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess()); + entity.save(valueOutput); + return valueOutput.buildResult(); + } + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.moonrise$getTickingBlockList().size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.properties(); + } + + public static String getPropertyValue(Property property) { + return property.value(); + } + + public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.getDragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absSnapTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSectionY(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinY(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxY(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.markUnsaved(); + } + + public static PalettedContainer> createBiomesContainer(Holder biome) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + Strategy> biomesStrategy = Strategy.createForBiomes(biomesRegistry.asHolderIdMap()); + return new PalettedContainerFactory( + null, + null, + null, + biomesStrategy, + biome, + null, + null + ).createForBiomes(); + } + + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { + blockEntityCompound.getCompound(key).ifPresent(textCompound -> { + ListTag messages = textCompound.getListOrEmpty("messages"); + List textLines = new ArrayList<>(); + for (net.minecraft.nbt.Tag lineTag : messages) { + try { + textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); + } catch (JsonParseException error) { + textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); + } + } + + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); + }); + } + + private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/vibration/IslandVibrationUser.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/vibration/IslandVibrationUser.java new file mode 100644 index 0000000000..305ef5a967 --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/vibration/IslandVibrationUser.java @@ -0,0 +1,90 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.PositionSource; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; + +import javax.annotation.Nullable; + +public class IslandVibrationUser implements VibrationSystem.User { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final VibrationSystem.User original; + + public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + this.island = island; + this.original = sculkSensorBlockEntity.getVibrationUser(); + } + + @Override + public int getListenerRadius() { + return this.original.getListenerRadius(); + } + + @Override + public PositionSource getPositionSource() { + return this.original.getPositionSource(); + } + + @Override + public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { + if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) + return false; + + if (context.sourceEntity() instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + + @Override + public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { + this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); + } + + @Override + public TagKey getListenableEvents() { + return this.original.getListenableEvents(); + } + + @Override + public boolean canTriggerAvoidVibration() { + return this.original.canTriggerAvoidVibration(); + } + + @Override + public boolean requiresAdjacentChunksToBeTicking() { + return this.original.requiresAdjacentChunksToBeTicking(); + } + + @Override + public int calculateTravelTimeInTicks(float distance) { + return this.original.calculateTravelTimeInTicks(distance); + } + + @Override + public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { + return this.original.isValidVibration(gameEvent, context); + } + + @Override + public void onDataChanged() { + this.original.onDataChanged(); + } + +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/PropertiesMapperVersioned.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..e26da4613a --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/PropertiesMapperVersioned.java @@ -0,0 +1,18 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9.world; + +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/build.gradle b/build.gradle index 2868a4c8f5..b8761f6b7c 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b14' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b15' implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b1' implementation 'org.bstats:bstats-bukkit:3.0.0' diff --git a/settings.gradle b/settings.gradle index 20ab62ef19..c8ada85806 100644 --- a/settings.gradle +++ b/settings.gradle @@ -69,4 +69,5 @@ include 'NMS:v1_21' include 'NMS:v1_21_3' include 'NMS:v1_21_4' include 'NMS:v1_21_5' -include 'NMS:v1_21_7' \ No newline at end of file +include 'NMS:v1_21_7' +include 'NMS:v1_21_9' \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java index 99425e6fec..250f8b530f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteArrayTag.java @@ -48,7 +48,8 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class ByteArrayTag extends Tag { - /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagByteArray", byte[].class); + /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( + new String[]{"NBTTagByteArray", "ByteArrayTag"}, byte[].class); private static final ByteArrayTag EMPTY = new ByteArrayTag(new byte[0]); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java index a62cb7eedb..7c3a3f87c1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ByteTag.java @@ -46,7 +46,8 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class ByteTag extends NumberTag { - /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagByte", byte.class); + /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( + new String[]{"NBTTagByte", "ByteTag"}, byte.class); private static final ByteTag[] CACHE = new ByteTag[256]; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java index fdacb6324d..999c1b7ca5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/CompoundTag.java @@ -57,7 +57,7 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class CompoundTag extends Tag>> implements Iterable> { - /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagCompound"); + /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice("NBTTagCompound", "CompoundTag"); private CompoundTag(Map> value, boolean cloneMap) { super(cloneMap ? new HashMap<>(value) : value); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java index fa5d5ffae7..ca20cc9df9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/DoubleTag.java @@ -46,7 +46,8 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class DoubleTag extends NumberTag { - /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagDouble", double.class); + /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( + new String[]{"NBTTagDouble", "DoubleTag"}, double.class); private static final DoubleTag[] CACHE = new DoubleTag[100]; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java index 73848065ba..d1185a1bfc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/EndTag.java @@ -43,7 +43,7 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class EndTag extends Tag { - /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagEnd"); + /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice("NBTTagEnd", "EndTag"); private static final EndTag INSTANCE = new EndTag(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java index b2f9502b57..835aa04120 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/FloatTag.java @@ -46,7 +46,8 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class FloatTag extends NumberTag { - /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagFloat", float.class); + /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( + new String[]{"NBTTagFloat", "FloatTag"}, float.class); private static final FloatTag[] CACHE = new FloatTag[100]; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java index c119db7a75..60c41144c3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/IntArrayTag.java @@ -53,7 +53,8 @@ @SuppressWarnings("WeakerAccess") public class IntArrayTag extends Tag { - /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagIntArray", int[].class); + /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( + new String[]{"NBTTagIntArray", "IntArrayTag"}, int[].class); private static final IntArrayTag EMPTY = new IntArrayTag(new int[0]); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java index e317915c32..6f6a9a935a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/IntTag.java @@ -46,7 +46,8 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class IntTag extends NumberTag { - /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagInt", int.class); + /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( + new String[]{"NBTTagInt", "IntTag"}, int.class); private static final IntTag[] CACHE = new IntTag[100]; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java index e3659e6fb4..0aab11ad9b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ListTag.java @@ -54,7 +54,7 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) @SuppressWarnings("rawtypes") public class ListTag extends Tag>> implements Iterable> { - /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagList"); + /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice("NBTTagList", "ListTag"); private static final byte DYNAMIC_LIST_INDICATOR = (byte) 0xFF; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java index 38975dee9e..76dd36caae 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/LongTag.java @@ -46,7 +46,8 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class LongTag extends NumberTag { - /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagLong", long.class); + /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( + new String[]{"NBTTagLong", "LongTag"}, long.class); private static final LongTag[] CACHE = new LongTag[100]; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/NMSTagConverter.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/NMSTagConverter.java index 99a4913b75..95f8fe237a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/NMSTagConverter.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/NMSTagConverter.java @@ -2,18 +2,48 @@ import com.bgsoftware.common.reflection.ReflectConstructor; import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.core.Either; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.Bukkit; +import javax.annotation.Nullable; + public class NMSTagConverter { + private static final Class[] EMPTY_PARAMS = new Class[0]; + private final Class clazz; private final ReflectMethod A; private final ReflectConstructor CONSTRUCTOR; - public NMSTagConverter(String nbtClassName, Class... parameterTypes) { - this.clazz = getNNTClass(nbtClassName); + public static NMSTagConverter of(String nbtClassName) { + return of(nbtClassName, null); + } + + public static NMSTagConverter of(String nbtClassName, @Nullable Class parameterType) { + Class[] parameterTypes = parameterType == null ? EMPTY_PARAMS : new Class[]{parameterType}; + return new NMSTagConverter(nbtClassName, parameterTypes); + } + + public static NMSTagConverter choice(String... nbtClassNames) { + return choice(nbtClassNames, null); + } + + public static NMSTagConverter choice(String[] nbtClassNames, @Nullable Class parameterType) { + for (int i = nbtClassNames.length - 1; i >= 1; --i) { + String nbtClassName = nbtClassNames[i]; + Either, Exception> clazz = getNNTClass(nbtClassName); + if (clazz.getLeft() != null) + return of(nbtClassName, parameterType); + } + + // Couldn't find one, we'll try the first one and return whatever the result is + return of(nbtClassNames[0], parameterType); + } + + private NMSTagConverter(String nbtClassName, Class[] parameterTypes) { + this.clazz = getNNTClassOrError(nbtClassName); this.A = new ReflectMethod<>(this.clazz, this.clazz, "a", parameterTypes); this.CONSTRUCTOR = new ReflectConstructor<>(this.clazz, parameterTypes); } @@ -30,18 +60,28 @@ public Object toNBT(Object... args) { } } - private static Class getNNTClass(String nbtType) { + private static Either, Exception> getNNTClass(String nbtType) { try { if (ServerVersion.isAtLeast(ServerVersion.v1_17)) { - return Class.forName("net.minecraft.nbt." + nbtType); + return Either.left(Class.forName("net.minecraft.nbt." + nbtType)); } else { String version = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]; - return Class.forName("net.minecraft.server." + version + "." + nbtType); + return Either.left(Class.forName("net.minecraft.server." + version + "." + nbtType)); } } catch (Exception error) { - Log.error(error, "An unexpected error while loading nbt class ", nbtType, ":"); + return Either.right(error); + } + } + + private static Class getNNTClassOrError(String nbtType) { + Either, Exception> clazz = getNNTClass(nbtType); + + if (clazz.getRight() != null) { + Log.error(clazz.getRight(), "An unexpected error while loading nbt class ", nbtType, ":"); return null; } + + return clazz.getLeft(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java index 63e2213817..eadae1f4ab 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/ShortTag.java @@ -46,7 +46,8 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class ShortTag extends NumberTag { - /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagShort", short.class); + /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( + new String[]{"NBTTagShort", "ShortTag"}, short.class); private static final ShortTag[] CACHE = new ShortTag[100]; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java index 7f75dc12e4..83bdddcfeb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/StringTag.java @@ -47,7 +47,8 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */ public class StringTag extends Tag { - /*package*/ static final NMSTagConverter TAG_CONVERTER = new NMSTagConverter("NBTTagString", String.class); + /*package*/ static final NMSTagConverter TAG_CONVERTER = NMSTagConverter.choice( + new String[]{"NBTTagString", "StringTag"}, String.class); private static final StringTag EMPTY = new StringTag(""); From 60a9b06c5ba91611099abbd9417c3823ed9842c4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 6 Oct 2025 13:18:16 +0300 Subject: [PATCH 358/600] Fix compiling errors in 1.21.9 --- .../templates/AbstractNMSAlgorithms.java.template | 11 ----------- .../superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java | 11 +++++++++++ .../superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java | 11 +++++++++++ .../superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java | 11 +++++++++++ .../nms/v1_20_3/NMSAlgorithmsImpl.java | 11 +++++++++++ .../nms/v1_20_4/NMSAlgorithmsImpl.java | 10 ++++++++++ .../superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java | 10 ++++++++++ .../nms/v1_21_3/NMSAlgorithmsImpl.java | 10 ++++++++++ .../nms/v1_21_4/NMSAlgorithmsImpl.java | 10 ++++++++++ .../nms/v1_21_5/NMSAlgorithmsImpl.java | 10 ++++++++++ .../nms/v1_21_7/NMSAlgorithmsImpl.java | 10 ++++++++++ .../nms/v1_21_9/NMSAlgorithmsImpl.java | 5 +++++ 12 files changed, 109 insertions(+), 11 deletions(-) diff --git a/NMS/src/main/templates/AbstractNMSAlgorithms.java.template b/NMS/src/main/templates/AbstractNMSAlgorithms.java.template index f2ccb552fc..f938b92406 100644 --- a/NMS/src/main/templates/AbstractNMSAlgorithms.java.template +++ b/NMS/src/main/templates/AbstractNMSAlgorithms.java.template @@ -24,7 +24,6 @@ import io.papermc.paper.chat.ChatRenderer; import net.kyori.adventure.audience.Audience; import net.kyori.adventure.text.TextReplacementConfig; import net.minecraft.core.BlockPos; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.Container; import net.minecraft.world.entity.item.FallingBlockEntity; @@ -232,16 +231,6 @@ public abstract class AbstractNMSAlgorithms implements NMSAlgorithms { return Bukkit.getMaxWorldSize(); } - @Override - public double getCurrentTps() { - try { - return MinecraftServer.getServer().tps1.getAverage(); - } catch (Throwable error) { - //noinspection removal - return MinecraftServer.getServer().recentTps[0]; - } - } - @Override public int getDataVersion() { return CraftMagicNumbers.INSTANCE.getDataVersion(); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java index 5f39410541..c162e979c0 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment; import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; +import net.minecraft.server.MinecraftServer; import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; @@ -31,6 +32,16 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java index a967a10304..d820a0fa70 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment; import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; +import net.minecraft.server.MinecraftServer; import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; @@ -31,6 +32,16 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java index e4463c6593..0fb353682b 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.nms.algorithms.SpigotGlowEnchantment; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; +import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; @@ -57,6 +58,16 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java index 73993fa5ed..7f0d521fba 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.algorithms.SpigotGlowEnchantment; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; +import net.minecraft.server.MinecraftServer; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.craftbukkit.v1_20_R3.CraftRegistry; @@ -38,6 +39,16 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.addEnchant(GLOW_ENCHANT, 1, true); } + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java index 3df07dcf65..02d804b95e 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java @@ -25,4 +25,14 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java index 5e7fe03610..23f4116a48 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java @@ -58,4 +58,14 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java index 1113ae7a21..17a8a56960 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java @@ -63,4 +63,14 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index bcffab4825..3f211c1c27 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -63,4 +63,14 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java index d010f85506..05993a282b 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java @@ -63,4 +63,14 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java index 50fcac1df5..88191fb920 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java @@ -75,4 +75,14 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } + @Override + public double getCurrentTps() { + try { + return MinecraftServer.getServer().tps1.getAverage(); + } catch (Throwable error) { + //noinspection removal + return MinecraftServer.getServer().recentTps[0]; + } + } + } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java index 97e26635c9..314a95dc51 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java @@ -74,4 +74,9 @@ public void makeItemGlow(ItemMeta itemMeta) { itemMeta.setEnchantmentGlintOverride(true); } + @Override + public double getCurrentTps() { + return Bukkit.getTPS()[0]; + } + } From 6a83cca0e752bd6a0371779b47cbc1b026222174 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 6 Oct 2025 14:04:25 +0300 Subject: [PATCH 359/600] Fixed many cases where lazy worlds should have been loaded but didn't (#2694) --- .../commands/admin/CmdAdminDelWarp.java | 7 +- .../commands/player/CmdDelWarp.java | 7 +- .../commands/player/CmdVisit.java | 27 +++-- .../superiorskyblock/core/IslandWorlds.java | 27 +++++ .../core/LazyWorldLocation.java | 34 +++++-- .../superiorskyblock/core/LocationKey.java | 98 ------------------- .../superiorskyblock/core/ObjectsPools.java | 1 + .../bridge/IslandsDatabaseBridge.java | 4 +- .../button/impl/WarpPagedObjectButton.java | 3 +- .../superiorskyblock/island/SIsland.java | 71 +++++++------- .../island/warp/SIslandWarp.java | 16 ++- .../island/warp/SignWarp.java | 29 ++++++ 12 files changed, 152 insertions(+), 172 deletions(-) delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/LocationKey.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java index 156ef78a3b..9a0fe1c2ec 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminDelWarp.java @@ -8,12 +8,9 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.warp.SignWarp; -import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; -import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import org.bukkit.command.CommandSender; import java.util.Collections; @@ -77,9 +74,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab island.deleteWarp(islandWarp.getName()); Message.DELETE_WARP.send(sender, islandWarp.getName()); - ChunksProvider.loadChunk(ChunkPosition.of(islandWarp), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { - SignWarp.trySignWarpBreak(islandWarp, sender); - }); + SignWarp.trySignWarpBreak(islandWarp, sender); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java index 3390bf6c94..6da87e3335 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDelWarp.java @@ -8,13 +8,10 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IPermissibleCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; -import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.warp.SignWarp; -import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; -import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import org.bukkit.entity.Player; import java.util.Collections; @@ -81,9 +78,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer island.deleteWarp(islandWarp.getName()); Message.DELETE_WARP.send(superiorPlayer, islandWarp.getName()); - ChunksProvider.loadChunk(ChunkPosition.of(islandWarp), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { - SignWarp.trySignWarpBreak(islandWarp, player); - }); + SignWarp.trySignWarpBreak(islandWarp, player); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java index 64ccc7e3ac..ca1895bfb2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java @@ -1,16 +1,13 @@ package com.bgsoftware.superiorskyblock.commands.player; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.IslandWorlds; -import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -122,23 +119,25 @@ private static void teleportPlayerInternal(Island targetIsland, SuperiorPlayer s Location finalVisitLocation = visitLocation; EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getVisitWarmup(), afterWarmup -> - teleportPlayerNoWarmup(superiorPlayer, targetIsland, finalVisitLocation, - isVisitorSign, afterWarmup /*checkIslandLock*/, true)); + teleportPlayerNoWarmup(superiorPlayer, targetIsland, finalVisitLocation, isVisitorSign, afterWarmup /*checkIslandLock*/)); } private static void teleportPlayerNoWarmup(SuperiorPlayer superiorPlayer, Island island, Location visitLocation, - boolean isVisitorSign, boolean checkIslandLock, boolean shouldRetryOnNullWorld) { + boolean isVisitorSign, boolean checkIslandLock) { if (visitLocation.getWorld() == null) { - if (shouldRetryOnNullWorld && visitLocation instanceof LazyWorldLocation && - plugin.getProviders().getWorldsProvider() instanceof LazyWorldsProvider) { - LazyWorldsProvider worldsProvider = (LazyWorldsProvider) plugin.getProviders().getWorldsProvider(); - WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(island, ((LazyWorldLocation) visitLocation).getWorldName()); - worldsProvider.prepareWorld(island, worldInfo.getDimension(), - () -> teleportPlayerNoWarmup(superiorPlayer, island, visitLocation, isVisitorSign, checkIslandLock, false)); - return; - } + IslandWorlds.accessIslandWorldAsync(island, visitLocation, true, islandWorldResult -> { + islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { + visitLocation.setWorld(world); + teleportPlayerNoWarmupWorldLoaded(superiorPlayer, island, visitLocation, isVisitorSign, checkIslandLock); + }); + }); + } else { + teleportPlayerNoWarmupWorldLoaded(superiorPlayer, island, visitLocation, isVisitorSign, checkIslandLock); } + } + private static void teleportPlayerNoWarmupWorldLoaded(SuperiorPlayer superiorPlayer, Island island, Location visitLocation, + boolean isVisitorSign, boolean checkIslandLock) { superiorPlayer.setTeleportTask(null); if (checkIslandLock && island.isLocked() && !island.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS)) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java index ef588a3a38..510c50f0bd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java @@ -24,6 +24,33 @@ public static void accessIslandWorldsAsync(Island island, boolean loadWorld, Con } } + public static void accessIslandWorldAsync(Island island, Location location, boolean loadWorld, Consumer> consumer) { + World world = location.getWorld(); + if (world != null) { + consumer.accept(Either.left(world)); + return; + } + + String worldName = LazyWorldLocation.getWorldName(location); + + if (!loadWorld) { + consumer.accept(Either.right(new NullPointerException("World " + worldName + " is not loaded when requested"))); + return; + } + + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, worldName); + + Dimension dimension = worldInfo.getDimension(); + + WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); + if (worldsProvider instanceof LazyWorldsProvider) { + ((LazyWorldsProvider) worldsProvider).prepareWorld(island, dimension, () -> + loadedWorldCallback(worldInfo, consumer)); + } else { + loadedWorldCallback(worldInfo, consumer); + } + } + public static void accessIslandWorldAsync(Island island, Dimension dimension, boolean loadWorld, Consumer> consumer) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); if (worldInfo == null) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java b/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java index 5298ac43a4..755045e57d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java @@ -11,7 +11,8 @@ */ public class LazyWorldLocation extends Location { - private final String worldName; + private String worldName; + private boolean updatedWorld = false; public static LazyWorldLocation of(Location location) { if (location instanceof LazyWorldLocation) @@ -26,19 +27,44 @@ public static LazyWorldLocation of(WorldInfo worldInfo, BlockPosition blockPosit 0f, 0f); } + public LazyWorldLocation(World world, double x, double y, double z) { + super(world, x, y, z); + this.worldName = null; + this.updatedWorld = false; + } + public LazyWorldLocation(String worldName, double x, double y, double z, float yaw, float pitch) { super(Bukkit.getWorld(worldName), x, y, z, yaw, pitch); this.worldName = worldName; + this.updatedWorld = false; + } + + public String getWorldName() { + return this.worldName; + } + + public void setWorldName(String worldName) { + this.worldName = worldName; + this.updatedWorld = false; } @Override public World getWorld() { - if (worldName != null) + if (!this.updatedWorld) { setWorld(Bukkit.getWorld(worldName)); + } return super.getWorld(); } + @Override + public void setWorld(World world) { + super.setWorld(world); + if (world != null) + this.worldName = world.getName(); + this.updatedWorld = true; + } + @Override public Location clone() { return clone(false); @@ -49,10 +75,6 @@ public Location clone(boolean keepLazy) { super.clone(); } - public String getWorldName() { - return worldName; - } - public static String getWorldName(Location location) { if (location instanceof LazyWorldLocation) return ((LazyWorldLocation) location).getWorldName(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/LocationKey.java b/src/main/java/com/bgsoftware/superiorskyblock/core/LocationKey.java deleted file mode 100644 index aa29b07852..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/LocationKey.java +++ /dev/null @@ -1,98 +0,0 @@ -package com.bgsoftware.superiorskyblock.core; - -import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; -import org.bukkit.Location; - -import java.util.Objects; - -public class LocationKey implements ObjectsPool.Releasable, AutoCloseable { - - private static final ObjectsPool POOL = new ObjectsPool<>(LocationKey::new); - - private String worldName; - private double x; - private double y; - private double z; - - public static LocationKey of(Location location) { - return of(location, true); - } - - public static LocationKey of(Location location, boolean fromPool) { - return of(LazyWorldLocation.getWorldName(location), location.getX(), location.getY(), location.getZ(), fromPool); - } - - public static LocationKey of(LazyWorldLocation location) { - return of(location, true); - } - - public static LocationKey of(LazyWorldLocation location, boolean fromPool) { - return of(location.getWorldName(), location.getX(), location.getY(), location.getZ(), fromPool); - } - - public static LocationKey of(String worldName, double x, double y, double z) { - return of(worldName, x, y, z, true); - } - - public static LocationKey of(String worldName, double x, double y, double z, boolean fromPool) { - LocationKey locationKey = fromPool ? POOL.obtain() : new LocationKey(); - return locationKey.initialize(worldName, x, y, z); - } - - public static LocationKey of(IslandWarp islandWarp) { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - return of(islandWarp.getLocation(wrapper.getHandle())); - } - } - - private LocationKey() { - - } - - private LocationKey initialize(String worldName, double x, double y, double z) { - this.worldName = worldName; - this.x = x; - this.y = y; - this.z = z; - return this; - } - - public LocationKey copy() { - return of(worldName, x, y, z, false); - } - - @Override - public void release() { - this.worldName = null; - POOL.release(this); - } - - @Override - public void close() { - release(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - LocationKey that = (LocationKey) o; - return Double.compare(that.x, x) == 0 && Double.compare(that.y, y) == 0 && Double.compare(that.z, z) == 0 && worldName.equals(that.worldName); - } - - @Override - public int hashCode() { - return Objects.hash(worldName, x, y, z); - } - - @Override - public String toString() { - return "LocationKey{" + - "worldName='" + worldName + '\'' + - ", x=" + x + - ", y=" + y + - ", z=" + z + - '}'; - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java index d4708083de..f57b012a81 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java @@ -9,6 +9,7 @@ public class ObjectsPools { public static final ObjectsPool> LOCATION = createNewPool(() -> new Location(null, 0D, 0D, 0D)); + public static final ObjectsPool> LAZY_LOCATION = createNewPool(() -> new LazyWorldLocation(null, 0D, 0D, 0D)); private ObjectsPools() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index 081c4255d3..d5677f4e05 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -360,7 +360,7 @@ public static void saveWarp(Island island, IslandWarp islandWarp) { WarpCategory category = islandWarp.getCategory(); ItemStack icon = islandWarp.getRawIcon(); runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { databaseBridge.insertObject("islands_warps", new Pair<>("island", island.getUniqueId().toString()), new Pair<>("name", islandWarp.getName()), @@ -382,7 +382,7 @@ public static void updateWarpName(Island island, IslandWarp islandWarp, String o public static void updateWarpLocation(Island island, IslandWarp islandWarp) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { databaseBridge.updateObject("islands_warps", createFilter("island", island, new Pair<>("name", islandWarp.getName())), new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(wrapper.getHandle()))) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java index 9cfc7d8b2d..29e8f69589 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpPagedObjectButton.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; @@ -48,7 +49,7 @@ public ItemStack modifyViewItem(ItemStack buttonItem) { if (menuView.hasManagePerms() && !Menus.MENU_WARPS.getEditLore().isEmpty()) itemBuilder.appendLore(Menus.MENU_WARPS.getEditLore()); - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { return itemBuilder.replaceAll("{0}", pagedObject.getName()) .replaceAll("{1}", Formatters.LOCATION_FORMATTER.format(pagedObject.getLocation(wrapper.getHandle()))) .replaceAll("{2}", pagedObject.hasPrivateFlag() ? diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 72aff47c37..3069f15649 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.enums.MemberRemoveReason; import com.bgsoftware.superiorskyblock.api.enums.Rating; -import com.bgsoftware.superiorskyblock.api.hooks.LazyWorldsProvider; import com.bgsoftware.superiorskyblock.api.island.BlockChangeResult; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandBlockFlags; @@ -3787,7 +3786,7 @@ public void warpPlayer(SuperiorPlayer superiorPlayer, String warpName, boolean f } EntityTeleports.warmupTeleport(superiorPlayer, plugin.getSettings().getWarpsWarmup(), - unused -> warpPlayerWithoutWarmup(superiorPlayer, islandWarp, true)); + unused -> warpPlayerWithoutWarmup(superiorPlayer, islandWarp)); } @Override @@ -3817,7 +3816,7 @@ public void deleteWarp(String name) { WarpCategory warpCategory = islandWarp == null ? null : islandWarp.getCategory(); if (islandWarp != null) { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { Location location = islandWarp.getLocation(wrapper.getHandle()); this.warpsByLocation.write(warpsByLocation -> warpsByLocation.remove(location)); } @@ -4702,7 +4701,7 @@ public IslandWarp loadIslandWarp(String name, LazyWorldLocation location, @Nulla if (warpCategory == null) warpCategory = warpCategories.values().stream().findFirst().orElseGet(() -> createWarpCategory("Default Category")); - IslandWarp islandWarp = new SIslandWarp(name, location.clone(true), warpCategory, isPrivate, icon); + IslandWarp islandWarp = new SIslandWarp(name, location, warpCategory, isPrivate, icon); islandWarp.getCategory().getWarps().add(islandWarp); @@ -4824,7 +4823,25 @@ public void syncUpgrades(boolean overrideCustom) { * Island top methods */ - private void warpPlayerWithoutWarmup(SuperiorPlayer superiorPlayer, IslandWarp islandWarp, boolean shouldRetryOnNullWorld) { + private void warpPlayerWithoutWarmup(SuperiorPlayer superiorPlayer, IslandWarp islandWarp) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { + Location location = islandWarp.getLocation(wrapper.getHandle()); + + if (location.getWorld() == null) { + Location clonedLocation = location.clone(); + IslandWorlds.accessIslandWorldAsync(this, location, true, islandWorldResult -> { + islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { + clonedLocation.setWorld(world); + warpPlayerWithoutWarmupWorldLoaded(superiorPlayer, islandWarp, clonedLocation); + }); + }); + } else { + warpPlayerWithoutWarmupWorldLoaded(superiorPlayer, islandWarp, location); + } + } + } + + private void warpPlayerWithoutWarmupWorldLoaded(SuperiorPlayer superiorPlayer, IslandWarp islandWarp, Location location) { // Warp doesn't exist anymore. if (getWarp(islandWarp.getName()) == null) { Message.INVALID_WARP.send(superiorPlayer, islandWarp.getName()); @@ -4832,38 +4849,24 @@ private void warpPlayerWithoutWarmup(SuperiorPlayer superiorPlayer, IslandWarp i return; } - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = islandWarp.getLocation(wrapper.getHandle()); - if (location.getWorld() == null) { - if (shouldRetryOnNullWorld && location instanceof LazyWorldLocation && - plugin.getProviders().getWorldsProvider() instanceof LazyWorldsProvider) { - LazyWorldsProvider worldsProvider = (LazyWorldsProvider) plugin.getProviders().getWorldsProvider(); - WorldInfo worldInfo = worldsProvider.getIslandsWorldInfo(this, ((LazyWorldLocation) location).getWorldName()); - worldsProvider.prepareWorld(this, worldInfo.getDimension(), - () -> warpPlayerWithoutWarmup(superiorPlayer, islandWarp, false)); - return; - } - } - - superiorPlayer.setTeleportTask(null); + superiorPlayer.setTeleportTask(null); - if (!isInsideRange(location) || !WorldBlocks.isSafeBlock(location.getBlock())) { - Message.UNSAFE_WARP.send(superiorPlayer); - if (plugin.getSettings().getDeleteUnsafeWarps()) - deleteWarp(islandWarp.getName()); - return; - } + if (!isInsideRange(location) || !WorldBlocks.isSafeBlock(location.getBlock())) { + Message.UNSAFE_WARP.send(superiorPlayer); + if (plugin.getSettings().getDeleteUnsafeWarps()) + deleteWarp(islandWarp.getName()); + return; + } - superiorPlayer.teleport(location, success -> { - if (success) { - Message.TELEPORTED_TO_WARP.send(superiorPlayer); - if (superiorPlayer.isShownAsOnline()) { - IslandUtils.sendMessage(this, Message.TELEPORTED_TO_WARP_ANNOUNCEMENT, - Collections.singletonList(superiorPlayer.getUniqueId()), superiorPlayer.getName(), islandWarp.getName()); - } + superiorPlayer.teleport(location, success -> { + if (success) { + Message.TELEPORTED_TO_WARP.send(superiorPlayer); + if (superiorPlayer.isShownAsOnline()) { + IslandUtils.sendMessage(this, Message.TELEPORTED_TO_WARP_ANNOUNCEMENT, + Collections.singletonList(superiorPlayer.getUniqueId()), superiorPlayer.getName(), islandWarp.getName()); } - }); - } + } + }); } /* diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java index 4a2553c509..e6d2a201ac 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.logging.Debug; @@ -20,13 +21,13 @@ public class SIslandWarp implements IslandWarp { private final WarpCategory warpCategory; private String name; - private Location location; + private LazyWorldLocation location; private boolean isPrivate; private ItemStack icon; - public SIslandWarp(String name, Location location, WarpCategory warpCategory, boolean isPrivate, @Nullable ItemStack icon) { + public SIslandWarp(String name, LazyWorldLocation location, WarpCategory warpCategory, boolean isPrivate, @Nullable ItemStack icon) { this.name = name; - this.location = location.clone(); + this.location = (LazyWorldLocation) location.clone(true); this.warpCategory = warpCategory; this.isPrivate = isPrivate; this.icon = icon; @@ -62,12 +63,17 @@ public Location getLocation() { @Override public Location getLocation(Location location) { if (location != null) { - location.setWorld(this.location.getWorld()); location.setX(this.location.getX()); location.setY(this.location.getY()); location.setZ(this.location.getZ()); location.setYaw(this.location.getYaw()); location.setPitch(this.location.getPitch()); + + if (location instanceof LazyWorldLocation) { + ((LazyWorldLocation) location).setWorldName(this.location.getWorldName()); + } else { + location.setWorld(this.location.getWorld()); + } } return location; @@ -79,7 +85,7 @@ public void setLocation(Location location) { Log.debug(Debug.SET_WARP_LOCATION, getOwnerName(), this.name, location); - this.location = location.clone(); + this.location = LazyWorldLocation.of(location); IslandsDatabaseBridge.updateWarpLocation(getIsland(), this); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java index bb98916ce4..5cd3bb8586 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SignWarp.java @@ -2,8 +2,13 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.IslandWorlds; +import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -24,8 +29,32 @@ private SignWarp() { } public static void trySignWarpBreak(IslandWarp islandWarp, CommandSender commandSender) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { + Location warpLocation = islandWarp.getLocation(wrapper.getHandle()); + + if (warpLocation.getWorld() == null) { + IslandWorlds.accessIslandWorldAsync(islandWarp.getIsland(), warpLocation, true, islandWorldResult -> { + islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(unused -> { + trySignWarpBreakWorldLoaded(islandWarp, commandSender); + }); + }); + return; + } + } + + trySignWarpBreakWorldLoaded(islandWarp, commandSender); + } + + private static void trySignWarpBreakWorldLoaded(IslandWarp islandWarp, CommandSender commandSender) { + ChunksProvider.loadChunk(ChunkPosition.of(islandWarp), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { + trySignWarpBreakChunkLoaded(islandWarp, commandSender); + }); + } + + private static void trySignWarpBreakChunkLoaded(IslandWarp islandWarp, CommandSender commandSender) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location warpLocation = islandWarp.getLocation(wrapper.getHandle()); + Block signBlock = warpLocation.getBlock(); BlockState blockState = signBlock.getState(); From 0ad3af2383ec3bde881d0786e9e9f3db62f6804b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 6 Oct 2025 15:02:38 +0300 Subject: [PATCH 360/600] Potential fix for the plugin not properly shutting down its tasks (#2687) --- .../SuperiorSkyblockPlugin.java | 4 +- .../core/threads/BukkitExecutor.java | 89 +++++++++++++++---- 2 files changed, 74 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index f90372a7c9..a837a54e43 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -327,7 +327,7 @@ public void onEnable() { public void onDisable() { try { if (loadingStage.isAtLeast(PluginLoadingStage.START_ENABLE)) - BukkitExecutor.prepareDisable(); + BukkitExecutor.prepareShutdown(); if (loadingStage.isAtLeast(PluginLoadingStage.CHUNKS_PROVIDER_INITIALIZED)) ChunksProvider.stop(); @@ -376,7 +376,7 @@ public void onDisable() { if (loadingStage.isAtLeast(PluginLoadingStage.START_ENABLE)) { Log.info("Shutting down executor"); - BukkitExecutor.close(); + BukkitExecutor.close(plugin); } if (loadingStage.isAtLeast(PluginLoadingStage.MANAGERS_INITIALIZED)) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java index 7ee2849bcf..69f82bd3ba 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java @@ -5,14 +5,18 @@ import org.bukkit.scheduler.BukkitTask; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.Function; public class BukkitExecutor { private static SuperiorSkyblockPlugin plugin; - private static boolean shutdown = false; - private static boolean syncBukkitCalls = false; + private static State state = State.RUNNING; + + private static final AtomicLong ACTIVE_TASKS_COUNT = new AtomicLong(0); + private static final CountDownLatch WAITABLE = new CountDownLatch(1); private BukkitExecutor() { @@ -26,7 +30,7 @@ public static void ensureMain(Runnable runnable) { if (ensureNotShudown()) return; - if (!syncBukkitCalls && !Bukkit.isPrimaryThread()) { + if (state != State.PREPARE_SHUTDOWN && !Bukkit.isPrimaryThread()) { sync(runnable); } else { runnable.run(); @@ -41,7 +45,7 @@ public static BukkitTask sync(Runnable runnable, long delay) { if (ensureNotShudown()) return null; - if (syncBukkitCalls) { + if (state == State.PREPARE_SHUTDOWN) { runnable.run(); return null; } else { @@ -53,7 +57,7 @@ public static void async(Runnable runnable) { if (ensureNotShudown()) return; - if (syncBukkitCalls) { + if (state == State.PREPARE_SHUTDOWN) { runnable.run(); } else { Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable); @@ -64,7 +68,7 @@ public static void async(Runnable runnable, long delay) { if (ensureNotShudown()) return; - if (syncBukkitCalls) { + if (state == State.PREPARE_SHUTDOWN) { runnable.run(); } else { Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay); @@ -89,16 +93,28 @@ public static NestedTask createTask() { return new NestedTask().complete(); } - public static void prepareDisable() { - syncBukkitCalls = true; + public static void prepareShutdown() { + state = State.PREPARE_SHUTDOWN; } - public static void close() { - shutdown = true; + public static void close(SuperiorSkyblockPlugin plugin) { + // Waiting for all active tasks to finish + + try { + WAITABLE.await(); + } catch (Throwable ignored) { + } + + if (ACTIVE_TASKS_COUNT.get() != 0) { + new RuntimeException("Not all active tasks finished").printStackTrace(); + } + + state = State.SHUTDOWN; + Bukkit.getScheduler().cancelTasks(plugin); } private static boolean ensureNotShudown() { - if (shutdown) { + if (state == State.SHUTDOWN) { new RuntimeException("Tried to call BukkitExecutor after it was shut down").printStackTrace(); return true; } @@ -114,48 +130,68 @@ public static class NestedTask { } public NestedTask runSync(Function function) { + ensureNotShudown(); + NestedTask nestedTask = new NestedTask<>(); - if (syncBukkitCalls) { + if (state == State.PREPARE_SHUTDOWN) { nestedTask.value.complete(function.apply(value.join())); } else { - value.whenComplete((value, ex) -> BukkitExecutor.ensureMain(() -> nestedTask.value.complete(function.apply(value)))); + nestedTask.onCreate(); + value.whenComplete((value, ex) -> BukkitExecutor.ensureMain(() -> { + nestedTask.value.complete(function.apply(value)); + onComplete(); + })); } return nestedTask; } public NestedTask runSync(Consumer consumer) { + ensureNotShudown(); + NestedTask nestedTask = new NestedTask<>(); - if (syncBukkitCalls) { + if (state == State.PREPARE_SHUTDOWN) { consumer.accept(value.join()); nestedTask.value.complete(null); } else { + nestedTask.onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.ensureMain(() -> { consumer.accept(value); nestedTask.value.complete(null); + onComplete(); })); } return nestedTask; } public NestedTask runAsync(Function function) { + ensureNotShudown(); + NestedTask nestedTask = new NestedTask<>(); - if (syncBukkitCalls) { + if (state == State.PREPARE_SHUTDOWN) { nestedTask.value.complete(function.apply(value.join())); } else { - value.whenComplete((value, ex) -> BukkitExecutor.async(() -> nestedTask.value.complete(function.apply(value)))); + nestedTask.onCreate(); + value.whenComplete((value, ex) -> BukkitExecutor.async(() -> { + nestedTask.value.complete(function.apply(value)); + onComplete(); + })); } return nestedTask; } public NestedTask runAsync(Consumer consumer) { + ensureNotShudown(); + NestedTask nestedTask = new NestedTask<>(); - if (syncBukkitCalls) { + if (state == State.PREPARE_SHUTDOWN) { consumer.accept(value.join()); nestedTask.value.complete(null); } else { + nestedTask.onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.async(() -> { consumer.accept(value); nestedTask.value.complete(null); + onComplete(); })); } return nestedTask; @@ -166,6 +202,25 @@ private NestedTask complete() { return this; } + private void onCreate() { + ACTIVE_TASKS_COUNT.incrementAndGet(); + } + + private void onComplete() { + long current = ACTIVE_TASKS_COUNT.decrementAndGet(); + if (current == 0) { + WAITABLE.countDown(); + } + } + + } + + private enum State { + + RUNNING, + PREPARE_SHUTDOWN, + SHUTDOWN + } } From 02007b7238c882f311f571b6dc523e80f75bafab Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 6 Oct 2025 15:26:24 +0300 Subject: [PATCH 361/600] Add debug messages & maximum wait time for shutting down tasks --- .../superiorskyblock/core/logging/Debug.java | 1 + .../core/threads/BukkitExecutor.java | 43 ++++++++++++------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java index 90576d04be..61ba7da6f0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java @@ -132,6 +132,7 @@ public enum Debug { FIND_SAFE_TELEPORT, PERMISSION_LOOKUP, REPLACE_PLAYER, + TRACK_TASK, SHOW_STACKTRACE, PROFILER; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java index 69f82bd3ba..a3cd9a0d73 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java @@ -1,22 +1,25 @@ package com.bgsoftware.superiorskyblock.core.threads; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.core.logging.Debug; +import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.Bukkit; import org.bukkit.scheduler.BukkitTask; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; import java.util.function.Function; public class BukkitExecutor { + private static final int DEFAULT_SHUTDOWN_TIMEOUT = 1000 * 20; + private static final int SHUTDOWN_INTERVAL_WAIT_TIME = 100; + private static SuperiorSkyblockPlugin plugin; private static State state = State.RUNNING; private static final AtomicLong ACTIVE_TASKS_COUNT = new AtomicLong(0); - private static final CountDownLatch WAITABLE = new CountDownLatch(1); private BukkitExecutor() { @@ -100,9 +103,16 @@ public static void prepareShutdown() { public static void close(SuperiorSkyblockPlugin plugin) { // Waiting for all active tasks to finish - try { - WAITABLE.await(); - } catch (Throwable ignored) { + Log.info("This can take up to " + (DEFAULT_SHUTDOWN_TIMEOUT / 1000) + " seconds to complete"); + + long timeoutLeft = DEFAULT_SHUTDOWN_TIMEOUT; + + while (ACTIVE_TASKS_COUNT.get() != 0 && timeoutLeft > 0) { + try { + Thread.sleep(SHUTDOWN_INTERVAL_WAIT_TIME); + timeoutLeft -= SHUTDOWN_INTERVAL_WAIT_TIME; + } catch (Throwable ignored) { + } } if (ACTIVE_TASKS_COUNT.get() != 0) { @@ -136,7 +146,7 @@ public NestedTask runSync(Function function) { if (state == State.PREPARE_SHUTDOWN) { nestedTask.value.complete(function.apply(value.join())); } else { - nestedTask.onCreate(); + onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.ensureMain(() -> { nestedTask.value.complete(function.apply(value)); onComplete(); @@ -153,7 +163,7 @@ public NestedTask runSync(Consumer consumer) { consumer.accept(value.join()); nestedTask.value.complete(null); } else { - nestedTask.onCreate(); + onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.ensureMain(() -> { consumer.accept(value); nestedTask.value.complete(null); @@ -170,7 +180,7 @@ public NestedTask runAsync(Function function) { if (state == State.PREPARE_SHUTDOWN) { nestedTask.value.complete(function.apply(value.join())); } else { - nestedTask.onCreate(); + onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.async(() -> { nestedTask.value.complete(function.apply(value)); onComplete(); @@ -187,7 +197,7 @@ public NestedTask runAsync(Consumer consumer) { consumer.accept(value.join()); nestedTask.value.complete(null); } else { - nestedTask.onCreate(); + onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.async(() -> { consumer.accept(value); nestedTask.value.complete(null); @@ -202,14 +212,17 @@ private NestedTask complete() { return this; } - private void onCreate() { - ACTIVE_TASKS_COUNT.incrementAndGet(); + private static void onCreate() { + long curr = ACTIVE_TASKS_COUNT.incrementAndGet(); + Log.debug(Debug.TRACK_TASK, curr); } - private void onComplete() { - long current = ACTIVE_TASKS_COUNT.decrementAndGet(); - if (current == 0) { - WAITABLE.countDown(); + private static void onComplete() { + long curr = ACTIVE_TASKS_COUNT.decrementAndGet(); + Log.debug(Debug.TRACK_TASK, curr); + if (curr < 0) { + new RuntimeException("Active tasks count is less than 0").printStackTrace(); + ACTIVE_TASKS_COUNT.set(0); } } From 630d2950db20a1cdf93e79a52f314c5034221ae5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 7 Oct 2025 13:53:07 +0300 Subject: [PATCH 362/600] Fix many issues regarding tracking of block changes when golems are created from structures (#2695) --- .../core/key/ConstantKeys.java | 47 ++++++----- .../listener/BlockChangesListener.java | 59 ++++++++++++-- .../listener/StackedBlocksListener.java | 78 ++++++++++++------- .../upgrades/type/UpgradeTypeBlockLimits.java | 17 ++++ 4 files changed, 148 insertions(+), 53 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java index 6c16863451..f7b9509f4b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java @@ -1,38 +1,41 @@ package com.bgsoftware.superiorskyblock.core.key; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.Materials; import org.bukkit.Material; import org.bukkit.entity.EntityType; -import javax.annotation.Nullable; import java.util.Optional; public class ConstantKeys { - public static final Key HOPPER = Keys.of(Material.HOPPER); - public static final Key WATER = Keys.of(Material.WATER); - public static final Key LAVA = Keys.of(Material.LAVA); - public static final Key DRAGON_EGG = Keys.of(Material.DRAGON_EGG); - public static final Key OBSIDIAN = Keys.of(Material.OBSIDIAN); - public static final Key COMMAND_BLOCK = Keys.of(EnumHelper.getEnum(Material.class, "COMMAND_BLOCK", "COMMAND")); - public static final Key TNT = Keys.of(Material.TNT); - public static final Key FURNACE = Keys.of(Material.FURNACE); - public static final Key CHEST = Keys.of(Material.CHEST); public static final Key AIR = Keys.of(Material.AIR); + @Nullable + public static final Key BASALT = Optional.ofNullable(EnumHelper.getEnum(Material.class, "BASALT")) + .map(Keys::of).orElse(null); + public static final Key CARVED_PUMPKIN = Keys.of(EnumHelper.getEnum(Material.class, "CARVED_PUMPKIN", "PUMPKIN")); public static final Key CAULDRON = Keys.of(Material.CAULDRON); + public static final Key CHEST = Keys.of(Material.CHEST); + public static final Key COBBLESTONE = Keys.of(Material.COBBLESTONE); + public static final Key COMMAND_BLOCK = Keys.of(EnumHelper.getEnum(Material.class, "COMMAND_BLOCK", "COMMAND")); public static final Key EGG_MOB_SPAWNER = Keys.ofSpawner("EGG"); - public static final Key MOB_SPAWNER = Keys.of(Materials.SPAWNER.toBukkitType()); - public static final Key END_PORTAL_FRAME_WITH_EYE = Keys.of(Materials.END_PORTAL_FRAME.toBukkitType(), (short) 7); public static final Key END_PORTAL_FRAME = Keys.of(Materials.END_PORTAL_FRAME.toBukkitType()); - public static final Key WET_SPONGE = Keys.of(EnumHelper.getEnum(Material.class, "WET_SPONGE", "SPONGE")); - public static final Key COBBLESTONE = Keys.of(Material.COBBLESTONE); + public static final Key END_PORTAL_FRAME_WITH_EYE = Keys.of(Materials.END_PORTAL_FRAME.toBukkitType(), (short) 7); + public static final Key FURNACE = Keys.of(Material.FURNACE); + public static final Key HOPPER = Keys.of(Material.HOPPER); @Nullable - public static final Key BASALT = Optional.ofNullable(EnumHelper.getEnum(Material.class, "BASALT")) - .map(Keys::of).orElse(null); - public static final Key CHORUS_FLOWER = Optional.ofNullable(EnumHelper.getEnum(Material.class, "CHORUS_FLOWER")) - .map(Keys::of).orElse(Keys.EMPTY); + public static final Key IRON_BLOCK = Keys.of(Material.IRON_BLOCK); + public static final Key LAVA = Keys.of(Material.LAVA); + public static final Key MOB_SPAWNER = Keys.of(Materials.SPAWNER.toBukkitType()); + public static final Key OBSIDIAN = Keys.of(Material.OBSIDIAN); + public static final Key SNOW_BLOCK = Keys.of(Material.SNOW_BLOCK); + public static final Key SOUL_SAND = Keys.of(Material.SOUL_SAND); + public static final Key TNT = Keys.of(Material.TNT); + public static final Key WATER = Keys.of(Material.WATER); + public static final Key WET_SPONGE = Keys.of(EnumHelper.getEnum(Material.class, "WET_SPONGE", "SPONGE")); + public static final Key WITHER_SKELETON_SKULL = initializeWitherSkeletonSkullKey(); public static final Key ENTITY_MINECART_COMMAND = Keys.of(EntityType.MINECART_COMMAND); public static final Key ENTITY_MINECART_CHEST = Keys.of(EntityType.MINECART_CHEST); @@ -45,4 +48,12 @@ private ConstantKeys() { } + private static Key initializeWitherSkeletonSkullKey() { + Material newSkullMaterial = EnumHelper.getEnum(Material.class, "WITHER_SKELETON_SKULL"); + if (newSkullMaterial != null) + return Keys.of(newSkullMaterial); + + return Keys.of(Material.SKULL_ITEM, (byte) 1); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index 05620ba373..2181bebeb7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -27,14 +27,17 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Item; import org.bukkit.entity.Minecart; +import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; import org.bukkit.event.block.Action; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.inventory.ItemStack; import java.util.Collection; @@ -49,6 +52,8 @@ public class BlockChangesListener extends AbstractGameEventListener { private static final Material CHORUS_FLOWER = EnumHelper.getEnum(Material.class, "CHORUS_FLOWER"); @Nullable private static final Material POINTED_DRIPSTONE = EnumHelper.getEnum(Material.class, "POINTED_DRIPSTONE"); + @Nullable + private static final CreatureSpawnEvent.SpawnReason BUILD_COPPERGOLEM = EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "BUILD_COPPERGOLEM"); @WorldRecordFlags private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS; @@ -162,9 +167,8 @@ private void onBlockForm(GameEvent e) { BlockState newState = e.getArgs().newState; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location location = newState.getLocation(wrapper.getHandle()); - // Do not save block counts - this.worldRecordService.get().recordBlockBreak(Keys.of(block), location, 1, WorldRecordFlags.DIRTY_CHUNKS); + Location location = block.getLocation(wrapper.getHandle()); + this.worldRecordService.get().recordBlockPlace(Keys.of(newState), location, 1, block.getState(), REGULAR_RECORD_FLAGS); } } @@ -243,6 +247,9 @@ private void onSpawnerChange(GameEvent e) { } private void onEntityChangeBlock(GameEvent e) { + if (e.getArgs().entity instanceof Player) + return; + Block block = e.getArgs().block; // We do not care about spawn island, and therefore only island worlds are relevant. @@ -311,16 +318,23 @@ private void onBucketFill(GameEvent e) { } } - private void onDragonEggDrop(GameEvent e) { + private void onEntitySpawn(GameEvent e) { Entity entity = e.getArgs().entity; - if (!(entity instanceof Item)) - return; - // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) return; + onDragonEggDrop(e); + onGolemStructure(e); + } + + private void onDragonEggDrop(GameEvent e) { + Entity entity = e.getArgs().entity; + + if (!(entity instanceof Item)) + return; + Item item = (Item) entity; if (item.getItemStack().getType() != Material.DRAGON_EGG) @@ -338,6 +352,35 @@ private void onDragonEggDrop(GameEvent e) { } } + private void onGolemStructure(GameEvent e) { + CreatureSpawnEvent.SpawnReason spawnReason = e.getArgs().spawnReason; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = e.getArgs().entity.getLocation(wrapper.getHandle()); + + if (spawnReason == CreatureSpawnEvent.SpawnReason.BUILD_IRONGOLEM) { + this.worldRecordService.get().recordBlockBreak(ConstantKeys.IRON_BLOCK, entityLocation, 4, 0); + this.worldRecordService.get().recordBlockBreak(ConstantKeys.CARVED_PUMPKIN, entityLocation, 1, REGULAR_RECORD_FLAGS); + } else if (spawnReason == CreatureSpawnEvent.SpawnReason.BUILD_SNOWMAN) { + this.worldRecordService.get().recordBlockBreak(ConstantKeys.SNOW_BLOCK, entityLocation, 2, 0); + this.worldRecordService.get().recordBlockBreak(ConstantKeys.CARVED_PUMPKIN, entityLocation, 1, REGULAR_RECORD_FLAGS); + } else if (spawnReason == CreatureSpawnEvent.SpawnReason.BUILD_WITHER) { + this.worldRecordService.get().recordBlockBreak(ConstantKeys.SOUL_SAND, entityLocation, 4, 0); + this.worldRecordService.get().recordBlockBreak(ConstantKeys.WITHER_SKELETON_SKULL, entityLocation, 3, REGULAR_RECORD_FLAGS); + } else if (spawnReason == BUILD_COPPERGOLEM) { + Block copperOrChestBlock = entityLocation.getBlock().getRelative(BlockFace.DOWN); + Key copperBlock = Keys.of(copperOrChestBlock); + this.worldRecordService.get().recordBlockBreak(copperBlock, entityLocation, 1, 0); + this.worldRecordService.get().recordBlockBreak(ConstantKeys.CARVED_PUMPKIN, entityLocation, 1, 0); + BukkitExecutor.sync(() -> { + Key chestBlock = Keys.of(copperOrChestBlock); + this.worldRecordService.get().recordBlockPlace(chestBlock, entityLocation, 1, null, REGULAR_RECORD_FLAGS); + }, 1L); + } + } + + } + private void onPistonExtend(GameEvent e) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) @@ -483,7 +526,7 @@ private void registerListeners() { registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.MONITOR, this::onBlockBreak); registerCallback(GameEventType.BLOCK_DESTROY_EVENT, GameEventPriority.MONITOR, this::onBlockDestroy); registerCallback(GameEventType.PLAYER_FILL_BUCKET_EVENT, GameEventPriority.MONITOR, this::onBucketFill); - registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.MONITOR, this::onDragonEggDrop); + registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.MONITOR, this::onEntitySpawn); registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.MONITOR, this::onPistonExtend); registerCallback(GameEventType.LEAVES_DECAY_EVENT, GameEventPriority.MONITOR, this::onLeavesDecay); registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.MONITOR, this::onBlockFromTo); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java index ba383a0697..5042045ed3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/StackedBlocksListener.java @@ -15,6 +15,7 @@ import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.impl.internal.StackedBlocksDepositMenu; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; @@ -24,16 +25,17 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.block.Action; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.inventory.ItemStack; -import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -42,6 +44,11 @@ public class StackedBlocksListener extends AbstractGameEventListener { @Nullable private static final Material COPPER_BLOCK = EnumHelper.getEnum(Material.class, "COPPER_BLOCK"); private static final Material HONEYCOMB = EnumHelper.getEnum(Material.class, "HONEYCOMB"); + @Nullable + private static final CreatureSpawnEvent.SpawnReason BUILD_COPPERGOLEM = EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "BUILD_COPPERGOLEM"); + @Nullable + private static final Material COPPER_CHEST = EnumHelper.getEnum(Material.class, "COPPER_CHEST"); + private final Map> ENTITY_TEMPLATE_OFFSETS = buildEntityTemplateOffsetsMap(); private final LazyReference stackedBlocksInteractionService = new LazyReference() { @@ -296,12 +303,23 @@ private void onGolemCreate(GameEvent e) { for (BlockOffset blockOffset : entityTemplateOffsets) { if (plugin.getStackedBlocks().getStackedBlockAmount(blockOffset.applyToLocation(entityLocation)) > 1) { e.setCancelled(); + if (e.getArgs().spawnReason == BUILD_COPPERGOLEM) + onCopperGolemCancel(entityLocation); return; } } } } + private void onCopperGolemCancel(Location entityLocation) { + Block copperChestBlock = entityLocation.getBlock().getRelative(BlockFace.DOWN); + BukkitExecutor.sync(() -> { + if (copperChestBlock.getType() == COPPER_CHEST) { + copperChestBlock.setType(COPPER_BLOCK); + } + }, 1L); + } + private void onSpongeAbsorb(GameEvent e) { // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(e.getArgs().block.getWorld())) @@ -349,32 +367,38 @@ private void registerListeners() { private static Map> buildEntityTemplateOffsetsMap() { EnumMap> offsetsMap = new EnumMap<>(CreatureSpawnEvent.SpawnReason.class); - offsetsMap.put(CreatureSpawnEvent.SpawnReason.BUILD_IRONGOLEM, Arrays.asList( - SBlockOffset.fromOffsets(0, 1, 0), - SBlockOffset.fromOffsets(1, 1, 0), - SBlockOffset.fromOffsets(1, 1, 1), - SBlockOffset.fromOffsets(-1, 1, 0), - SBlockOffset.fromOffsets(-1, 1, -1), - SBlockOffset.fromOffsets(0, 2, 0) - )); - - offsetsMap.put(CreatureSpawnEvent.SpawnReason.BUILD_SNOWMAN, Arrays.asList( - SBlockOffset.fromOffsets(0, 1, 0), - SBlockOffset.fromOffsets(0, 2, 0) - )); - - offsetsMap.put(CreatureSpawnEvent.SpawnReason.BUILD_WITHER, Arrays.asList( - SBlockOffset.fromOffsets(0, 1, 0), - SBlockOffset.fromOffsets(1, 1, 0), - SBlockOffset.fromOffsets(1, 1, 1), - SBlockOffset.fromOffsets(-1, 1, 0), - SBlockOffset.fromOffsets(-1, 1, -1), - SBlockOffset.fromOffsets(0, 2, 0), - SBlockOffset.fromOffsets(1, 2, 0), - SBlockOffset.fromOffsets(1, 2, 1), - SBlockOffset.fromOffsets(-1, 2, 0), - SBlockOffset.fromOffsets(-1, 2, -1) - )); + List blockOffsets = new LinkedList<>(); + blockOffsets.add(SBlockOffset.fromOffsets(0, 1, 0)); + blockOffsets.add(SBlockOffset.fromOffsets(1, 1, 0)); + blockOffsets.add(SBlockOffset.fromOffsets(1, 1, 1)); + blockOffsets.add(SBlockOffset.fromOffsets(-1, 1, 0)); + blockOffsets.add(SBlockOffset.fromOffsets(-1, 1, -1)); + blockOffsets.add(SBlockOffset.fromOffsets(0, 2, 0)); + offsetsMap.put(CreatureSpawnEvent.SpawnReason.BUILD_IRONGOLEM, blockOffsets); + + blockOffsets = new LinkedList<>(); + blockOffsets.add(SBlockOffset.fromOffsets(0, 1, 0)); + blockOffsets.add(SBlockOffset.fromOffsets(0, 2, 0)); + offsetsMap.put(CreatureSpawnEvent.SpawnReason.BUILD_SNOWMAN, blockOffsets); + + blockOffsets = new LinkedList<>(); + blockOffsets.add(SBlockOffset.fromOffsets(0, 1, 0)); + blockOffsets.add(SBlockOffset.fromOffsets(1, 1, 0)); + blockOffsets.add(SBlockOffset.fromOffsets(1, 1, 1)); + blockOffsets.add(SBlockOffset.fromOffsets(-1, 1, 0)); + blockOffsets.add(SBlockOffset.fromOffsets(-1, 1, -1)); + blockOffsets.add(SBlockOffset.fromOffsets(0, 2, 0)); + blockOffsets.add(SBlockOffset.fromOffsets(1, 2, 0)); + blockOffsets.add(SBlockOffset.fromOffsets(1, 2, 1)); + blockOffsets.add(SBlockOffset.fromOffsets(-1, 2, 0)); + blockOffsets.add(SBlockOffset.fromOffsets(-1, 2, -1)); + offsetsMap.put(CreatureSpawnEvent.SpawnReason.BUILD_WITHER, blockOffsets); + + if (BUILD_COPPERGOLEM != null) { + blockOffsets = new LinkedList<>(); + blockOffsets.add(SBlockOffset.fromOffsets(0, -1, 0)); + offsetsMap.put(BUILD_COPPERGOLEM, blockOffsets); + } return Collections.unmodifiableMap(offsetsMap); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java index 633596008f..db170c41c6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java @@ -23,6 +23,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockDispenseEvent; +import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.BlockGrowEvent; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.player.PlayerBucketEmptyEvent; @@ -257,6 +258,22 @@ public void onStructureGrow(StructureGrowEvent e) { e.getBlocks().removeIf(blockState -> island.hasReachedBlockLimit(Keys.of(blockState))); } + @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) + public void onBlockForm(BlockFormEvent e) { + Island island; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + island = plugin.getGrid().getIslandAt(e.getBlock().getLocation(wrapper.getHandle())); + } + if (island == null) + return; + + Key blockKey = Keys.of(e.getNewState()); + + if (island.hasReachedBlockLimit(blockKey)) { + e.setCancelled(true); + } + } + } From d97ece6dc4bac02fa4eab2ebe6b5f0fffeed5122 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 7 Oct 2025 18:40:06 +0300 Subject: [PATCH 363/600] Use BlockPosition / WorldPosition whenever possible --- .../api/handlers/FactoriesManager.java | 39 + .../api/handlers/GridManager.java | 20 + .../api/hooks/WorldsProvider.java | 19 +- .../api/island/DelegateIsland.java | 428 ++++------ .../superiorskyblock/api/island/Island.java | 754 +++++++----------- .../api/wrappers/BlockPosition.java | 59 +- .../api/wrappers/WorldPosition.java | 107 +++ .../commands/admin/CmdAdminResetWorld.java | 4 +- .../commands/admin/CmdAdminTeleport.java | 11 +- .../commands/player/CmdVisit.java | 4 +- .../superiorskyblock/core/IslandArea.java | 10 +- .../superiorskyblock/core/IslandWorlds.java | 17 +- .../core/LazyWorldLocation.java | 13 +- .../superiorskyblock/core/SBlockPosition.java | 105 ++- .../superiorskyblock/core/SWorldPosition.java | 164 ++++ .../core/collections/EnumerateMap.java | 13 + .../database/bridge/GridDatabaseBridge.java | 9 +- .../bridge/IslandsDatabaseBridge.java | 35 +- .../serialization/IslandsDeserializer.java | 9 +- .../core/factory/FactoriesManagerImpl.java | 33 +- .../core/menu/impl/MenuGlobalWarps.java | 2 +- .../core/serialization/Serializers.java | 6 + .../impl/BlockPositionSerializer.java | 57 ++ .../impl/WorldPositionSerializer.java | 62 ++ .../core/stackedblocks/StackedBlock.java | 17 +- .../StackedBlocksManagerImpl.java | 16 +- .../worlds/WorldsProvider_Default.java | 64 +- .../island/GridManagerImpl.java | 50 +- .../superiorskyblock/island/SIsland.java | 584 +++++--------- .../superiorskyblock/island/SpawnIsland.java | 466 ++++------- .../DefaultIslandCreationAlgorithm.java | 5 +- .../island/builder/IslandBuilderImpl.java | 99 +-- .../listener/SignsListener.java | 4 +- .../player/SSuperiorPlayer.java | 4 +- .../placeholders/PlaceholdersServiceImpl.java | 28 +- .../portals/PortalsManagerServiceImpl.java | 2 +- .../schematic/SchematicsManagerImpl.java | 4 +- 37 files changed, 1647 insertions(+), 1676 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/WorldPosition.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/SWorldPosition.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/BlockPositionSerializer.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/WorldPositionSerializer.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java index fbc53e6810..11e56d75e0 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java @@ -15,6 +15,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.World; @@ -122,9 +123,20 @@ public interface FactoriesManager { * @param blockX The x-coords of the block. * @param blockY The y-coords of the block. * @param blockZ The z-coords of the block. + * @deprecated See {@link #createBlockPosition(int, int, int)} */ + @Deprecated BlockPosition createBlockPosition(String world, int blockX, int blockY, int blockZ); + /** + * Create a {@link BlockPosition} object from given block coords. + * + * @param blockX The x-coords of the block. + * @param blockY The y-coords of the block. + * @param blockZ The z-coords of the block. + */ + BlockPosition createBlockPosition(int blockX, int blockY, int blockZ); + /** * Create a {@link BlockPosition} object from a location. * @@ -132,6 +144,33 @@ public interface FactoriesManager { */ BlockPosition createBlockPosition(Location location); + /** + * Create a {@link WorldPosition} object from given world coords. + * + * @param x The x-coords of the position. + * @param y The y-coords of the position. + * @param z The z-coords of the position. + */ + WorldPosition createWorldPosition(double x, double y, double z); + + /** + * Create a {@link WorldPosition} object from given world coords. + * + * @param x The x-coords of the position. + * @param y The y-coords of the position. + * @param z The z-coords of the position. + * @param yaw The yaw of the position. + * @param pitch The pitch of the position. + */ + WorldPosition createWorldPosition(double x, double y, double z, float yaw, float pitch); + + /** + * Create a {@link WorldPosition} object from a location. + * + * @param location The location. + */ + WorldPosition createWorldPosition(Location location); + /** * Create a new bank transaction. * diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java index 4fb5ef0a79..ec8dd17287 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.world.algorithm.IslandCreationAlgorithm; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import org.bukkit.Chunk; import org.bukkit.Location; @@ -475,7 +476,11 @@ void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bo /** * Get the location of the last island that was generated. + * The location's getWorld will always return null. + * + * @deprecated See {@link #getLastIslandPosition()} */ + @Deprecated Location getLastIslandLocation(); /** @@ -483,9 +488,24 @@ void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bo * Warning: Do not use this method unless you know what you're doing * * @param location The location to set. + * @deprecated See {@link #setLastIslandPosition(BlockPosition)} */ + @Deprecated void setLastIslandLocation(Location location); + /** + * Get the position of the last island that was generated. + */ + BlockPosition getLastIslandPosition(); + + /** + * Set the position of the last island. + * Warning: Do not use this method unless you know what you're doing + * + * @param blockPosition The position to set. + */ + void setLastIslandPosition(BlockPosition blockPosition); + /** * Get the islands container. */ diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/WorldsProvider.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/WorldsProvider.java index 5aac9025ee..95bc9bbade 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/WorldsProvider.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/WorldsProvider.java @@ -1,8 +1,10 @@ package com.bgsoftware.superiorskyblock.api.hooks; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import org.bukkit.Location; import org.bukkit.World; @@ -62,8 +64,23 @@ default World getIslandsWorld(Island island, World.Environment environment) { * @param maxIslandSize The default maximum island size. * @param islandOwner The owner of the island. * @param islandUUID The UUID of the island. + * @deprecated See {@link #getNextLocation(BlockPosition, int, int, UUID, UUID)} */ - Location getNextLocation(Location previousLocation, int islandsHeight, int maxIslandSize, UUID islandOwner, UUID islandUUID); + default Location getNextLocation(Location previousLocation, int islandsHeight, int maxIslandSize, UUID islandOwner, UUID islandUUID) { + return getNextLocation(SuperiorSkyblockAPI.getFactory().createBlockPosition(previousLocation), + islandsHeight, maxIslandSize, islandOwner, islandUUID); + } + + /** + * Get the location for a new island that is created. + * + * @param previousPosition The position of the previous island that was created. + * @param islandsHeight The default islands height. + * @param maxIslandSize The default maximum island size. + * @param islandOwner The owner of the island. + * @param islandUUID The UUID of the island. + */ + Location getNextLocation(BlockPosition previousPosition, int islandsHeight, int maxIslandSize, UUID islandOwner, UUID islandUUID); /** * Callback upon finishing of creation of islands. diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index 138f748345..9c4a39b49a 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -23,6 +23,7 @@ import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; @@ -225,12 +226,6 @@ public boolean isVisitor(SuperiorPlayer superiorPlayer, boolean checkCoopStatus) return this.handle.isVisitor(superiorPlayer, checkCoopStatus); } - @Override - @Deprecated - public Location getCenter(World.Environment environment) { - return this.handle.getCenter(environment); - } - @Override public Location getCenter(Dimension dimension) { return this.handle.getCenter(dimension); @@ -241,36 +236,9 @@ public BlockPosition getCenterPosition() { return this.handle.getCenterPosition(); } - @Nullable @Override - @Deprecated - public Location getTeleportLocation(World.Environment environment) { - return this.handle.getTeleportLocation(environment); - } - - @Override - @Deprecated - public Map getTeleportLocations() { - return this.handle.getTeleportLocations(); - } - - @Override - @Deprecated - public void setTeleportLocation(Location teleportLocation) { - this.handle.setTeleportLocation(teleportLocation); - } - - @Override - @Deprecated - public void setTeleportLocation(World.Environment environment, @Nullable Location teleportLocation) { - this.handle.setTeleportLocation(environment, teleportLocation); - } - - @Nullable - @Override - @Deprecated - public Location getIslandHome(World.Environment environment) { - return this.handle.getIslandHome(environment); + public CompletableFuture accessIslandWorld(Dimension dimension) { + return this.handle.accessIslandWorld(dimension); } @Override @@ -279,9 +247,8 @@ public Location getIslandHome(Dimension dimension) { } @Override - @Deprecated - public Map getIslandHomes() { - return this.handle.getIslandHomes(); + public WorldPosition getIslandHomePosition(Dimension dimension) { + return this.handle.getIslandHomePosition(dimension); } @Override @@ -290,38 +257,34 @@ public Map getIslandHomesAsDimensions() { } @Override - public void setIslandHome(Location homeLocation) { - this.handle.setIslandHome(homeLocation); + public Map getIslandHomes() { + return this.handle.getIslandHomes(); } @Override - @Deprecated - public void setIslandHome(World.Environment environment, @Nullable Location homeLocation) { - this.handle.setIslandHome(environment, homeLocation); + public void setIslandHome(Location homeLocation) { + this.handle.setIslandHome(homeLocation); } @Override + @Deprecated public void setIslandHome(Dimension dimension, Location homeLocation) { this.handle.setIslandHome(dimension, homeLocation); } - @Nullable @Override - @Deprecated - public Location getVisitorsLocation() { - return this.handle.getVisitorsLocation(); + public void setIslandHome(Dimension dimension, WorldPosition homePosition) { + this.handle.setIslandHome(dimension, homePosition); } - @Nullable @Override - @Deprecated - public Location getVisitorsLocation(World.Environment environment) { - return this.handle.getVisitorsLocation(environment); + public Location getVisitorsLocation(Dimension dimension) { + return this.handle.getVisitorsLocation(dimension); } @Override - public Location getVisitorsLocation(Dimension dimension) { - return this.handle.getVisitorsLocation(dimension); + public WorldPosition getVisitorsPosition(Dimension dimension) { + return this.handle.getVisitorsPosition(dimension); } @Override @@ -329,6 +292,11 @@ public void setVisitorsLocation(@Nullable Location visitorsLocation) { this.handle.setVisitorsLocation(visitorsLocation); } + @Override + public void setVisitorsLocation(Dimension dimension, WorldPosition visitorsPosition) { + this.handle.setVisitorsLocation(dimension, visitorsPosition); + } + @Override public Location getMinimum() { return this.handle.getMinimum(); @@ -380,283 +348,285 @@ public List getAllChunks(@IslandChunkFlags int flags) { } @Override - @Deprecated - public List getAllChunks(World.Environment environment) { - return this.handle.getAllChunks(environment); + public List getAllChunks(Dimension dimension) { + return this.handle.getAllChunks(dimension); } @Override - public List getAllChunks(Dimension dimension) { - return this.handle.getAllChunks(dimension); + public List getAllChunks(Dimension dimension, @IslandChunkFlags int flags) { + return this.handle.getAllChunks(dimension, flags); } @Override - @Deprecated - public List getAllChunks(World.Environment environment, @IslandChunkFlags int flags) { - return this.handle.getAllChunks(environment, flags); + public List getLoadedChunks() { + return this.handle.getLoadedChunks(); } @Override - public List getAllChunks(Dimension dimension, @IslandChunkFlags int flags) { - return this.handle.getAllChunks(dimension, flags); + public List getLoadedChunks(@IslandChunkFlags int flags) { + return this.handle.getLoadedChunks(flags); } @Override - @Deprecated - public List getAllChunks(boolean onlyProtected) { - return this.handle.getAllChunks(onlyProtected); + public List getLoadedChunks(Dimension dimension) { + return this.handle.getLoadedChunks(dimension); } @Override - @Deprecated - public List getAllChunks(World.Environment environment, boolean onlyProtected) { - return this.handle.getAllChunks(environment, onlyProtected); + public List getLoadedChunks(Dimension dimension, @IslandChunkFlags int flags) { + return this.handle.getLoadedChunks(dimension, flags); } @Override - @Deprecated - public List getAllChunks(World.Environment environment, boolean onlyProtected, boolean noEmptyChunks) { - return this.handle.getAllChunks(environment, onlyProtected, noEmptyChunks); + public List> getAllChunksAsync(Dimension dimension) { + return this.handle.getAllChunksAsync(dimension); } @Override - public List getLoadedChunks() { - return this.handle.getLoadedChunks(); + public List> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags) { + return this.handle.getAllChunksAsync(dimension, flags); } @Override - public List getLoadedChunks(@IslandChunkFlags int flags) { - return this.handle.getLoadedChunks(flags); + public List> getAllChunksAsync(Dimension dimension, Consumer onChunkLoad) { + return this.handle.getAllChunksAsync(dimension, onChunkLoad); } @Override - @Deprecated - public List getLoadedChunks(World.Environment environment) { - return this.handle.getLoadedChunks(environment); + public List> getAllChunksAsync(Dimension dimension, + @IslandChunkFlags int flags, + Consumer onChunkLoad) { + return this.handle.getAllChunksAsync(dimension, flags, onChunkLoad); } @Override - public List getLoadedChunks(Dimension dimension) { - return this.handle.getLoadedChunks(dimension); + public void resetChunks() { + this.handle.resetChunks(); } @Override - @Deprecated - public List getLoadedChunks(World.Environment environment, @IslandChunkFlags int flags) { - return this.handle.getLoadedChunks(environment, flags); + public void resetChunks(@Nullable Runnable onFinish) { + this.handle.resetChunks(onFinish); } @Override - public List getLoadedChunks(Dimension dimension, @IslandChunkFlags int flags) { - return this.handle.getLoadedChunks(dimension, flags); + public void resetChunks(Dimension dimension) { + this.handle.resetChunks(dimension); } @Override - @Deprecated - public List getLoadedChunks(boolean onlyProtected, boolean noEmptyChunks) { - return this.handle.getLoadedChunks(onlyProtected, noEmptyChunks); + public void resetChunks(Dimension dimension, Runnable onFinish) { + this.handle.resetChunks(dimension, onFinish); } @Override - @Deprecated - public List getLoadedChunks(World.Environment environment, boolean onlyProtected, boolean noEmptyChunks) { - return this.handle.getLoadedChunks(environment, onlyProtected, noEmptyChunks); + public void resetChunks(@IslandChunkFlags int flags) { + this.handle.resetChunks(flags); } @Override - @Deprecated - public List> getAllChunksAsync(World.Environment environment) { - return this.handle.getAllChunksAsync(environment); + public void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish) { + this.handle.resetChunks(flags, onFinish); } @Override - public List> getAllChunksAsync(Dimension dimension) { - return this.handle.getAllChunksAsync(dimension); + public void resetChunks(Dimension dimension, @IslandChunkFlags int flags) { + this.handle.resetChunks(dimension, flags); } @Override - @Deprecated - public List> getAllChunksAsync(World.Environment environment, @IslandChunkFlags int flags) { - return this.handle.getAllChunksAsync(environment, flags); + public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, Runnable onFinish) { + this.handle.resetChunks(dimension, flags, onFinish); } @Override - public List> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags) { - return this.handle.getAllChunksAsync(dimension, flags); + public boolean isInside(Location location) { + return this.handle.isInside(location); } @Override - @Deprecated - public List> getAllChunksAsync(World.Environment environment, - @Nullable Consumer onChunkLoad) { - return this.handle.getAllChunksAsync(environment, onChunkLoad); + public boolean isInside(Location location, int extraRadius) { + return this.handle.isInside(location, extraRadius); } @Override - public List> getAllChunksAsync(Dimension dimension, Consumer onChunkLoad) { - return this.handle.getAllChunksAsync(dimension, onChunkLoad); + public boolean isInside(Location location, double extraRadius) { + return this.handle.isInside(location, extraRadius); } @Override - @Deprecated - public List> getAllChunksAsync(World.Environment environment, - @IslandChunkFlags int flags, - @Nullable Consumer onChunkLoad) { - return this.handle.getAllChunksAsync(environment, flags, onChunkLoad); + public boolean isInside(BlockPosition blockPosition) { + return this.handle.isInside(blockPosition); } @Override - public List> getAllChunksAsync(Dimension dimension, - @IslandChunkFlags int flags, - Consumer onChunkLoad) { - return this.handle.getAllChunksAsync(dimension, flags, onChunkLoad); + public boolean isInside(BlockPosition blockPosition, int extraRadius) { + return this.handle.isInside(blockPosition, extraRadius); } @Override - @Deprecated - public List> getAllChunksAsync(World.Environment environment, boolean onlyProtected, - @Nullable Consumer onChunkLoad) { - return this.handle.getAllChunksAsync(environment, onlyProtected, onChunkLoad); + public boolean isInside(BlockPosition blockPosition, double extraRadius) { + return this.handle.isInside(blockPosition, extraRadius); } @Override - @Deprecated - public List> getAllChunksAsync(World.Environment environment, boolean onlyProtected, - boolean noEmptyChunks, @Nullable Consumer onChunkLoad) { - return this.handle.getAllChunksAsync(environment, onlyProtected, noEmptyChunks, onChunkLoad); + public boolean isInside(WorldPosition worldPosition) { + return this.handle.isInside(worldPosition); } @Override - public void resetChunks() { - this.handle.resetChunks(); + public boolean isInside(WorldPosition worldPosition, int extraRadius) { + return this.handle.isInside(worldPosition, extraRadius); } @Override - public void resetChunks(@Nullable Runnable onFinish) { - this.handle.resetChunks(onFinish); + public boolean isInside(WorldPosition worldPosition, double extraRadius) { + return this.handle.isInside(worldPosition, extraRadius); } @Override - @Deprecated - public void resetChunks(World.Environment environment) { - this.handle.resetChunks(environment); + public boolean isInside(Chunk chunk) { + return this.handle.isInside(chunk); } @Override - public void resetChunks(Dimension dimension) { - this.handle.resetChunks(dimension); + public boolean isInside(World world, int chunkX, int chunkZ) { + return this.handle.isInside(world, chunkX, chunkZ); } @Override - @Deprecated - public void resetChunks(World.Environment environment, @Nullable Runnable onFinish) { - this.handle.resetChunks(environment, onFinish); + public boolean isInside(World world, int chunkX, int chunkZ, int extraRadius) { + return this.handle.isInside(world, chunkX, chunkZ, extraRadius); } @Override - public void resetChunks(Dimension dimension, Runnable onFinish) { - this.handle.resetChunks(dimension, onFinish); + public boolean isInside(World world, int chunkX, int chunkZ, double extraRadius) { + return this.handle.isInside(world, chunkX, chunkZ, extraRadius); } @Override - public void resetChunks(@IslandChunkFlags int flags) { - this.handle.resetChunks(flags); + public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) { + return this.handle.isInside(worldInfo, chunkX, chunkZ); } @Override - public void resetChunks(@IslandChunkFlags int flags, @Nullable Runnable onFinish) { - this.handle.resetChunks(flags, onFinish); + public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) { + return this.handle.isInside(worldInfo, chunkX, chunkZ, extraRadius); } @Override - @Deprecated - public void resetChunks(World.Environment environment, @IslandChunkFlags int flags) { - this.handle.resetChunks(environment, flags); + public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) { + return this.handle.isInside(worldInfo, chunkX, chunkZ, extraRadius); } @Override - public void resetChunks(Dimension dimension, @IslandChunkFlags int flags) { - this.handle.resetChunks(dimension, flags); + public boolean isInside(int chunkX, int chunkZ) { + return this.handle.isInside(chunkX, chunkZ); } @Override - @Deprecated - public void resetChunks(World.Environment environment, @IslandChunkFlags int flags, @Nullable Runnable onFinish) { - this.handle.resetChunks(environment, flags, onFinish); + public boolean isInside(int chunkX, int chunkZ, int extraRadius) { + return this.handle.isInside(chunkX, chunkZ, extraRadius); } @Override - public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, Runnable onFinish) { - this.handle.resetChunks(dimension, flags, onFinish); + public boolean isInside(int chunkX, int chunkZ, double extraRadius) { + return this.handle.isInside(chunkX, chunkZ, extraRadius); } @Override - @Deprecated - public void resetChunks(World.Environment environment, boolean onlyProtected) { - this.handle.resetChunks(environment, onlyProtected); + public boolean isInsideRange(Location location) { + return this.handle.isInsideRange(location); } @Override - @Deprecated - public void resetChunks(World.Environment environment, boolean onlyProtected, @Nullable Runnable onFinish) { - this.handle.resetChunks(environment, onlyProtected, onFinish); + public boolean isInsideRange(Location location, int extraRadius) { + return this.handle.isInsideRange(location, extraRadius); } @Override - @Deprecated - public void resetChunks(boolean onlyProtected) { - this.handle.resetChunks(onlyProtected); + public boolean isInsideRange(Location location, double extraRadius) { + return this.handle.isInsideRange(location, extraRadius); } @Override - @Deprecated - public void resetChunks(boolean onlyProtected, @Nullable Runnable onFinish) { - this.handle.resetChunks(onlyProtected, onFinish); + public boolean isInsideRange(BlockPosition blockPosition) { + return this.handle.isInsideRange(blockPosition); } @Override - public boolean isInside(Location location) { - return this.handle.isInside(location); + public boolean isInsideRange(BlockPosition blockPosition, int extraRadius) { + return this.handle.isInsideRange(blockPosition, extraRadius); } @Override - public boolean isInside(Location location, int extraRadius) { - return this.handle.isInside(location, extraRadius); + public boolean isInsideRange(BlockPosition blockPosition, double extraRadius) { + return this.handle.isInsideRange(blockPosition, extraRadius); } @Override - public boolean isInside(Location location, double extraRadius) { - return this.handle.isInside(location, extraRadius); + public boolean isInsideRange(WorldPosition worldPosition) { + return this.handle.isInsideRange(worldPosition); } @Override - public boolean isInside(World world, int chunkX, int chunkZ) { - return this.handle.isInside(world, chunkX, chunkZ); + public boolean isInsideRange(WorldPosition worldPosition, int extraRadius) { + return this.handle.isInsideRange(worldPosition, extraRadius); } @Override - public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) { - return this.handle.isInside(worldInfo, chunkX, chunkZ); + public boolean isInsideRange(WorldPosition worldPosition, double extraRadius) { + return this.handle.isInsideRange(worldPosition, extraRadius); } @Override - public boolean isInsideRange(Location location) { - return this.handle.isInsideRange(location); + public boolean isInsideRange(Chunk chunk) { + return this.handle.isInsideRange(chunk); } @Override - public boolean isInsideRange(Location location, int extraRadius) { - return this.handle.isInsideRange(location, extraRadius); + public boolean isInsideRange(World world, int chunkX, int chunkZ) { + return this.handle.isInsideRange(world, chunkX, chunkZ); } @Override - public boolean isInsideRange(Location location, double extraRadius) { - return this.handle.isInsideRange(location, extraRadius); + public boolean isInsideRange(World world, int chunkX, int chunkZ, int extraRadius) { + return this.handle.isInsideRange(world, chunkX, chunkZ, extraRadius); } @Override - public boolean isInsideRange(Chunk chunk) { - return this.handle.isInsideRange(chunk); + public boolean isInsideRange(World world, int chunkX, int chunkZ, double extraRadius) { + return this.handle.isInsideRange(world, chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ) { + return this.handle.isInsideRange(worldInfo, chunkX, chunkZ); + } + + @Override + public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) { + return this.handle.isInsideRange(worldInfo, chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) { + return this.handle.isInsideRange(worldInfo, chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInsideRange(int chunkX, int chunkZ) { + return this.handle.isInsideRange(chunkX, chunkZ); + } + + @Override + public boolean isInsideRange(int chunkX, int chunkZ, int extraRadius) { + return this.handle.isInsideRange(chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInsideRange(int chunkX, int chunkZ, double extraRadius) { + return this.handle.isInsideRange(chunkX, chunkZ, extraRadius); } @Override @@ -1853,124 +1823,57 @@ public void resetSettings() { this.handle.resetSettings(); } - @Override - @Deprecated - public void setGeneratorPercentage(Key key, int percentage, World.Environment environment) { - this.handle.setGeneratorPercentage(key, percentage, environment); - } - @Override public void setGeneratorPercentage(Key key, int percentage, Dimension dimension) { this.handle.setGeneratorPercentage(key, percentage, dimension); } - @Override - @Deprecated - public boolean setGeneratorPercentage(Key key, int percentage, World.Environment environment, - @Nullable SuperiorPlayer caller, boolean callEvent) { - return this.handle.setGeneratorPercentage(key, percentage, environment, caller, callEvent); - } - @Override public boolean setGeneratorPercentage(Key key, int percentage, Dimension dimension, @Nullable SuperiorPlayer caller, boolean callEvent) { return this.handle.setGeneratorPercentage(key, percentage, dimension, caller, callEvent); } - @Override - @Deprecated - public int getGeneratorPercentage(Key key, World.Environment environment) { - return this.handle.getGeneratorPercentage(key, environment); - } - @Override public int getGeneratorPercentage(Key key, Dimension dimension) { return this.handle.getGeneratorPercentage(key, dimension); } - @Override - @Deprecated - public Map getGeneratorPercentages(World.Environment environment) { - return this.handle.getGeneratorPercentages(environment); - } - @Override public Map getGeneratorPercentages(Dimension dimension) { return this.handle.getGeneratorPercentages(dimension); } - @Override - @Deprecated - public void setGeneratorAmount(Key key, @Size int amount, World.Environment environment) { - this.handle.setGeneratorAmount(key, amount, environment); - } - @Override public void setGeneratorAmount(Key key, int amount, Dimension dimension) { this.handle.setGeneratorAmount(key, amount, dimension); } - @Override - @Deprecated - public void removeGeneratorAmount(Key key, World.Environment environment) { - this.handle.removeGeneratorAmount(key, environment); - } - @Override public void removeGeneratorAmount(Key key, Dimension dimension) { this.handle.removeGeneratorAmount(key, dimension); } - @Override - @Deprecated - public int getGeneratorAmount(Key key, World.Environment environment) { - return this.handle.getGeneratorAmount(key, environment); - } - @Override public int getGeneratorAmount(Key key, Dimension dimension) { return this.handle.getGeneratorAmount(key, dimension); } - @Override - @Deprecated - public int getGeneratorTotalAmount(World.Environment environment) { - return this.handle.getGeneratorTotalAmount(environment); - } - @Override public int getGeneratorTotalAmount(Dimension dimension) { return this.handle.getGeneratorTotalAmount(dimension); } - @Override - @Deprecated - public Map getGeneratorAmounts(World.Environment environment) { - return this.handle.getGeneratorAmounts(environment); - } - @Override public Map getGeneratorAmounts(Dimension dimension) { return this.handle.getGeneratorAmounts(dimension); } - @Override - @Deprecated - public Map getCustomGeneratorAmounts(World.Environment environment) { - return this.handle.getCustomGeneratorAmounts(environment); - } - @Override public Map getCustomGeneratorAmounts(Dimension dimension) { return this.handle.getCustomGeneratorAmounts(dimension); } - @Override - @Deprecated - public void clearGeneratorAmounts(World.Environment environment) { - this.handle.clearGeneratorAmounts(environment); - } - @Override public void clearGeneratorAmounts(Dimension dimension) { this.handle.clearGeneratorAmounts(dimension); @@ -1982,46 +1885,21 @@ public Key generateBlock(Location location, boolean optimizeDefaultBlock) { return this.handle.generateBlock(location, optimizeDefaultBlock); } - @Nullable - @Override - @Deprecated - public Key generateBlock(Location location, World.Environment environment, boolean optimizeDefaultBlock) { - return this.handle.generateBlock(location, environment, optimizeDefaultBlock); - } - @Override public Key generateBlock(Location location, Dimension dimension, boolean optimizeDefaultBlock) { return this.handle.generateBlock(location, dimension, optimizeDefaultBlock); } - @Override - @Deprecated - public boolean wasSchematicGenerated(World.Environment environment) { - return this.handle.wasSchematicGenerated(environment); - } - @Override public boolean wasSchematicGenerated(Dimension dimension) { return this.handle.wasSchematicGenerated(dimension); } - @Override - @Deprecated - public void setSchematicGenerate(World.Environment environment) { - this.handle.setSchematicGenerate(environment); - } - @Override public void setSchematicGenerate(Dimension dimension) { this.handle.setSchematicGenerate(dimension); } - @Override - @Deprecated - public void setSchematicGenerate(World.Environment environment, boolean generated) { - this.handle.setSchematicGenerate(environment, generated); - } - @Override public void setSchematicGenerate(Dimension dimension, boolean generated) { this.handle.setSchematicGenerate(dimension, generated); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java index d6821f15ac..3f1a63855f 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java @@ -29,6 +29,7 @@ import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; @@ -291,57 +292,18 @@ public interface Island extends Comparable, IMissionsHolder, IPersistent */ Location getCenter(Dimension dimension); - /** - * Get the center location of the island, depends on the world environment. - * - * @param environment The environment. - * @deprecated See {@link #getCenter(Dimension)} - */ - @Deprecated - Location getCenter(World.Environment environment); - /** * Get the center position of the island. */ BlockPosition getCenterPosition(); /** - * Get the members' teleport location of the island, depends on the world environment. - * Similar to {@link #getIslandHome(Dimension)} - * - * @param environment The environment. - * @deprecated See {@link #getIslandHome(Dimension)} - */ - @Deprecated - @Nullable - Location getTeleportLocation(World.Environment environment); - - /** - * Get all the teleport locations of the island. - * - * @deprecated See {@link #getIslandHomesAsDimensions()} - */ - @Deprecated - Map getTeleportLocations(); - - /** - * Set the members' teleport location of the island. + * Access the island's world. + * This method will load the world safely if it is not loaded. * - * @param teleportLocation The new teleport location. - * @deprecated See {@link #setIslandHome(Location)} + * @param dimension The dimension of the island world. */ - @Deprecated - void setTeleportLocation(Location teleportLocation); - - /** - * Set the members' teleport location of the island. - * - * @param environment The environment to change teleport location for. - * @param teleportLocation The new teleport location. - * @deprecated See {@link #setIslandHome(Dimension, Location)} - */ - @Deprecated - void setTeleportLocation(World.Environment environment, @Nullable Location teleportLocation); + CompletableFuture accessIslandWorld(Dimension dimension); /** * Get the members' home location of the island, depends on the world dimension. @@ -352,55 +314,54 @@ public interface Island extends Comparable, IMissionsHolder, IPersistent Location getIslandHome(Dimension dimension); /** - * Get the members' home location of the island, depends on the world environment. + * Get the members' home location of the island, depends on the world dimension. * - * @param environment The environment. - * @deprecated See {@link #getIslandHome(Dimension)} + * @param dimension The dimension. */ - @Deprecated @Nullable - Location getIslandHome(World.Environment environment); + WorldPosition getIslandHomePosition(Dimension dimension); /** * Get all the home locations of the island. + * If the world is not loaded, the location's getWorld will return null. */ Map getIslandHomesAsDimensions(); /** - * Get all the home locations of the island. - * - * @deprecated See {@link #getIslandHomesAsDimensions()} + * Get all the home positions of the island. */ - @Deprecated - Map getIslandHomes(); + Map getIslandHomes(); /** - * Set the members' teleport location of the island. + * Set the home location of the island. + * The location will be set for the world provided in {@param homeLocation} * * @param homeLocation The new home location. */ void setIslandHome(Location homeLocation); /** - * Set the members' teleport location of the island. + * Set the home position of the island. + * The world of {@param homeLocation} is ignored. * - * @param dimension The dimension to change teleport location for. + * @param dimension The dimension to change home position for. * @param homeLocation The new home location. + * @deprecated See {@link #setIslandHome(Dimension, WorldPosition)} */ + @Deprecated void setIslandHome(Dimension dimension, @Nullable Location homeLocation); /** - * Set the members' teleport location of the island. + * Set the home position of the island. * - * @param environment The environment to change teleport location for. - * @param homeLocation The new home location. - * @deprecated See {@link #setIslandHome(Dimension, Location)} + * @param dimension The dimension to change home position for. + * @param homePosition The new home position. */ - @Deprecated - void setIslandHome(World.Environment environment, @Nullable Location homeLocation); + void setIslandHome(Dimension dimension, @Nullable WorldPosition homePosition); /** * Get the visitors' teleport location of the island. + * If the world is unloaded, the location's getWorld method will return null. * * @param dimension The dimension to get the visitors-location from. * Currently unused, it has no effect. @@ -409,34 +370,33 @@ public interface Island extends Comparable, IMissionsHolder, IPersistent Location getVisitorsLocation(Dimension dimension); /** - * Get the visitors' teleport location of the island. + * Get the visitors' teleport position of the island. * - * @deprecated See {@link #getVisitorsLocation(Dimension)} + * @param dimension The dimension to get the visitors-position from. + * Currently unused, it has no effect. */ @Nullable - @Deprecated - Location getVisitorsLocation(); + WorldPosition getVisitorsPosition(Dimension dimension); /** - * Get the visitors' teleport location of the island. + * Set the visitors' teleport location of the island. * - * @param environment The environment to get the visitors-location from. - * Currently unused, it has no effect. - * @deprecated See {@link #getVisitorsLocation(Dimension)} + * @param visitorsLocation The new visitors location. */ - @Nullable - @Deprecated - Location getVisitorsLocation(World.Environment environment); + void setVisitorsLocation(@Nullable Location visitorsLocation); /** - * Set the visitors' teleport location of the island. + * Set the visitors' teleport position of the island. * - * @param visitorsLocation The new visitors location. + * @param dimension The dimension to change the visitors-position. + * Currently unused, it has no effect. + * @param visitorsPosition The new visitors position. */ - void setVisitorsLocation(@Nullable Location visitorsLocation); + void setVisitorsLocation(Dimension dimension, @Nullable WorldPosition visitorsPosition); /** * Get the minimum location of the island. + * If the world is unloaded, the location's getWorld will return null. */ Location getMinimum(); @@ -447,6 +407,7 @@ public interface Island extends Comparable, IMissionsHolder, IPersistent /** * Get the minimum protected location of the island. + * If the world is unloaded, the location's getWorld will return null. */ Location getMinimumProtected(); @@ -457,6 +418,7 @@ public interface Island extends Comparable, IMissionsHolder, IPersistent /** * Get the maximum location of the island. + * If the world is unloaded, the location's getWorld will return null. */ Location getMaximum(); @@ -467,6 +429,7 @@ public interface Island extends Comparable, IMissionsHolder, IPersistent /** * Get the minimum protected location of the island. + * If the world is unloaded, the location's getWorld will return null. */ Location getMaximumProtected(); @@ -504,55 +467,6 @@ public interface Island extends Comparable, IMissionsHolder, IPersistent */ List getAllChunks(Dimension dimension, @IslandChunkFlags int flags); - /** - * Get all the chunks of the island. - * - * @param environment The environment to get the chunks from. - * @deprecated See {@link #getAllChunks(Dimension)} - */ - @Deprecated - List getAllChunks(World.Environment environment); - - /** - * Get all the chunks of the island. - * - * @param environment The environment to get the chunks from. - * @param flags See {@link IslandChunkFlags} - * @deprecated See {@link #getAllChunks(Dimension, int)} - */ - @Deprecated - List getAllChunks(World.Environment environment, @IslandChunkFlags int flags); - - /** - * Get all the chunks of the island from all the environments. - * - * @param onlyProtected Whether only chunks inside the protected area should be returned. - * @deprecated See {@link #getAllChunks(int)} - */ - @Deprecated - List getAllChunks(boolean onlyProtected); - - /** - * Get all the chunks of the island, including empty ones. - * - * @param environment The environment to get the chunks from. - * @param onlyProtected Whether only chunks inside the protected area should be returned. - * @deprecated See {@link #getAllChunks(Dimension, int)} - */ - @Deprecated - List getAllChunks(World.Environment environment, boolean onlyProtected); - - /** - * Get all the chunks of the island. - * - * @param environment The environment to get the chunks from. - * @param onlyProtected Whether only chunks inside the protected area should be returned. - * @param noEmptyChunks Should empty chunks be loaded or not? - * @deprecated See {@link #getAllChunks(Dimension, int)} - */ - @Deprecated - List getAllChunks(World.Environment environment, boolean onlyProtected, boolean noEmptyChunks); - /** * Get all the loaded chunks of the island. * Similar to {@link #getLoadedChunks(int)} with 0 as flags parameter. @@ -582,46 +496,6 @@ public interface Island extends Comparable, IMissionsHolder, IPersistent */ List getLoadedChunks(Dimension dimension, @IslandChunkFlags int flags); - /** - * Get all the loaded chunks of the island. - * - * @param environment The environment to get the chunks from. - * @deprecated See {@link #getLoadedChunks(Dimension)} - */ - @Deprecated - List getLoadedChunks(World.Environment environment); - - /** - * Get all the loaded chunks of the island. - * - * @param environment The environment to get the chunks from. - * @param flags See {@link IslandChunkFlags} - * @deprecated See {@link #getLoadedChunks(Dimension, int)} - */ - @Deprecated - List getLoadedChunks(World.Environment environment, @IslandChunkFlags int flags); - - /** - * Get all the loaded chunks of the island. - * - * @param onlyProtected Whether only chunks inside the protected area should be returned. - * @param noEmptyChunks Should empty chunks be loaded or not? - * @deprecated See {@link #getLoadedChunks(int)} - */ - @Deprecated - List getLoadedChunks(boolean onlyProtected, boolean noEmptyChunks); - - /** - * Get all the loaded chunks of the island. - * - * @param environment The environment to get the chunks from. - * @param onlyProtected Whether only chunks inside the protected area should be returned. - * @param noEmptyChunks Should empty chunks be loaded or not? - * @deprecated See {@link #getLoadedChunks(Dimension, int)} - */ - @Deprecated - List getLoadedChunks(World.Environment environment, boolean onlyProtected, boolean noEmptyChunks); - /** * Get all the chunks of the island asynchronized, including empty chunks. * Similar to {@link #getAllChunksAsync(Dimension, int, Consumer)}, with 0 as flags parameter. @@ -657,72 +531,6 @@ public interface Island extends Comparable, IMissionsHolder, IPersistent List> getAllChunksAsync(Dimension dimension, @IslandChunkFlags int flags, @Nullable Consumer onChunkLoad); - /** - * Get all the chunks of the island asynchronized, including empty chunks. - * - * @param environment The environment to get the chunks from. - * @deprecated See {@link #getAllChunksAsync(Dimension)} - */ - @Deprecated - List> getAllChunksAsync(World.Environment environment); - - /** - * Get all the chunks of the island asynchronized, including empty chunks. - * - * @param environment The environment to get the chunks from. - * @param flags See {@link IslandChunkFlags} - * @deprecated See {@link #getAllChunks(Dimension, int)} - */ - @Deprecated - List> getAllChunksAsync(World.Environment environment, @IslandChunkFlags int flags); - - /** - * Get all the chunks of the island asynchronized, including empty chunks. - * - * @param environment The environment to get the chunks from. - * @param onChunkLoad A consumer that will be ran when the chunk is loaded. Can be null. - * @deprecated See {@link #getAllChunksAsync(Dimension, Consumer)} - */ - @Deprecated - List> getAllChunksAsync(World.Environment environment, @Nullable Consumer onChunkLoad); - - /** - * Get all the chunks of the island asynchronized, including empty chunks. - * - * @param environment The environment to get the chunks from. - * @param flags See {@link IslandChunkFlags} - * @param onChunkLoad A consumer that will be ran when the chunk is loaded. Can be null. - * @deprecated See {@link #getAllChunksAsync(Dimension, int, Consumer)} - */ - @Deprecated - List> getAllChunksAsync(World.Environment environment, @IslandChunkFlags int flags, - @Nullable Consumer onChunkLoad); - - /** - * Get all the chunks of the island asynchronized, including empty chunks. - * - * @param environment The environment to get the chunks from. - * @param onlyProtected Whether only chunks inside the protected area should be returned. - * @param onChunkLoad A consumer that will be ran when the chunk is loaded. Can be null. - * @deprecated See {@link #getAllChunksAsync(Dimension, int, Consumer)} - */ - @Deprecated - List> getAllChunksAsync(World.Environment environment, boolean onlyProtected, - @Nullable Consumer onChunkLoad); - - /** - * Get all the chunks of the island asynchronized. - * - * @param environment The environment to get the chunks from. - * @param onlyProtected Whether only chunks inside the protected area should be returned. - * @param noEmptyChunks Should empty chunks be loaded or not? - * @param onChunkLoad A consumer that will be ran when the chunk is loaded. Can be null. - * @deprecated See {@link #getAllChunksAsync(Dimension, int, Consumer)} - */ - @Deprecated - List> getAllChunksAsync(World.Environment environment, boolean onlyProtected, - boolean noEmptyChunks, @Nullable Consumer onChunkLoad); - /** * Reset all the chunks of the island from all the worlds (will make all chunks empty). * Similar to {@link #resetChunks(int)}, with 0 as flags parameter. @@ -786,108 +594,92 @@ List> getAllChunksAsync(World.Environment environment, void resetChunks(Dimension dimension, @IslandChunkFlags int flags, @Nullable Runnable onFinish); /** - * Reset all the chunks of the island (will make all chunks empty). - * - * @param environment The environment to reset chunks in. - * @deprecated See {@link #resetChunks(Dimension)} - */ - @Deprecated - void resetChunks(World.Environment environment); - - /** - * Reset all the chunks of the island (will make all chunks empty). + * Check if the location is inside the island's area. + * Similar to {@link #isInside(Location, int)} or {@link #isInside(Location, double)} with extraRadius set to 0. * - * @param environment The environment to reset chunks in. - * @param onFinish Callback runnable. - * @deprecated {@link #resetChunks(Dimension, Runnable)} + * @param location The location to check. */ - @Deprecated - void resetChunks(World.Environment environment, @Nullable Runnable onFinish); + boolean isInside(Location location); /** - * Reset all the chunks of the island (will make all chunks empty). + * Check if the location is inside the island's area. * - * @param environment The environment to reset chunks in. - * @param flags See {@link IslandChunkFlags} - * @deprecated See {@link #resetChunks(Dimension, int)} + * @param location The location to check. + * @param extraRadius Add extra radius to the range. */ - @Deprecated - void resetChunks(World.Environment environment, @IslandChunkFlags int flags); + boolean isInside(Location location, int extraRadius); /** - * Reset all the chunks of the island (will make all chunks empty). + * Check if the location is inside the island's area. * - * @param environment The environment to reset chunks in. - * @param flags See {@link IslandChunkFlags} - * @param onFinish Callback runnable. - * @deprecated See {@link #resetChunks(Dimension, int, Runnable)} + * @param location The location to check. + * @param extraRadius Add extra radius to the range. */ - @Deprecated - void resetChunks(World.Environment environment, @IslandChunkFlags int flags, @Nullable Runnable onFinish); + boolean isInside(Location location, double extraRadius); /** - * Reset all the chunks of the island (will make all chunks empty). + * Check if the location is inside the island's area. + * The world is ignored in this case. + * Similar to {@link #isInside(BlockPosition, int)} or {@link #isInside(BlockPosition, double)} with extraRadius set to 0. * - * @param environment The environment to reset chunks in. - * @param onlyProtected Whether only chunks inside the protected area should be reset. - * @deprecated See {@link #resetChunks(Dimension, int)} + * @param blockPosition The position to check. */ - @Deprecated - void resetChunks(World.Environment environment, boolean onlyProtected); + boolean isInside(BlockPosition blockPosition); /** - * Reset all the chunks of the island (will make all chunks empty). + * Check if the position is inside the island's area. + * The world is ignored in this case. * - * @param environment The environment to reset chunks in. - * @param onlyProtected Whether only chunks inside the protected area should be reset. - * @param onFinish Callback runnable. - * @deprecated See {@link #resetChunks(Dimension, int, Runnable)} + * @param blockPosition The position to check. + * @param extraRadius Add extra radius to the range. */ - @Deprecated - void resetChunks(World.Environment environment, boolean onlyProtected, @Nullable Runnable onFinish); + boolean isInside(BlockPosition blockPosition, int extraRadius); /** - * Reset all the chunks of the island from all the worlds (will make all chunks empty). + * Check if the position is inside the island's area. * - * @param onlyProtected Whether only chunks inside the protected area should be reset. - * @deprecated See {@link #resetChunks(int)} + * @param blockPosition The position to check. + * @param extraRadius Add extra radius to the range. */ - @Deprecated - void resetChunks(boolean onlyProtected); + boolean isInside(BlockPosition blockPosition, double extraRadius); /** - * Reset all the chunks of the island from all the worlds (will make all chunks empty). + * Check if the location is inside the island's area. + * The world is ignored in this case. + * Similar to {@link #isInside(WorldPosition, int)} or {@link #isInside(WorldPosition, double)} with extraRadius set to 0. * - * @param onlyProtected Whether only chunks inside the protected area should be reset. - * @param onFinish Callback runnable. - * @deprecated See {@link #resetChunks(int, Runnable)} + * @param worldPosition The position to check. */ - @Deprecated - void resetChunks(boolean onlyProtected, @Nullable Runnable onFinish); + boolean isInside(WorldPosition worldPosition); /** - * Check if the location is inside the island's area. + * Check if the position is inside the island's area. + * The world is ignored in this case. * - * @param location The location to check. + * @param worldPosition The position to check. + * @param extraRadius Add extra radius to the range. */ - boolean isInside(Location location); + boolean isInside(WorldPosition worldPosition, int extraRadius); /** - * Check if the location is inside the island's area. + * Check if the position is inside the island's area. * - * @param location The location to check. + * @param worldPosition The position to check. + * @param extraRadius Add extra radius to the range. */ - boolean isInside(Location location, int extraRadius); + boolean isInside(WorldPosition worldPosition, double extraRadius); /** - * Check if the location is inside the island's area. + * Check if a chunk is inside the island's area. + * Similar to {@link #isInside(World, int, int)} * - * @param location The location to check. + * @param chunk The chunk to check. */ - boolean isInside(Location location, double extraRadius); + boolean isInside(Chunk chunk); /** * Check if a chunk location is inside the island's area. + * Similar to {@link #isInside(World, int, int, int)} or {@link #isInside(World, int, int, double)} with extraRadius set to 0. * * @param world The world of the chunk. * @param chunkX The x-coords of the chunk. @@ -898,12 +690,83 @@ List> getAllChunksAsync(World.Environment environment, /** * Check if a chunk location is inside the island's area. * + * @param world The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param extraRadius Add extra radius to the range. + */ + boolean isInside(World world, int chunkX, int chunkZ, int extraRadius); + + /** + * Check if a chunk location is inside the island's area. + * + * @param world The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param extraRadius Add extra radius to the range. + */ + boolean isInside(World world, int chunkX, int chunkZ, double extraRadius); + + /** + * Check if a chunk location is inside the island's area. + * Similar to {@link #isInside(WorldInfo, int, int, int)} or {@link #isInside(WorldInfo, int, int, double)} with extraRadius set to 0. + * * @param worldInfo The world of the chunk. * @param chunkX The x-coords of the chunk. * @param chunkZ The z-coords of the chunk. */ boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ); + /** + * Check if a chunk location is inside the island's area. + * + * @param worldInfo The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param extraRadius Add extra radius to the range. + */ + boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius); + + /** + * Check if a chunk location is inside the island's area. + * + * @param worldInfo The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param extraRadius Add extra radius to the range. + */ + boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius); + + /** + * Check if a chunk position is inside the island's area. + * The world in this case is ignored. + * Similar to {@link #isInside(int, int, int)} or {@link #isInside(int, int, double)} with extraRadius set to 0. + * + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + */ + boolean isInside(int chunkX, int chunkZ); + + /** + * Check if a chunk position is inside the island's area. + * The world in this case is ignored. + * + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param extraRadius Add extra radius to the range. + */ + boolean isInside(int chunkX, int chunkZ, int extraRadius); + + /** + * Check if a chunk position is inside the island's area. + * The world in this case is ignored. + * + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param extraRadius Add extra radius to the range. + */ + boolean isInside(int chunkX, int chunkZ, double extraRadius); + /** * Check if the location is inside the island's protected area. * @@ -927,6 +790,58 @@ List> getAllChunksAsync(World.Environment environment, */ boolean isInsideRange(Location location, double extraRadius); + /** + * Check if the position is inside the island's protected area. + * The world in this case is ignored. + * + * @param blockPosition The position to check. + */ + boolean isInsideRange(BlockPosition blockPosition); + + /** + * Check if the position is inside the island's protected area. + * The world in this case is ignored. + * + * @param blockPosition The position to check. + * @param extraRadius Add extra radius to the protected range. + */ + boolean isInsideRange(BlockPosition blockPosition, int extraRadius); + + /** + * Check if the position is inside the island's protected area. + * The world in this case is ignored. + * + * @param blockPosition The position to check. + * @param extraRadius Add extra radius to the protected range. + */ + boolean isInsideRange(BlockPosition blockPosition, double extraRadius); + + /** + * Check if the position is inside the island's protected area. + * The world in this case is ignored. + * + * @param worldPosition The position to check. + */ + boolean isInsideRange(WorldPosition worldPosition); + + /** + * Check if the position is inside the island's protected area. + * The world in this case is ignored. + * + * @param worldPosition The position to check. + * @param extraRadius Add extra radius to the protected range. + */ + boolean isInsideRange(WorldPosition worldPosition, int extraRadius); + + /** + * Check if the position is inside the island's protected area. + * The world in this case is ignored. + * + * @param worldPosition The position to check. + * @param extraRadius Add extra radius to the protected range. + */ + boolean isInsideRange(WorldPosition worldPosition, double extraRadius); + /** * Check if the chunk is inside the island's protected area. * @@ -934,6 +849,96 @@ List> getAllChunksAsync(World.Environment environment, */ boolean isInsideRange(Chunk chunk); + /** + * Check if a chunk location is inside the island's protected area. + * Similar to {@link #isInside(World, int, int, int)} or {@link #isInside(World, int, int, double)} with extraRadius set to 0. + * + * @param world The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + */ + boolean isInsideRange(World world, int chunkX, int chunkZ); + + /** + * Check if a chunk location is inside the island's protected area. + * + * @param world The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param extraRadius Add extra radius to the protected range. + */ + boolean isInsideRange(World world, int chunkX, int chunkZ, int extraRadius); + + /** + * Check if a chunk location is inside the island's protected area. + * + * @param world The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param extraRadius Add extra radius to the protected range. + */ + boolean isInsideRange(World world, int chunkX, int chunkZ, double extraRadius); + + /** + * Check if a chunk location is inside the island's protected area. + * Similar to {@link #isInside(WorldInfo, int, int, int)} or {@link #isInside(WorldInfo, int, int, double)} with extraRadius set to 0. + * + * @param worldInfo The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + */ + boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ); + + /** + * Check if a chunk location is inside the island's protected area. + * + * @param worldInfo The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param extraRadius Add extra radius to the protected range. + */ + boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius); + + /** + * Check if a chunk location is inside the island's protected area. + * + * @param worldInfo The world of the chunk. + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param extraRadius Add extra radius to the protected range. + */ + boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius); + + /** + * Check if a chunk position is inside the island's protected area. + * The world in this case is ignored. + * Similar to {@link #isInside(int, int, int)} or {@link #isInside(int, int, double)} with extraRadius set to 0. + * + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + */ + boolean isInsideRange(int chunkX, int chunkZ); + + /** + * Check if a chunk position is inside the island's protected area. + * The world in this case is ignored. + * + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param extraRadius Add extra radius to the protected range. + */ + boolean isInsideRange(int chunkX, int chunkZ, int extraRadius); + + /** + * Check if a chunk position is inside the island's protected area. + * The world in this case is ignored. + * + * @param chunkX The x-coords of the chunk. + * @param chunkZ The z-coords of the chunk. + * @param extraRadius Add extra radius to the protected range. + */ + boolean isInsideRange(int chunkX, int chunkZ, double extraRadius); + /** * Is the normal world enabled for the island? */ @@ -2606,34 +2611,6 @@ List> getAllChunksAsync(World.Environment environment, boolean setGeneratorPercentage(Key key, int percentage, Dimension dimension, @Nullable SuperiorPlayer caller, boolean callEvent); - /** - * Set a percentage for a specific key in a specific world. - * - * @param key The block to change the generator rate of. - * @param percentage The percentage to set the new rate. - * @param environment The world to change the rates in. - * @deprecated See {@link #setGeneratorPercentage(Key, int, Dimension)} - */ - @Deprecated - void setGeneratorPercentage(Key key, int percentage, World.Environment environment); - - /** - * Set a percentage for a specific key in a specific world. - * - * @param key The block to change the generator rate of. - * @param percentage The percentage to set the new rate. - * @param environment The world to change the rates in. - * @param caller The player that changes the percentages (used for the event). - * If null, it means the console did the operation. - * @param callEvent Whether to call the {@link IslandChangeGeneratorRateEvent} - * @return Whether the operation succeed. - * The operation may fail if callEvent is true and the event was cancelled. - * @deprecated See {@link #setGeneratorPercentage(Key, int, Dimension, SuperiorPlayer, boolean)} - */ - @Deprecated - boolean setGeneratorPercentage(Key key, int percentage, World.Environment environment, - @Nullable SuperiorPlayer caller, boolean callEvent); - /** * Get the percentage for a specific key in a specific world. * The formula is (amount * 100) / total_amount. @@ -2643,121 +2620,46 @@ boolean setGeneratorPercentage(Key key, int percentage, World.Environment enviro */ int getGeneratorPercentage(Key key, Dimension dimension); - /** - * Get the percentage for a specific key in a specific world. - * The formula is (amount * 100) / total_amount. - * - * @param key The material key - * @param environment The world environment. - * @deprecated See {@link #getGeneratorPercentage(Key, Dimension)} - */ - @Deprecated - int getGeneratorPercentage(Key key, World.Environment environment); - /** * Get the percentages of the materials for the cobblestone generator in the island for a specific world. */ Map getGeneratorPercentages(Dimension dimension); - /** - * Get the percentages of the materials for the cobblestone generator in the island for a specific world. - * - * @deprecated See {@link #getGeneratorPercentages(Dimension)} - */ - @Deprecated - Map getGeneratorPercentages(World.Environment environment); - /** * Set an amount for a specific key in a specific world. */ void setGeneratorAmount(Key key, @Size int amount, Dimension dimension); - /** - * Set an amount for a specific key in a specific world. - * - * @deprecated See {@link #setGeneratorAmount(Key, int, Dimension)} - */ - @Deprecated - void setGeneratorAmount(Key key, @Size int amount, World.Environment environment); - /** * Remove a rate for a specific key in a specific world. */ void removeGeneratorAmount(Key key, Dimension dimension); - /** - * Remove a rate for a specific key in a specific world. - * - * @deprecated See {@link #removeGeneratorAmount(Key, Dimension)} - */ - @Deprecated - void removeGeneratorAmount(Key key, World.Environment environment); - /** * Get the amount of a specific key in a specific world. */ int getGeneratorAmount(Key key, Dimension dimension); - /** - * Get the amount of a specific key in a specific world. - * - * @deprecated See {@link #getGeneratorAmount(Key, Dimension)} - */ - @Deprecated - int getGeneratorAmount(Key key, World.Environment environment); - /** * Get the total amount of all the generator keys together. */ int getGeneratorTotalAmount(Dimension dimension); - /** - * Get the total amount of all the generator keys together. - * - * @deprecated See {@link #getGeneratorTotalAmount(Dimension)} - */ - @Deprecated - int getGeneratorTotalAmount(World.Environment environment); - /** * Get the amounts of the materials for the cobblestone generator in the island. */ Map getGeneratorAmounts(Dimension dimension); - /** - * Get the amounts of the materials for the cobblestone generator in the island. - * - * @deprecated See {@link #getGeneratorAmounts(Dimension)} - */ - @Deprecated - Map getGeneratorAmounts(World.Environment environment); - /** * Get the custom amounts of the materials for the cobblestone generator in the island. */ Map getCustomGeneratorAmounts(Dimension dimension); - /** - * Get the custom amounts of the materials for the cobblestone generator in the island. - * - * @deprecated See {@link #getCustomGeneratorAmounts(Dimension)} - */ - @Deprecated - Map getCustomGeneratorAmounts(World.Environment environment); - /** * Clear all the custom generator amounts for this island. */ void clearGeneratorAmounts(Dimension dimension); - /** - * Clear all the custom generator amounts for this island. - * - * @deprecated See {@link #clearGeneratorAmounts(Dimension)} - */ - @Deprecated - void clearGeneratorAmounts(World.Environment environment); - /** * Generate a block at a specified location. * The method calculates a block to generate from {@link #getGeneratorAmounts(Dimension)}. @@ -2791,22 +2693,6 @@ boolean setGeneratorPercentage(Key key, int percentage, World.Environment enviro @Nullable Key generateBlock(Location location, Dimension dimension, boolean optimizeDefaultBlock); - /** - * Generate a block at a specified location. - * - * @param location The location to generate block at. - * @param environment The world to get generator rates from. - * @param optimizeDefaultBlock When set to true and the default block needs to be generated, the plugin will - * not play any effect, count the block towards the block counts or set the block. - * This is useful when calling the method from BlockFromToEvent, and instead of letting - * the plugin do the logic of vanilla, the plugin lets the game do it. - * @return The block type that was generated, null if failed. - * @deprecated See {@link #generateBlock(Location, Dimension, boolean)} - */ - @Deprecated - @Nullable - Key generateBlock(Location location, World.Environment environment, boolean optimizeDefaultBlock); - /* * Schematic methods */ @@ -2818,15 +2704,6 @@ boolean setGeneratorPercentage(Key key, int percentage, World.Environment enviro */ boolean wasSchematicGenerated(Dimension dimension); - /** - * Checks if a schematic was generated already. - * - * @param environment The environment to check. - * @deprecated See {@link #wasSchematicGenerated(Dimension)} - */ - @Deprecated - boolean wasSchematicGenerated(World.Environment environment); - /** * Set schematic generated flag to true. * @@ -2842,25 +2719,6 @@ boolean setGeneratorPercentage(Key key, int percentage, World.Environment enviro */ void setSchematicGenerate(Dimension dimension, boolean generated); - /** - * Set schematic generated flag to true. - * - * @param environment The environment to set. - * @deprecated See {@link #setSchematicGenerate(Dimension)} - */ - @Deprecated - void setSchematicGenerate(World.Environment environment); - - /** - * Set schematic generated flag. - * - * @param environment The environment to set. - * @param generated The flag to set. - * @deprecated See {@link #setSchematicGenerate(Dimension, boolean)} - */ - @Deprecated - void setSchematicGenerate(World.Environment environment, boolean generated); - /** * Get the generated schematics. */ @@ -3014,14 +2872,10 @@ interface Builder { Builder setIslandHome(Location location, Dimension dimension); - @Deprecated - Builder setIslandHome(Location location, World.Environment environment); + Builder setIslandHome(Dimension dimension, WorldPosition worldPosition); Map getIslandHomesAsDimensions(); - @Deprecated - Map getIslandHomes(); - Builder addIslandMember(SuperiorPlayer superiorPlayer); List getIslandMembers(); @@ -3060,14 +2914,8 @@ interface Builder { Builder setGeneratorRate(Key block, int rate, Dimension dimension); - @Deprecated - Builder setGeneratorRate(Key block, int rate, World.Environment environment); - Map> getGeneratorRatesAsDimensions(); - @Deprecated - Map> getGeneratorRates(); - Builder addUniqueVisitor(SuperiorPlayer superiorPlayer, long visitTime); Map getUniqueVisitors(); @@ -3090,14 +2938,10 @@ interface Builder { Builder setVisitorHome(Location location, Dimension dimension); - @Deprecated - Builder setVisitorHome(Location location, World.Environment environment); + Builder setVisitorHome(Dimension dimension, WorldPosition worldPosition); Map getVisitorHomesAsDimensions(); - @Deprecated - Map getVisitorHomes(); - Builder setIslandSize(int islandSize); int getIslandSize(); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/BlockPosition.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/BlockPosition.java index b916ae09a4..2030737db2 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/BlockPosition.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/BlockPosition.java @@ -1,31 +1,17 @@ package com.bgsoftware.superiorskyblock.api.wrappers; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.block.Block; /** * This object represents a position of a block in the world. - * You can create a new instance of this class by using {@link com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager} + * You can create a new instance of this class by using {@link FactoriesManager} */ public interface BlockPosition { - /** - * Get the name of the world of the position. - */ - @Deprecated - String getWorldName(); - - /** - * Get the world of the position. - * - * @return The world object. May be null if the {@link #getWorldName()} is not a valid world. - */ - @Nullable - @Deprecated - World getWorld(); - /** * Get the x value of the position. */ @@ -51,21 +37,42 @@ public interface BlockPosition { BlockPosition offset(int x, int y, int z); /** - * Get the block object of that position. + * Get the bukkit representation of this block position in the provided world. + * + * @param world The world for this block position. + */ + Location toLocation(@Nullable World world); + + /** + * Get the bukkit representation of this block position in the provided world. + * + * @param world The world for this block position. + * @param location The location to write the output to. If null, null will be returned as well. + */ + @Nullable + Location toLocation(@Nullable World world, @Nullable Location location); + + /** + * Get the bukkit representation of this block position in the provided world. + * If the world is unloaded, the location's getWorld will return null. + * + * @param worldInfo The world information for this world position. */ - @Deprecated - Block getBlock(); + Location toLocation(WorldInfo worldInfo); /** - * Get the location of that position in a specific world. + * Get the bukkit representation of this block position in the provided world. + * If the world is unloaded, the location's getWorld will return null. + * + * @param worldInfo The world information for this world position. + * @param location The location to write the output to. If null, null will be returned as well. */ - @Deprecated - Location parse(World world); + @Nullable + Location toLocation(WorldInfo worldInfo, @Nullable Location location); /** - * Get the location of that position in the default world. + * Get the world position representation of this block position. */ - @Deprecated - Location parse(); + WorldPosition toWorldPosition(); } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/WorldPosition.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/WorldPosition.java new file mode 100644 index 0000000000..4362815cb2 --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/WorldPosition.java @@ -0,0 +1,107 @@ +package com.bgsoftware.superiorskyblock.api.wrappers; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.handlers.FactoriesManager; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import org.bukkit.Location; +import org.bukkit.World; + +/** + * This object represents a position of an entity in the world. + * You can create a new instance of this class by using {@link FactoriesManager} + */ +public interface WorldPosition { + + /** + * Get the x value of the position. + */ + double getX(); + + /** + * Get the y value of the position. + */ + double getY(); + + /** + * Get the z value of the position. + */ + double getZ(); + + /** + * Get the yaw value of the position. + */ + float getYaw(); + + /** + * Get the pitch value of the position. + */ + float getPitch(); + + /** + * Get a new position by an offset from this position. + * + * @param x The x-axis offset. + * @param y The y-axis offset. + * @param z The z-axis offset. + */ + WorldPosition offset(double x, double y, double z); + + /** + * Get a new position by rotating this position. + * + * @param yaw The y-axis rotation. + * @param pitch The z-axis rotation. + */ + WorldPosition rotate(float yaw, float pitch); + + /** + * Get a new position by an offset from this position. + * + * @param x The x-axis offset. + * @param y The y-axis offset. + * @param z The z-axis offset. + * @param yaw The y-axis rotation. + * @param pitch The z-axis rotation. + */ + WorldPosition offset(double x, double y, double z, float yaw, float pitch); + + /** + * Get the bukkit representation of this world position in the provided world. + * + * @param world The world for this world position. + */ + Location toLocation(@Nullable World world); + + /** + * Get the bukkit representation of this world position in the provided world. + * + * @param world The world for this world position. + * @param location The location to write the output to. If null, null will be returned as well. + */ + @Nullable + Location toLocation(@Nullable World world, @Nullable Location location); + + /** + * Get the bukkit representation of this world position in the provided world info. + * If the world is unloaded, the location's getWorld will return null. + * + * @param worldInfo The world information for this world position. + */ + Location toLocation(WorldInfo worldInfo); + + /** + * Get the bukkit representation of this world position in the provided world info. + * If the world is unloaded, the location's getWorld will return null. + * + * @param worldInfo The world information for this world position. + * @param location The location to write the output to. If null, null will be returned as well. + */ + @Nullable + Location toLocation(WorldInfo worldInfo, @Nullable Location location); + + /** + * Get the block position representation of this world position. + */ + BlockPosition toBlockPosition(); + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java index f620bc9ed1..b204e00556 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java @@ -152,14 +152,12 @@ private static void regenerateSchematicInternal(Island island, Dimension dimensi island.setSchematicGenerate(dimension); Location homeLocation = schematic.adjustRotation(centerLocation); - island.setIslandHome(dimension, homeLocation); + island.setIslandHome(homeLocation); if (dimension.getEnvironment() == World.Environment.THE_END) { dragonBattleService.get().resetEnderDragonBattle(island, dimension); } - island.setIslandHome(dimension, homeLocation); - island.calcIslandWorth(null); }, Throwable::printStackTrace); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java index bb60135adb..84e919da5c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java @@ -9,8 +9,10 @@ import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.messages.Message; +import org.bukkit.Location; import org.bukkit.PortalType; import org.bukkit.World; import org.bukkit.command.CommandSender; @@ -93,8 +95,13 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (dimension != plugin.getSettings().getWorlds().getDefaultWorldDimension()) { if (!island.wasSchematicGenerated(dimension)) { PortalType portalType = dimension.getEnvironment() == World.Environment.NETHER ? PortalType.NETHER : PortalType.ENDER; - portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, - island.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()), portalType, false); + Location homeLocation = island.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()); + IslandWorlds.accessIslandWorldAsync(island, homeLocation, true, islandWorldResult -> { + islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { + homeLocation.setWorld(world); + portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, homeLocation, portalType, false); + }); + }); return; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java index ca1895bfb2..b8794b14fa 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java @@ -84,7 +84,7 @@ public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sen plugin.getSettings().isTabCompleteHideVanished(), (onlinePlayer, onlineIsland) -> onlineIsland != null && ( (!plugin.getSettings().getVisitorsSign().isRequiredForVisit() || - onlineIsland.getVisitorsLocation((Dimension) null /* unused */) != null) || + onlineIsland.getVisitorsPosition(null /* unused */) != null) || superiorPlayer.hasBypassModeEnabled()) && (!onlineIsland.isLocked() || onlineIsland.hasPermission(superiorPlayer, IslandPrivileges.CLOSE_BYPASS))) : Collections.emptyList(); } @@ -95,7 +95,7 @@ private static void teleportPlayerInternal(Island targetIsland, SuperiorPlayer s if (plugin.getSettings().getVisitorsSign().isRequiredForVisit()) { isVisitorSign = true; - visitLocation = targetIsland.getVisitorsLocation((Dimension) null /* unused */); + visitLocation = targetIsland.getVisitorsLocation(null /* unused */); } else { isVisitorSign = false; visitLocation = targetIsland.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java index 721b8e8987..784fc17c88 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandArea.java @@ -34,13 +34,13 @@ public boolean expandAndIntercepts(double x, double z, double expandFactor) { return x >= minX && x <= maxX && z >= minZ && z <= maxZ; } - public boolean rshiftAndIntercepts(double x, double z, int shiftFactor) { + public boolean expandRshiftAndIntercepts(double x, double z, double expandFactor, int shiftFactor) { if (shiftFactor == 0) return intercepts(x, z); - int minX = (int) this.minX >> shiftFactor; - int minZ = (int) this.minZ >> shiftFactor; - int maxX = (int) this.maxX >> shiftFactor; - int maxZ = (int) this.maxZ >> shiftFactor; + int minX = (int) (this.minX - expandFactor) >> shiftFactor; + int minZ = (int) (this.minZ - expandFactor) >> shiftFactor; + int maxX = (int) (this.maxX + expandFactor) >> shiftFactor; + int maxZ = (int) (this.maxZ + expandFactor) >> shiftFactor; return x >= minX && x <= maxX && z >= minZ && z <= maxZ; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java index 510c50f0bd..3adfd1d5b5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; @@ -78,22 +79,14 @@ public static void accessIslandWorldAsync(Island island, Dimension dimension, bo } } - public static Location setWorldToLocation(Island island, Dimension dimension, Location location) { + public static Location setWorldToLocation(Island island, Dimension dimension, WorldPosition worldPosition) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); World world = Bukkit.getWorld(worldInfo.getName()); + Location location; if (world != null) { - location = location.clone(); - location.setWorld(world); + location = worldPosition.toLocation(world); } else { - WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); - if (worldsProvider instanceof LazyWorldsProvider) { - location = new LazyWorldLocation(worldInfo.getName(), location.getX(), location.getY(), - location.getZ(), location.getYaw(), location.getPitch()); - } else { - location = location.clone(); - world = plugin.getGrid().getIslandsWorld(island, dimension); - location.setWorld(world); - } + throw new IllegalStateException("You cannot call this method while the world is unloaded. Use Island#accessIslandWorld"); } return location; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java b/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java index 755045e57d..4086a41e86 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java @@ -1,7 +1,9 @@ package com.bgsoftware.superiorskyblock.core; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; @@ -11,6 +13,7 @@ */ public class LazyWorldLocation extends Location { + @Nullable private String worldName; private boolean updatedWorld = false; @@ -27,6 +30,11 @@ public static LazyWorldLocation of(WorldInfo worldInfo, BlockPosition blockPosit 0f, 0f); } + public static LazyWorldLocation of(WorldInfo worldInfo, WorldPosition worldPosition) { + return new LazyWorldLocation(worldInfo.getName(), worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(), + worldPosition.getYaw(), worldPosition.getPitch()); + } + public LazyWorldLocation(World world, double x, double y, double z) { super(world, x, y, z); this.worldName = null; @@ -51,7 +59,7 @@ public void setWorldName(String worldName) { @Override public World getWorld() { if (!this.updatedWorld) { - setWorld(Bukkit.getWorld(worldName)); + setWorld(worldName == null ? null : Bukkit.getWorld(worldName)); } return super.getWorld(); @@ -60,8 +68,7 @@ public World getWorld() { @Override public void setWorld(World world) { super.setWorld(world); - if (world != null) - this.worldName = world.getName(); + this.worldName = world == null ? null : world.getName(); this.updatedWorld = true; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/SBlockPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/SBlockPosition.java index 1e446c81fd..938463c71b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/SBlockPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/SBlockPosition.java @@ -1,51 +1,46 @@ package com.bgsoftware.superiorskyblock.core; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; -import javax.annotation.Nullable; import java.util.Objects; public class SBlockPosition implements BlockPosition { - @Nullable - private final String worldName; private final int x; private final int y; private final int z; - public SBlockPosition(LazyWorldLocation location) { - this(location.getWorldName(), location.getBlockX(), location.getBlockY(), location.getBlockZ()); - } + @Nullable + private WorldPosition cachedWorldPosition; - public SBlockPosition(Location location) { - this(LazyWorldLocation.getWorldName(location), location.getBlockX(), location.getBlockY(), location.getBlockZ()); + public static SBlockPosition of(Location location) { + return of(location.getBlockX(), location.getBlockY(), location.getBlockZ()); } - public SBlockPosition(Block block) { - this(block.getWorld().getName(), block.getX(), block.getY(), block.getZ()); + public static SBlockPosition of(Block block) { + return of(block.getX(), block.getY(), block.getZ()); } - public SBlockPosition(String worldName, int x, int y, int z) { - this.worldName = worldName; - this.x = x; - this.y = y; - this.z = z; + public static SBlockPosition of(WorldPosition worldPosition) { + return new SBlockPosition(Location.locToBlock(worldPosition.getX()), + Location.locToBlock(worldPosition.getY()), Location.locToBlock(worldPosition.getZ())); } - @Override - @Deprecated - public String getWorldName() { - return this.worldName; + public static SBlockPosition of(int x, int y, int z) { + return new SBlockPosition(x, y, z); } - @Override - @Deprecated - public World getWorld() { - return this.worldName == null ? null : Bukkit.getWorld(this.worldName); + private SBlockPosition(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; } @Override @@ -65,27 +60,60 @@ public int getZ() { @Override public BlockPosition offset(int x, int y, int z) { - return new SBlockPosition(this.worldName, this.x + x, this.y + y, this.z + z); + return new SBlockPosition(this.x + x, this.y + y, this.z + z); } @Override - @Deprecated - public Block getBlock() { - return parse().getBlock(); + public Location toLocation(@Nullable World world) { + return new Location(world, x, y, z); } @Override - @Deprecated - public Location parse(World world) { - return new Location(world, getX(), getY(), getZ()); + public Location toLocation(@Nullable World world, @Nullable Location location) { + if (location != null) { + location.setWorld(world); + location.setX(this.x); + location.setY(this.y); + location.setZ(this.z); + location.setYaw(0f); + location.setPitch(0f); + } + + return location; + } + + @Override + public Location toLocation(WorldInfo worldInfo) { + return LazyWorldLocation.of(worldInfo, this); } @Override - @Deprecated - public Location parse() { - World world = getWorld(); - return world == null ? new LazyWorldLocation(this.worldName, getX(), getY(), getZ(), 0, 0) : - new Location(world, getX(), getY(), getZ()); + public Location toLocation(WorldInfo worldInfo, @Nullable Location location) { + if (location != null) { + location.setX(this.x); + location.setY(this.y); + location.setZ(this.z); + location.setYaw(0f); + location.setPitch(0f); + + if (location instanceof LazyWorldLocation) { + ((LazyWorldLocation) location).setWorldName(worldInfo.getName()); + } else { + World world = Bukkit.getWorld(worldInfo.getName()); + location.setWorld(world); + } + + } + + return location; + } + + @Override + public WorldPosition toWorldPosition() { + if (this.cachedWorldPosition == null) + this.cachedWorldPosition = SWorldPosition.of(this); + + return this.cachedWorldPosition; } @Override @@ -93,18 +121,17 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SBlockPosition that = (SBlockPosition) o; - return x == that.x && y == that.y && z == that.z && Objects.equals(worldName, that.worldName); + return x == that.x && y == that.y && z == that.z; } @Override public int hashCode() { - return Objects.hash(x, y, z, worldName); + return Objects.hash(x, y, z); } @Override public String toString() { - String worldName = this.worldName == null ? "null" : this.worldName; - return worldName + ", " + x + ", " + y + ", " + z; + return x + ", " + y + ", " + z; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/SWorldPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/SWorldPosition.java new file mode 100644 index 0000000000..508229d25e --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/SWorldPosition.java @@ -0,0 +1,164 @@ +package com.bgsoftware.superiorskyblock.core; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; + +import java.util.Objects; + +public class SWorldPosition implements WorldPosition { + + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + + @Nullable + private BlockPosition cachedBlockPosition; + + public static SWorldPosition of(Location location) { + return of(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + } + + public static SWorldPosition of(Block block) { + return of(block.getX(), block.getY(), block.getZ()); + } + + public static SWorldPosition of(double x, double y, double z) { + return of(x, y, z, 0f, 0f); + } + + public static SWorldPosition of(BlockPosition blockPosition) { + return of(blockPosition.getX() + 0.5, blockPosition.getY(), blockPosition.getZ() + 0.5); + } + + public static SWorldPosition of(double x, double y, double z, float yaw, float pitch) { + return new SWorldPosition(x, y, z, yaw, pitch); + } + + private SWorldPosition(double x, double y, double z, float yaw, float pitch) { + this.x = x; + this.y = y; + this.z = z; + this.yaw = yaw; + this.pitch = pitch; + } + + @Override + public double getX() { + return this.x; + } + + @Override + public double getY() { + return this.y; + } + + @Override + public double getZ() { + return this.z; + } + + @Override + public float getYaw() { + return this.yaw; + } + + @Override + public float getPitch() { + return this.pitch; + } + + @Override + public WorldPosition offset(double x, double y, double z) { + return of(this.x + x, this.y + y, this.z + z, this.yaw, this.pitch); + } + + @Override + public WorldPosition rotate(float yaw, float pitch) { + return of(this.x, this.y, this.z, this.yaw + yaw, this.pitch + pitch); + } + + @Override + public WorldPosition offset(double x, double y, double z, float yaw, float pitch) { + return of(this.x + x, this.y + y, this.z + z, this.yaw + yaw, this.pitch + pitch); + } + + @Override + public Location toLocation(@Nullable World world) { + return new Location(world, this.x, this.y, this.z, this.yaw, this.pitch); + } + + @Override + public Location toLocation(@Nullable World world, @Nullable Location location) { + if (location != null) { + location.setWorld(world); + location.setX(this.x); + location.setY(this.y); + location.setZ(this.z); + location.setYaw(this.yaw); + location.setPitch(this.pitch); + } + + return location; + } + + @Override + public Location toLocation(WorldInfo worldInfo) { + return LazyWorldLocation.of(worldInfo, this); + } + + @Override + public Location toLocation(WorldInfo worldInfo, @Nullable Location location) { + if (location != null) { + location.setX(this.x); + location.setY(this.y); + location.setZ(this.z); + location.setYaw(this.yaw); + location.setPitch(this.pitch); + + if (location instanceof LazyWorldLocation) { + ((LazyWorldLocation) location).setWorldName(worldInfo.getName()); + } else { + World world = Bukkit.getWorld(worldInfo.getName()); + location.setWorld(world); + } + + } + + return location; + } + + @Override + public BlockPosition toBlockPosition() { + if (this.cachedBlockPosition == null) + this.cachedBlockPosition = SBlockPosition.of(this); + + return this.cachedBlockPosition; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SWorldPosition that = (SWorldPosition) o; + return x == that.x && y == that.y && z == that.z && yaw == that.yaw && pitch == that.pitch; + } + + @Override + public int hashCode() { + return Objects.hash(x, y, z, yaw, pitch); + } + + @Override + public String toString() { + return x + ", " + y + ", " + z + ", " + yaw + ", " + pitch; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/EnumerateMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/EnumerateMap.java index 90782295c3..113e0d0e7a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/collections/EnumerateMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/collections/EnumerateMap.java @@ -13,6 +13,7 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.function.BiFunction; import java.util.function.Function; public class EnumerateMap { @@ -121,6 +122,18 @@ public Map collect(Collection enumerables, Function valuesMap return map; } + public Map collect(Collection enumerables, BiFunction valuesMapper) { + Map map = new IdentityHashMap<>(); + + for (K key : enumerables) { + V value = get(key); + if (value != null) + map.put(key, valuesMapper.apply(key, value)); + } + + return map; + } + public Map collect(Collection enumerables) { Map map = new IdentityHashMap<>(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/GridDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/GridDatabaseBridge.java index f56dc505d2..c48f4deabf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/GridDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/GridDatabaseBridge.java @@ -5,7 +5,7 @@ import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.SBlockPosition; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import java.util.function.Consumer; @@ -18,9 +18,10 @@ public class GridDatabaseBridge { private GridDatabaseBridge() { } - public static void saveLastIsland(GridManager gridManager, SBlockPosition lastIsland) { + public static void saveLastIsland(GridManager gridManager, BlockPosition lastIsland) { runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> - databaseBridge.updateObject("grid", null, new Pair<>("last_island", lastIsland.toString()))); + databaseBridge.updateObject("grid", null, + new Pair<>("last_island", Serializers.BLOCK_POSITION_SERIALIZER.serialize(lastIsland)))); } public static void updateVersion(GridManager gridManager, int version) { @@ -33,7 +34,7 @@ public static void updateVersion(GridManager gridManager, int version) { public static void insertGrid(GridManager gridManager) { runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("grid", - new Pair<>("last_island", Serializers.LOCATION_SPACED_SERIALIZER.serialize(gridManager.getLastIslandLocation())), + new Pair<>("last_island", Serializers.BLOCK_POSITION_SERIALIZER.serialize(gridManager.getLastIslandPosition())), new Pair<>("max_island_size", plugin.getSettings().getMaxIslandSize()), new Pair<>("world", plugin.getSettings().getWorlds().getDefaultWorldName()) )); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index d5677f4e05..36f66225dd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -22,6 +22,7 @@ import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.LegacyMasks; @@ -101,8 +102,8 @@ public static void saveCoopLimit(Island island) { )); } - public static void saveIslandHome(Island island, Dimension dimension, Location location) { - if (location == null) { + public static void saveIslandHome(Island island, Dimension dimension, @Nullable WorldPosition worldPosition) { + if (worldPosition == null) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_homes", createFilter("island", island, new Pair<>("environment", dimension.getName())) )); @@ -110,23 +111,23 @@ public static void saveIslandHome(Island island, Dimension dimension, Location l runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_homes", new Pair<>("island", island.getUniqueId().toString()), new Pair<>("environment", dimension.getName()), - new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(location)) + new Pair<>("location", Serializers.WORLD_POSITION_SERIALIZER.serialize(worldPosition)) )); } } - public static void saveVisitorLocation(Island island, Dimension dimension, Location location) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_visitor_homes", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("environment", dimension.getName()), - new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(location)) - )); - } - - public static void removeVisitorLocation(Island island, Dimension dimension) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_visitor_homes", - createFilter("island", island, new Pair<>("environment", dimension.getName())) - )); + public static void saveVisitorLocation(Island island, Dimension dimension, @Nullable WorldPosition worldPosition) { + if (worldPosition == null) { + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_visitor_homes", + createFilter("island", island, new Pair<>("environment", dimension.getName())) + )); + } else { + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_visitor_homes", + new Pair<>("island", island.getUniqueId().toString()), + new Pair<>("environment", dimension.getName()), + new Pair<>("location", Serializers.WORLD_POSITION_SERIALIZER.serialize(worldPosition)) + )); + } } public static void saveUnlockedWorlds(Island island) { @@ -712,7 +713,7 @@ public static void deleteIsland(Island island) { break; } } - if (!island.getIslandHomesAsDimensions().isEmpty()) + if (!island.getIslandHomes().isEmpty()) databaseBridge.deleteObject("islands_homes", islandFilter); if (!island.getIslandMembers(false).isEmpty()) databaseBridge.deleteObject("islands_members", islandFilter); @@ -729,7 +730,7 @@ public static void deleteIsland(Island island) { if (!island.getUpgrades().isEmpty()) databaseBridge.deleteObject("islands_upgrades", islandFilter); for (Dimension dimension : Dimension.values()) { - if (island.getVisitorsLocation(dimension) != null) { + if (island.getVisitorsPosition(dimension) != null) { databaseBridge.deleteObject("islands_visitor_homes", islandFilter); break; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java index 971e2a8c58..9f897a913a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; import com.bgsoftware.superiorskyblock.core.database.cache.DatabaseCache; @@ -516,14 +517,14 @@ public static void deserializeIslandHomes(DatabaseBridge databaseBridge, Databas return; } - Optional location = islandHomes.getString("location").map(Serializers.LOCATION_SERIALIZER::deserialize); + Optional location = islandHomes.getString("location").map(Serializers.WORLD_POSITION_SERIALIZER::deserialize); if (!location.isPresent()) { Log.warn("Cannot load island homes with invalid location for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); - builder.setIslandHome(location.get(), dimension.get()); + builder.setIslandHome(dimension.get(), location.get()); }); } @@ -543,14 +544,14 @@ public static void deserializeVisitorHomes(DatabaseBridge databaseBridge, Databa return; } - Optional location = islandVisitorHomes.getString("location").map(Serializers.LOCATION_SERIALIZER::deserialize); + Optional location = islandVisitorHomes.getString("location").map(Serializers.WORLD_POSITION_SERIALIZER::deserialize); if (!location.isPresent()) { Log.warn("Cannot load island homes with invalid location for ", uuid.get(), ", skipping..."); return; } Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); - builder.setVisitorHome(location.get(), dimension.get()); + builder.setVisitorHome(dimension.get(), location.get()); }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java index 1247e07ff8..ccb0e230d1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java @@ -25,10 +25,11 @@ import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; -import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.SBlockPosition; +import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.WorldInfoImpl; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge; @@ -156,16 +157,36 @@ public BlockOffset createBlockOffset(int offsetX, int offsetY, int offsetZ) { } @Override + @Deprecated public BlockPosition createBlockPosition(String world, int blockX, int blockY, int blockZ) { - Preconditions.checkNotNull(world, "world cannot be null."); - return new SBlockPosition(world, blockX, blockY, blockZ); + return createBlockPosition(blockX, blockY, blockZ); + } + + @Override + public BlockPosition createBlockPosition(int blockX, int blockY, int blockZ) { + return SBlockPosition.of(blockX, blockY, blockZ); } @Override public BlockPosition createBlockPosition(Location location) { - if (!(location instanceof LazyWorldLocation)) - Preconditions.checkNotNull(location.getWorld(), "location's world cannot be null."); - return new SBlockPosition(location); + Preconditions.checkNotNull(location, "location cannot be null."); + return SBlockPosition.of(location); + } + + @Override + public WorldPosition createWorldPosition(double x, double y, double z) { + return SWorldPosition.of(x, y, z); + } + + @Override + public WorldPosition createWorldPosition(double x, double y, double z, float yaw, float pitch) { + return SWorldPosition.of(x, y, z, yaw, pitch); + } + + @Override + public WorldPosition createWorldPosition(Location location) { + Preconditions.checkNotNull(location, "location cannot be null."); + return SWorldPosition.of(location); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java index 78cd267982..76fdb979fe 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java @@ -93,7 +93,7 @@ protected List requestObjects() { private final Predicate ISLANDS_FILTER = island -> { if (visitorWarps) - return island.getVisitorsLocation((Dimension) null /* unused */) != null; + return island.getVisitorsPosition(null /* unused */) != null; else if (island.equals(getInventoryViewer().getIsland())) return !island.getIslandWarps().isEmpty(); else diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/Serializers.java b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/Serializers.java index 083ef9f558..75bc3f8317 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/Serializers.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/Serializers.java @@ -1,11 +1,15 @@ package com.bgsoftware.superiorskyblock.core.serialization; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; +import com.bgsoftware.superiorskyblock.core.serialization.impl.BlockPositionSerializer; import com.bgsoftware.superiorskyblock.core.serialization.impl.InventorySerializer; import com.bgsoftware.superiorskyblock.core.serialization.impl.ItemStack2TagSerializer; import com.bgsoftware.superiorskyblock.core.serialization.impl.ItemStackSerializer; import com.bgsoftware.superiorskyblock.core.serialization.impl.LocationSerializer; import com.bgsoftware.superiorskyblock.core.serialization.impl.OffsetSerializer; +import com.bgsoftware.superiorskyblock.core.serialization.impl.WorldPositionSerializer; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import org.bukkit.Location; import org.bukkit.inventory.ItemStack; @@ -17,6 +21,8 @@ public class Serializers { public static final ISerializer ITEM_STACK_TO_TAG_SERIALIZER = ItemStack2TagSerializer.getInstance(); public static final ISerializer LOCATION_SPACED_SERIALIZER = new LocationSerializer(", "); public static final ISerializer LOCATION_SERIALIZER = new LocationSerializer(","); + public static final ISerializer BLOCK_POSITION_SERIALIZER = BlockPositionSerializer.getInstance(); + public static final ISerializer WORLD_POSITION_SERIALIZER = WorldPositionSerializer.getInstance(); public static final ISerializer OFFSET_SPACED_SERIALIZER = new OffsetSerializer(", "); public static final ISerializer OFFSET_SERIALIZER = new OffsetSerializer(","); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/BlockPositionSerializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/BlockPositionSerializer.java new file mode 100644 index 0000000000..fc2e8ecec1 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/BlockPositionSerializer.java @@ -0,0 +1,57 @@ +package com.bgsoftware.superiorskyblock.core.serialization.impl; + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; +import com.bgsoftware.superiorskyblock.core.SBlockPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.serialization.ISerializer; + +public class BlockPositionSerializer implements ISerializer { + + private static final BlockPositionSerializer INSTANCE = new BlockPositionSerializer(); + + public static BlockPositionSerializer getInstance() { + return INSTANCE; + } + + private BlockPositionSerializer() { + } + + @NotNull + @Override + public String serialize(@Nullable BlockPosition serializable) { + return serializable == null ? "" : + serializable.getX() + ", " + serializable.getY() + ", " + serializable.getZ(); + } + + @Nullable + @Override + public BlockPosition deserialize(@Nullable String element) { + if (Text.isBlank(element)) + return null; + + try { + String[] sections = element.split(", "); + + int startIndex = 0; + if (sections.length >= 4) { + // In the past, BlockPositions were serialized with a world, yaw and pitch. + // Nowadays, we ignore all of them. + ++startIndex; + } + + int x = (int) Double.parseDouble(sections[startIndex++]); + int y = (int) Double.parseDouble(sections[startIndex++]); + int z = (int) Double.parseDouble(sections[startIndex]); + + return SBlockPosition.of(x, y, z); + } catch (Exception error) { + Log.entering("ENTER", element); + Log.error(error, "An unexpected error occurred while deserializing position '" + element + "':"); + return null; + } + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/WorldPositionSerializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/WorldPositionSerializer.java new file mode 100644 index 0000000000..f515c220c6 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/WorldPositionSerializer.java @@ -0,0 +1,62 @@ +package com.bgsoftware.superiorskyblock.core.serialization.impl; + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; +import com.bgsoftware.superiorskyblock.core.SBlockPosition; +import com.bgsoftware.superiorskyblock.core.SWorldPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.serialization.ISerializer; + +public class WorldPositionSerializer implements ISerializer { + + private static final WorldPositionSerializer INSTANCE = new WorldPositionSerializer(); + + public static WorldPositionSerializer getInstance() { + return INSTANCE; + } + + private WorldPositionSerializer() { + } + + @NotNull + @Override + public String serialize(@Nullable WorldPosition serializable) { + return serializable == null ? "" : + serializable.getX() + "," + serializable.getY() + "," + serializable.getZ() + + "," + serializable.getYaw() + "," + serializable.getPitch(); + } + + @Nullable + @Override + public WorldPosition deserialize(@Nullable String element) { + if (Text.isBlank(element)) + return null; + + try { + String[] sections = element.split(", "); + + int startIndex = 0; + if (sections.length >= 6) { + // In the past, WorldPositions were serialized with a world. + // Nowadays, we ignore all of them. + ++startIndex; + } + + double x = Double.parseDouble(sections[startIndex++]); + double y = Double.parseDouble(sections[startIndex++]); + double z = Double.parseDouble(sections[startIndex++]); + float yaw = Float.parseFloat(sections[startIndex++]); + float pitch = Float.parseFloat(sections[startIndex]); + + return SWorldPosition.of(x, y, z, yaw, pitch); + } catch (Exception error) { + Log.entering("ENTER", element); + Log.error(error, "An unexpected error occurred while deserializing position '" + element + "':"); + return null; + } + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java index 4015758676..1ea63b1f88 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java @@ -4,13 +4,13 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.service.hologram.Hologram; import com.bgsoftware.superiorskyblock.api.service.hologram.HologramsService; -import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; -import com.bgsoftware.superiorskyblock.core.SBlockPosition; +import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import org.bukkit.Location; +import org.bukkit.World; public class StackedBlock { @@ -22,7 +22,7 @@ protected HologramsService create() { } }; - private final BlockPosition blockPosition; + private final LazyWorldLocation location; private int amount; private Key blockKey; @@ -30,12 +30,11 @@ protected HologramsService create() { private boolean removed; public StackedBlock(Location location) { - this.blockPosition = new SBlockPosition(location); + this.location = LazyWorldLocation.of(location); } - public Location getLocation() { - //noinspection deprecation - return this.blockPosition.parse(); + public LazyWorldLocation getLocation() { + return location; } public int getAmount() { @@ -65,8 +64,8 @@ public void updateName() { return; } - Location location = getLocation(); - if (location.getWorld() == null) + World world = this.location.getWorld(); + if (world == null) return; Key currentBlockKey = Keys.of(location.getBlock()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java index 73d81a092c..693f6edc82 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlocksManagerImpl.java @@ -179,7 +179,7 @@ public Map removeStackedBlocks(ChunkPosition chunkPosition) { databaseBridge.batchOperations(false); } - return Collections.unmodifiableMap(removedStackedBlocks); + return removedStackedBlocks.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(removedStackedBlocks); } @Override @@ -194,19 +194,21 @@ public Map getStackedBlocks(World world, int chunkX, int chun Map chunkStackedBlocks = new LinkedHashMap<>(); try (ChunkPosition chunkPosition = ChunkPosition.of(world, chunkX, chunkZ)) { - this.stackedBlocksContainer.forEach(chunkPosition, stackedBlock -> - chunkStackedBlocks.put(stackedBlock.getLocation(), stackedBlock.getAmount())); + this.stackedBlocksContainer.forEach(chunkPosition, stackedBlock -> { + chunkStackedBlocks.put(stackedBlock.getLocation(), stackedBlock.getAmount()); + }); } - return Collections.unmodifiableMap(chunkStackedBlocks); + return chunkStackedBlocks.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(chunkStackedBlocks); } @Override public Map getStackedBlocks() { Map allStackedBlocks = new LinkedHashMap<>(); - this.stackedBlocksContainer.forEach(stackedBlock -> - allStackedBlocks.put(stackedBlock.getLocation(), stackedBlock.getAmount())); - return Collections.unmodifiableMap(allStackedBlocks); + this.stackedBlocksContainer.forEach(stackedBlock -> { + allStackedBlocks.put(stackedBlock.getLocation(), stackedBlock.getAmount()); + }); + return allStackedBlocks.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(allStackedBlocks); } public boolean hasStackedBlocks() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java index 415c192de6..7cfd7124d6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java @@ -34,6 +34,8 @@ public class WorldsProvider_Default implements WorldsProvider { private final Map islandWorldsToDimensions = new HashMap<>(); private final SuperiorSkyblockPlugin plugin; + private World islandsWorld; + private final LazyReference dragonBattleService = new LazyReference() { @Override protected DragonBattleService create() { @@ -58,6 +60,8 @@ public void prepareWorlds() { ((SettingsManager.Worlds.End) dimensionConfig).isDragonFight()) { dragonBattleService.get().prepareEndWorld(world); } + if (dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) + this.islandsWorld = world; } } } @@ -81,51 +85,53 @@ public boolean isIslandsWorld(World world) { } @Override - public Location getNextLocation(Location previousLocation, int islandsHeight, int maxIslandSize, UUID islandOwner, UUID islandUUID) { - Preconditions.checkNotNull(previousLocation, "previousLocation parameter cannot be null."); + public Location getNextLocation(BlockPosition previousPosition, int islandsHeight, int maxIslandSize, UUID islandOwner, UUID islandUUID) { + Preconditions.checkNotNull(previousPosition, "previousPosition parameter cannot be null."); + + BlockFace islandFace = getIslandFace(previousPosition); - Location location = previousLocation.clone(); - location.setY(islandsHeight); - BlockFace islandFace = getIslandFace(location); + BlockPosition nextPosition; int islandRange = maxIslandSize * 3; if (islandFace == BlockFace.NORTH) { - location.add(islandRange, 0, 0); + nextPosition = nextPosition(previousPosition, islandsHeight, islandRange, 0); } else if (islandFace == BlockFace.EAST) { - if (location.getX() == -location.getZ()) - location.add(islandRange, 0, 0); - else if (location.getX() == location.getZ()) - location.subtract(islandRange, 0, 0); + if (previousPosition.getX() == -previousPosition.getZ()) + nextPosition = nextPosition(previousPosition, islandsHeight, islandRange, 0); + else if (previousPosition.getX() == previousPosition.getZ()) + nextPosition = nextPosition(previousPosition, islandsHeight, -islandRange, 0); else - location.add(0, 0, islandRange); + nextPosition = nextPosition(previousPosition, islandsHeight, 0, islandRange); } else if (islandFace == BlockFace.SOUTH) { - if (location.getX() == -location.getZ()) - location.subtract(0, 0, islandRange); + if (previousPosition.getX() == -previousPosition.getZ()) + nextPosition = nextPosition(previousPosition, islandsHeight, 0, -islandRange); else - location.subtract(islandRange, 0, 0); + nextPosition = nextPosition(previousPosition, islandsHeight, -islandRange, 0); } else if (islandFace == BlockFace.WEST) { - if (location.getX() == location.getZ()) - location.add(islandRange, 0, 0); + if (previousPosition.getX() == previousPosition.getZ()) + nextPosition = nextPosition(previousPosition, islandsHeight, islandRange, 0); else - location.subtract(0, 0, islandRange); + nextPosition = nextPosition(previousPosition, islandsHeight, 0, -islandRange); + } else { + throw new IllegalStateException(); } - BlockPosition blockPosition = new SBlockPosition(location); + Location nextLocation = nextPosition.toLocation(this.islandsWorld); - if (servedPositions.contains(blockPosition) || plugin.getGrid().getIslandAt(location) != null) { - return getNextLocation(location.clone(), islandsHeight, maxIslandSize, islandOwner, islandUUID); + if (servedPositions.contains(nextPosition) || plugin.getGrid().getIslandAt(nextLocation) != null) { + return getNextLocation(nextPosition, islandsHeight, maxIslandSize, islandOwner, islandUUID); } - servedPositions.add(blockPosition); + servedPositions.add(nextPosition); - return location; + return nextLocation; } @Override public void finishIslandCreation(Location islandLocation, UUID islandOwner, UUID islandUUID) { Preconditions.checkNotNull(islandLocation, "islandLocation parameter cannot be null."); - servedPositions.remove(new SBlockPosition(islandLocation)); + servedPositions.remove(SBlockPosition.of(islandLocation)); } @Override @@ -154,14 +160,14 @@ public boolean isDimensionUnlocked(Dimension dimension) { return dimensionConfig != null && dimensionConfig.isEnabled() && dimensionConfig.isUnlocked(); } - private BlockFace getIslandFace(Location location) { + private BlockFace getIslandFace(BlockPosition blockPosition) { //Possibilities: North / East - if (location.getX() >= location.getZ()) { - return -location.getX() > location.getZ() ? BlockFace.NORTH : BlockFace.EAST; + if (blockPosition.getX() >= blockPosition.getZ()) { + return -blockPosition.getX() > blockPosition.getZ() ? BlockFace.NORTH : BlockFace.EAST; } //Possibilities: South / West else { - return -location.getX() > location.getZ() ? BlockFace.WEST : BlockFace.SOUTH; + return -blockPosition.getX() > blockPosition.getZ() ? BlockFace.WEST : BlockFace.SOUTH; } } @@ -192,4 +198,8 @@ private World loadWorld(String worldName, Difficulty difficulty, Dimension dimen return world; } + private static BlockPosition nextPosition(BlockPosition previousPosition, int islandsHeight, int offsetX, int offsetZ) { + return SBlockPosition.of(previousPosition.getX() + offsetX, islandsHeight, previousPosition.getZ() + offsetZ); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index 5bc1110bdb..0bc6d15c5c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -18,10 +18,10 @@ import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.world.algorithm.IslandCreationAlgorithm; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyReference; -import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockPosition; @@ -96,7 +96,7 @@ protected DragonBattleService create() { private IslandCreationAlgorithm islandCreationAlgorithm; private Island spawnIsland; - private SBlockPosition lastIsland; + private BlockPosition lastIsland; @Nullable private UUID serverUUID; @@ -135,7 +135,7 @@ public void loadData() { loadServerUuid(); - this.lastIsland = new SBlockPosition(plugin.getSettings().getWorlds().getDefaultWorldName(), 0, 100, 0); + this.lastIsland = SBlockPosition.of(0, 100, 0); BukkitExecutor.sync(this::updateSpawn); } @@ -328,7 +328,7 @@ private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Bi Log.debugResult(Debug.CREATE_ISLAND, "Creation Callback", "Registering new island"); this.islandsContainer.addIsland(island); - setLastIsland(new SBlockPosition(islandLocation)); + setLastIslandPosition(SBlockPosition.of(islandLocation)); try { island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.IDLE); @@ -351,7 +351,7 @@ private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Bi if (spawnOffset != null) homeLocation = spawnOffset.applyToLocation(homeLocation); - island.setIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension(), homeLocation); + island.setIslandHome(homeLocation); BukkitExecutor.sync(() -> builder.owner.runIfOnline(player -> { if (updateGameMode) @@ -963,13 +963,34 @@ public BigDecimal getTotalLevel() { } @Override + @Deprecated public Location getLastIslandLocation() { - return lastIsland.parse(); + return lastIsland.toLocation((World) null); } @Override + @Deprecated public void setLastIslandLocation(Location location) { - this.setLastIsland(new SBlockPosition(location)); + Preconditions.checkNotNull(location, "location parameter cannot be null"); + setLastIslandPosition(SBlockPosition.of(location)); + } + + @Override + public BlockPosition getLastIslandPosition() { + return this.lastIsland; + } + + @Override + public void setLastIslandPosition(BlockPosition lastIsland) { + Preconditions.checkNotNull(lastIsland, "lastIsland parameter cannot be null"); + + Log.debug(Debug.SET_LAST_ISLAND, lastIsland); + + if (Objects.equals(this.lastIsland, lastIsland)) + return; + + this.lastIsland = lastIsland; + GridDatabaseBridge.saveLastIsland(this, lastIsland); } @Override @@ -1010,13 +1031,8 @@ public boolean wasPluginDisabled() { } public void loadGrid(DatabaseResult resultSet) { - resultSet.getString("last_island").map(Serializers.LOCATION_SPACED_SERIALIZER::deserialize) - .ifPresent(lastIsland -> this.lastIsland = new SBlockPosition((LazyWorldLocation) lastIsland)); - - if (!plugin.getSettings().getWorlds().getDefaultWorldName().equals(lastIsland.getWorldName())) { - lastIsland = new SBlockPosition(plugin.getSettings().getWorlds().getDefaultWorldName(), - lastIsland.getX(), lastIsland.getY(), lastIsland.getZ()); - } + resultSet.getString("last_island").map(Serializers.BLOCK_POSITION_SERIALIZER::deserialize) + .ifPresent(lastIsland -> this.lastIsland = lastIsland); int maxIslandSize = resultSet.getInt("max_island_size").orElse(plugin.getSettings().getMaxIslandSize()); String world = resultSet.getString("world").orElse(plugin.getSettings().getWorlds().getDefaultWorldName()); @@ -1057,12 +1073,6 @@ public void saveIslands() { getIslands().forEach(Island::removeEffects); } - private void setLastIsland(SBlockPosition lastIsland) { - Log.debug(Debug.SET_LAST_ISLAND, lastIsland); - this.lastIsland = lastIsland; - GridDatabaseBridge.saveLastIsland(this, lastIsland); - } - private void initializeDatabaseBridge() { databaseBridge = plugin.getFactory().createDatabaseBridge(this); databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 3069f15649..c6d3bd63eb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -38,6 +38,7 @@ import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.IslandArea; @@ -46,7 +47,7 @@ import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.LegacyMasks; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.SBlockPosition; +import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; @@ -133,7 +134,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.Date; -import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -233,8 +233,8 @@ protected IslandCache create() { /* * General Settings */ - private final Synchronized> islandHomes = Synchronized.of(new EnumerateMap<>(Dimension.values())); - private final Synchronized> visitorHomes = Synchronized.of(new EnumerateMap<>(Dimension.values())); + private final Synchronized> islandHomes = Synchronized.of(new EnumerateMap<>(Dimension.values())); + private final Synchronized> visitorHomes = Synchronized.of(new EnumerateMap<>(Dimension.values())); private final Map rolePermissions = new ConcurrentHashMap<>(); private final Map islandFlags = new ConcurrentHashMap<>(); private final IslandUpgrades upgrades = new IslandUpgrades(); @@ -283,7 +283,7 @@ public SIsland(IslandBuilderImpl builder) { this.owner.setIsland(this); } - this.center = new SBlockPosition(builder.center); + this.center = builder.center; this.creationTime = builder.creationTime; setNameInternal(builder.islandName); this.schematicName = builder.islandType; @@ -407,22 +407,6 @@ public SIsland(IslandBuilderImpl builder) { * General methods */ - private static boolean adjustLocationToCenterOfBlock(Location location) { - boolean changed = false; - - if (location.getX() - 0.5 != location.getBlockX()) { - location.setX(location.getBlockX() + 0.5); - changed = true; - } - - if (location.getZ() - 0.5 != location.getBlockZ()) { - location.setZ(location.getBlockZ() + 0.5); - changed = true; - } - - return changed; - } - @Override public SuperiorPlayer getOwner() { return owner; @@ -870,14 +854,7 @@ public Location getCenter(Dimension dimension) { Preconditions.checkNotNull(world, "Couldn't find world for dimension " + dimension + "."); - // noinspection deprecation - return center.parse(world).add(0.5, 0, 0.5); - } - - @Override - @Deprecated - public Location getCenter(World.Environment environment) { - return getCenter(Dimensions.fromEnvironment(environment)); + return this.center.toWorldPosition().toLocation(world); } @Override @@ -886,73 +863,41 @@ public BlockPosition getCenterPosition() { } @Override - @Deprecated - public Location getTeleportLocation(World.Environment environment) { - return this.getIslandHome(Dimensions.fromEnvironment(environment)); - } - - @Override - @Deprecated - public Map getTeleportLocations() { - return this.getIslandHomes(); - } - - @Override - @Deprecated - public void setTeleportLocation(Location teleportLocation) { - this.setIslandHome(teleportLocation); + public CompletableFuture accessIslandWorld(Dimension dimension) { + CompletableFuture completableFuture = new CompletableFuture<>(); + IslandWorlds.accessIslandWorldAsync(this, dimension, true, islandWorldResult -> { + islandWorldResult.ifRight(completableFuture::completeExceptionally).ifLeft(completableFuture::complete); + }); + return completableFuture; } @Override - @Deprecated - public void setTeleportLocation(World.Environment environment, @Nullable Location teleportLocation) { - this.setIslandHome(Dimensions.fromEnvironment(environment), teleportLocation); + public Location getIslandHome(Dimension dimension) { + WorldPosition islandHome = getIslandHomePosition(dimension); + return islandHome == null ? null : IslandWorlds.setWorldToLocation(this, dimension, islandHome); } @Override - public Location getIslandHome(Dimension dimension) { + public WorldPosition getIslandHomePosition(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); - Location islandHome = islandHomes.readAndGet(islandHomes -> islandHomes.get(dimension)); + WorldPosition islandHome = islandHomes.readAndGet(islandHomes -> islandHomes.get(dimension)); - if (islandHome == null) - islandHome = getCenter(dimension); - - if (islandHome == null) - return null; - - return IslandWorlds.setWorldToLocation(this, dimension, islandHome); - } - - @Override - @Deprecated - public Location getIslandHome(World.Environment environment) { - return getIslandHome(Dimensions.fromEnvironment(environment)); + return islandHome == null ? this.center.toWorldPosition() : islandHome; } @Override public Map getIslandHomesAsDimensions() { - return Collections.unmodifiableMap(islandHomes.readAndGet(islandHomes -> islandHomes.collect(Dimension.values()))); + Map islandHomes = this.islandHomes.readAndGet(map -> + map.collect(Dimension.values(), this::worldPositionToLocation)); + return islandHomes.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandHomes); } @Override - @Deprecated - public Map getIslandHomes() { - EnumMap islandHomes = new EnumMap<>(World.Environment.class); - - this.islandHomes.read(islandHomesAsDimensions -> { - for (Dimension dimension : Dimension.values()) { - Location islandHome = islandHomesAsDimensions.get(dimension); - if (islandHome != null) { - Object oldValue = islandHomes.put(dimension.getEnvironment(), islandHome); - if (oldValue != null) - throw new IllegalStateException("Called getIslandHomes but there are multiple environments. " + - "Use getIslandHomesAsDimensions instead."); - } - } - }); - - return Collections.unmodifiableMap(islandHomes); + public Map getIslandHomes() { + Map islandHomes = this.islandHomes.readAndGet(map -> + map.collect(Dimension.values())); + return islandHomes.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandHomes); } @Override @@ -962,76 +907,62 @@ public void setIslandHome(Location homeLocation) { Preconditions.checkArgument(isInside(homeLocation), "homeLocation must be inside island."); Dimension dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(homeLocation.getWorld()); - - setIslandHome(dimension, homeLocation); + setIslandHome(dimension, SWorldPosition.of(homeLocation)); } @Override public void setIslandHome(Dimension dimension, @Nullable Location homeLocation) { + setIslandHome(dimension, homeLocation == null ? null : SWorldPosition.of(homeLocation)); + } + + @Override + public void setIslandHome(Dimension dimension, @Nullable WorldPosition homePosition) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); - Log.debug(Debug.SET_ISLAND_HOME, owner.getName(), dimension, homeLocation); + Log.debug(Debug.SET_ISLAND_HOME, owner.getName(), dimension, homePosition); - Location oldHome = islandHomes.writeAndGet(islandHomes -> - islandHomes.put(dimension, homeLocation == null ? null : homeLocation.clone())); + WorldPosition newHome = adjustPositionToCenterOfBlock(homePosition); - if (!Objects.equals(oldHome, homeLocation)) - IslandsDatabaseBridge.saveIslandHome(this, dimension, homeLocation); - } + WorldPosition oldHome = islandHomes.writeAndGet(islandHomes -> + newHome == null ? islandHomes.remove(dimension) : islandHomes.put(dimension, newHome)); - @Override - public void setIslandHome(World.Environment environment, @Nullable Location homeLocation) { - setIslandHome(Dimensions.fromEnvironment(environment), homeLocation); + if (!Objects.equals(oldHome, newHome)) + IslandsDatabaseBridge.saveIslandHome(this, dimension, newHome); } + @Nullable @Override - public Location getVisitorsLocation() { - return getVisitorsLocation((Dimension) null /* unused */); + public Location getVisitorsLocation(Dimension unused) { + WorldPosition visitorsPosition = getVisitorsPosition(null /*unused*/); + return visitorsPosition == null ? null : IslandWorlds.setWorldToLocation( + this, plugin.getSettings().getWorlds().getDefaultWorldDimension(), visitorsPosition); } - @Nullable @Override - public Location getVisitorsLocation(Dimension unused) { + public WorldPosition getVisitorsPosition(Dimension unused) { Dimension defaultWorldDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); - - Location visitorsLocation = this.visitorHomes.readAndGet(visitorsLocations -> - visitorsLocations.get(defaultWorldDimension)); - - if (visitorsLocation == null) - return null; - - if (adjustLocationToCenterOfBlock(visitorsLocation)) - IslandsDatabaseBridge.saveVisitorLocation(this, defaultWorldDimension, visitorsLocation); - - return IslandWorlds.setWorldToLocation(this, defaultWorldDimension, visitorsLocation); + return this.visitorHomes.readAndGet(visitorHomes -> + visitorHomes.get(defaultWorldDimension)); } @Override - @Deprecated - public Location getVisitorsLocation(World.Environment unused) { - return getVisitorsLocation((Dimension) null /* unused */); + public void setVisitorsLocation(@Nullable Location visitorsLocation) { + setVisitorsLocation(null /*unused*/, visitorsLocation == null ? null : SWorldPosition.of(visitorsLocation)); } @Override - public void setVisitorsLocation(Location visitorsLocation) { - Log.debug(Debug.SET_VISITOR_HOME, owner.getName(), visitorsLocation); + public void setVisitorsLocation(Dimension unused, @Nullable WorldPosition visitorsPosition) { + Log.debug(Debug.SET_VISITOR_HOME, owner.getName(), visitorsPosition); Dimension defaultWorldDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); - if (visitorsLocation == null) { - Location oldVisitorsLocation = this.visitorHomes.writeAndGet(visitorsLocations -> - visitorsLocations.remove(defaultWorldDimension)); - if (oldVisitorsLocation != null) - IslandsDatabaseBridge.removeVisitorLocation(this, defaultWorldDimension); - } else { - adjustLocationToCenterOfBlock(visitorsLocation); + WorldPosition newHome = adjustPositionToCenterOfBlock(visitorsPosition); - Location oldVisitorsLocation = this.visitorHomes.writeAndGet(visitorsLocations -> - visitorsLocations.put(defaultWorldDimension, visitorsLocation.clone())); + WorldPosition oldHome = visitorHomes.writeAndGet(visitorHomes -> + newHome == null ? visitorHomes.remove(defaultWorldDimension) : visitorHomes.put(defaultWorldDimension, newHome)); - if (!Objects.equals(oldVisitorsLocation, visitorsLocation)) - IslandsDatabaseBridge.saveVisitorLocation(this, defaultWorldDimension, visitorsLocation); - } + if (!Objects.equals(oldHome, newHome)) + IslandsDatabaseBridge.saveVisitorLocation(this, defaultWorldDimension, newHome); } @Override @@ -1119,39 +1050,6 @@ public List getAllChunks(Dimension dimension, @IslandChunkFlags int flags chunkPosition -> world.getChunkAt(chunkPosition.getX(), chunkPosition.getZ())); } - @Override - @Deprecated - public List getAllChunks(World.Environment environment) { - return getAllChunks(Dimensions.fromEnvironment(environment)); - } - - @Override - @Deprecated - public List getAllChunks(World.Environment environment, @IslandChunkFlags int flags) { - return getAllChunks(Dimensions.fromEnvironment(environment), flags); - } - - @Override - @Deprecated - public List getAllChunks(boolean onlyProtected) { - return getAllChunks(onlyProtected ? IslandChunkFlags.ONLY_PROTECTED : 0); - } - - @Override - @Deprecated - public List getAllChunks(World.Environment environment, boolean onlyProtected) { - return getAllChunks(Dimensions.fromEnvironment(environment), onlyProtected ? IslandChunkFlags.ONLY_PROTECTED : 0); - } - - @Override - @Deprecated - public List getAllChunks(World.Environment environment, boolean onlyProtected, boolean noEmptyChunks) { - int flags = 0; - if (onlyProtected) flags |= IslandChunkFlags.ONLY_PROTECTED; - if (noEmptyChunks) flags |= IslandChunkFlags.NO_EMPTY_CHUNKS; - return getAllChunks(Dimensions.fromEnvironment(environment), flags); - } - @Override public List getLoadedChunks() { return getLoadedChunks(0); @@ -1186,35 +1084,6 @@ public List getLoadedChunks(Dimension dimension, @IslandChunkFlags int fl IslandUtils.getChunkCoords(this, worldInfo, flags), plugin.getNMSChunks()::getChunkIfLoaded); } - @Override - @Deprecated - public List getLoadedChunks(World.Environment environment) { - return getLoadedChunks(Dimensions.fromEnvironment(environment)); - } - - @Override - public List getLoadedChunks(World.Environment environment, @IslandChunkFlags int flags) { - return getLoadedChunks(Dimensions.fromEnvironment(environment), flags); - } - - @Override - @Deprecated - public List getLoadedChunks(boolean onlyProtected, boolean noEmptyChunks) { - int flags = 0; - if (onlyProtected) flags |= IslandChunkFlags.ONLY_PROTECTED; - if (noEmptyChunks) flags |= IslandChunkFlags.NO_EMPTY_CHUNKS; - return getLoadedChunks(flags); - } - - @Override - @Deprecated - public List getLoadedChunks(World.Environment environment, boolean onlyProtected, boolean noEmptyChunks) { - int flags = 0; - if (onlyProtected) flags |= IslandChunkFlags.ONLY_PROTECTED; - if (noEmptyChunks) flags |= IslandChunkFlags.NO_EMPTY_CHUNKS; - return getLoadedChunks(Dimensions.fromEnvironment(environment), flags); - } - @Override public List> getAllChunksAsync(Dimension dimension) { return getAllChunksAsync(dimension, 0); @@ -1240,48 +1109,6 @@ public List> getAllChunksAsync(Dimension dimension, @Is return IslandUtils.getAllChunksAsync(this, worldInfo, flags, ChunkLoadReason.API_REQUEST, onChunkLoad); } - @Override - @Deprecated - public List> getAllChunksAsync(World.Environment environment) { - return getAllChunksAsync(Dimensions.fromEnvironment(environment)); - } - - @Override - @Deprecated - public List> getAllChunksAsync(World.Environment environment, @IslandChunkFlags int flags) { - return getAllChunksAsync(Dimensions.fromEnvironment(environment), flags); - } - - @Override - public List> getAllChunksAsync(World.Environment environment, - @Nullable Consumer onChunkLoad) { - return getAllChunksAsync(Dimensions.fromEnvironment(environment), onChunkLoad); - } - - @Override - public List> getAllChunksAsync(World.Environment environment, @IslandChunkFlags int flags, - @Nullable Consumer onChunkLoad) { - return getAllChunksAsync(Dimensions.fromEnvironment(environment), flags, onChunkLoad); - } - - @Override - @Deprecated - public List> getAllChunksAsync(World.Environment environment, boolean onlyProtected, - @Nullable Consumer onChunkLoad) { - return getAllChunksAsync(environment, onlyProtected ? IslandChunkFlags.ONLY_PROTECTED : 0, onChunkLoad); - } - - @Override - @Deprecated - public List> getAllChunksAsync(World.Environment environment, - boolean onlyProtected, boolean noEmptyChunks, - @Nullable Consumer onChunkLoad) { - int flags = 0; - if (onlyProtected) flags |= IslandChunkFlags.ONLY_PROTECTED; - if (noEmptyChunks) flags |= IslandChunkFlags.NO_EMPTY_CHUNKS; - return getAllChunksAsync(environment, flags, onChunkLoad); - } - @Override public void resetChunks() { resetChunks((Runnable) null); @@ -1378,88 +1205,105 @@ public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, @Nulla } @Override - @Deprecated - public void resetChunks(World.Environment environment) { - resetChunks(Dimensions.fromEnvironment(environment)); + public boolean isInside(Location location) { + return isInside(location, 0); } @Override - @Deprecated - public void resetChunks(World.Environment environment, @Nullable Runnable onFinish) { - resetChunks(Dimensions.fromEnvironment(environment), onFinish); + public boolean isInside(Location location, int extraRadius) { + return isInside(location, (double) extraRadius); } @Override - @Deprecated - public void resetChunks(World.Environment environment, @IslandChunkFlags int flags) { - resetChunks(Dimensions.fromEnvironment(environment), flags); + public boolean isInside(Location location, double extraRadius) { + Preconditions.checkNotNull(location, "location parameter cannot be null."); + Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); + return isIslandWorld(location.getWorld()) && this.entireArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); } @Override - @Deprecated - public void resetChunks(World.Environment environment, @IslandChunkFlags int flags, @Nullable Runnable onFinish) { - resetChunks(Dimensions.fromEnvironment(environment), flags, onFinish); + public boolean isInside(BlockPosition blockPosition) { + return isInside(blockPosition, 0D); } @Override - @Deprecated - public void resetChunks(World.Environment environment, boolean onlyProtected) { - resetChunks(Dimensions.fromEnvironment(environment), onlyProtected ? IslandChunkFlags.ONLY_PROTECTED : 0); + public boolean isInside(BlockPosition blockPosition, int extraRadius) { + return isInside(blockPosition, (double) extraRadius); } @Override - @Deprecated - public void resetChunks(World.Environment environment, boolean onlyProtected, @Nullable Runnable onFinish) { - resetChunks(Dimensions.fromEnvironment(environment), onlyProtected ? IslandChunkFlags.ONLY_PROTECTED : 0, onFinish); + public boolean isInside(BlockPosition blockPosition, double extraRadius) { + Preconditions.checkNotNull(blockPosition, "blockPosition parameter cannot be null."); + return this.entireArea.expandAndIntercepts(blockPosition.getX(), blockPosition.getZ(), extraRadius); } @Override - @Deprecated - public void resetChunks(boolean onlyProtected) { - resetChunks(onlyProtected ? IslandChunkFlags.ONLY_PROTECTED : 0); + public boolean isInside(WorldPosition worldPosition) { + return isInside(worldPosition, 0D); } @Override - @Deprecated - public void resetChunks(boolean onlyProtected, @Nullable Runnable onFinish) { - resetChunks(onlyProtected ? IslandChunkFlags.ONLY_PROTECTED : 0, onFinish); + public boolean isInside(WorldPosition worldPosition, int extraRadius) { + return isInside(worldPosition, (double) extraRadius); } @Override - public boolean isInside(Location location) { - return isInside(location, 0); + public boolean isInside(WorldPosition worldPosition, double extraRadius) { + Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null."); + return this.entireArea.expandAndIntercepts(worldPosition.getX(), worldPosition.getZ(), extraRadius); } @Override - public boolean isInside(Location location, int extraRadius) { - return isInside(location, (double) extraRadius); + public boolean isInside(Chunk chunk) { + Preconditions.checkNotNull(chunk, "chunk parameter cannot be null."); + return isInside(chunk.getWorld(), chunk.getX(), chunk.getZ()); } @Override - public boolean isInside(Location location, double extraRadius) { - Preconditions.checkNotNull(location, "location parameter cannot be null."); - Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); - - if (!isIslandWorld(location.getWorld())) - return false; + public boolean isInside(World world, int chunkX, int chunkZ) { + return isInside(world, chunkX, chunkZ, 0D); + } - return this.entireArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); + @Override + public boolean isInside(World world, int chunkX, int chunkZ, int extraRadius) { + return isInside(world, chunkX, chunkZ, (double) extraRadius); } @Override - public boolean isInside(World world, int chunkX, int chunkZ) { + public boolean isInside(World world, int chunkX, int chunkZ, double extraRadius) { Preconditions.checkNotNull(world, "world parameter cannot be null."); - return isIslandWorld(world) && isChunkInside(chunkX, chunkZ); + return isIslandWorld(world) && isInside(chunkX, chunkZ, extraRadius); } @Override public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) { + return isInside(worldInfo, chunkX, chunkZ, 0D); + } + + @Override + public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) { + return isInside(worldInfo, chunkX, chunkZ, (double) extraRadius); + } + + @Override + public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) { Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); - return isIslandWorld(worldInfo) && isChunkInside(chunkX, chunkZ); + return isIslandWorld(worldInfo) && isInside(chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInside(int chunkX, int chunkZ) { + return isInside(chunkX, chunkZ, 0D); } - private boolean isChunkInside(int chunkX, int chunkZ) { - return this.entireArea.rshiftAndIntercepts(chunkX, chunkZ, 4); + @Override + public boolean isInside(int chunkX, int chunkZ, int extraRadius) { + return isInside(chunkX, chunkZ, (double) extraRadius); + } + + @Override + public boolean isInside(int chunkX, int chunkZ, double extraRadius) { + return this.entireArea.expandRshiftAndIntercepts(chunkX, chunkZ, extraRadius, 4); } @Override @@ -1476,21 +1320,91 @@ public boolean isInsideRange(Location location, int extraRadius) { public boolean isInsideRange(Location location, double extraRadius) { Preconditions.checkNotNull(location, "location parameter cannot be null."); Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); + return isIslandWorld(location.getWorld()) && this.protectedArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); + } - if (!isIslandWorld(location.getWorld())) - return false; + @Override + public boolean isInsideRange(BlockPosition blockPosition) { + return isInsideRange(blockPosition, 0D); + } + + @Override + public boolean isInsideRange(BlockPosition blockPosition, int extraRadius) { + return isInsideRange(blockPosition, (double) extraRadius); + } + + @Override + public boolean isInsideRange(BlockPosition blockPosition, double extraRadius) { + Preconditions.checkNotNull(blockPosition, "blockPosition parameter cannot be null."); + return this.protectedArea.expandAndIntercepts(blockPosition.getX(), blockPosition.getZ(), extraRadius); + } + + @Override + public boolean isInsideRange(WorldPosition worldPosition) { + return isInsideRange(worldPosition, 0D); + } + + @Override + public boolean isInsideRange(WorldPosition worldPosition, int extraRadius) { + return isInsideRange(worldPosition, (double) extraRadius); + } - return this.protectedArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); + @Override + public boolean isInsideRange(WorldPosition worldPosition, double extraRadius) { + Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null."); + return this.protectedArea.expandAndIntercepts(worldPosition.getX(), worldPosition.getZ(), extraRadius); } @Override public boolean isInsideRange(Chunk chunk) { - Preconditions.checkNotNull(chunk, "chunk parameter cannot be null."); + return isInsideRange(chunk.getWorld(), chunk.getX(), chunk.getZ()); + } - if (!isIslandWorld(chunk.getWorld())) - return false; + @Override + public boolean isInsideRange(World world, int chunkX, int chunkZ) { + return isInsideRange(world, chunkX, chunkZ, 0D); + } + + @Override + public boolean isInsideRange(World world, int chunkX, int chunkZ, int extraRadius) { + return isInsideRange(world, chunkX, chunkZ, (double) extraRadius); + } + + @Override + public boolean isInsideRange(World world, int chunkX, int chunkZ, double extraRadius) { + Preconditions.checkNotNull(world, "world parameter cannot be null."); + return isIslandWorld(world) && isInsideRange(chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ) { + return isInsideRange(worldInfo, chunkX, chunkZ, 0D); + } - return this.protectedArea.rshiftAndIntercepts(chunk.getX(), chunk.getZ(), 4); + @Override + public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) { + return isInsideRange(worldInfo, chunkX, chunkZ, (double) extraRadius); + } + + @Override + public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) { + Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); + return isIslandWorld(worldInfo) && isInsideRange(chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInsideRange(int chunkX, int chunkZ) { + return isInsideRange(chunkX, chunkZ, 0D); + } + + @Override + public boolean isInsideRange(int chunkX, int chunkZ, int extraRadius) { + return isInsideRange(chunkX, chunkZ, (double) extraRadius); + } + + @Override + public boolean isInsideRange(int chunkX, int chunkZ, double extraRadius) { + return this.protectedArea.expandRshiftAndIntercepts(chunkX, chunkZ, extraRadius, 4); } private static boolean isIslandWorld(@Nullable World world) { @@ -2075,7 +1989,7 @@ private CompletableFuture getBiomeAsyncTask(CompletableFuture curr ChunkPosition.of(world, centerBlockPosition.getX() >> 4, centerBlockPosition.getZ() >> 4); ChunksProvider.loadChunk(centerChunkPosition, ChunkLoadReason.BIOME_REQUEST, null) - .thenApply(chunk -> centerBlockPosition.parse(world).getBlock().getBiome()) + .thenApply(chunk -> centerBlockPosition.toLocation(world).getBlock().getBiome()) .whenComplete((biome, error) -> { if (error != null) newTask.completeExceptionally(error); @@ -2848,7 +2762,7 @@ public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) { @Override public boolean isChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ) { - Preconditions.checkArgument(worldInfo != null && isChunkInside(chunkX, chunkZ), + Preconditions.checkArgument(worldInfo != null && isInside(chunkX, chunkZ), "Chunk must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) { return this.dirtyChunksContainer.isMarkedDirty(chunkPosition); @@ -4208,18 +4122,6 @@ public boolean setGeneratorPercentage(Key key, int percentage, Dimension dimensi return true; } - @Override - @Deprecated - public void setGeneratorPercentage(Key key, int percentage, World.Environment environment) { - setGeneratorPercentage(key, percentage, Dimensions.fromEnvironment(environment)); - } - - @Override - @Deprecated - public boolean setGeneratorPercentage(Key key, int percentage, World.Environment environment, SuperiorPlayer caller, boolean callEvent) { - return setGeneratorPercentage(key, percentage, Dimensions.fromEnvironment(environment), caller, callEvent); - } - @Override public int getGeneratorPercentage(Key key, Dimension dimension) { Preconditions.checkNotNull(key, "key parameter cannot be null."); @@ -4229,12 +4131,6 @@ public int getGeneratorPercentage(Key key, Dimension dimension) { return totalAmount == 0 ? 0 : (getGeneratorAmount(key, dimension) * 100) / totalAmount; } - @Override - @Deprecated - public int getGeneratorPercentage(Key key, World.Environment environment) { - return getGeneratorPercentage(key, Dimensions.fromEnvironment(environment)); - } - @Override public Map getGeneratorPercentages(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); @@ -4242,12 +4138,6 @@ public Map getGeneratorPercentages(Dimension dimension) { key -> getGeneratorAmount(Keys.ofMaterialAndData(key), dimension))); } - @Override - @Deprecated - public Map getGeneratorPercentages(World.Environment environment) { - return getGeneratorPercentages(Dimensions.fromEnvironment(environment)); - } - @Override public void setGeneratorAmount(Key key, @Size int amount, Dimension dimension) { Preconditions.checkNotNull(key, "key parameter cannot be null."); @@ -4267,11 +4157,6 @@ public void setGeneratorAmount(Key key, @Size int amount, Dimension dimension) { IslandsDatabaseBridge.saveGeneratorRate(this, dimension, key, amount); } - @Override - public void setGeneratorAmount(Key key, int amount, World.Environment environment) { - setGeneratorAmount(key, amount, Dimensions.fromEnvironment(environment)); - } - @Override public void removeGeneratorAmount(Key key, Dimension dimension) { Preconditions.checkNotNull(key, "key parameter cannot be null."); @@ -4300,12 +4185,6 @@ public void removeGeneratorAmount(Key key, Dimension dimension) { } } - @Override - @Deprecated - public void removeGeneratorAmount(Key key, World.Environment environment) { - removeGeneratorAmount(key, Dimensions.fromEnvironment(environment)); - } - @Override public int getGeneratorAmount(Key key, Dimension dimension) { Preconditions.checkNotNull(key, "key parameter cannot be null."); @@ -4321,12 +4200,6 @@ public int getGeneratorAmount(Key key, Dimension dimension) { return generatorRate == null ? 0 : generatorRate.get(); } - @Override - @Deprecated - public int getGeneratorAmount(Key key, World.Environment environment) { - return getGeneratorAmount(key, Dimensions.fromEnvironment(environment)); - } - @Override public int getGeneratorTotalAmount(Dimension dimension) { int totalAmount = 0; @@ -4335,12 +4208,6 @@ public int getGeneratorTotalAmount(Dimension dimension) { return totalAmount; } - @Override - @Deprecated - public int getGeneratorTotalAmount(World.Environment environment) { - return getGeneratorTotalAmount(Dimensions.fromEnvironment(environment)); - } - @Override public Map getGeneratorAmounts(Dimension dimension) { KeyMap worldGeneratorRates = this.cobbleGeneratorValues.readAndGet( @@ -4361,12 +4228,6 @@ public Map getGeneratorAmounts(Dimension dimension) { return generatorAmountsResult.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(generatorAmountsResult); } - @Override - @Deprecated - public Map getGeneratorAmounts(World.Environment environment) { - return getGeneratorAmounts(Dimensions.fromEnvironment(environment)); - } - @Override public Map getCustomGeneratorAmounts(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); @@ -4382,12 +4243,6 @@ public Map getCustomGeneratorAmounts(Dimension dimension) { .collect(KeyMap.getCollector(Map.Entry::getKey, entry -> entry.getValue().get()))); } - @Override - @Deprecated - public Map getCustomGeneratorAmounts(World.Environment environment) { - return getCustomGeneratorAmounts(Dimensions.fromEnvironment(environment)); - } - @Override public void clearGeneratorAmounts(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); @@ -4402,12 +4257,6 @@ public void clearGeneratorAmounts(Dimension dimension) { } } - @Override - @Deprecated - public void clearGeneratorAmounts(World.Environment environment) { - clearGeneratorAmounts(Dimensions.fromEnvironment(environment)); - } - @Nullable @Override public Key generateBlock(Location location, boolean optimizeDefaultBlock) { @@ -4495,24 +4344,12 @@ public Key generateBlock(Location location, Dimension dimension, boolean optimiz return generatedBlock; } - @Override - @Deprecated - public Key generateBlock(Location location, World.Environment environment, boolean optimizeDefaultBlock) { - return generateBlock(location, Dimensions.fromEnvironment(environment), optimizeDefaultBlock); - } - @Override public boolean wasSchematicGenerated(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); return this.generatedSchematics.readAndGet(generatedSchematics -> generatedSchematics.contains(dimension)); } - @Override - @Deprecated - public boolean wasSchematicGenerated(World.Environment environment) { - return wasSchematicGenerated(Dimensions.fromEnvironment(environment)); - } - @Override public void setSchematicGenerate(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); @@ -4534,18 +4371,6 @@ public void setSchematicGenerate(Dimension dimension, boolean generated) { IslandsDatabaseBridge.saveGeneratedSchematics(this); } - @Override - @Deprecated - public void setSchematicGenerate(World.Environment environment) { - setSchematicGenerate(Dimensions.fromEnvironment(environment)); - } - - @Override - @Deprecated - public void setSchematicGenerate(World.Environment environment, boolean generated) { - setSchematicGenerate(Dimensions.fromEnvironment(environment), generated); - } - @Override public Set getGeneratedSchematics() { return Collections.unmodifiableSet(this.generatedSchematics.readAndGet(generatedSchematics -> @@ -5374,6 +5199,10 @@ private void notifyCropGrowthChange(double newCropGrowth) { }); } + private Location worldPositionToLocation(Dimension dimension, WorldPosition worldPosition) { + return IslandWorlds.setWorldToLocation(this, dimension, worldPosition); + } + public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SIsland::onSettingsUpdate); } @@ -5388,6 +5217,31 @@ private static void onSettingsUpdate() { }); } + private static WorldPosition adjustPositionToCenterOfBlock(@Nullable WorldPosition worldPosition) { + if (worldPosition == null) + return null; + + boolean changed = false; + + BlockPosition blockPosition = worldPosition.toBlockPosition(); + + double x = worldPosition.getX(); + double z = worldPosition.getZ(); + + if (worldPosition.getX() - 0.5 != blockPosition.getX()) { + x = blockPosition.getX() + 0.5; + changed = true; + } + + if (worldPosition.getZ() - 0.5 != blockPosition.getZ()) { + z = blockPosition.getZ() + 0.5; + changed = true; + } + + return !changed ? worldPosition : + SWorldPosition.of(x, worldPosition.getY(), z, worldPosition.getYaw(), worldPosition.getPitch()); + } + public static class UniqueVisitor { private final Pair pair; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 60c42772c4..0e66cf4715 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -34,6 +34,7 @@ import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.IslandArea; import com.bgsoftware.superiorskyblock.core.LazyReference; @@ -138,41 +139,35 @@ protected IslandCache create() { private final int islandSize; private final IslandArea islandArea = new IslandArea(); - private final float homeYaw; - private final float homePitch; - private Biome biome = Biome.PLAINS; public SpawnIsland() throws ManagerLoadException { String spawnLocation = plugin.getSettings().getSpawn().getLocation(); - Location smartCenter = Serializers.LOCATION_SPACED_SERIALIZER.deserialize(spawnLocation); - if (smartCenter == null) { + Location centerLocation = Serializers.LOCATION_SPACED_SERIALIZER.deserialize(spawnLocation); + if (centerLocation == null) { throw new ManagerLoadException("The spawn location could not be parsed", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } String worldName = spawnLocation.split(", ")[0]; - if (smartCenter.getWorld() == null) + if (centerLocation.getWorld() == null) plugin.getProviders().runWorldsListeners(worldName); - this.spawnWorld = smartCenter.getWorld(); + this.spawnWorld = centerLocation.getWorld(); if (this.spawnWorld == null) throw new ManagerLoadException("The spawn location is in invalid world.", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); this.islandSize = plugin.getSettings().getSpawn().getSize(); - this.center = new SBlockPosition(worldName, smartCenter.getBlockX(), smartCenter.getBlockY(), smartCenter.getBlockZ()); + this.center = SBlockPosition.of(centerLocation); this.islandArea.update(this.center, this.islandSize); this.spawnWorldInfo = new WorldInfoImpl(this.spawnWorld.getName(), Dimensions.fromEnvironment(this.spawnWorld.getEnvironment())); - this.homeYaw = smartCenter.getYaw(); - this.homePitch = smartCenter.getPitch(); - this.dirtyChunksContainer = new DirtyChunksContainer(this); - BukkitExecutor.sync(() -> biome = getCenter((Dimension) null /* unused */).getBlock().getBiome()); + BukkitExecutor.sync(() -> biome = getCenter(null /* unused */).getBlock().getBiome()); } @Override @@ -351,18 +346,17 @@ public boolean isVisitor(SuperiorPlayer superiorPlayer, boolean includeCoopStatu @Override public Location getCenter(Dimension unused) { - return center.parse(this.spawnWorld).add(0.5, 0, 0.5); + return this.center.toWorldPosition().toLocation(this.spawnWorld); } @Override - @Deprecated - public Location getCenter(World.Environment environment) { - return getCenter((Dimension) null /* unused */); + public BlockPosition getCenterPosition() { + return this.center; } @Override - public BlockPosition getCenterPosition() { - return this.center; + public CompletableFuture accessIslandWorld(Dimension unused) { + return CompletableFuture.completedFuture(this.spawnWorld); } public World getSpawnWorld() { @@ -373,57 +367,29 @@ public WorldInfo getSpawnWorldInfo() { return spawnWorldInfo; } - @Override - @Deprecated - public Location getTeleportLocation(World.Environment unused) { - return this.getIslandHome((Dimension) null /*unused*/); - } - - @Override - @Deprecated - public Map getTeleportLocations() { - return Collections.emptyMap(); - } - - @Override - @Deprecated - public void setTeleportLocation(Location teleportLocation) { - // Do nothing. - } - - @Override - @Deprecated - public void setTeleportLocation(World.Environment environment, @Nullable Location teleportLocation) { - // Do nothing. - } - @Override public Location getIslandHome(Dimension unused) { - Location center = getCenter((Dimension) null /*unused*/); - center.setYaw(this.homeYaw); - center.setPitch(this.homePitch); - return center; + return getCenter(null /*unused*/); } @Override - @Deprecated - public Location getIslandHome(World.Environment environment) { - return getIslandHome((Dimension) null /*unused*/); + public WorldPosition getIslandHomePosition(Dimension unused) { + return getCenterPosition().toWorldPosition(); } @Override public Map getIslandHomesAsDimensions() { return Collections.singletonMap( plugin.getSettings().getWorlds().getDefaultWorldDimension(), - getIslandHome((Dimension) null /*unused*/)); + getIslandHome(null /*unused*/)); } @Override @Deprecated - public Map getIslandHomes() { + public Map getIslandHomes() { return Collections.singletonMap( - plugin.getSettings().getWorlds().getDefaultWorldDimension().getEnvironment(), - getIslandHome((Dimension) null /*unused*/)); + plugin.getSettings().getWorlds().getDefaultWorldDimension(), + getIslandHomePosition(null /*unused*/)); } @Override @@ -437,41 +403,38 @@ public void setIslandHome(Dimension dimension, Location homeLocation) { } @Override - @Deprecated - public void setIslandHome(World.Environment environment, @Nullable Location homeLocation) { + public void setIslandHome(Dimension dimension, WorldPosition homePosition) { // Do nothing. } @Override - public Location getVisitorsLocation() { - return getVisitorsLocation((Dimension) null /* unused */); + public Location getVisitorsLocation(Dimension unused) { + return this.getIslandHome(null /*unused*/); } @Override - public Location getVisitorsLocation(Dimension dimension) { - return this.getIslandHome((Dimension) null /*unused*/); + public WorldPosition getVisitorsPosition(Dimension unused) { + return getIslandHomePosition(null /*unused*/); } - @Nullable @Override - @Deprecated - public Location getVisitorsLocation(World.Environment unused) { - return this.getIslandHome((Dimension) null /*unused*/); + public void setVisitorsLocation(Location visitorsLocation) { + // Do nothing. } @Override - public void setVisitorsLocation(Location visitorsLocation) { + public void setVisitorsLocation(Dimension dimension, WorldPosition visitorsPosition) { // Do nothing. } @Override public Location getMinimum() { - return this.getMinimumPosition().parse(this.spawnWorld).add(0.5, 0, 0.5); + return this.getMinimumPosition().toWorldPosition().toLocation(this.spawnWorld); } @Override public BlockPosition getMinimumPosition() { - return this.center.offset(-this.islandSize, 0, -this.islandSize); + return getCenterPosition().offset(-this.islandSize, 0, -this.islandSize); } @Override @@ -486,12 +449,12 @@ public BlockPosition getMinimumProtectedPosition() { @Override public Location getMaximum() { - return this.getMaximumPosition().parse(this.spawnWorld).add(0.5, 0, 0.5); + return this.getMaximumPosition().toWorldPosition().toLocation(this.spawnWorld); } @Override public BlockPosition getMaximumPosition() { - return this.center.offset(this.islandSize, 0, this.islandSize); + return getCenterPosition().offset(this.islandSize, 0, this.islandSize); } @Override @@ -547,39 +510,6 @@ public List getAllChunks(Dimension unused, @IslandChunkFlags int flags) { return Collections.unmodifiableList(chunks); } - @Override - @Deprecated - public List getAllChunks(World.Environment environment) { - return getAllChunks((Dimension) null /*unused*/, 0); - } - - @Override - @Deprecated - public List getAllChunks(World.Environment environment, @IslandChunkFlags int flags) { - return getAllChunks((Dimension) null /*unused*/, flags); - } - - @Override - @Deprecated - public List getAllChunks(boolean onlyProtected) { - return getAllChunks(onlyProtected ? IslandChunkFlags.ONLY_PROTECTED : 0); - } - - @Override - @Deprecated - public List getAllChunks(World.Environment environment, boolean onlyProtected) { - return getAllChunks(Dimensions.fromEnvironment(environment), onlyProtected ? IslandChunkFlags.ONLY_PROTECTED : 0); - } - - @Override - @Deprecated - public List getAllChunks(World.Environment environment, boolean onlyProtected, boolean noEmptyChunks) { - int flags = 0; - if (onlyProtected) flags |= IslandChunkFlags.ONLY_PROTECTED; - if (noEmptyChunks) flags |= IslandChunkFlags.NO_EMPTY_CHUNKS; - return getAllChunks(Dimensions.fromEnvironment(environment), flags); - } - @Override public List getLoadedChunks() { return getLoadedChunks(0); @@ -620,34 +550,6 @@ public List getLoadedChunks(Dimension unused, @IslandChunkFlags int flags return Collections.unmodifiableList(chunks); } - @Override - public List getLoadedChunks(World.Environment unused) { - return getLoadedChunks((Dimension) null /*unused*/, 0); - } - - @Override - public List getLoadedChunks(World.Environment unused, @IslandChunkFlags int flags) { - return getLoadedChunks((Dimension) null /*unused*/, flags); - } - - @Override - @Deprecated - public List getLoadedChunks(boolean onlyProtected, boolean noEmptyChunks) { - int flags = 0; - if (onlyProtected) flags |= IslandChunkFlags.ONLY_PROTECTED; - if (noEmptyChunks) flags |= IslandChunkFlags.NO_EMPTY_CHUNKS; - return getLoadedChunks(flags); - } - - @Override - @Deprecated - public List getLoadedChunks(World.Environment unused, boolean onlyProtected, boolean noEmptyChunks) { - int flags = 0; - if (onlyProtected) flags |= IslandChunkFlags.ONLY_PROTECTED; - if (noEmptyChunks) flags |= IslandChunkFlags.NO_EMPTY_CHUNKS; - return getLoadedChunks((Dimension) null /*unused*/, flags); - } - @Override public List> getAllChunksAsync(Dimension unused) { return getAllChunksAsync((Dimension) null /*unused*/, 0); @@ -671,46 +573,6 @@ public List> getAllChunksAsync(Dimension unused, return IslandUtils.getAllChunksAsync(this, spawnWorldInfo, flags, ChunkLoadReason.API_REQUEST, onChunkLoad); } - @Override - public List> getAllChunksAsync(World.Environment unused) { - return getAllChunksAsync((Dimension) null /*unused*/); - } - - @Override - public List> getAllChunksAsync(World.Environment unused, @IslandChunkFlags int flags) { - return getAllChunksAsync((Dimension) null /*unused*/, flags); - } - - @Override - public List> getAllChunksAsync(World.Environment unused, - @Nullable Consumer onChunkLoad) { - return getAllChunksAsync((Dimension) null /*unused*/, onChunkLoad); - } - - @Override - public List> getAllChunksAsync(World.Environment unused, @IslandChunkFlags int flags, - @Nullable Consumer onChunkLoad) { - return getAllChunksAsync((Dimension) null /*unused*/, flags, onChunkLoad); - } - - @Override - @Deprecated - public List> getAllChunksAsync(World.Environment unused, boolean onlyProtected, - @Nullable Consumer onChunkLoad) { - return getAllChunksAsync((Dimension) null /*unused*/, onlyProtected ? IslandChunkFlags.ONLY_PROTECTED : 0, onChunkLoad); - } - - @Override - @Deprecated - public List> getAllChunksAsync(World.Environment unused, - boolean onlyProtected, boolean noEmptyChunks, - @Nullable Consumer onChunkLoad) { - int flags = 0; - if (onlyProtected) flags |= IslandChunkFlags.ONLY_PROTECTED; - if (noEmptyChunks) flags |= IslandChunkFlags.NO_EMPTY_CHUNKS; - return getAllChunksAsync((Dimension) null /*unused*/, flags, onChunkLoad); - } - @Override public void resetChunks() { // Do nothing. @@ -752,85 +614,107 @@ public void resetChunks(Dimension dimension, @IslandChunkFlags int flags, @Nulla } @Override - public void resetChunks(World.Environment environment) { - // Do nothing. + public boolean isInside(Location location) { + return isInside(location, 0D); } @Override - public void resetChunks(World.Environment environment, @Nullable Runnable onFinish) { - // Do nothing. + public boolean isInside(Location location, int extraRadius) { + return isInside(location, (double) extraRadius); } @Override - public void resetChunks(World.Environment environment, @IslandChunkFlags int flags) { - // Do nothing. + public boolean isInside(Location location, double extraRadius) { + World bukkitWorld = location.getWorld(); + if (bukkitWorld == null || !bukkitWorld.equals(this.spawnWorld)) + return false; + + return this.islandArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); } @Override - public void resetChunks(World.Environment environment, @IslandChunkFlags int flags, @Nullable Runnable onFinish) { - // Do nothing. + public boolean isInside(BlockPosition blockPosition) { + return isInside(blockPosition, 0D); } @Override - @Deprecated - public void resetChunks(World.Environment environment, boolean onlyProtected) { - // Do nothing. + public boolean isInside(BlockPosition blockPosition, int extraRadius) { + return isInside(blockPosition, (double) extraRadius); } @Override - @Deprecated - public void resetChunks(World.Environment environment, boolean onlyProtected, @Nullable Runnable onFinish) { - // Do nothing. + public boolean isInside(BlockPosition blockPosition, double extraRadius) { + return this.islandArea.expandAndIntercepts(blockPosition.getX(), blockPosition.getZ(), extraRadius); } @Override - @Deprecated - public void resetChunks(boolean onlyProtected) { - // Do nothing. + public boolean isInside(WorldPosition worldPosition) { + return isInside(worldPosition, 0D); } @Override - @Deprecated - public void resetChunks(boolean onlyProtected, @Nullable Runnable onFinish) { - // Do nothing. + public boolean isInside(WorldPosition worldPosition, int extraRadius) { + return isInside(worldPosition, (double) extraRadius); } @Override - public boolean isInside(Location location) { - return isInside(location, 0); + public boolean isInside(WorldPosition worldPosition, double extraRadius) { + return this.islandArea.expandAndIntercepts(worldPosition.getX(), worldPosition.getZ(), extraRadius); } @Override - public boolean isInside(Location location, int extraRadius) { - return isInside(location, (double) extraRadius); + public boolean isInside(Chunk chunk) { + return isInside(chunk.getWorld(), chunk.getX(), chunk.getZ()); } @Override - public boolean isInside(Location location, double extraRadius) { - World bukkitWorld = location.getWorld(); - if (bukkitWorld == null || !bukkitWorld.equals(this.spawnWorld)) - return false; + public boolean isInside(World world, int chunkX, int chunkZ) { + return isInside(world, chunkX, chunkZ, 0D); + } - return this.islandArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); + @Override + public boolean isInside(World world, int chunkX, int chunkZ, int extraRadius) { + return isInside(world, chunkX, chunkZ, (double) extraRadius); } @Override - public boolean isInside(World world, int chunkX, int chunkZ) { - return world.equals(this.spawnWorld) && isChunkInside(chunkX, chunkZ); + public boolean isInside(World world, int chunkX, int chunkZ, double extraRadius) { + return world.equals(this.spawnWorld) && isInside(chunkX, chunkZ, extraRadius); } @Override public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ) { - return this.spawnWorldInfo.getName().equals(worldInfo.getName()) && isChunkInside(chunkX, chunkZ); + return isInside(worldInfo, chunkX, chunkZ, 0D); } - public boolean isChunkInside(int chunkX, int chunkZ) { - return this.islandArea.rshiftAndIntercepts(chunkX, chunkZ, 4); + @Override + public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) { + return isInside(worldInfo, chunkX, chunkZ, (double) extraRadius); + } + + @Override + public boolean isInside(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) { + return this.spawnWorldInfo.getName().equals(worldInfo.getName()) && isInside(chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInside(int chunkX, int chunkZ) { + return isInside(chunkX, chunkZ, 0D); + } + + @Override + public boolean isInside(int chunkX, int chunkZ, int extraRadius) { + return isInside(chunkX, chunkZ, (double) extraRadius); + } + + @Override + public boolean isInside(int chunkX, int chunkZ, double extraRadius) { + return this.islandArea.expandRshiftAndIntercepts(chunkX, chunkZ, extraRadius, 4); } @Override public boolean isInsideRange(Location location) { - return isInsideRange(location, 0); + return isInside(location); } @Override @@ -843,16 +727,84 @@ public boolean isInsideRange(Location location, double extraRadius) { return isInside(location, extraRadius); } + @Override + public boolean isInsideRange(BlockPosition blockPosition) { + return isInside(blockPosition); + } + + @Override + public boolean isInsideRange(BlockPosition blockPosition, int extraRadius) { + return isInside(blockPosition, extraRadius); + } + + @Override + public boolean isInsideRange(BlockPosition blockPosition, double extraRadius) { + return isInside(blockPosition, extraRadius); + } + + @Override + public boolean isInsideRange(WorldPosition worldPosition) { + return isInside(worldPosition); + } + + @Override + public boolean isInsideRange(WorldPosition worldPosition, int extraRadius) { + return isInside(worldPosition, extraRadius); + } + + @Override + public boolean isInsideRange(WorldPosition worldPosition, double extraRadius) { + return isInside(worldPosition, extraRadius); + } + @Override public boolean isInsideRange(Chunk chunk) { - if (!chunk.getWorld().equals(this.spawnWorld)) - return false; + return isInside(chunk); + } - Location min = getMinimum(); - Location max = getMaximum(); + @Override + public boolean isInsideRange(World world, int chunkX, int chunkZ) { + return isInside(world, chunkX, chunkZ); + } - return (min.getBlockX() >> 4) <= chunk.getX() && (min.getBlockZ() >> 4) <= chunk.getZ() && - (max.getBlockX() >> 4) >= chunk.getX() && (max.getBlockZ() >> 4) >= chunk.getZ(); + @Override + public boolean isInsideRange(World world, int chunkX, int chunkZ, int extraRadius) { + return isInside(world, chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInsideRange(World world, int chunkX, int chunkZ, double extraRadius) { + return isInside(world, chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ) { + return isInside(worldInfo, chunkX, chunkZ); + } + + @Override + public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, int extraRadius) { + return isInside(worldInfo, chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInsideRange(WorldInfo worldInfo, int chunkX, int chunkZ, double extraRadius) { + return isInside(worldInfo, chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInsideRange(int chunkX, int chunkZ) { + return isInside(chunkX, chunkZ); + } + + @Override + public boolean isInsideRange(int chunkX, int chunkZ, int extraRadius) { + return isInside(chunkX, chunkZ, extraRadius); + } + + @Override + public boolean isInsideRange(int chunkX, int chunkZ, double extraRadius) { + return isInside(chunkX, chunkZ, extraRadius); } @Override @@ -1459,7 +1411,7 @@ public boolean isChunkDirty(World world, int chunkX, int chunkZ) { @Override public boolean isChunkDirty(String worldName, int chunkX, int chunkZ) { Preconditions.checkNotNull(worldName, "worldName parameter cannot be null."); - Preconditions.checkArgument(this.spawnWorldInfo.getName().equals(worldName) && isChunkInside(chunkX, chunkZ), + Preconditions.checkArgument(this.spawnWorldInfo.getName().equals(worldName) && isInside(chunkX, chunkZ), "Chunk must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(this.spawnWorldInfo, chunkX, chunkZ)) { return this.dirtyChunksContainer.isMarkedDirty(chunkPosition); @@ -2027,118 +1979,51 @@ public boolean setGeneratorPercentage(Key key, int percentage, Dimension dimensi return true; } - @Override - @Deprecated - public void setGeneratorPercentage(Key key, int percentage, World.Environment environment) { - // Do nothing. - } - - @Override - @Deprecated - public boolean setGeneratorPercentage(Key key, int percentage, World.Environment environment, - @Nullable SuperiorPlayer caller, boolean callEvent) { - return true; - } - @Override public int getGeneratorPercentage(Key key, Dimension dimension) { return 0; } - @Override - @Deprecated - public int getGeneratorPercentage(Key key, World.Environment environment) { - return 0; - } - @Override public Map getGeneratorPercentages(Dimension dimension) { return Collections.emptyMap(); } - @Override - @Deprecated - public Map getGeneratorPercentages(World.Environment environment) { - return Collections.emptyMap(); - } - @Override public void setGeneratorAmount(Key key, @Size int amount, Dimension dimension) { // Do nothing. } - @Override - @Deprecated - public void setGeneratorAmount(Key key, int amount, World.Environment environment) { - // Do nothing. - } - @Override public void removeGeneratorAmount(Key key, Dimension dimension) { // Do nothing. } - @Override - @Deprecated - public void removeGeneratorAmount(Key key, World.Environment environment) { - // Do nothing. - } - @Override public int getGeneratorAmount(Key key, Dimension dimension) { return 0; } - @Override - @Deprecated - public int getGeneratorAmount(Key key, World.Environment environment) { - return 0; - } - @Override public int getGeneratorTotalAmount(Dimension dimension) { return 0; } - @Override - @Deprecated - public int getGeneratorTotalAmount(World.Environment environment) { - return 0; - } - @Override public Map getGeneratorAmounts(Dimension dimension) { return Collections.emptyMap(); } - @Override - @Deprecated - public Map getGeneratorAmounts(World.Environment environment) { - return Collections.emptyMap(); - } - @Override public Map getCustomGeneratorAmounts(Dimension dimension) { return Collections.emptyMap(); } - @Override - @Deprecated - public Map getCustomGeneratorAmounts(World.Environment environment) { - return Collections.emptyMap(); - } - @Override public void clearGeneratorAmounts(Dimension dimension) { // Do nothing. } - @Override - @Deprecated - public void clearGeneratorAmounts(World.Environment environment) { - // Do nothing. - } - @Nullable @Override public Key generateBlock(Location location, boolean optimizeDefaultBlock) { @@ -2150,24 +2035,11 @@ public Key generateBlock(Location location, Dimension dimension, boolean optimiz return null; } - @Nullable - @Override - @Deprecated - public Key generateBlock(Location location, World.Environment environment, boolean optimizeDefaultBlock) { - return null; - } - @Override public boolean wasSchematicGenerated(Dimension dimension) { return false; } - @Override - @Deprecated - public boolean wasSchematicGenerated(World.Environment environment) { - return true; - } - @Override public void setSchematicGenerate(Dimension dimension) { // Do nothing. @@ -2178,18 +2050,6 @@ public void setSchematicGenerate(Dimension dimension, boolean generated) { // Do nothing. } - @Override - @Deprecated - public void setSchematicGenerate(World.Environment environment) { - // Do nothing. - } - - @Override - @Deprecated - public void setSchematicGenerate(World.Environment environment, boolean generated) { - // Do nothing. - } - @Override public Collection getGeneratedSchematics() { return Collections.emptySet(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java index 00aa2350e0..69039ca76a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCreationAlgorithm.java @@ -59,7 +59,7 @@ public CompletableFuture createIsland(Island.Builder build Preconditions.checkNotNull(builder, "builder parameter cannot be null."); Preconditions.checkArgument(builder instanceof IslandBuilderImpl, "Cannot create an island from custom builder."); Preconditions.checkNotNull(lastIsland, "lastIsland parameter cannot be null."); - + try { return createIslandInternal((IslandBuilderImpl) builder, lastIsland); } catch (Throwable error) { @@ -85,9 +85,8 @@ private CompletableFuture createIslandInternal(IslandBuild long profiler = Profiler.start(ProfileType.CREATE_ISLAND, schematic.getName()); - Location islandLocation = plugin.getProviders().getWorldsProvider().getNextLocation( - lastIsland.parse().clone(), + lastIsland, plugin.getSettings().getIslandHeight(), plugin.getSettings().getMaxIslandSize(), builder.owner.getUniqueId(), diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java index 0dab9913d1..859aabeedd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java @@ -15,11 +15,15 @@ import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.DirtyChunk; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.LegacyMasks; +import com.bgsoftware.superiorskyblock.core.SBlockPosition; +import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; @@ -32,7 +36,6 @@ import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import com.bgsoftware.superiorskyblock.mission.MissionReference; -import com.bgsoftware.superiorskyblock.world.Dimensions; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.World; @@ -43,7 +46,6 @@ import java.math.BigInteger; import java.util.ArrayList; import java.util.Collections; -import java.util.EnumMap; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.Iterator; @@ -64,7 +66,7 @@ public class IslandBuilderImpl implements Island.Builder { @Nullable public SuperiorPlayer owner; public UUID uuid = null; - public Location center = null; + public BlockPosition center = null; public String islandName = ""; @Nullable public String islandType; @@ -82,7 +84,7 @@ public class IslandBuilderImpl implements Island.Builder { public final Set dirtyChunks = new LinkedHashSet<>(); public final KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); public final KeyMap entityCounts = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - public final EnumerateMap islandHomes = new EnumerateMap<>(Dimension.values()); + public final EnumerateMap islandHomes = new EnumerateMap<>(Dimension.values()); public final List members = new LinkedList<>(); public final List bannedPlayers = new LinkedList<>(); public final Map playerPermissions = new LinkedHashMap<>(); @@ -98,7 +100,7 @@ public class IslandBuilderImpl implements Island.Builder { public final Map islandEffects = new LinkedHashMap<>(); public final List islandChests = new ArrayList<>(plugin.getSettings().getIslandChests().getDefaultPages()); public final Int2ObjectMapView roleLimits = CollectionsFactory.createInt2ObjectArrayMap(); - public final EnumerateMap visitorHomes = new EnumerateMap<>(Dimension.values()); + public final EnumerateMap visitorHomes = new EnumerateMap<>(Dimension.values()); public IntValue islandSize = IntValue.syncedFixed(-1); public IntValue warpsLimit = IntValue.syncedFixed(-1); public IntValue teamLimit = IntValue.syncedFixed(-1); @@ -148,13 +150,13 @@ public Island.Builder setCenter(Location center) { Preconditions.checkNotNull(center, "center parameter cannot be null."); Preconditions.checkState(isValidCenter(center), "The provided center is not centered. center: " + center + ", maxIslandSize: " + plugin.getSettings().getMaxIslandSize()); - this.center = center; + this.center = SBlockPosition.of(center); return this; } @Override public Location getCenter() { - return this.center; + return this.center.toLocation((World) null); } @Override @@ -374,38 +376,29 @@ public KeyMap getEntityCounts() { @Override public Island.Builder setIslandHome(Location location, Dimension dimension) { Preconditions.checkNotNull(location, "location parameter cannot be null."); - Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); - this.islandHomes.put(dimension, location); - return this; + return setIslandHome(dimension, SWorldPosition.of(location)); } @Override - @Deprecated - public Island.Builder setIslandHome(Location location, World.Environment environment) { - return setIslandHome(location, Dimensions.fromEnvironment(environment)); + public Island.Builder setIslandHome(Dimension dimension, WorldPosition worldPosition) { + Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); + Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null."); + this.islandHomes.put(dimension, worldPosition); + return this; } @Override public Map getIslandHomesAsDimensions() { - return Collections.unmodifiableMap(this.islandHomes.collect(Dimension.values())); - } - - @Override - @Deprecated - public Map getIslandHomes() { - EnumMap islandHomes = new EnumMap<>(World.Environment.class); + Map islandHomes = new LinkedHashMap<>(); for (Dimension dimension : Dimension.values()) { - Location islandHome = this.islandHomes.get(dimension); + WorldPosition islandHome = this.islandHomes.get(dimension); if (islandHome != null) { - Object oldValue = islandHomes.put(dimension.getEnvironment(), islandHome); - if (oldValue != null) - throw new IllegalStateException("Called getIslandHomes but there are multiple environments. " + - "Use getIslandHomesAsDimensions instead."); + islandHomes.put(dimension, islandHome.toLocation((World) null)); } } - return Collections.unmodifiableMap(islandHomes); + return islandHomes.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(islandHomes); } @Override @@ -548,12 +541,6 @@ public Island.Builder setGeneratorRate(Key block, int rate, Dimension dimension) return this; } - @Override - @Deprecated - public Island.Builder setGeneratorRate(Key block, int rate, World.Environment environment) { - return setGeneratorRate(block, rate, Dimensions.fromEnvironment(environment)); - } - @Override public Map> getGeneratorRatesAsDimensions() { Map> result = new IdentityHashMap<>(); @@ -572,25 +559,6 @@ public Map> getGeneratorRatesAsDimensions() { return Collections.unmodifiableMap(result); } - @Override - @Deprecated - public Map> getGeneratorRates() { - EnumMap> result = new EnumMap<>(World.Environment.class); - - for (Dimension dimension : Dimension.values()) { - KeyMap dimensionGeneratorValues = this.cobbleGeneratorValues.get(dimension); - if (dimensionGeneratorValues != null) { - KeyMap oldValue = result.put(dimension.getEnvironment(), - KeyMap.createKeyMap(IntValue.unboxMap(dimensionGeneratorValues))); - if (oldValue != null) - throw new IllegalStateException("Called getGeneratorRates but there are multiple environments. " + - "Use getGeneratorRatesAsDimensions instead."); - } - } - - return Collections.unmodifiableMap(result); - } - @Override public Island.Builder addUniqueVisitor(SuperiorPlayer superiorPlayer, long visitTime) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); @@ -677,38 +645,29 @@ public Map getRoleLimits() { @Override public Island.Builder setVisitorHome(Location location, Dimension dimension) { Preconditions.checkNotNull(location, "location parameter cannot be null."); - Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); - this.visitorHomes.put(dimension, location); - return this; + return setVisitorHome(dimension, SWorldPosition.of(location)); } @Override - @Deprecated - public Island.Builder setVisitorHome(Location location, World.Environment environment) { - return setVisitorHome(location, Dimensions.fromEnvironment(environment)); + public Island.Builder setVisitorHome(Dimension dimension, WorldPosition worldPosition) { + Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); + Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null."); + this.visitorHomes.put(dimension, worldPosition); + return this; } @Override public Map getVisitorHomesAsDimensions() { - return Collections.unmodifiableMap(this.visitorHomes.collect(Dimension.values())); - } - - @Override - @Deprecated - public Map getVisitorHomes() { - EnumMap visitorHomes = new EnumMap<>(World.Environment.class); + Map visitorHomes = new LinkedHashMap<>(); for (Dimension dimension : Dimension.values()) { - Location visitorHome = this.visitorHomes.get(dimension); + WorldPosition visitorHome = this.visitorHomes.get(dimension); if (visitorHome != null) { - Object oldValue = visitorHomes.put(dimension.getEnvironment(), visitorHome); - if (oldValue != null) - throw new IllegalStateException("Called getVisitorHomes but there are multiple environments. " + - "Use getVisitorHomesAsDimensions instead."); + visitorHomes.put(dimension, visitorHome.toLocation((World) null)); } } - return Collections.unmodifiableMap(visitorHomes); + return visitorHomes.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(visitorHomes); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java index 3994d99593..a2d32f94ac 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/SignsListener.java @@ -3,8 +3,6 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; -import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; @@ -193,7 +191,7 @@ private void registerListeners() { } private static boolean isValidIsland(Island island) { - return island != null && (!island.getIslandWarps().isEmpty() || island.getVisitorsLocation((Dimension) null) != null); + return island != null && (!island.getIslandWarps().isEmpty() || island.getVisitorsPosition(null) != null); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index f253709d06..b784628e3b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -843,7 +843,7 @@ public void setSchematicPos1(@Nullable Block block) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Log.debug(Debug.SET_SCHEMATIC_POSITION, getName(), block == null ? "null" : block.getLocation(wrapper.getHandle())); } - this.schematicPos1 = block == null ? null : new SBlockPosition(block); + this.schematicPos1 = block == null ? null : SBlockPosition.of(block); } @Override @@ -856,7 +856,7 @@ public void setSchematicPos2(@Nullable Block block) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Log.debug(Debug.SET_SCHEMATIC_POSITION, getName(), block == null ? "null" : block.getLocation(wrapper.getHandle())); } - this.schematicPos2 = block == null ? null : new SBlockPosition(block); + this.schematicPos2 = block == null ? null : SBlockPosition.of(block); } /* diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index a6c8c5a1db..7ebdc97e3c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -221,14 +221,16 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { Formatters.BOOLEAN_FORMATTER.format(island.isEndEnabled(), superiorPlayer.getUserLocale())) .put("exists", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island != null, superiorPlayer.getUserLocale())) - .put("home", (island, superiorPlayer) -> - Formatters.LOCATION_FORMATTER.format(island.getIslandHome(getDefaultWorldInfo(island).getDimension()))) + .put("home", (island, superiorPlayer) -> { + WorldInfo worldInfo = getDefaultWorldInfo(island); + return Formatters.LOCATION_FORMATTER.format(island.getIslandHomePosition(worldInfo.getDimension()).toLocation(worldInfo)); + }) .put("home_x", (island, superiorPlayer) -> - island.getIslandHome(getDefaultWorldInfo(island).getDimension()).getBlockX() + "") + island.getIslandHomePosition(getDefaultWorldDimension()).getX() + "") .put("home_y", (island, superiorPlayer) -> - island.getIslandHome(getDefaultWorldInfo(island).getDimension()).getBlockY() + "") + island.getIslandHomePosition(getDefaultWorldDimension()).getY() + "") .put("home_z", (island, superiorPlayer) -> - island.getIslandHome(getDefaultWorldInfo(island).getDimension()).getBlockZ() + "") + island.getIslandHomePosition(getDefaultWorldDimension()).getZ() + "") .put("is_coop", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isCoop(superiorPlayer), superiorPlayer.getUserLocale())) .put("is_leader", (island, superiorPlayer) -> @@ -383,14 +385,16 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { } return teamBuilder.substring(2); }) - .put("visitors_location", (island, superiorPlayer) -> - Formatters.LOCATION_FORMATTER.format(island.getVisitorsLocation(getDefaultWorldInfo(island).getDimension()))) + .put("visitors_location", (island, superiorPlayer) -> { + WorldInfo worldInfo = getDefaultWorldInfo(island); + return Formatters.LOCATION_FORMATTER.format(island.getVisitorsPosition(null /*unused*/).toLocation(worldInfo)); + }) .put("visitors_location_x", (island, superiorPlayer) -> - island.getVisitorsLocation(getDefaultWorldInfo(island).getDimension()).getBlockX() + "") + island.getVisitorsPosition(getDefaultWorldDimension()).getX() + "") .put("visitors_location_y", (island, superiorPlayer) -> - island.getVisitorsLocation(getDefaultWorldInfo(island).getDimension()).getBlockY() + "") + island.getVisitorsPosition(getDefaultWorldDimension()).getY() + "") .put("visitors_location_z", (island, superiorPlayer) -> - island.getVisitorsLocation(getDefaultWorldInfo(island).getDimension()).getBlockZ() + "") + island.getVisitorsPosition(getDefaultWorldDimension()).getZ() + "") .put("warps", (island, superiorPlayer) -> island.getIslandWarps().size() + "") .put("warps_limit", (island, superiorPlayer) -> @@ -881,4 +885,8 @@ private static WorldInfo getDefaultWorldInfo(Island island) { return plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension()); } + private static Dimension getDefaultWorldDimension() { + return plugin.getSettings().getWorlds().getDefaultWorldDimension(); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java index 6f3c681f97..e5df2639fb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java @@ -269,7 +269,7 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island } Location homeLocation = schematic.adjustRotation(centerLocation); - island.setIslandHome(destination, homeLocation); + island.setIslandHome(homeLocation); if (destination.getEnvironment() == World.Environment.THE_END && superiorPlayer != null) { plugin.getNMSDragonFight().awardTheEndAchievement((Player) entity); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index 018b09f55f..819ff87e2d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -201,7 +201,9 @@ public void saveSchematic(SuperiorPlayer superiorPlayer, String schematicName, b .setSaveAir(saveAir) .build(); - saveSchematic(pos1.parse(), pos2.parse(), schematicOptions, () -> Message.SCHEMATIC_SAVED.send(superiorPlayer)); + World world = offset.getWorld(); + saveSchematic(pos1.toLocation(world), pos2.toLocation(world), schematicOptions, + () -> Message.SCHEMATIC_SAVED.send(superiorPlayer)); superiorPlayer.setSchematicPos1(null); superiorPlayer.setSchematicPos2(null); From e7f892e0e997f664dd33ed9fcd54391e46e4c3d5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 7 Oct 2025 22:55:14 +0300 Subject: [PATCH 364/600] Fix deserializing of WorldPositions (#2698) --- .../core/serialization/impl/WorldPositionSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/WorldPositionSerializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/WorldPositionSerializer.java index f515c220c6..6f90cb0f8f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/WorldPositionSerializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/WorldPositionSerializer.java @@ -36,7 +36,7 @@ public WorldPosition deserialize(@Nullable String element) { return null; try { - String[] sections = element.split(", "); + String[] sections = element.split(","); int startIndex = 0; if (sections.length >= 6) { From ec258c12c35e74563803211b1aecaa179f4787e3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 7 Oct 2025 22:56:51 +0300 Subject: [PATCH 365/600] Fix teleporting using admin teleport command can throw errors if the world is not loaded --- .../superiorskyblock/commands/admin/CmdAdminTeleport.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java index 84e919da5c..2b936953d7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.portals.PortalsManagerService; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; @@ -95,7 +96,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (dimension != plugin.getSettings().getWorlds().getDefaultWorldDimension()) { if (!island.wasSchematicGenerated(dimension)) { PortalType portalType = dimension.getEnvironment() == World.Environment.NETHER ? PortalType.NETHER : PortalType.ENDER; - Location homeLocation = island.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()); + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); + Location homeLocation = island.getIslandHomePosition(dimension).toLocation(worldInfo); IslandWorlds.accessIslandWorldAsync(island, homeLocation, true, islandWorldResult -> { islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { homeLocation.setWorld(world); From 48208d366cde367c4c3717a26dccabf162dbf186 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 8 Oct 2025 23:40:17 +0300 Subject: [PATCH 366/600] Disable cached schematics due to serious dupe glitch involving them (#2699) --- .../superiorskyblock/world/schematic/SchematicsManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index 819ff87e2d..e512ac7beb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -112,7 +112,7 @@ public void loadSchematics() throws ManagerLoadException { } public void cacheSchematics() { - if (!plugin.getSettings().isCacheSchematics() || plugin.getSettings().getMaxIslandSize() % 4 != 0) + if (!plugin.getSettings().isCacheSchematics() || plugin.getSettings().getMaxIslandSize() % 4 != 0 || true) return; List newSchematics = new LinkedList<>(); From cd4ebe6b44a8e7635737a493bba8d5441e4791c0 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 10 Oct 2025 14:13:13 +0300 Subject: [PATCH 367/600] Adds support to 1.21.10 --- .../templates/AbstractNMSWorld.java.template | 5 +++- NMS/v1_21_9/build.gradle | 17 ++++++++++++- .../nms/v1_21_9/NMSAlgorithmsImpl.java | 7 +++++- .../nms/v1_21_9/NMSChunksImpl.java | 24 +++++++++++++------ .../nms/v1_21_9/NMSTagsImpl.java | 10 ++++---- build.gradle | 2 +- 6 files changed, 48 insertions(+), 17 deletions(-) diff --git a/NMS/src/main/templates/AbstractNMSWorld.java.template b/NMS/src/main/templates/AbstractNMSWorld.java.template index df703217cd..283ac25758 100644 --- a/NMS/src/main/templates/AbstractNMSWorld.java.template +++ b/NMS/src/main/templates/AbstractNMSWorld.java.template @@ -142,7 +142,10 @@ public abstract class AbstractNMSWorld implements NMSWorld { Location center = island.getCenter(dimension); worldBorder = new WorldBorder(); - worldBorder.world = serverLevel; + try { + worldBorder.world = serverLevel; + } catch (Throwable ignored) { + } worldBorder.setWarningBlocks(0); worldBorder.setCenter(center.getX(), center.getZ()); diff --git a/NMS/v1_21_9/build.gradle b/NMS/v1_21_9/build.gradle index 7f628e113f..9f4c3882a7 100644 --- a/NMS/v1_21_9/build.gradle +++ b/NMS/v1_21_9/build.gradle @@ -11,13 +11,28 @@ java { group 'NMS:v1_21_9' dependencies { - paperweight.paperDevBundle("1.21.9-R0.1-SNAPSHOT") + paperweight.paperDevBundle("1.21.10-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") compileOnly rootProject } +shadowJar { + archiveFileName = "${project.name}-exclude.jar" +} + +assemble { + dependsOn(reobfJar) +} + +tasks { + reobfJar { + File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") + outputJar.set(layout.buildDirectory.file(outputFile.getPath())) + } +} + if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java index 314a95dc51..fdb91ad9d8 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_9; +import com.bgsoftware.common.reflection.ReflectField; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; @@ -21,11 +22,15 @@ import org.bukkit.inventory.meta.trim.TrimMaterial; import org.bukkit.inventory.meta.trim.TrimPattern; +import java.lang.reflect.Modifier; import java.util.Locale; import java.util.Objects; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms { + public static final ReflectField SERVER_RECENT_TPS = new ReflectField<>(MinecraftServer.class, + double[].class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create(); @Override @@ -76,7 +81,7 @@ public void makeItemGlow(ItemMeta itemMeta) { @Override public double getCurrentTps() { - return Bukkit.getTPS()[0]; + return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0]; } } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java index c2bb2aa19e..e022b4e81a 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_9; +import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; @@ -16,11 +17,10 @@ import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.logging.LogUtils; +import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; -import net.minecraft.core.Registry; -import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; @@ -64,8 +64,10 @@ public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSChunks { - private static final Logger LOGGER = LogUtils.getLogger(); + private static final ReflectMethod>>> CONTAINER_FACTORY_BIOME_RW_CODEC = + new ReflectMethod<>(PalettedContainerFactory.class, "biomeContainerCodecRW"); + private static final Logger LOGGER = LogUtils.getLogger(); public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -93,7 +95,7 @@ public void onLoadedChunk(LevelChunk levelChunk) { ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null, true); + levelChunk, levelChunk.level.getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); @@ -109,7 +111,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); - DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerRWCodec() + DataResult dataResult = getBiomeContainerRWCodec() .encodeStart(NbtOps.INSTANCE, biomesContainer); Tag biomesCompound = dataResult.getOrThrow(); @@ -264,8 +266,8 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound PalettedContainer> biomesPalettedContainer; Optional biomesCompound = sectionCompound.getCompound("biomes"); if (biomesCompound.isPresent()) { - DataResult>> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY - .biomeContainerRWCodec().parse(NbtOps.INSTANCE, biomesCompound.get()) + DataResult>> dataResult = getBiomeContainerRWCodec() + .parse(NbtOps.INSTANCE, biomesCompound.get()) .promotePartial((sx) -> { }); biomesPalettedContainer = dataResult.getOrThrow(); @@ -362,4 +364,12 @@ private static void removeBlocks(ChunkAccess chunk) { NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); } + private static Codec>> getBiomeContainerRWCodec() { + if (CONTAINER_FACTORY_BIOME_RW_CODEC.isValid()) { + return CONTAINER_FACTORY_BIOME_RW_CODEC.invoke(DEFAULT_PALETTED_CONTAINER_FACTORY); + } else { + return DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerRWCodec(); + } + } + } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java index 4810d897a2..b2476d3243 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java @@ -3,10 +3,11 @@ import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; +import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; -import com.mojang.datafixers.util.Either; import com.mojang.logging.LogUtils; +import net.minecraft.Util; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.ByteArrayTag; import net.minecraft.nbt.IntArrayTag; @@ -19,7 +20,6 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.player.PlayerSkin; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.ResolvableProfile; @@ -28,7 +28,6 @@ import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.slf4j.Logger; -import java.util.Optional; import java.util.Set; public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSTags { @@ -42,10 +41,9 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I Multimap properties = HashMultimap.create(); properties.put("textures", new Property("textures", texture)); - ResolvableProfile.Partial partialProfile = new ResolvableProfile.Partial( - Optional.empty(), Optional.empty(), new PropertyMap(properties)); + GameProfile gameProfile = new GameProfile(Util.NIL_UUID, "", new PropertyMap(properties)); - ResolvableProfile resolvableProfile = new ResolvableProfile.Static(Either.right(partialProfile), PlayerSkin.Patch.EMPTY); + ResolvableProfile resolvableProfile = ResolvableProfile.createResolved(gameProfile); itemStack.set(DataComponents.PROFILE, resolvableProfile); diff --git a/build.gradle b/build.gradle index b8761f6b7c..6585a2e3a7 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b15' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b16' implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b1' implementation 'org.bstats:bstats-bukkit:3.0.0' From 1dcb00cc5b683b574695eeecb9b51e9393478106 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 10 Oct 2025 15:48:07 +0300 Subject: [PATCH 368/600] Fix some tasks are not tracked correctly, causing the plugin to not properly shut down its tasks (#2687) --- NMS/src/main/templates/NMSUtils.java.template | 25 +++++++++------ .../nms/v1_16_R3/NMSUtils.java | 17 +++++++--- .../core/threads/BukkitExecutor.java | 32 +++++++++++++------ 3 files changed, 51 insertions(+), 23 deletions(-) diff --git a/NMS/src/main/templates/NMSUtils.java.template b/NMS/src/main/templates/NMSUtils.java.template index a123030798..f118592508 100644 --- a/NMS/src/main/templates/NMSUtils.java.template +++ b/NMS/src/main/templates/NMSUtils.java.template @@ -394,11 +394,11 @@ public class NMSUtils { public record UnloadedChunkCompound(ChunkPosition chunkPosition, net.minecraft.nbt.CompoundTag chunkCompound) { - public ServerLevel serverLevel() { + public ServerLevel serverLevel () { return ((CraftWorld) chunkPosition.getWorld()).getHandle(); } - public ChunkPos chunkPos() { + public ChunkPos chunkPos () { return new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); } @@ -435,15 +435,22 @@ public class NMSUtils { } public final void onChunkNotExist(ChunkPosition chunkPosition) { - if (!plugin.getProviders().hasCustomWorldsSupport()) + if (!plugin.getProviders().hasCustomWorldsSupport()) { + latchCountDown(); return; + } - ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { - BukkitExecutor.ensureMain(() -> { - ServerLevel serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle(); - LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); - onLoadedChunk(levelChunk); - }); + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, null).whenComplete((bukkitChunk, error) -> { + if (error == null) { + BukkitExecutor.ensureMain(() -> { + ServerLevel serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle(); + LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); + onLoadedChunk(levelChunk); + }); + } else { + latchCountDown(); + throw new RuntimeException(error); + } }); } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java index d14024458a..0df1b2ac12 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSUtils.java @@ -343,12 +343,21 @@ protected final void latchCountDown() { } public final void onChunkNotExist(ChunkPosition chunkPosition) { - if (!plugin.getProviders().hasCustomWorldsSupport()) + if (!plugin.getProviders().hasCustomWorldsSupport()) { + latchCountDown(); return; + } - ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, bukkitChunk -> { - Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); - BukkitExecutor.ensureMain(() -> onLoadedChunk(chunk)); + ChunksProvider.loadChunk(chunkPosition, this.chunkLoadReason, null).whenComplete((bukkitChunk, error) -> { + if (error == null) { + BukkitExecutor.ensureMain(() -> { + Chunk chunk = ((CraftChunk) bukkitChunk).getHandle(); + onLoadedChunk(chunk); + }); + } else { + latchCountDown(); + throw new RuntimeException(error); + } }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java index a3cd9a0d73..36ace404b3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java @@ -148,8 +148,11 @@ public NestedTask runSync(Function function) { } else { onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.ensureMain(() -> { - nestedTask.value.complete(function.apply(value)); - onComplete(); + try { + nestedTask.value.complete(function.apply(value)); + } finally { + onComplete(); + } })); } return nestedTask; @@ -165,9 +168,12 @@ public NestedTask runSync(Consumer consumer) { } else { onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.ensureMain(() -> { - consumer.accept(value); - nestedTask.value.complete(null); - onComplete(); + try { + consumer.accept(value); + nestedTask.value.complete(null); + } finally { + onComplete(); + } })); } return nestedTask; @@ -182,8 +188,11 @@ public NestedTask runAsync(Function function) { } else { onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.async(() -> { - nestedTask.value.complete(function.apply(value)); - onComplete(); + try { + nestedTask.value.complete(function.apply(value)); + } finally { + onComplete(); + } })); } return nestedTask; @@ -199,9 +208,12 @@ public NestedTask runAsync(Consumer consumer) { } else { onCreate(); value.whenComplete((value, ex) -> BukkitExecutor.async(() -> { - consumer.accept(value); - nestedTask.value.complete(null); - onComplete(); + try { + consumer.accept(value); + nestedTask.value.complete(null); + } finally { + onComplete(); + } })); } return nestedTask; From ba55f5703898046ea9cdff30a07917187797d77d Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 10 Oct 2025 15:56:34 +0200 Subject: [PATCH 369/600] Fixed tab completes in island admin commands (#2683) --- .../commands/CommandTabCompletes.java | 11 +++++------ .../commands/IAdminIslandCommand.java | 2 +- .../superiorskyblock/commands/admin/CmdAdminData.java | 2 +- .../superiorskyblock/commands/admin/CmdAdminShow.java | 7 ------- .../superiorskyblock/commands/player/CmdAccept.java | 4 ++-- .../superiorskyblock/commands/player/CmdRate.java | 5 ++--- .../superiorskyblock/commands/player/CmdVisit.java | 2 +- 7 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index 2185944778..ea03f581ea 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -55,7 +55,7 @@ public static List getPlayerIslandsExceptSender(SuperiorSkyblockPlugin p BiPredicate islandPredicate) { SuperiorPlayer superiorPlayer = sender instanceof Player ? plugin.getPlayers().getSuperiorPlayer(sender) : null; Island island = superiorPlayer == null ? null : superiorPlayer.getIsland(); - return getOnlinePlayersWithIslands(plugin, argument, hideVanish, (onlinePlayer, onlineIsland) -> + return getOnlinePlayersAndIslands(plugin, argument, hideVanish, (onlinePlayer, onlineIsland) -> onlineIsland != null && (superiorPlayer == null || island == null || !island.equals(onlineIsland)) && islandPredicate.test(onlinePlayer, onlineIsland)); } @@ -94,9 +94,8 @@ public static List getOnlinePlayers(SuperiorSkyblockPlugin plugin, Strin .map(getOnlineSuperiorPlayers(plugin), SuperiorPlayer::getName); } - public static List getOnlinePlayersWithIslands(SuperiorSkyblockPlugin plugin, String argument, - boolean hideVanish, - @Nullable BiPredicate predicate) { + public static List getOnlinePlayersAndIslands(SuperiorSkyblockPlugin plugin, String argument, boolean hideVanish, + @Nullable BiPredicate predicate) { List tabArguments = new LinkedList<>(); String lowerArgument = argument.toLowerCase(Locale.ENGLISH); @@ -104,10 +103,10 @@ public static List getOnlinePlayersWithIslands(SuperiorSkyblockPlugin pl SuperiorPlayer onlinePlayer = plugin.getPlayers().getSuperiorPlayer(player); if (!hideVanish || onlinePlayer.isShownAsOnline()) { Island onlineIsland = onlinePlayer.getIsland(); - if (predicate == null || predicate.test(onlinePlayer, onlineIsland)) { + if (onlineIsland != null && (predicate == null || predicate.test(onlinePlayer, onlineIsland))) { if (onlinePlayer.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) tabArguments.add(onlinePlayer.getName()); - if (onlineIsland != null && onlineIsland.getStrippedName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) + if (onlineIsland.getStrippedName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) tabArguments.add(onlineIsland.getStrippedName()); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/IAdminIslandCommand.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/IAdminIslandCommand.java index ce44d88145..e05d0048df 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/IAdminIslandCommand.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/IAdminIslandCommand.java @@ -35,7 +35,7 @@ default List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender se if (args.length == 3) { if (supportMultipleIslands() && "*".contains(args[2])) tabVariables.add("*"); - tabVariables.addAll(CommandTabCompletes.getOnlinePlayersWithIslands(plugin, args[2], false, null)); + tabVariables.addAll(CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[2], false, null)); } else if (args.length > 3) { if (supportMultipleIslands()) { tabVariables = adminTabComplete(plugin, sender, null, args); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminData.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminData.java index bb8ce13ecc..61b60efb13 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminData.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminData.java @@ -111,7 +111,7 @@ public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sen case 5: { SubCommand subCommand = subCommands.get(args[2].toLowerCase(Locale.ENGLISH)); return subCommand == null ? Collections.emptyList() : args[3].equalsIgnoreCase("island") ? - CommandTabCompletes.getOnlinePlayersWithIslands(plugin, args[4], false, null) : + CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[4], false, null) : CommandTabCompletes.getOnlinePlayers(plugin, args[4], false); } default: { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java index 37c1bc7a42..7aa161f3c7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java @@ -9,7 +9,6 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; @@ -294,12 +293,6 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ Message.CUSTOM.send(sender, infoMessage.toString(), false); } - @Override - public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { - return args.length == 3 ? CommandTabCompletes.getOnlinePlayersWithIslands(plugin, args[2], false, null) - : Collections.emptyList(); - } - private static Optional collectIslandData(Locale locale, Supplier> dataFunction, Supplier> customDataFunction, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java index 6f3f1655cd..73cf1dd778 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java @@ -109,9 +109,9 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - return args.length == 2 ? CommandTabCompletes.getOnlinePlayersWithIslands(plugin, args[1], + return args.length == 2 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), (onlinePlayer, onlineIsland) -> - onlineIsland != null && onlineIsland.isInvited(superiorPlayer)) : Collections.emptyList(); + onlineIsland.isInvited(superiorPlayer)) : Collections.emptyList(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRate.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRate.java index 9b1ecfb6cf..8a3d5818c5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRate.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdRate.java @@ -89,9 +89,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); Island island = superiorPlayer.getIsland(); - return args.length == 2 ? CommandTabCompletes.getOnlinePlayersWithIslands(plugin, args[1], - plugin.getSettings().isTabCompleteHideVanished(), - (onlinePlayer, onlineIsland) -> onlineIsland != null && + return args.length == 2 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[1], + plugin.getSettings().isTabCompleteHideVanished(), (onlinePlayer, onlineIsland) -> canRateIsland(plugin, superiorPlayer, island, onlineIsland) == RateResult.SUCCESS) : Collections.emptyList(); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java index b8794b14fa..0e2fb18ad9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdVisit.java @@ -80,7 +80,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - return args.length == 2 ? CommandTabCompletes.getOnlinePlayersWithIslands(plugin, args[1], + return args.length == 2 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[1], plugin.getSettings().isTabCompleteHideVanished(), (onlinePlayer, onlineIsland) -> onlineIsland != null && ( (!plugin.getSettings().getVisitorsSign().isRequiredForVisit() || From d16d05ac2548a16964e90fe9e41a88e305b4198a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Oct 2025 12:18:40 +0300 Subject: [PATCH 370/600] Fixed errors when using /is warp and the world is not loaded (#2694) --- .../superiorskyblock/core/LazyWorldLocation.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java b/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java index 4086a41e86..27e30cbd8a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/LazyWorldLocation.java @@ -59,7 +59,7 @@ public void setWorldName(String worldName) { @Override public World getWorld() { if (!this.updatedWorld) { - setWorld(worldName == null ? null : Bukkit.getWorld(worldName)); + updateWorldInternal(worldName == null ? null : Bukkit.getWorld(worldName)); } return super.getWorld(); @@ -67,8 +67,12 @@ public World getWorld() { @Override public void setWorld(World world) { - super.setWorld(world); + updateWorldInternal(world); this.worldName = world == null ? null : world.getName(); + } + + private void updateWorldInternal(@Nullable World world) { + super.setWorld(world); this.updatedWorld = true; } From d61be37e458bbe6e0cf09579d958d009c4398886 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Oct 2025 12:37:39 +0300 Subject: [PATCH 371/600] Fixed reaching minecart entity limits still triggering block place (#2391) --- .../superiorskyblock/listener/BlockChangesListener.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index 2181bebeb7..15abccdbcc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -194,10 +194,6 @@ private void onMinecartPlace(GameEvent e) { if (!(vehicle instanceof Minecart)) return; - // We do not care about spawn island, and therefore only island worlds are relevant. - if (!plugin.getGrid().isIslandsWorld(vehicle.getWorld())) - return; - Key minecartBlockKey = getMinecartBlockKey(vehicle.getType()); if (minecartBlockKey != null) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { @@ -321,10 +317,14 @@ private void onBucketFill(GameEvent e) { private void onEntitySpawn(GameEvent e) { Entity entity = e.getArgs().entity; + if (entity.isDead()) + return; + // We do not care about spawn island, and therefore only island worlds are relevant. if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) return; + onMinecartPlace(e); onDragonEggDrop(e); onGolemStructure(e); } @@ -520,7 +520,6 @@ private void registerListeners() { registerCallback(GameEventType.BLOCK_GROW_EVENT, GameEventPriority.MONITOR, this::onBlockGrow); registerCallback(GameEventType.BLOCK_FORM_EVENT, GameEventPriority.MONITOR, this::onBlockForm); registerCallback(GameEventType.BLOCK_SPREAD_EVENT, GameEventPriority.MONITOR, this::onBlockSpread); - registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.MONITOR, this::onMinecartPlace); registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.MONITOR, this::onSpawnerChange); registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.MONITOR, this::onEntityChangeBlock); registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.MONITOR, this::onBlockBreak); From b89349a67edb1c416d7073662c9b1da583c30244 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Oct 2025 13:13:53 +0300 Subject: [PATCH 372/600] Fix action bars do not support hex colors --- NMS/src/main/templates/NMSPlayersImpl.java.template | 2 +- .../superiorskyblock/nms/v1_12_R1/NMSPlayersImpl.java | 2 +- .../superiorskyblock/nms/v1_16_R3/NMSPlayersImpl.java | 2 +- .../superiorskyblock/nms/v1_8_R3/NMSPlayersImpl.java | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/NMS/src/main/templates/NMSPlayersImpl.java.template b/NMS/src/main/templates/NMSPlayersImpl.java.template index 97513c5af0..cd76f4226f 100644 --- a/NMS/src/main/templates/NMSPlayersImpl.java.template +++ b/NMS/src/main/templates/NMSPlayersImpl.java.template @@ -53,7 +53,7 @@ public class NMSPlayersImpl implements NMSPlayers { @SuppressWarnings("deprecation") @Override public void sendActionBar(Player player, String message) { - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message)); } @Override diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSPlayersImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSPlayersImpl.java index 280e8f3045..c48bda3b6c 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSPlayersImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSPlayersImpl.java @@ -49,7 +49,7 @@ public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { @Override public void sendActionBar(Player player, String message) { //noinspection deprecation - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message)); } @Override diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSPlayersImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSPlayersImpl.java index 0f4ee88c88..b31b31a1c8 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSPlayersImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSPlayersImpl.java @@ -51,7 +51,7 @@ public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { @Override public void sendActionBar(Player player, String message) { //noinspection deprecation - player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(message)); + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message)); } @Override diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSPlayersImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSPlayersImpl.java index dfd0e70861..c3d0e6de82 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSPlayersImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSPlayersImpl.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.service.bossbar.EmptyBossBar; import com.mojang.authlib.properties.Property; +import net.md_5.bungee.api.chat.TextComponent; import net.minecraft.server.v1_8_R3.Entity; import net.minecraft.server.v1_8_R3.EntityItem; import net.minecraft.server.v1_8_R3.EntityPlayer; @@ -47,7 +48,8 @@ public void setSkinTexture(SuperiorPlayer superiorPlayer, Property property) { @Override public void sendActionBar(Player player, String message) { - PacketPlayOutChat packetPlayOutChat = new PacketPlayOutChat(CraftChatMessage.fromString(message)[0], (byte) 2); + PacketPlayOutChat packetPlayOutChat = new PacketPlayOutChat(null, (byte) 2); + packetPlayOutChat.components = TextComponent.fromLegacyText(message); ((CraftPlayer) player).getHandle().playerConnection.sendPacket(packetPlayOutChat); } From 12af8f86f2dfb6a4ec2304aa42998acde991a1cc Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Oct 2025 14:14:14 +0300 Subject: [PATCH 373/600] [CI SKIP] Update README & fix funding link --- .github/FUNDING.yml | 11 +---------- README.md | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 7932aa9a2f..f5bd63f8c9 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,12 +1,3 @@ # These are supported funding model platforms -github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: Ome_R -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] +custom: https://bg-software.com/patreon diff --git a/README.md b/README.md index 590aa71c14..d940f20ad6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

    - +

    The most optimized Skyblock core on the market.


    From a4072a16f956bcbc3a45ba832cbdb050beb55993 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Oct 2025 17:48:32 +0300 Subject: [PATCH 374/600] Adds the ability to debug entities recalculations --- .../templates/AbstractNMSChunks.java.template | 74 ++++++++++++++----- .../nms/v1_12_R1/NMSChunksImpl.java | 32 +++++--- .../nms/v1_16_R3/NMSChunksImpl.java | 51 ++++++++----- .../nms/v1_17/NMSChunksImpl.java | 50 +++++-------- .../nms/v1_18/NMSChunksImpl.java | 52 ++++++------- .../nms/v1_19/NMSChunksImpl.java | 52 ++++++------- .../nms/v1_20_3/NMSChunksImpl.java | 52 ++++++------- .../nms/v1_20_4/NMSChunksImpl.java | 52 ++++++------- .../nms/v1_21/NMSChunksImpl.java | 52 ++++++------- .../nms/v1_21_3/NMSChunksImpl.java | 52 ++++++------- .../nms/v1_21_4/NMSChunksImpl.java | 51 +++++-------- .../nms/v1_21_5/NMSChunksImpl.java | 51 +++++-------- .../nms/v1_21_7/NMSChunksImpl.java | 59 ++++++--------- .../nms/v1_21_9/NMSChunksImpl.java | 59 ++++++--------- .../nms/v1_8_R3/NMSChunksImpl.java | 29 +++++--- .../core/CalculatedChunk.java | 42 ++++++++--- .../superiorskyblock/core/logging/Debug.java | 3 +- .../DefaultIslandCalculationAlgorithm.java | 10 +-- ...DefaultIslandEntitiesTrackerAlgorithm.java | 17 +++-- .../superiorskyblock/nms/NMSChunks.java | 6 +- 20 files changed, 413 insertions(+), 433 deletions(-) diff --git a/NMS/src/main/templates/AbstractNMSChunks.java.template b/NMS/src/main/templates/AbstractNMSChunks.java.template index 8e7cdd8363..440d35b15f 100644 --- a/NMS/src/main/templates/AbstractNMSChunks.java.template +++ b/NMS/src/main/templates/AbstractNMSChunks.java.template @@ -20,9 +20,14 @@ import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsBlockEntity import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsTickingMethod; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.world.BukkitEntities; import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; @@ -40,12 +45,14 @@ import org.bukkit.Location; import org.bukkit.World; import ${CRAFTBUKKIT_PACKAGE}.CraftChunk; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; +import ${CRAFTBUKKIT_PACKAGE}.util.CraftNamespacedKey; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.Optional; import java.util.concurrent.CompletableFuture; public abstract class AbstractNMSChunks implements NMSChunks { @@ -84,15 +91,15 @@ public abstract class AbstractNMSChunks implements NMSChunks { protected abstract NMSUtils.ChunkCallback getDeleteChunkCallback(@Nullable Runnable onFinish); @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); + public CompletableFuture> calculateChunks(List chunkPositions, + Synchronized> unloadedChunksCache) { + List allCalculatedChunks = new LinkedList<>(); List chunkPositionsToCalculate = new LinkedList<>(); Iterator chunkPositionsIterator = chunkPositions.iterator(); while (chunkPositionsIterator.hasNext()) { ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); + CalculatedChunk.Blocks cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); if (cachedCalculatedChunk != null) { allCalculatedChunks.add(cachedCalculatedChunk); chunkPositionsIterator.remove(); @@ -104,7 +111,7 @@ public abstract class AbstractNMSChunks implements NMSChunks { if (chunkPositions.isEmpty()) return CompletableFuture.completedFuture(allCalculatedChunks); - CompletableFuture> completableFuture = new CompletableFuture<>(); + CompletableFuture> completableFuture = new CompletableFuture<>(); NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, getCalculateChunkCallback(completableFuture, unloadedChunksCache, allCalculatedChunks)); @@ -113,26 +120,28 @@ public abstract class AbstractNMSChunks implements NMSChunks { } protected abstract NMSUtils.ChunkCallback getCalculateChunkCallback( - CompletableFuture> completableFuture, - Synchronized> unloadedChunksCache, - List allCalculatedChunks); + CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks); @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); + public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { + CompletableFuture> completableFuture = new CompletableFuture<>(); - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + List allCalculatedChunks = new LinkedList<>(); List unloadedChunkCompounds = new LinkedList<>(); NMSUtils.runActionOnEntityChunks(chunkPositions, - getEntitiesChunkCallback(chunkEntities, unloadedChunkCompounds, completableFuture)); + getEntitiesChunkCallback(allCalculatedChunks, unloadedChunkCompounds, completableFuture)); return completableFuture; } protected abstract NMSUtils.ChunkCallback getEntitiesChunkCallback( - KeyMap chunkEntities, List unloadedChunkCompounds, - CompletableFuture> completableFuture); + List allCalculatedChunks, List unloadedChunkCompounds, + CompletableFuture> completableFuture); + + protected abstract Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel); @Override public void injectChunkSections(Chunk chunk) { @@ -204,7 +213,7 @@ public abstract class AbstractNMSChunks implements NMSChunks { return blockEntities; } - protected CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { + protected CalculatedChunk.Blocks calculateChunk(ChunkPosition chunkPosition, Level level, LevelChunkSection[] chunkSections) { KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); List spawnersLocations = new LinkedList<>(); @@ -220,10 +229,41 @@ public abstract class AbstractNMSChunks implements NMSChunks { } } - return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); + return new CalculatedChunk.Blocks(chunkPosition, blockCounts, spawnersLocations); + } + + protected CalculatedChunk.Entities calculatedChunk(ChunkPosition chunkPosition, LevelChunk levelChunk) { + KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + + for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { + if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) + chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); + } + + return new CalculatedChunk.Entities(chunkPosition, chunkEntities); + } + + protected CalculatedChunk.Entities calculatedChunk(ChunkPosition chunkPosition, ServerLevel serverLevel, ListTag entitiesTag) { + KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + + for (Tag entityTag : entitiesTag) { + Entity fakeEntity = createEntityFromTag((CompoundTag) entityTag, serverLevel).orElse(null); + if(fakeEntity == null) + continue; + + fakeEntity.valid = false; + if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) + continue; + + Key entityKey = Keys.of(fakeEntity.getBukkitEntity()); + + chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); + } + + return new CalculatedChunk.Entities(chunkPosition, chunkEntities); } - protected void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, + private void calculateChunkInternal(BlockState blockState, int x, int y, int z, ChunkPosition chunkPosition, int sectionBottomY, KeyMap blockCounts, List spawnersLocations) { Block block = blockState.getBlock(); diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java index 01c4845b2f..10ad1699b7 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java @@ -10,8 +10,8 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; @@ -50,6 +50,7 @@ import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -135,15 +136,15 @@ private static boolean isChunkSectionEmpty(ChunkSection chunkSection) { } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); + public CompletableFuture> calculateChunks(List chunkPositions, + Synchronized> unloadedChunksCache) { + List allCalculatedChunks = new LinkedList<>(); List chunkPositionsToCalculate = new LinkedList<>(); Iterator chunkPositionsIterator = chunkPositions.iterator(); while (chunkPositionsIterator.hasNext()) { ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); + CalculatedChunk.Blocks cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); if (cachedCalculatedChunk != null) { allCalculatedChunks.add(cachedCalculatedChunk); chunkPositionsIterator.remove(); @@ -155,7 +156,7 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); + CompletableFuture> completableFuture = new CompletableFuture<>(); NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback() { @Override @@ -197,7 +198,7 @@ public void onChunk(Chunk chunk, boolean isLoaded) { } } - CalculatedChunk calculatedChunk = new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); + CalculatedChunk.Blocks calculatedChunk = new CalculatedChunk.Blocks(chunkPosition, blockCounts, spawnersLocations); allCalculatedChunks.add(calculatedChunk); if (!isLoaded) unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -218,19 +219,28 @@ public void onFinish() { } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); + public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { + if (chunkPositions.isEmpty()) + return CompletableFuture.completedFuture(Collections.emptyList()); + + CompletableFuture> completableFuture = new CompletableFuture<>(); - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + List allCalculatedChunks = new LinkedList<>(); NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback() { @Override public void onChunk(Chunk chunk, boolean isLoaded) { + KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + for (org.bukkit.entity.Entity bukkitEntity : chunk.bukkitChunk.getEntities()) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(), chunk.locX, chunk.locZ, false); + CalculatedChunk.Entities calculatedChunk = new CalculatedChunk.Entities(chunkPosition, chunkEntities); + allCalculatedChunks.add(calculatedChunk); } @Override @@ -240,7 +250,7 @@ public void onUpdateChunk(Chunk chunk) { @Override public void onFinish() { - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); } }); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java index 48cb45397f..91eb999006 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java @@ -65,6 +65,7 @@ import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -217,15 +218,15 @@ public void onFinish() { } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); + public CompletableFuture> calculateChunks(List chunkPositions, + Synchronized> unloadedChunksCache) { + List allCalculatedChunks = new LinkedList<>(); List chunkPositionsToCalculate = new LinkedList<>(); Iterator chunkPositionsIterator = chunkPositions.iterator(); while (chunkPositionsIterator.hasNext()) { ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); + CalculatedChunk.Blocks cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); if (cachedCalculatedChunk != null) { allCalculatedChunks.add(cachedCalculatedChunk); chunkPositionsIterator.remove(); @@ -237,7 +238,7 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); + CompletableFuture> completableFuture = new CompletableFuture<>(); NMSUtils.runActionOnChunks(chunkPositionsToCalculate, false, new NMSUtils.ChunkCallback( ChunkLoadReason.BLOCKS_RECALCULATE, true) { @@ -265,7 +266,7 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloaded } } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, chunkSections); + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -282,42 +283,52 @@ public void onFinish() { } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { - CompletableFuture> completableFuture = new CompletableFuture<>(); + public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { + if (chunkPositions.isEmpty()) + return CompletableFuture.completedFuture(Collections.emptyList()); + + CompletableFuture> completableFuture = new CompletableFuture<>(); - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - List> unloadedEntityTags = new LinkedList<>(); + List allCalculatedChunks = new LinkedList<>(); + List> unloadedEntityTags = new LinkedList<>(); NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback( ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(Chunk chunk) { + KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + for (org.bukkit.entity.Entity bukkitEntity : chunk.getBukkitChunk().getEntities()) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(), chunk.locX, chunk.locZ, false); + CalculatedChunk.Entities calculatedChunk = new CalculatedChunk.Entities(chunkPosition, chunkEntities); + allCalculatedChunks.add(calculatedChunk); + latchCountDown(); } @Override public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound entityData) { - WorldServer worldServer = ((CraftWorld) chunkPosition.getWorld()).getHandle(); - unloadedEntityTags.add(new Pair<>(worldServer, entityData.getList("Entities", 10))); - + unloadedEntityTags.add(new Pair<>(chunkPosition, entityData.getList("Entities", 10))); latchCountDown(); } @Override public void onFinish() { BukkitExecutor.sync(() -> { - for (Pair worldUnloadedEntityTagsPair : unloadedEntityTags) { + for (Pair worldUnloadedEntityTagsPair : unloadedEntityTags) { + WorldServer worldServer = ((CraftWorld) worldUnloadedEntityTagsPair.getKey().getWorld()).getHandle(); + KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + for (NBTBase entityTag : worldUnloadedEntityTagsPair.getValue()) { EntityTypes entityType = EntityTypes.a((NBTTagCompound) entityTag).orElse(null); if (entityType == null) continue; - Entity fakeEntity = EntityTypes.a((NBTTagCompound) entityTag, worldUnloadedEntityTagsPair.getKey()).orElse(null); + Entity fakeEntity = EntityTypes.a((NBTTagCompound) entityTag, worldServer).orElse(null); if (fakeEntity != null) { fakeEntity.valid = false; if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) @@ -327,11 +338,15 @@ public void onFinish() { Key entityKey = Keys.of(Registry.ENTITY_TYPE.get( CraftNamespacedKey.fromMinecraft(EntityTypes.getName(entityType)))); + chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); } + + CalculatedChunk.Entities calculatedChunk = new CalculatedChunk.Entities(worldUnloadedEntityTagsPair.getKey(), chunkEntities); + allCalculatedChunks.add(calculatedChunk); } - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); }); } }); @@ -405,7 +420,7 @@ public List getBlockEntities(org.bukkit.Chunk bukkitChunk) { return blockEntities; } - private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, ChunkSection[] chunkSections) { + private static CalculatedChunk.Blocks calculateChunk(ChunkPosition chunkPosition, ChunkSection[] chunkSections) { KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); List spawnersLocations = new LinkedList<>(); @@ -438,7 +453,7 @@ private static CalculatedChunk calculateChunk(ChunkPosition chunkPosition, Chunk } } - return new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); + return new CalculatedChunk.Blocks(chunkPosition, blockCounts, spawnersLocations); } private static void removeEntities(Chunk chunk) { diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java index aba28e52c6..71279a172a 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java @@ -5,7 +5,9 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; @@ -53,6 +55,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSChunks { @@ -192,9 +195,9 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, - Synchronized> unloadedChunksCache, - List allCalculatedChunks) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { @@ -231,7 +234,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, levelChunkSections); + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, levelChunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -246,16 +249,15 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, - CompletableFuture> completableFuture) { + CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { - for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { - if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) - chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); - } + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @@ -277,33 +279,21 @@ public void onFinish() { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getCompound("Level") .getList("Entities", 10); - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - - for (Tag entityTag : entitiesTag) { - EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); - if (entityType == null) - continue; - - Entity fakeEntity = EntityType.create((CompoundTag) entityTag, serverLevel).orElse(null); - if (fakeEntity != null) { - fakeEntity.valid = false; - if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) - continue; - } - - Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( - CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); - - chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); - } + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); } - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); }); } }; } + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + return EntityType.create(compoundTag, serverLevel); + } + private static void removeBlocks(LevelChunk levelChunk) { ServerLevel serverLevel = levelChunk.level; diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java index 57d14bb73b..cc1b94396a 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils; @@ -55,6 +57,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSChunks { @@ -241,9 +244,9 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, - Synchronized> unloadedChunksCache, - List allCalculatedChunks) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { @@ -312,7 +315,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -327,16 +330,15 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, - CompletableFuture> completableFuture) { + CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { - for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { - if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) - chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); - } + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @@ -352,34 +354,22 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - - for (Tag entityTag : chunkCompound.getList("entities", 10)) { - EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); - if (entityType == null) - continue; - - Entity fakeEntity = EntityType.create((CompoundTag) entityTag, serverLevel).orElse(null); - if (fakeEntity != null) { - fakeEntity.valid = false; - if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) - continue; - } - - Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( - CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); - - chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); - } + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); } - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); }); } }; } + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + return EntityType.create(compoundTag, serverLevel); + } + private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java index 00a698d366..94c8376eed 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; @@ -57,6 +59,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSChunks { @@ -244,9 +247,9 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, - Synchronized> unloadedChunksCache, - List allCalculatedChunks) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { @@ -315,7 +318,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -330,16 +333,15 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, - CompletableFuture> completableFuture) { + CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { - for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { - if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) - chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); - } + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @@ -355,34 +357,22 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - - for (Tag entityTag : chunkCompound.getList("entities", 10)) { - EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); - if (entityType == null) - continue; - - Entity fakeEntity = EntityType.create((CompoundTag) entityTag, serverLevel).orElse(null); - if (fakeEntity != null) { - fakeEntity.valid = false; - if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) - continue; - } - - Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( - CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); - - chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); - } + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); } - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); }); } }; } + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + return EntityType.create(compoundTag, serverLevel); + } + private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java index 1a3e6cb7b7..5666171a36 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; @@ -54,6 +56,7 @@ import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSChunks { @@ -240,9 +243,9 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, - Synchronized> unloadedChunksCache, - List allCalculatedChunks) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { @@ -311,7 +314,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -326,16 +329,15 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, - CompletableFuture> completableFuture) { + CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { - for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { - if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) - chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); - } + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @@ -351,34 +353,22 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - - for (Tag entityTag : chunkCompound.getList("entities", 10)) { - EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); - if (entityType == null) - continue; - - Entity fakeEntity = EntityType.create((CompoundTag) entityTag, serverLevel).orElse(null); - if (fakeEntity != null) { - fakeEntity.valid = false; - if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) - continue; - } - - Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( - CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); - - chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); - } + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); } - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); }); } }; } + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + return EntityType.create(compoundTag, serverLevel); + } + private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java index 2fe657aa47..bbd0c397cd 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; @@ -54,6 +56,7 @@ import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSChunks { @@ -237,9 +240,9 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, - Synchronized> unloadedChunksCache, - List allCalculatedChunks) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { @@ -306,7 +309,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -321,16 +324,15 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, - CompletableFuture> completableFuture) { + CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { - for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { - if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) - chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); - } + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @@ -346,34 +348,22 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - - for (Tag entityTag : chunkCompound.getList("entities", 10)) { - EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); - if (entityType == null) - continue; - - Entity fakeEntity = EntityType.create((CompoundTag) entityTag, serverLevel).orElse(null); - if (fakeEntity != null) { - fakeEntity.valid = false; - if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) - continue; - } - - Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( - CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); - - chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); - } + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); } - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); }); } }; } + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + return EntityType.create(compoundTag, serverLevel); + } + private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java index 1d7ad80e16..f5115ed5a5 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; @@ -54,6 +56,7 @@ import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSChunks { @@ -237,9 +240,9 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, - Synchronized> unloadedChunksCache, - List allCalculatedChunks) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { @@ -306,7 +309,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -321,16 +324,15 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, - CompletableFuture> completableFuture) { + CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { - for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { - if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) - chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); - } + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @@ -346,34 +348,22 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - - for (Tag entityTag : chunkCompound.getList("entities", 10)) { - EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); - if (entityType == null) - continue; - - Entity fakeEntity = EntityType.create((CompoundTag) entityTag, serverLevel).orElse(null); - if (fakeEntity != null) { - fakeEntity.valid = false; - if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) - continue; - } - - Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( - CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); - - chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); - } + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); } - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); }); } }; } + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + return EntityType.create(compoundTag, serverLevel); + } + private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java index 56d2897678..bdd863d3da 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; @@ -55,6 +57,7 @@ import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSChunks { @@ -238,9 +241,9 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, - Synchronized> unloadedChunksCache, - List allCalculatedChunks) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { @@ -307,7 +310,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -322,16 +325,15 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, - CompletableFuture> completableFuture) { + CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { - for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { - if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) - chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); - } + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @@ -347,34 +349,22 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - - for (Tag entityTag : chunkCompound.getList("entities", 10)) { - EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); - if (entityType == null) - continue; - - Entity fakeEntity = EntityType.create((CompoundTag) entityTag, serverLevel, EntitySpawnReason.NATURAL).orElse(null); - if (fakeEntity != null) { - fakeEntity.valid = false; - if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) - continue; - } - - Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( - CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); - - chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); - } + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); } - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); }); } }; } + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + return EntityType.create(compoundTag, serverLevel, EntitySpawnReason.NATURAL); + } + private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java index 1ca8e7cb71..919dc1a01e 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; @@ -55,6 +57,7 @@ import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.concurrent.CompletableFuture; public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSChunks { @@ -238,9 +241,9 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, - Synchronized> unloadedChunksCache, - List allCalculatedChunks) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { @@ -307,7 +310,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -322,16 +325,15 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, - CompletableFuture> completableFuture) { + CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { - for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { - if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) - chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); - } + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @@ -347,34 +349,21 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - - for (Tag entityTag : chunkCompound.getList("entities", 10)) { - EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); - if (entityType == null) - continue; - - Entity fakeEntity = EntityType.create((CompoundTag) entityTag, serverLevel, EntitySpawnReason.NATURAL).orElse(null); - if (fakeEntity != null) { - fakeEntity.valid = false; - if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) - continue; - } - - Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( - CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); - - chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); - } + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); } - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); }); } }; } + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + return EntityType.create(compoundTag, serverLevel, EntitySpawnReason.NATURAL); + } private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java index 62c59994e5..f5b9e2710b 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java @@ -7,7 +7,9 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; @@ -239,9 +241,9 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, - Synchronized> unloadedChunksCache, - List allCalculatedChunks) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { @@ -310,7 +312,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -325,16 +327,15 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, - CompletableFuture> completableFuture) { + CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { - for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { - if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) - chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); - } + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @@ -350,34 +351,22 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - - for (Tag entityTag : chunkCompound.getListOrEmpty("entities")) { - EntityType entityType = EntityType.by((CompoundTag) entityTag).orElse(null); - if (entityType == null) - continue; - - Entity fakeEntity = EntityType.create((CompoundTag) entityTag, serverLevel, EntitySpawnReason.NATURAL).orElse(null); - if (fakeEntity != null) { - fakeEntity.valid = false; - if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) - continue; - } - - Key entityKey = Keys.of(org.bukkit.Registry.ENTITY_TYPE.get( - CraftNamespacedKey.fromMinecraft(EntityType.getKey(entityType)))); - - chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); - } + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("entities"); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); } - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); }); } }; } + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + return EntityType.create(compoundTag, serverLevel, EntitySpawnReason.NATURAL); + } + private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java index 28d7c4debc..dbb81ca4dd 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java @@ -247,9 +247,9 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, - Synchronized> unloadedChunksCache, - List allCalculatedChunks) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { @@ -318,7 +318,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -333,16 +333,15 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, - CompletableFuture> completableFuture) { + CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { - for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { - if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) - chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); - } + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @@ -358,40 +357,26 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - - for (Tag entityTag : chunkCompound.getListOrEmpty("entities")) { - Entity fakeEntity; - EntityType entityType; - try (ProblemReporter.ScopedCollector scopedCollector = - new ProblemReporter.ScopedCollector(entityTag::toString, LOGGER)) { - ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), (CompoundTag) entityTag); - - entityType = EntityType.by(valueInput).orElse(null); - if (entityType == null) - continue; - - fakeEntity = EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL).orElse(null); - } - - if (fakeEntity != null) { - fakeEntity.valid = false; - if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) - continue; - } - - Key entityKey = Keys.of(CraftEntityType.minecraftToBukkit(entityType)); - chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); - } + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("entities"); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); } - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); }); } }; } + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag); + return EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL); + } + } + private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java index e022b4e81a..770e10f69c 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java @@ -223,9 +223,9 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, - Synchronized> unloadedChunksCache, - List allCalculatedChunks) { + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { @@ -280,7 +280,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound } - CalculatedChunk calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); allCalculatedChunks.add(calculatedChunk); unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); @@ -295,16 +295,15 @@ public void onFinish() { } @Override - protected NMSUtils.ChunkCallback getEntitiesChunkCallback(KeyMap chunkEntities, + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, List unloadedChunkCompounds, - CompletableFuture> completableFuture) { + CompletableFuture> completableFuture) { return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { @Override public void onLoadedChunk(LevelChunk levelChunk) { - for (org.bukkit.entity.Entity bukkitEntity : new CraftChunk(levelChunk).getEntities()) { - if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) - chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); - } + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); latchCountDown(); } @@ -320,40 +319,26 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); - CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); - - for (Tag entityTag : chunkCompound.getListOrEmpty("entities")) { - Entity fakeEntity; - EntityType entityType; - try (ProblemReporter.ScopedCollector scopedCollector = - new ProblemReporter.ScopedCollector(entityTag::toString, LOGGER)) { - ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), (CompoundTag) entityTag); - - entityType = EntityType.by(valueInput).orElse(null); - if (entityType == null) - continue; - - fakeEntity = EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL).orElse(null); - } - - if (fakeEntity != null) { - fakeEntity.valid = false; - if (BukkitEntities.canBypassEntityLimit(fakeEntity.getBukkitEntity())) - continue; - } - - Key entityKey = Keys.of(CraftEntityType.minecraftToBukkit(entityType)); - chunkEntities.computeIfAbsent(entityKey, k -> new Counter(0)).inc(1); - } + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("entities"); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); } - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); }); } }; } + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag); + return EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL); + } + } + private static void removeBlocks(ChunkAccess chunk) { ServerLevel serverLevel = ((LevelChunk) chunk).level; ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java index e6ec0c543a..26711ec42a 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java @@ -43,6 +43,7 @@ import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -107,15 +108,15 @@ public void onFinish() { } @Override - public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { - List allCalculatedChunks = new LinkedList<>(); + public CompletableFuture> calculateChunks(List chunkPositions, + Synchronized> unloadedChunksCache) { + List allCalculatedChunks = new LinkedList<>(); List chunkPositionsToCalculate = new LinkedList<>(); Iterator chunkPositionsIterator = chunkPositions.iterator(); while (chunkPositionsIterator.hasNext()) { ChunkPosition chunkPosition = chunkPositionsIterator.next(); - CalculatedChunk cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); + CalculatedChunk.Blocks cachedCalculatedChunk = unloadedChunksCache.readAndGet(m -> m.get(chunkPosition)); if (cachedCalculatedChunk != null) { allCalculatedChunks.add(cachedCalculatedChunk); chunkPositionsIterator.remove(); @@ -127,7 +128,7 @@ public CompletableFuture> calculateChunks(List> completableFuture = new CompletableFuture<>(); + CompletableFuture> completableFuture = new CompletableFuture<>(); NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback() { @Override @@ -169,7 +170,7 @@ public void onChunk(Chunk chunk, boolean isLoaded) { } } - CalculatedChunk calculatedChunk = new CalculatedChunk(chunkPosition, blockCounts, spawnersLocations); + CalculatedChunk.Blocks calculatedChunk = new CalculatedChunk.Blocks(chunkPosition, blockCounts, spawnersLocations); allCalculatedChunks.add(calculatedChunk); if (!isLoaded) @@ -186,27 +187,33 @@ public void onFinish() { } @Override - public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { + public CompletableFuture> calculateChunkEntities(Collection chunkPositions) { if (chunkPositions.isEmpty()) - return CompletableFuture.completedFuture(KeyMaps.createEmptyMap()); + return CompletableFuture.completedFuture(Collections.emptyList()); - CompletableFuture> completableFuture = new CompletableFuture<>(); + CompletableFuture> completableFuture = new CompletableFuture<>(); - KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + List allCalculatedChunks = new LinkedList<>(); NMSUtils.runActionOnChunks(chunkPositions, false, new NMSUtils.ChunkCallback() { @Override public void onChunk(Chunk chunk, boolean isLoaded) { + KeyMap chunkEntities = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); + for (org.bukkit.entity.Entity bukkitEntity : chunk.bukkitChunk.getEntities()) { if (!BukkitEntities.canBypassEntityLimit(bukkitEntity)) chunkEntities.computeIfAbsent(Keys.of(bukkitEntity), i -> new Counter(0)).inc(1); } + + ChunkPosition chunkPosition = ChunkPosition.of(chunk.getWorld().getWorld(), chunk.locX, chunk.locZ, false); + CalculatedChunk.Entities calculatedChunk = new CalculatedChunk.Entities(chunkPosition, chunkEntities); + allCalculatedChunks.add(calculatedChunk); } @Override public void onFinish() { - completableFuture.complete(chunkEntities); + completableFuture.complete(allCalculatedChunks); } }); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/CalculatedChunk.java b/src/main/java/com/bgsoftware/superiorskyblock/core/CalculatedChunk.java index 75ab972a34..bae30cbff2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/CalculatedChunk.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/CalculatedChunk.java @@ -8,25 +8,49 @@ public class CalculatedChunk { private final ChunkPosition chunkPosition; - private final KeyMap blockCounts; - private final List spawners; - public CalculatedChunk(ChunkPosition chunkPosition, KeyMap blockCounts, List spawners) { + protected CalculatedChunk(ChunkPosition chunkPosition) { this.chunkPosition = chunkPosition; - this.blockCounts = blockCounts; - this.spawners = spawners; } public ChunkPosition getPosition() { return chunkPosition; } - public KeyMap getBlockCounts() { - return blockCounts; + public static class Blocks extends CalculatedChunk { + + private final KeyMap blockCounts; + private final List spawners; + + public Blocks(ChunkPosition chunkPosition, KeyMap blockCounts, List spawners) { + super(chunkPosition); + this.blockCounts = blockCounts; + this.spawners = spawners; + } + + public KeyMap getBlockCounts() { + return blockCounts; + } + + public List getSpawners() { + return spawners; + } + } - public List getSpawners() { - return spawners; + public static class Entities extends CalculatedChunk { + + private final KeyMap entityCounts; + + public Entities(ChunkPosition chunkPosition, KeyMap entityCounts) { + super(chunkPosition); + this.entityCounts = entityCounts; + } + + public KeyMap getEntityCounts() { + return entityCounts; + } + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java index 61ba7da6f0..2eafec62ca 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java @@ -93,7 +93,8 @@ public enum Debug { BLOCK_BREAK, BLOCK_COUNT_INCREASE, BLOCK_COUNT_DECREASE, - CHUNK_CALCULATION, + CHUNK_CALCULATION_BLOCKS, + CHUNK_CALCULATION_ENTITIES, ENTITY_SPAWN, ENTITY_DESPAWN, DEPOSIT_MONEY, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java index 4080032c2a..d1cc1d36a1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandCalculationAlgorithm.java @@ -41,7 +41,7 @@ public class DefaultIslandCalculationAlgorithm implements IslandCalculationAlgorithm { - public static final Synchronized> CACHED_CALCULATED_CHUNKS = + public static final Synchronized> CACHED_CALCULATED_CHUNKS = Synchronized.of(new Chunk2ObjectMap<>()); private static final List> MINECART_BLOCK_TYPES = createMinecartBlockTypes(); @@ -65,10 +65,10 @@ public CompletableFuture calculateIsland(Island island) } private void calculateIslandInternal(Island island, CompletableFuture result) { - CompletableFutureList> chunksToLoad = new CompletableFutureList<>(plugin.getSettings().getRecalcTaskTimeout()); + CompletableFutureList> chunksToLoad = new CompletableFutureList<>(plugin.getSettings().getRecalcTaskTimeout()); long profiler = Profiler.start(ProfileType.CALCULATE_ISLAND); - Log.debug(Debug.CHUNK_CALCULATION, island.getOwner().getName()); + Log.debug(Debug.CHUNK_CALCULATION_BLOCKS, island.getOwner().getName()); if (!plugin.getProviders().hasSnapshotsSupport()) { IslandUtils.getChunkCoords(island, IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS) @@ -81,7 +81,7 @@ private void calculateIslandInternal(Island island, CompletableFuture { - CompletableFuture> calculateCompletable = new CompletableFuture<>(); + CompletableFuture> calculateCompletable = new CompletableFuture<>(); completableFuture.whenComplete((chunk, ex) -> { try (ChunkPosition chunkPosition = ChunkPosition.of(chunk)) { plugin.getNMSChunks().calculateChunks(Collections.singletonList(chunkPosition), CACHED_CALCULATED_CHUNKS) @@ -98,7 +98,7 @@ private void calculateIslandInternal(Island island, CompletableFuture { chunksToLoad.forEachCompleted(worldCalculatedChunks -> worldCalculatedChunks.forEach(calculatedChunk -> { - Log.debugResult(Debug.CHUNK_CALCULATION, "Chunk Finished", calculatedChunk.getPosition()); + Log.debugResult(Debug.CHUNK_CALCULATION_BLOCKS, "Chunk Finished", calculatedChunk.getPosition()); // We want to remove spawners from the chunkInfo, as it will be used later calculatedChunk.getBlockCounts().removeIf(key -> key instanceof SpawnerKey); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java index 84859793a8..f12b823c4b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.island.algorithms.IslandEntitiesTrackerAlgorithm; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.CompletableFutureList; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; @@ -19,6 +20,7 @@ import org.bukkit.World; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -116,14 +118,14 @@ public void recalculateEntityCounts() { this.beingRecalculated = true; + Log.debug(Debug.CHUNK_CALCULATION_ENTITIES, island.getOwner().getName()); + try { this.lastCalculateTime = System.currentTimeMillis(); clearEntityCounts(); - KeyMap recalculatedEntityCounts = KeyMaps.createConcurrentHashMap(KeyIndicator.ENTITY_TYPE); - - CompletableFutureList> chunkEntities = new CompletableFutureList<>(-1); + CompletableFutureList> chunkEntities = new CompletableFutureList<>(-1); IslandUtils.getChunkCoords(island, IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS) .forEach(((worldInfo, worldChunks) -> { @@ -135,12 +137,15 @@ public void recalculateEntityCounts() { BukkitExecutor.async(() -> { try { - chunkEntities.forEachCompleted(entities -> { - entities.forEach((entity, count) -> { + KeyMap recalculatedEntityCounts = KeyMaps.createConcurrentHashMap(KeyIndicator.ENTITY_TYPE); + + chunkEntities.forEachCompleted(worldCalculatedChunk -> worldCalculatedChunk.forEach(calculatedChunk -> { + Log.debugResult(Debug.CHUNK_CALCULATION_ENTITIES, "Chunk Finished", calculatedChunk.getPosition()); + calculatedChunk.getEntityCounts().forEach((entity, count) -> { if (canTrackEntity(entity)) recalculatedEntityCounts.computeIfAbsent(entity, i -> new Counter(0)).inc(count.get()); }); - }, error -> { + }), error -> { error.printStackTrace(); beingRecalculated = false; }); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSChunks.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSChunks.java index 3ffb9f1b9c..6748318e10 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSChunks.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSChunks.java @@ -24,10 +24,10 @@ public interface NMSChunks { void deleteChunks(Island island, List chunkPositions, @Nullable Runnable onFinish); - CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache); + CompletableFuture> calculateChunks(List chunkPositions, + Synchronized> unloadedChunksCache); - CompletableFuture> calculateChunkEntities(Collection chunkPositions); + CompletableFuture> calculateChunkEntities(Collection chunkPositions); void injectChunkSections(Chunk chunk); From 06d8dedc6ef82160fcafa6b5cbe17e2ac478eb8d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Oct 2025 17:56:56 +0300 Subject: [PATCH 375/600] Debug entity spawning at the end of entity recalculation --- .../algorithm/DefaultIslandEntitiesTrackerAlgorithm.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java index f12b823c4b..021b876747 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java @@ -154,8 +154,10 @@ public void recalculateEntityCounts() { return; if (!recalculatedEntityCounts.isEmpty()) { - recalculatedEntityCounts.forEach((entity, count) -> - this.entityCounts.put(entity, count.get())); + recalculatedEntityCounts.forEach((entity, count) -> { + Log.debug(Debug.ENTITY_SPAWN, island.getOwner().getName(), entity, count.get()); + this.entityCounts.put(entity, count.get()); + }); } } finally { IslandsDatabaseBridge.saveEntityCounts(this.island); From 1e26990f5eadf6b452d4e3a1e85a98ae2a1c76e0 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Oct 2025 18:10:44 +0300 Subject: [PATCH 376/600] Optimized the way tracked entities are detected --- .../core/key/types/EntityTypeKey.java | 3 ++ ...DefaultIslandEntitiesTrackerAlgorithm.java | 40 +++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/EntityTypeKey.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/EntityTypeKey.java index e993fa1cd4..9b4888ff8f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/EntityTypeKey.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/types/EntityTypeKey.java @@ -84,4 +84,7 @@ public EntityTypeKey createAPIKeyInternal() { return this.apiKeyCache.get(); } + public EntityType getEntityType() { + return entityType; + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java index 021b876747..ade0247988 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java @@ -12,20 +12,25 @@ import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.types.EntityTypeKey; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.google.common.base.Preconditions; import org.bukkit.World; +import org.bukkit.entity.EntityType; import java.util.Collections; +import java.util.EnumSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; public class DefaultIslandEntitiesTrackerAlgorithm implements IslandEntitiesTrackerAlgorithm { + private static final Set TRACKABLE_ENTITIES = initializeTrackableEntities(); private static final long CALCULATE_DELAY = TimeUnit.MINUTES.toMillis(5); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @@ -47,6 +52,11 @@ public boolean trackEntity(Key key, int amount) { Log.debug(Debug.ENTITY_SPAWN, island.getOwner().getName(), key, amount); + if (beingRecalculated) { + Log.debugResult(Debug.ENTITY_SPAWN, "Return", "Recalculating"); + return false; + } + if (amount <= 0) { Log.debugResult(Debug.ENTITY_SPAWN, "Return", "Negative Amount"); return false; @@ -71,6 +81,11 @@ public boolean untrackEntity(Key key, int amount) { Log.debug(Debug.ENTITY_DESPAWN, island.getOwner().getName(), key, amount); + if (beingRecalculated) { + Log.debugResult(Debug.ENTITY_DESPAWN, "Return", "Recalculating"); + return false; + } + if (amount <= 0) { Log.debugResult(Debug.ENTITY_DESPAWN, "Return", "Negative Amount"); return false; @@ -123,8 +138,6 @@ public void recalculateEntityCounts() { try { this.lastCalculateTime = System.currentTimeMillis(); - clearEntityCounts(); - CompletableFutureList> chunkEntities = new CompletableFutureList<>(-1); IslandUtils.getChunkCoords(island, IslandChunkFlags.ONLY_PROTECTED | IslandChunkFlags.NO_EMPTY_CHUNKS) @@ -153,6 +166,8 @@ public void recalculateEntityCounts() { if (!beingRecalculated) return; + clearEntityCounts(); + if (!recalculatedEntityCounts.isEmpty()) { recalculatedEntityCounts.forEach((entity, count) -> { Log.debug(Debug.ENTITY_SPAWN, island.getOwner().getName(), entity, count.get()); @@ -178,7 +193,26 @@ public boolean canRecalculateEntityCounts() { } private boolean canTrackEntity(Key key) { - return island.getEntityLimit(key) != -1 || key.toString().contains("MINECART"); + if (island.getEntityLimit(key) != -1) + return true; + + if (key instanceof EntityTypeKey) { + return TRACKABLE_ENTITIES.contains(((EntityTypeKey) key).getEntityType()); + } else { + return key.toString().contains("MINECART"); + } + } + + private static Set initializeTrackableEntities() { + EnumSet trackableEntities = EnumSet.noneOf(EntityType.class); + + for (EntityType entityType : EntityType.values()) { + if (entityType.name().contains("MINECART")) { + trackableEntities.add(entityType); + } + } + + return trackableEntities.isEmpty() ? Collections.emptySet() : Collections.unmodifiableSet(trackableEntities); } } From 954451dd12ec67e27edd9e949838832c049bba48 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Oct 2025 18:58:45 +0300 Subject: [PATCH 377/600] Fixed counting of entities in unloaded chunks does not work properly (#2650) --- .../superiorskyblock/nms/v1_18/NMSChunksImpl.java | 4 ++-- .../superiorskyblock/nms/v1_19/NMSChunksImpl.java | 4 ++-- .../superiorskyblock/nms/v1_20_3/NMSChunksImpl.java | 4 ++-- .../superiorskyblock/nms/v1_20_4/NMSChunksImpl.java | 4 ++-- .../superiorskyblock/nms/v1_21/NMSChunksImpl.java | 4 ++-- .../superiorskyblock/nms/v1_21_3/NMSChunksImpl.java | 4 ++-- .../nms/v1_21_3/utils/NMSUtilsVersioned.java | 8 ++++++-- .../superiorskyblock/nms/v1_21_4/NMSChunksImpl.java | 4 ++-- .../nms/v1_21_4/utils/NMSUtilsVersioned.java | 8 ++++++-- .../superiorskyblock/nms/v1_21_5/NMSChunksImpl.java | 4 ++-- .../nms/v1_21_5/utils/NMSUtilsVersioned.java | 8 ++++++-- .../superiorskyblock/nms/v1_21_7/NMSChunksImpl.java | 4 ++-- .../nms/v1_21_7/utils/NMSUtilsVersioned.java | 8 ++++++-- .../superiorskyblock/nms/v1_21_9/NMSChunksImpl.java | 4 ++-- .../nms/v1_21_9/utils/NMSUtilsVersioned.java | 8 ++++++-- 15 files changed, 50 insertions(+), 30 deletions(-) diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java index cc1b94396a..4bb11e214c 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java @@ -163,7 +163,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - chunkCompound.put("entities", new ListTag()); + chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { @@ -354,7 +354,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java index 94c8376eed..37c3cbfdc9 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java @@ -165,7 +165,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - chunkCompound.put("entities", new ListTag()); + chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { @@ -357,7 +357,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java index 5666171a36..44b05900a7 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java @@ -161,7 +161,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - chunkCompound.put("entities", new ListTag()); + chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { @@ -353,7 +353,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java index bbd0c397cd..8e905fb283 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java @@ -160,7 +160,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - chunkCompound.put("entities", new ListTag()); + chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { @@ -348,7 +348,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java index f5115ed5a5..886ae4f8f6 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java @@ -160,7 +160,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - chunkCompound.put("entities", new ListTag()); + chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { @@ -348,7 +348,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java index bdd863d3da..d38baa3370 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java @@ -161,7 +161,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - chunkCompound.put("entities", new ListTag()); + chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { @@ -349,7 +349,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java index 0f8f5b6ad9..f385cf7e1a 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java @@ -139,8 +139,12 @@ public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); - if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { - net.minecraft.nbt.CompoundTag entityData = readData.syncRead(); + if(readData != null) { + CompoundTag entityData = switch (readData.result()) { + case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); + case SYNC_READ -> readData.syncRead(); + default -> null; + }; if (entityData != null) { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java index 919dc1a01e..40700d061b 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -161,7 +161,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - chunkCompound.put("entities", new ListTag()); + chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { @@ -349,7 +349,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("entities", 10); + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getList("Entities", 10); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java index cd461926c7..7d5522975f 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java @@ -139,8 +139,12 @@ public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); - if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { - CompoundTag entityData = readData.syncRead(); + if(readData != null) { + CompoundTag entityData = switch (readData.result()) { + case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); + case SYNC_READ -> readData.syncRead(); + default -> null; + }; if (entityData != null) { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java index f5b9e2710b..eb386bfc31 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java @@ -161,7 +161,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - chunkCompound.put("entities", new ListTag()); + chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { @@ -351,7 +351,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("entities"); + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("Entities"); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java index 1750ea4a2c..5902adb139 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java @@ -139,8 +139,12 @@ public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); - if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { - CompoundTag entityData = readData.syncRead(); + if(readData != null) { + CompoundTag entityData = switch (readData.result()) { + case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); + case SYNC_READ -> readData.syncRead(); + default -> null; + }; if (entityData != null) { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java index dbb81ca4dd..d6a6492944 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java @@ -167,7 +167,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - chunkCompound.put("entities", new ListTag()); + chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { @@ -357,7 +357,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("entities"); + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("Entities"); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java index 8340410458..db8305d81a 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java @@ -147,8 +147,12 @@ public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); - if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { - CompoundTag entityData = readData.syncRead(); + if (readData != null) { + CompoundTag entityData = switch (readData.result()) { + case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); + case SYNC_READ -> readData.syncRead(); + default -> null; + }; if (entityData != null) { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java index 770e10f69c..6a0d83e4ce 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java @@ -150,7 +150,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound ListTag tileEntities = new ListTag(); - chunkCompound.put("entities", new ListTag()); + chunkCompound.put("Entities", new ListTag()); chunkCompound.put("block_entities", tileEntities); if (serverLevel.generator instanceof IslandsGenerator) { @@ -319,7 +319,7 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound public void onFinish() { BukkitExecutor.ensureMain(() -> { for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { - ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("entities"); + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("Entities"); allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), unloadedChunkCompound.serverLevel(), entitiesTag)); } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java index 3852fb8c99..e0a468d15a 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java @@ -152,8 +152,12 @@ public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); - if (readData != null && readData.result() == MoonriseRegionFileIO.RegionDataController.ReadData.ReadResult.SYNC_READ) { - CompoundTag entityData = readData.syncRead(); + if(readData != null) { + CompoundTag entityData = switch (readData.result()) { + case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); + case SYNC_READ -> readData.syncRead(); + default -> null; + }; if (entityData != null) { NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); chunkCallback.onUnloadedChunk(unloadedChunkCompound); From 94224a8a1eeafff5620db5910293b249c60d1ba2 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Oct 2025 21:29:48 +0300 Subject: [PATCH 378/600] Support MiniMessage in text sections of ComplexMessageComponents (#2572) --- .../external/MiniMessageHook.java | 42 +++++++++++-------- .../component/MultipleComponents.java | 17 +++++++- .../service/message/MessagesServiceImpl.java | 4 +- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java index c71946f831..20db4117e9 100644 --- a/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java +++ b/Hooks/MiniMessage/src/main/java/com/bgsoftware/superiorskyblock/external/MiniMessageHook.java @@ -31,30 +31,38 @@ public class MiniMessageHook { private static boolean registered = false; + private static final MessagesServiceImpl.CustomComponentParser PARSER = new MessagesServiceImpl.CustomComponentParser() { + @Override + public Optional parse(YamlConfiguration config, String path) { + if (!config.isString(path)) + return Optional.empty(); + + String content = config.getString(path); + if (Text.isBlank(content)) + return Optional.empty(); + + return parse(content); + } + + @Override + public Optional parse(String content) { + try { + Component component = MINI_MESSAGE.deserialize(Formatters.COLOR_FORMATTER.format(content)); + return Optional.of(new MiniMessageComponent(component)); + } catch (ParsingException error) { + return Optional.empty(); + } + } + }; + public static void register(SuperiorSkyblockPlugin plugin) { if (!registered) { MessagesServiceImpl messagesService = (MessagesServiceImpl) plugin.getServices().getService(MessagesService.class); - messagesService.registerCustomComponentParser(MiniMessageHook::parseMiniMessage); + messagesService.registerCustomComponentParser(PARSER); registered = true; } } - private static Optional parseMiniMessage(YamlConfiguration config, String path) { - if (!config.isString(path)) - return Optional.empty(); - - String content = config.getString(path); - if (Text.isBlank(content)) - return Optional.empty(); - - try { - Component component = MINI_MESSAGE.deserialize(Formatters.COLOR_FORMATTER.format(content)); - return Optional.of(new MiniMessageComponent(component)); - } catch (ParsingException error) { - return Optional.empty(); - } - } - private static class MiniMessageComponent implements IMessageComponent { private final Component component; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java index fbab4d3fe8..5cb520fb75 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/component/MultipleComponents.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.core.messages.component.impl.ComplexMessageComponent; import com.bgsoftware.superiorskyblock.core.messages.component.impl.SoundComponent; import com.bgsoftware.superiorskyblock.core.messages.component.impl.TitleComponent; +import com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.HoverEvent; @@ -18,14 +19,16 @@ import java.util.LinkedList; import java.util.List; +import java.util.Optional; public class MultipleComponents implements IMessageComponent { private final List messageComponents; - public static IMessageComponent parseSection(ConfigurationSection section) { + public static IMessageComponent parseSection(ConfigurationSection section, List customComponentParsers) { List messageComponents = new LinkedList<>(); + keysLoop: for (String key : section.getKeys(false)) { if (key.equals("action-bar")) { messageComponents.add(ActionBarComponent.of(Formatters.COLOR_FORMATTER.format(section.getString(key + ".text")))); @@ -52,7 +55,17 @@ public static IMessageComponent parseSection(ConfigurationSection section) { Formatters.COLOR_FORMATTER.format(section.getString(key + ".message")), color, section.getInt(key + ".ticks"))); } else { - BaseComponent[] baseComponents = TextComponent.fromLegacyText(Formatters.COLOR_FORMATTER.format(section.getString(key + ".text"))); + String text = section.getString(key + ".text"); + + for (MessagesServiceImpl.CustomComponentParser parser : customComponentParsers) { + Optional res = parser.parse(text); + if (res.isPresent()) { + messageComponents.add(res.get()); + continue keysLoop; + } + } + + BaseComponent[] baseComponents = TextComponent.fromLegacyText(Formatters.COLOR_FORMATTER.format(text)); String toolTipMessage = section.getString(key + ".tooltip"); if (toolTipMessage != null) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java index 77b8187b78..7ebd0a2190 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java @@ -44,7 +44,7 @@ public Class getAPIClass() { @Override public IMessageComponent parseComponent(YamlConfiguration config, String path) { if (config.isConfigurationSection(path)) { - return MultipleComponents.parseSection(config.getConfigurationSection(path)); + return MultipleComponents.parseSection(config.getConfigurationSection(path), this.customComponentParsers); } else { for (CustomComponentParser parser : this.customComponentParsers) { Optional res = parser.parse(config, path); @@ -75,6 +75,8 @@ public interface CustomComponentParser { Optional parse(YamlConfiguration config, String path); + Optional parse(String raw); + } private static class BuilderImpl implements Builder { From fe38ba417ef71a0c82425f313ece136ebb5f3604 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Oct 2025 22:05:20 +0300 Subject: [PATCH 379/600] Support MiniMessage in more places --- .../core/messages/Message.java | 28 +++++++++++++++---- .../service/message/MessagesServiceImpl.java | 4 +++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 4853a98d0c..03bc9b7387 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -25,6 +25,7 @@ import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.component.impl.ComplexMessageComponent; import com.bgsoftware.superiorskyblock.player.PlayerLocales; +import com.bgsoftware.superiorskyblock.service.message.MessagesServiceImpl; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.HoverEvent; @@ -38,6 +39,7 @@ import java.util.Collection; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -863,9 +865,25 @@ public void send(CommandSender sender, Locale locale, Object... args) { @Override public void send(CommandSender sender, Locale locale, Object... args) { String message = args.length == 0 ? null : args[0] == null ? null : args[0].toString(); + + if (Text.isBlank(message)) + return; + boolean translateColors = args.length >= 2 && args[1] instanceof Boolean && (boolean) args[1]; - if (!Text.isBlank(message)) - sender.sendMessage(translateColors ? Formatters.COLOR_FORMATTER.format(message) : message); + + if (translateColors) { + message = Formatters.COLOR_FORMATTER.format(message); + } + + for (MessagesServiceImpl.CustomComponentParser parser : messagesService.get().getCustomComponentParsers()) { + Optional component = parser.parse(message); + if (component.isPresent()) { + component.get().sendMessage(sender); + return; + } + } + + sender.sendMessage(message); } }; @@ -873,10 +891,10 @@ public void send(CommandSender sender, Locale locale, Object... args) { private static final Object[] EMPTY_ARGS = new Object[0]; private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final LazyReference messagesService = new LazyReference() { + private static final LazyReference messagesService = new LazyReference() { @Override - protected MessagesService create() { - return plugin.getServices().getService(MessagesService.class); + protected MessagesServiceImpl create() { + return (MessagesServiceImpl) plugin.getServices().getService(MessagesService.class); } }; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java index 7ebd0a2190..23a199aabb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/message/MessagesServiceImpl.java @@ -71,6 +71,10 @@ public void registerCustomComponentParser(CustomComponentParser parser) { this.customComponentParsers.add(parser); } + public List getCustomComponentParsers() { + return customComponentParsers; + } + public interface CustomComponentParser { Optional parse(YamlConfiguration config, String path); From 5a03e31aed9463b13439c07f45dcd4a1a634e74b Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 11 Oct 2025 21:07:50 +0200 Subject: [PATCH 380/600] Fixed /is admin setpermission command (#2708) --- .../commands/CommandTabCompletes.java | 3 ++- .../commands/admin/CmdAdminSetPermission.java | 12 +++++++++--- .../commands/arguments/CommandArguments.java | 18 ++++++++++++++++-- .../island/role/SPlayerRole.java | 10 ++++++++++ 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index ea03f581ea..5da7fec367 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -164,7 +164,8 @@ public static List getUpgrades(SuperiorSkyblockPlugin plugin, String arg public static List getPlayerRoles(SuperiorSkyblockPlugin plugin, String argument, Predicate predicate) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder() - .filter(playerRole -> predicate.test(playerRole) && playerRole.toString().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) + .filter(playerRole -> (predicate == null || predicate.test(playerRole)) && + playerRole.toString().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) .map(plugin.getRoles().getRoles(), PlayerRole::getName); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java index 078c4e06eb..0a272a8b2f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetPermission.java @@ -71,7 +71,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (islandPrivilege == null) return; - PlayerRole playerRole = CommandArguments.getPlayerRoleFromLadder(sender, args[4]); + PlayerRole playerRole = islandPrivilege.getType() == IslandPrivilege.Type.COMMAND ? + CommandArguments.getPlayerRoleFromLadder(sender, args[4]) : CommandArguments.getPlayerRole(sender, args[4]); if (playerRole == null) return; @@ -102,8 +103,13 @@ public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSende return CommandTabCompletes.getIslandPrivileges(args[3]); case 5: { IslandPrivilege islandPrivilege = getIslandPrivilegeSafe(args[3]); - return islandPrivilege == null || islandPrivilege.getType() == IslandPrivilege.Type.COMMAND ? - Collections.emptyList() : CommandTabCompletes.getPlayerRoles(plugin, args[4], PlayerRole::isRoleLadder); + + if (islandPrivilege == null) + return Collections.emptyList(); + else if (islandPrivilege.getType() == IslandPrivilege.Type.COMMAND) + return CommandTabCompletes.getPlayerRoles(plugin, args[4], PlayerRole::isRoleLadder); + else + return CommandTabCompletes.getPlayerRoles(plugin, args[4], null); } default: return Collections.emptyList(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java index 4b586801af..3d15ba3806 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java @@ -183,6 +183,21 @@ public static String buildLongString(String[] args, int start, boolean colorize) return colorize ? Formatters.COLOR_FORMATTER.format(stringBuilder.substring(1)) : stringBuilder.substring(1); } + public static PlayerRole getPlayerRole(CommandSender sender, String argument) { + PlayerRole playerRole = null; + + try { + playerRole = SPlayerRole.of(argument); + } catch (IllegalArgumentException ignored) { + } + + if (playerRole == null) { + Message.INVALID_ROLE.send(sender, argument, SPlayerRole.getAllRoleNames()); + } + + return playerRole; + } + public static PlayerRole getPlayerRoleFromLadder(CommandSender sender, String argument) { PlayerRole playerRole = null; @@ -339,9 +354,8 @@ public static IslandPrivilege getIslandPrivilege(CommandSender sender, String ar } catch (NullPointerException ignored) { } - if (islandPrivilege == null || islandPrivilege.getType() == IslandPrivilege.Type.COMMAND) { + if (islandPrivilege == null) { Message.INVALID_ISLAND_PERMISSION.send(sender, argument, IslandPrivileges.getPrivilegesNames()); - islandPrivilege = null; } return islandPrivilege; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java b/src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java index a5e165d1e3..25a1ea7097 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/role/SPlayerRole.java @@ -16,6 +16,7 @@ public class SPlayerRole implements PlayerRole { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static String ALL_ROLE_NAMES; private static String LIMIT_ROLE_NAMES; private static String LADDER_ROLE_NAMES; @@ -67,6 +68,15 @@ public static PlayerRole of(String name) { return plugin.getRoles().getPlayerRole(name); } + public static String getAllRoleNames() { + if (ALL_ROLE_NAMES == null) { + ALL_ROLE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getRoles().getRoles().stream() + .map(playerRole -> playerRole.getName().toLowerCase(Locale.ENGLISH))); + } + + return ALL_ROLE_NAMES; + } + public static String getRoleLimitsNames() { if (LIMIT_ROLE_NAMES == null) { LIMIT_ROLE_NAMES = Formatters.COMMA_FORMATTER.format(plugin.getRoles().getRoles().stream() From b67f65f86be705d45d2660eb3bd1c1ff98a937b4 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 11 Oct 2025 21:11:11 +0200 Subject: [PATCH 381/600] Fixed /is mission and /is admin mission commands (#2680) --- .../commands/CommandTabCompletes.java | 12 ++++---- .../core/messages/Message.java | 1 + .../missions/commands/CmdAdminMission.java | 29 +++++++++++++++---- .../module/missions/commands/CmdMission.java | 15 ++++++---- src/main/resources/lang/de-DE.yml | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/tr-TR.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + 16 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index 5da7fec367..8c25c4f3b1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -213,13 +213,11 @@ public static List getMaterialsForGenerators(String argument) { .filter(materialName -> materialName.contains(lowerArgument))); } - public static List getAllMissions(SuperiorSkyblockPlugin plugin) { - return new SequentialListBuilder() - .build(plugin.getMissions().getAllMissions(), Mission::getName); - } - - public static List getMissions(SuperiorSkyblockPlugin plugin, String argument) { - return filterByArgument(plugin.getMissions().getAllMissions(), Mission::getName, argument.toLowerCase(Locale.ENGLISH)); + public static List getMissions(SuperiorSkyblockPlugin plugin, String argument, Predicate> predicate) { + String lowerArgument = argument.toLowerCase(Locale.ENGLISH); + return new SequentialListBuilder().build(plugin.getMissions().getAllMissions().stream() + .filter(mission -> predicate.test(mission) && mission.getName().contains(lowerArgument)) + .map(mission -> mission.getName().toLowerCase(Locale.ENGLISH))); } public static List getCustomMenus(SuperiorSkyblockPlugin plugin, String argument) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 03bc9b7387..d5f3ab1fb1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -135,6 +135,7 @@ public enum Message { CHANGED_WARPS_LIMIT_NAME, CHANGE_PERMISSION_FOR_HIGHER_ROLE, COMMAND_ARGUMENT_ALL_ISLANDS("*"), + COMMAND_ARGUMENT_ALL_MISSIONS("*"), COMMAND_ARGUMENT_ALL_PLAYERS("*"), COMMAND_ARGUMENT_AMOUNT("amount"), COMMAND_ARGUMENT_BIOME("biome"), diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdAdminMission.java b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdAdminMission.java index 29a9b0e22c..29e7a6bbf1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdAdminMission.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdAdminMission.java @@ -14,6 +14,7 @@ import org.bukkit.command.CommandSender; import java.util.Collections; +import java.util.LinkedList; import java.util.List; public class CmdAdminMission implements IAdminPlayerCommand { @@ -30,7 +31,10 @@ public String getPermission() { @Override public String getUsage(java.util.Locale locale) { - return "admin mission <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MISSION_NAME.getMessage(locale) + ">"; + return "admin mission <" + + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "> <" + + Message.COMMAND_ARGUMENT_MISSION_NAME.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ALL_MISSIONS.getMessage(locale) + ">"; } @Override @@ -100,10 +104,25 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, Superio @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, SuperiorPlayer targetPlayer, String[] args) { - return args.length == 4 ? CommandTabCompletes.getCustomComplete(args[3], "complete", "reset") : - args.length == 5 && args[3].equalsIgnoreCase("complete") || args[3].equalsIgnoreCase("reset") ? - args[4].equals("*") ? CommandTabCompletes.getAllMissions(plugin) : CommandTabCompletes.getMissions(plugin, args[4]) : - Collections.emptyList(); + if (args.length == 4) { + return CommandTabCompletes.getCustomComplete(args[3], "complete", "reset"); + } else if (args.length == 5) { + List list = new LinkedList<>(); + + if (args[3].equalsIgnoreCase("complete")) + list.addAll(CommandTabCompletes.getMissions(plugin, args[4], mission -> + plugin.getMissions().canCompleteAgain(targetPlayer, mission))); + else if (args[3].equalsIgnoreCase("reset")) + list.addAll(CommandTabCompletes.getMissions(plugin, args[4], mission -> + !plugin.getMissions().canCompleteAgain(targetPlayer, mission))); + + if ("*".contains(args[4]) && !list.isEmpty()) + list.add("*"); + + return Collections.unmodifiableList(list); + } + + return Collections.emptyList(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMission.java b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMission.java index 7c2110b8b7..c246150750 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMission.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMission.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -12,6 +13,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Locale; public class CmdMission implements ISuperiorCommand { @@ -55,10 +57,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (!args[1].equalsIgnoreCase("complete")) { - String description = getDescription(PlayerLocales.getLocale(sender)); - if (description == null) - new NullPointerException("The description of the command " + getAliases().get(0) + " is null.").printStackTrace(); - Message.CUSTOM.send(sender, description, false); + Locale locale = PlayerLocales.getLocale(sender); + Message.COMMAND_USAGE.send(sender, plugin.getCommands().getLabel() + " " + getUsage(locale)); return; } @@ -96,7 +96,12 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { - return Collections.emptyList(); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); + + return args.length == 2 ? CommandTabCompletes.getCustomComplete(args[1], "complete") : + args.length == 3 && args[1].equalsIgnoreCase("complete") ? + CommandTabCompletes.getMissions(plugin, args[2], mission -> + mission.canComplete(superiorPlayer)) : Collections.emptyList(); } } diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index e594410d80..1efa7ccad2 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -155,6 +155,7 @@ CHANGED_WARPS_LIMIT_ALL: '&e&lUpgrades | &7Das Warps-Limit aller Inseln wurde er CHANGED_WARPS_LIMIT_NAME: '&e&lUpgrades | &7Das Warps-Limit von {0} wurde erfolgreich aktualisiert.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: Betrag COMMAND_ARGUMENT_BIOME: biom diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 7ad33d2e3a..6e905b2c36 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&lUpgrades | &7Successfully updated the warps limit of { CHANGED_WARPS_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the warps limit of all the islands.' CHANGED_WARPS_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the warps limit of {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'amount' COMMAND_ARGUMENT_BIOME: 'biome' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 7e05868153..84104d00ff 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&lMejoras| &7Se actualizó con éxito el límite de warp CHANGED_WARPS_LIMIT_ALL: '&e&lMejoras| &7Se actualizó con éxito el límite de warps de todas las islas.' CHANGED_WARPS_LIMIT_NAME: '&e&lMejoras| &7Se actualizó correctamente el límite de warps de {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'cantidad' COMMAND_ARGUMENT_BIOME: 'bioma' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index a5ecb613ac..0c00cb874f 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&lAméliorations | &7Vous avez changé la limite de warp CHANGED_WARPS_LIMIT_ALL: '&e&lAméliorations | &7Vous avez changé la limite de warps de toutes les îles.' CHANGED_WARPS_LIMIT_NAME: '&e&lAméliorations | &7Vous avez changé la limite de warps d''île de {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: quantité COMMAND_ARGUMENT_BIOME: biome diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 4d605fabc4..e295003af3 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -106,6 +106,7 @@ CHANGED_WARPS_LIMIT: '&e&lAggiornamenti | &7Aggiornato con successo il limite di CHANGED_WARPS_LIMIT_ALL: '&e&lAggiornamenti | &7Aggioranto con successo il limite di warps di tutte le isole.' CHANGED_WARPS_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il mite di warps dell''isola {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: quantità COMMAND_ARGUMENT_BIOME: bioma diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 2cab5f8112..5ef5d8ecbc 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -111,6 +111,7 @@ CHANGED_WARPS_LIMIT: '&e&lםיגורדש | &7החלצהב הנכדוע {0} לש CHANGED_WARPS_LIMIT_ALL: '&e&lםיגורדש | &7החלצהב הנכדוע םייאה לכ לש םימוקימה תלבגמ.' CHANGED_WARPS_LIMIT_NAME: '&e&lםיגורדש | &7החלצהב הנכדוע {0} יאה לש םימוקימה תלבגמ.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: תומכ COMMAND_ARGUMENT_BIOME: 'biome' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index f138ffd8cc..afbcfce12c 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit warpow CHANGED_WARPS_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit warp na wszystkich wyspach.' CHANGED_WARPS_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit warpow {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'kwota' COMMAND_ARGUMENT_BIOME: 'biom' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 335444e072..e8b3ca2389 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&lMelhorias | &7O limite de warps da ilha de {0} foi atu CHANGED_WARPS_LIMIT_ALL: '&e&lMelhorias | &7O limite de warps de todas as ilhas foi atualizado com sucesso.' CHANGED_WARPS_LIMIT_NAME: '&e&lMelhorias | &7O limite de warps de {0} foi atualizado com sucesso.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'quantidade' COMMAND_ARGUMENT_BIOME: 'bioma' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index df6d037a33..28c158b806 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&lУлучшения | &7Успешно обновлен CHANGED_WARPS_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит варпов для всех островов.' CHANGED_WARPS_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит варпов для {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'количество' COMMAND_ARGUMENT_BIOME: 'биом' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 1cf25bcfc1..a3fa96e415 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -147,6 +147,7 @@ CHANGED_WARPS_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların ışınlanma limi CHANGED_WARPS_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının ışınlanma limiti başarıyla güncellendi.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: miktar COMMAND_ARGUMENT_BIOME: biyom diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 2d7307d428..b5c3970b0d 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -128,6 +128,7 @@ CHANGED_WARPS_LIMIT_ALL: '&e&lNâng Cấp | &7Cập nhật thành công giới h CHANGED_WARPS_LIMIT_NAME: '&e&lNâng Cấp | &7Cập nhật thành công giới hạn khu vực của đảo {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: so-luong COMMAND_ARGUMENT_BIOME: quan-xa diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 3cda266d5d..6f8d75bb2d 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&l升级 | &7成功更新了玩家 {0} 岛屿的传送 CHANGED_WARPS_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的传送点数量限制.' CHANGED_WARPS_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的传送点数量限制.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: '数量' COMMAND_ARGUMENT_BIOME: '群系' From cafc6fbb9cc1d9a2274c404242d7ff862ec13921 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 13 Oct 2025 23:56:21 +0300 Subject: [PATCH 382/600] Add many methods that take WorldPosition and Dimension for IslandWarps --- .../api/island/DelegateIsland.java | 5 ++ .../superiorskyblock/api/island/Island.java | 15 +++++ .../api/island/warps/DelegateIslandWarp.java | 17 ++++++ .../api/island/warps/IslandWarp.java | 20 +++++++ .../superiorskyblock/island/SIsland.java | 32 +++++++--- .../superiorskyblock/island/SpawnIsland.java | 5 ++ .../island/builder/IslandBuilderImpl.java | 33 ++++++++++- .../island/builder/WarpRecord.java | 10 ++-- .../island/warp/SIslandWarp.java | 59 +++++++++++++++---- 9 files changed, 171 insertions(+), 25 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index 9c4a39b49a..d69ec29572 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -1721,6 +1721,11 @@ public IslandWarp createWarp(String name, Location location, @Nullable WarpCateg return this.handle.createWarp(name, location, warpCategory); } + @Override + public IslandWarp createWarp(String name, WorldInfo worldInfo, WorldPosition position, WarpCategory warpCategory) { + return this.handle.createWarp(name, worldInfo, position, warpCategory); + } + @Override public void renameWarp(IslandWarp islandWarp, String newName) { this.handle.renameWarp(islandWarp, newName); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java index 3f1a63855f..ba4396f4fc 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java @@ -2421,6 +2421,17 @@ List> getAllChunksAsync(Dimension dimension, @IslandChu */ IslandWarp createWarp(String name, Location location, @Nullable WarpCategory warpCategory); + /** + * Create a warp for the island. + * + * @param name The name of the warp. + * @param worldInfo The world of the warp. + * @param position The position of the warp. + * @param warpCategory The category to add the island. + * @return The new island warp object. + */ + IslandWarp createWarp(String name, WorldInfo worldInfo, WorldPosition position, @Nullable WarpCategory warpCategory); + /** * Rename a warp. * @@ -2984,10 +2995,14 @@ interface Builder { Builder addWarp(String name, String category, Location location, boolean isPrivate, @Nullable ItemStack icon); + Builder addWarp(String name, String category, WorldInfo worldInfo, WorldPosition worldPosition, boolean isPrivate, @Nullable ItemStack icon); + boolean hasWarp(String name); boolean hasWarp(Location location); + boolean hasWarp(WorldInfo worldInfo, WorldPosition worldPosition); + Builder addWarpCategory(String name, int slot, @Nullable ItemStack icon); boolean hasWarpCategory(String name); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java index 10d74d221e..a541558d8c 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java @@ -2,7 +2,9 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Location; import org.bukkit.inventory.ItemStack; @@ -44,6 +46,21 @@ public void setLocation(Location location) { this.handle.setLocation(location); } + @Override + public WorldPosition getPosition() { + return this.handle.getPosition(); + } + + @Override + public Dimension getPositionDimension() { + return this.handle.getPositionDimension(); + } + + @Override + public void setPosition(Dimension dimension, WorldPosition worldPosition) { + this.handle.setPosition(dimension, worldPosition); + } + @Override public boolean hasPrivateFlag() { return this.handle.hasPrivateFlag(); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/IslandWarp.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/IslandWarp.java index e51432b2ae..4df3e9b8ff 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/IslandWarp.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/IslandWarp.java @@ -2,7 +2,9 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Location; import org.bukkit.inventory.ItemStack; @@ -46,6 +48,24 @@ public interface IslandWarp { */ void setLocation(Location location); + /** + * Get the position of the warp. + */ + WorldPosition getPosition(); + + /** + * Get the dimension of the position of the warp. + */ + Dimension getPositionDimension(); + + /** + * Set the position of the warp. + * + * @param dimension The dimension of the new position to set. + * @param worldPosition The new position to set. + */ + void setPosition(Dimension dimension, WorldPosition worldPosition); + /** * Check if the warp is private or public to visitors. */ diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index c6d3bd63eb..16c8f6191a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -372,7 +372,9 @@ public SIsland(IslandBuilderImpl builder) { if (!warpRecord.category.isEmpty()) warpCategory = getWarpCategory(warpRecord.category); - loadIslandWarp(warpRecord.name, warpRecord.location, warpCategory, warpRecord.isPrivate, warpRecord.icon); + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, warpRecord.worldName); + + loadIslandWarp(warpRecord.name, worldInfo, warpRecord.worldPosition, warpCategory, warpRecord.isPrivate, warpRecord.icon); }); int islandDistance = (int) Math.round(plugin.getSettings().getMaxIslandSize() * @@ -3623,15 +3625,31 @@ public Map getWarpCategories() { @Override public IslandWarp createWarp(String name, Location location, @Nullable WarpCategory warpCategory) { - Preconditions.checkNotNull(name, "name parameter cannot be null."); Preconditions.checkNotNull(location, "location parameter cannot be null."); if (!(location instanceof LazyWorldLocation)) Preconditions.checkNotNull(location.getWorld(), "location's world cannot be null."); + + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, LazyWorldLocation.getWorldName(location)); + WorldPosition worldPosition = SWorldPosition.of(location); + + return createIslandInternal(name, worldInfo, worldPosition, warpCategory); + } + + @Override + public IslandWarp createWarp(String name, WorldInfo worldInfo, WorldPosition position, @Nullable WarpCategory warpCategory) { + Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); + Preconditions.checkNotNull(position, "position parameter cannot be null."); + + return createIslandInternal(name, worldInfo, position, warpCategory); + } + + private IslandWarp createIslandInternal(String name, WorldInfo worldInfo, WorldPosition worldPosition, @Nullable WarpCategory warpCategory) { + Preconditions.checkNotNull(name, "name parameter cannot be null."); Preconditions.checkState(getWarp(name) == null, "Warp already exists: " + name); - Log.debug(Debug.CREATE_WARP, owner.getName(), name, location, warpCategory); + Log.debug(Debug.CREATE_WARP, owner.getName(), name, worldInfo, worldPosition, warpCategory); - IslandWarp islandWarp = loadIslandWarp(name, LazyWorldLocation.of(location), warpCategory, + IslandWarp islandWarp = loadIslandWarp(name, worldInfo, worldPosition, warpCategory, !plugin.getSettings().isPublicWarps(), null); IslandsDatabaseBridge.saveWarp(this, islandWarp); @@ -4521,12 +4539,12 @@ private WarpCategory loadWarpCategory(String name, int slot, @Nullable ItemStack return warpCategory; } - public IslandWarp loadIslandWarp(String name, LazyWorldLocation location, @Nullable WarpCategory warpCategory, + public IslandWarp loadIslandWarp(String name, WorldInfo worldInfo, WorldPosition worldPosition, @Nullable WarpCategory warpCategory, boolean isPrivate, @Nullable ItemStack icon) { if (warpCategory == null) warpCategory = warpCategories.values().stream().findFirst().orElseGet(() -> createWarpCategory("Default Category")); - IslandWarp islandWarp = new SIslandWarp(name, location, warpCategory, isPrivate, icon); + IslandWarp islandWarp = new SIslandWarp(name, worldInfo, worldPosition, warpCategory, isPrivate, icon); islandWarp.getCategory().getWarps().add(islandWarp); @@ -4538,7 +4556,7 @@ public IslandWarp loadIslandWarp(String name, LazyWorldLocation location, @Nulla warpsByName.put(warpName, islandWarp); this.warpsByLocation.write(warpsByLocation -> - warpsByLocation.put(location, islandWarp)); + warpsByLocation.put(LazyWorldLocation.of(worldInfo, worldPosition), islandWarp)); return islandWarp; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 0e66cf4715..59045490ca 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -1868,6 +1868,11 @@ public IslandWarp createWarp(String name, Location location, WarpCategory warpCa return null; } + @Override + public IslandWarp createWarp(String s, WorldInfo worldInfo, WorldPosition worldPosition, WarpCategory warpCategory) { + return null; + } + @Override public void renameWarp(IslandWarp islandWarp, String newName) { // Do nothing. diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java index 859aabeedd..203385957c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java @@ -15,6 +15,7 @@ import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; @@ -787,7 +788,17 @@ public Island.Builder addWarp(String name, String category, Location location, b Preconditions.checkNotNull(name, "name parameter cannot be null."); Preconditions.checkNotNull(category, "category parameter cannot be null."); Preconditions.checkNotNull(location, "location parameter cannot be null."); - this.warps.add(new WarpRecord(name, category, LazyWorldLocation.of(location), isPrivate, icon)); + this.warps.add(new WarpRecord(name, category, SWorldPosition.of(location), LazyWorldLocation.getWorldName(location), isPrivate, icon)); + return this; + } + + @Override + public Island.Builder addWarp(String name, String category, WorldInfo worldInfo, WorldPosition worldPosition, boolean isPrivate, @Nullable ItemStack icon) { + Preconditions.checkNotNull(name, "name parameter cannot be null."); + Preconditions.checkNotNull(category, "category parameter cannot be null."); + Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); + Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null."); + this.warps.add(new WarpRecord(name, category, worldPosition, worldInfo.getName(), isPrivate, icon)); return this; } @@ -807,8 +818,26 @@ public boolean hasWarp(String name) { public boolean hasWarp(Location location) { Preconditions.checkNotNull(location, "location parameter cannot be null"); + WorldPosition worldPosition = SWorldPosition.of(location); + String worldName = LazyWorldLocation.getWorldName(location); + + for (WarpRecord warpRecord : this.warps) { + if (warpRecord.worldName.equals(worldName) && warpRecord.worldPosition.equals(worldPosition)) + return true; + } + + return false; + } + + @Override + public boolean hasWarp(WorldInfo worldInfo, WorldPosition worldPosition) { + Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null"); + Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null"); + + String worldName = worldInfo.getName(); + for (WarpRecord warpRecord : this.warps) { - if (warpRecord.location.equals(location)) + if (warpRecord.worldName.equals(worldName) && warpRecord.worldPosition.equals(worldPosition)) return true; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/WarpRecord.java b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/WarpRecord.java index e17a2150f6..49e839d337 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/WarpRecord.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/WarpRecord.java @@ -1,22 +1,24 @@ package com.bgsoftware.superiorskyblock.island.builder; import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.inventory.ItemStack; public class WarpRecord { public final String name; public final String category; - public final LazyWorldLocation location; + public final WorldPosition worldPosition; + public final String worldName; public final boolean isPrivate; @Nullable public final ItemStack icon; - public WarpRecord(String name, String category, LazyWorldLocation location, boolean isPrivate, @Nullable ItemStack icon) { + public WarpRecord(String name, String category, WorldPosition worldPosition, String worldName, boolean isPrivate, @Nullable ItemStack icon) { this.name = name; this.category = category; - this.location = location; + this.worldPosition = worldPosition; + this.worldName = worldName; this.isPrivate = isPrivate; this.icon = icon; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java index e6d2a201ac..8e5dcdf452 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java @@ -1,33 +1,43 @@ package com.bgsoftware.superiorskyblock.island.warp; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.island.warps.WarpCategory; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; +import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.inventory.ItemStack; import java.util.Objects; public class SIslandWarp implements IslandWarp { + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private final WarpCategory warpCategory; private String name; - private LazyWorldLocation location; + private WorldPosition worldPosition; + private WorldInfo worldInfo; private boolean isPrivate; private ItemStack icon; - public SIslandWarp(String name, LazyWorldLocation location, WarpCategory warpCategory, boolean isPrivate, @Nullable ItemStack icon) { + public SIslandWarp(String name, WorldInfo worldInfo, WorldPosition worldPosition, WarpCategory warpCategory, boolean isPrivate, @Nullable ItemStack icon) { this.name = name; - this.location = (LazyWorldLocation) location.clone(true); + this.worldPosition = worldPosition; + this.worldInfo = worldInfo; this.warpCategory = warpCategory; this.isPrivate = isPrivate; this.icon = icon; @@ -57,22 +67,23 @@ public void setName(String name) { @Override public Location getLocation() { - return location.clone(); + return LazyWorldLocation.of(worldInfo, worldPosition); } @Override public Location getLocation(Location location) { if (location != null) { - location.setX(this.location.getX()); - location.setY(this.location.getY()); - location.setZ(this.location.getZ()); - location.setYaw(this.location.getYaw()); - location.setPitch(this.location.getPitch()); + location.setX(this.worldPosition.getX()); + location.setY(this.worldPosition.getY()); + location.setZ(this.worldPosition.getZ()); + location.setYaw(this.worldPosition.getYaw()); + location.setPitch(this.worldPosition.getPitch()); if (location instanceof LazyWorldLocation) { - ((LazyWorldLocation) location).setWorldName(this.location.getWorldName()); + ((LazyWorldLocation) location).setWorldName(this.worldInfo.getName()); } else { - location.setWorld(this.location.getWorld()); + World world = plugin.getGrid().getIslandsWorld(getIsland(), this.worldInfo.getDimension()); + location.setWorld(world); } } @@ -85,7 +96,31 @@ public void setLocation(Location location) { Log.debug(Debug.SET_WARP_LOCATION, getOwnerName(), this.name, location); - this.location = LazyWorldLocation.of(location); + this.worldInfo = plugin.getGrid().getIslandsWorldInfo(getIsland(), LazyWorldLocation.getWorldName(location)); + this.worldPosition = SWorldPosition.of(location); + + IslandsDatabaseBridge.updateWarpLocation(getIsland(), this); + } + + @Override + public WorldPosition getPosition() { + return this.worldPosition; + } + + @Override + public Dimension getPositionDimension() { + return this.worldInfo.getDimension(); + } + + @Override + public void setPosition(Dimension dimension, WorldPosition worldPosition) { + Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); + Preconditions.checkNotNull(worldPosition, "worldPosition parameter cannot be null."); + + Log.debug(Debug.SET_WARP_LOCATION, getOwnerName(), this.name, dimension, worldPosition); + + this.worldInfo = plugin.getGrid().getIslandsWorldInfo(getIsland(), dimension); + this.worldPosition = worldPosition; IslandsDatabaseBridge.updateWarpLocation(getIsland(), this); } From 69646a90b21edcc98610dc85a4cf575f4e89742a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 14 Oct 2025 11:44:33 +0300 Subject: [PATCH 383/600] Potential fix for villager sieges still happening even with natural monster spawn being disabled for the island (#2521) --- .../listener/IslandFlagsListener.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java index 1bd4a55103..62f9d75c87 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java @@ -43,6 +43,9 @@ public class IslandFlagsListener extends AbstractGameEventListener { private static final EnumSet NATURAL_SPAWN_REASONS = initializeNaturalSpawnReasons(); + @Nullable + private static final CreatureSpawnEvent.SpawnReason VILLAGE_INVASION = EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "VILLAGE_INVASION"); + private final Int2ObjectMapView originalFireballsDamager = CollectionsFactory.createInt2ObjectArrayMap(); private World spawnIslandWorld; @@ -109,6 +112,34 @@ private void onAttemptEntitySpawn(GameEvent e) { + if (e.getArgs().spawnReason != VILLAGE_INVASION) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = e.getArgs().entity.getLocation(wrapper.getHandle()); + + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(entityLocation.getWorld())) + return; + + if (!preventAction(entityLocation, IslandFlags.NATURAL_MONSTER_SPAWN)) + return; + } + + Entity entity = e.getArgs().entity; + + // We should prevent the spawn of the entity + e.setCancelled(); + + BukkitExecutor.sync(() -> { + // The entity was not removed, let's remove it now + if (entity.isValid() || !entity.isDead()) + entity.remove(); + }, 1L); + } + /* ENTITY EXPLOSIONS */ private void onHangingBreakByEntity(GameEvent e) { @@ -379,6 +410,8 @@ private boolean preventAction(Location location, IslandFlag islandFlag) { private void registerListeners() { registerCallback(GameEventType.ATTEMPT_ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onAttemptEntitySpawn); + if (VILLAGE_INVASION != null) + registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onEntitySpawnFromVillageSiege); registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.LOWEST, this::onEntityExplode); registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.LOWEST, this::onEntityChangeBlock); registerCallback(GameEventType.HANGING_BREAK_EVENT, GameEventPriority.LOWEST, this::onHangingBreakByEntity); From a477c833e28233ee80cedb372e99fc95ba86ebdc Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 14 Oct 2025 11:47:19 +0300 Subject: [PATCH 384/600] Added debug mode for DISABLE_REDSTONE (#2712) --- .../com/bgsoftware/superiorskyblock/core/logging/Debug.java | 1 + .../listener/IslandWorldEventsListener.java | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java index 2eafec62ca..fa2fc222d6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java @@ -134,6 +134,7 @@ public enum Debug { PERMISSION_LOOKUP, REPLACE_PLAYER, TRACK_TASK, + DISABLE_REDSTONE, SHOW_STACKTRACE, PROFILER; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java index 9acd8da18b..37e1977f85 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandWorldEventsListener.java @@ -6,6 +6,8 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.logging.Debug; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; @@ -51,6 +53,10 @@ private void onBlockRedstone(GameEvent e) { if ((plugin.getSettings().isDisableRedstoneOffline() && !island.isCurrentlyActive()) || (plugin.getSettings().getAFKIntegrations().isDisableRedstone() && island.getAllPlayersInside().stream().allMatch(SuperiorPlayer::isAFK))) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Log.debug(Debug.DISABLE_REDSTONE, island.getOwner().getName(), block.getLocation(wrapper.getHandle())); + } + e.setCancelled(); } } From 046768199e0fc2ac489e0605b6bfcd1a33a652a9 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Tue, 14 Oct 2025 12:15:59 +0200 Subject: [PATCH 385/600] Fixed usage of /is admin count command (#2713) --- .../commands/admin/CmdAdminCount.java | 54 ++++++------------- .../core/messages/Message.java | 1 + src/main/resources/lang/de-DE.yml | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/tr-TR.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + 14 files changed, 30 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminCount.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminCount.java index bc3912f675..2699ccff33 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminCount.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminCount.java @@ -5,15 +5,14 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; -import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.PlayerLocales; -import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -42,7 +41,8 @@ public String getUsage(java.util.Locale locale) { return "admin count <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "> [" + - Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + "]"; + Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ALL_MATERIALS.getMessage(locale) + "]"; } @Override @@ -65,40 +65,6 @@ public boolean canBeExecutedByConsole() { return true; } - @Override - public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { - List list = new LinkedList<>(); - - if (args.length == 3) { - String argument = args[2].toLowerCase(Locale.ENGLISH); - for (Player player : Bukkit.getOnlinePlayers()) { - SuperiorPlayer onlinePlayer = plugin.getPlayers().getSuperiorPlayer(player); - Island playerIsland = onlinePlayer.getIsland(); - if (playerIsland != null) { - if (player.getName().toLowerCase(Locale.ENGLISH).contains(argument)) - list.add(player.getName()); - if (!playerIsland.getStrippedName().isEmpty() && playerIsland.getStrippedName().toLowerCase(Locale.ENGLISH).contains(argument)) - list.add(playerIsland.getStrippedName()); - } - } - } else if (args.length == 4) { - SuperiorPlayer targetPlayer = plugin.getPlayers().getSuperiorPlayer(args[2]); - Island island = targetPlayer == null ? plugin.getGrid().getIsland(args[2]) : targetPlayer.getIsland(); - - if (island != null) { - String materialArgument = args[3].toLowerCase(Locale.ENGLISH); - Materials.getBlocksNonLegacy().stream() - .map(material -> material.name().toLowerCase(Locale.ENGLISH)) - .filter(materialName -> materialName.contains(materialArgument)) - .forEach(list::add); - if ("*".contains(materialArgument)) - list.add("*"); - } - } - - return Collections.unmodifiableList(list); - } - @Override public boolean supportMultipleIslands() { return false; @@ -152,4 +118,18 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab Formatters.CAPITALIZED_FORMATTER.format(materialName)); } } + + @Override + public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { + if (args.length != 4) + return Collections.emptyList(); + + List list = new LinkedList<>(CommandTabCompletes.getMaterials(args[3])); + + if ("*".contains(args[3])) + list.add("*"); + + return Collections.unmodifiableList(list); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index d5f3ab1fb1..86752f7c71 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -135,6 +135,7 @@ public enum Message { CHANGED_WARPS_LIMIT_NAME, CHANGE_PERMISSION_FOR_HIGHER_ROLE, COMMAND_ARGUMENT_ALL_ISLANDS("*"), + COMMAND_ARGUMENT_ALL_MATERIALS("*"), COMMAND_ARGUMENT_ALL_MISSIONS("*"), COMMAND_ARGUMENT_ALL_PLAYERS("*"), COMMAND_ARGUMENT_AMOUNT("amount"), diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 1efa7ccad2..70feaf1355 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -155,6 +155,7 @@ CHANGED_WARPS_LIMIT_ALL: '&e&lUpgrades | &7Das Warps-Limit aller Inseln wurde er CHANGED_WARPS_LIMIT_NAME: '&e&lUpgrades | &7Das Warps-Limit von {0} wurde erfolgreich aktualisiert.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: Betrag diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 6e905b2c36..3a61931151 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&lUpgrades | &7Successfully updated the warps limit of { CHANGED_WARPS_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the warps limit of all the islands.' CHANGED_WARPS_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the warps limit of {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'amount' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 84104d00ff..6dd0c21ec7 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&lMejoras| &7Se actualizó con éxito el límite de warp CHANGED_WARPS_LIMIT_ALL: '&e&lMejoras| &7Se actualizó con éxito el límite de warps de todas las islas.' CHANGED_WARPS_LIMIT_NAME: '&e&lMejoras| &7Se actualizó correctamente el límite de warps de {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'cantidad' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 0c00cb874f..1494cc53fe 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&lAméliorations | &7Vous avez changé la limite de warp CHANGED_WARPS_LIMIT_ALL: '&e&lAméliorations | &7Vous avez changé la limite de warps de toutes les îles.' CHANGED_WARPS_LIMIT_NAME: '&e&lAméliorations | &7Vous avez changé la limite de warps d''île de {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: quantité diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index e295003af3..c5c9e394ce 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -106,6 +106,7 @@ CHANGED_WARPS_LIMIT: '&e&lAggiornamenti | &7Aggiornato con successo il limite di CHANGED_WARPS_LIMIT_ALL: '&e&lAggiornamenti | &7Aggioranto con successo il limite di warps di tutte le isole.' CHANGED_WARPS_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il mite di warps dell''isola {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: quantità diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 5ef5d8ecbc..d4b954efa9 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -111,6 +111,7 @@ CHANGED_WARPS_LIMIT: '&e&lםיגורדש | &7החלצהב הנכדוע {0} לש CHANGED_WARPS_LIMIT_ALL: '&e&lםיגורדש | &7החלצהב הנכדוע םייאה לכ לש םימוקימה תלבגמ.' CHANGED_WARPS_LIMIT_NAME: '&e&lםיגורדש | &7החלצהב הנכדוע {0} יאה לש םימוקימה תלבגמ.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: תומכ diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index afbcfce12c..50f064e023 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit warpow CHANGED_WARPS_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit warp na wszystkich wyspach.' CHANGED_WARPS_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit warpow {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'kwota' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index e8b3ca2389..c2e3014df8 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&lMelhorias | &7O limite de warps da ilha de {0} foi atu CHANGED_WARPS_LIMIT_ALL: '&e&lMelhorias | &7O limite de warps de todas as ilhas foi atualizado com sucesso.' CHANGED_WARPS_LIMIT_NAME: '&e&lMelhorias | &7O limite de warps de {0} foi atualizado com sucesso.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'quantidade' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 28c158b806..7814bbaaf7 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&lУлучшения | &7Успешно обновлен CHANGED_WARPS_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит варпов для всех островов.' CHANGED_WARPS_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит варпов для {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: 'количество' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index a3fa96e415..1bd495129f 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -147,6 +147,7 @@ CHANGED_WARPS_LIMIT_ALL: '&e&lYükseltmeler | &7Tüm adaların ışınlanma limi CHANGED_WARPS_LIMIT_NAME: '&e&lYükseltmeler | &7{0} adasının ışınlanma limiti başarıyla güncellendi.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: miktar diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index b5c3970b0d..76e7c3ba11 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -128,6 +128,7 @@ CHANGED_WARPS_LIMIT_ALL: '&e&lNâng Cấp | &7Cập nhật thành công giới h CHANGED_WARPS_LIMIT_NAME: '&e&lNâng Cấp | &7Cập nhật thành công giới hạn khu vực của đảo {0}.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: so-luong diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 6f8d75bb2d..c503f76823 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -103,6 +103,7 @@ CHANGED_WARPS_LIMIT: '&e&l升级 | &7成功更新了玩家 {0} 岛屿的传送 CHANGED_WARPS_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的传送点数量限制.' CHANGED_WARPS_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的传送点数量限制.' COMMAND_ARGUMENT_ALL_ISLANDS: '*' +COMMAND_ARGUMENT_ALL_MATERIALS: '*' COMMAND_ARGUMENT_ALL_MISSIONS: '*' COMMAND_ARGUMENT_ALL_PLAYERS: '*' COMMAND_ARGUMENT_AMOUNT: '数量' From ed6f89812c0e09c6bd3179bf39d94daad35c1e9b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 14 Oct 2025 16:57:36 +0300 Subject: [PATCH 386/600] Do not rely on PreCreatureSpawnEvent and always listen to CreatureSpawnEvent (#2521) --- .../listener/BukkitEventsListener.java | 36 ------- .../listener/IslandFlagsListener.java | 99 +++++++------------ .../platform/event/GameEventType.java | 1 - .../platform/event/args/GameEventArgs.java | 9 -- 4 files changed, 33 insertions(+), 112 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index 85371c5b98..a45476fdae 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -114,8 +114,6 @@ public class BukkitEventsListener implements Listener { private final SuperiorSkyblockPlugin plugin; - private boolean shouldFireAttemptEntitySpawnEvent = false; - public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; @@ -214,13 +212,6 @@ public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { createEventListener(GameEventType.ENTITY_DEATH_EVENT, EntityDeathEvent.class, this::createGameEvent); } - try { - Class.forName("com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent"); - createEventListener(GameEventType.ATTEMPT_ENTITY_SPAWN_EVENT, com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent.class, new AttemptEntitySpawnEventFunction()); - } catch (ClassNotFoundException ignored) { - shouldFireAttemptEntitySpawnEvent = true; - } - boolean registeredChatListener = false; if (plugin.getSettings().getChatSigningSupport()) { try { @@ -542,20 +533,6 @@ private GameEvent createGameEvent(GameEventType createGameEvent(GameEventType eventType, GameEventPriority priority, CreatureSpawnEvent e) { - if (this.shouldFireAttemptEntitySpawnEvent) { - GameEventArgs.AttemptEntitySpawnEvent attemptEntitySpawnEvent = new GameEventArgs.AttemptEntitySpawnEvent(); - attemptEntitySpawnEvent.entityType = e.getEntityType(); - attemptEntitySpawnEvent.spawnLocation = e.getLocation(); - attemptEntitySpawnEvent.spawnReason = e.getSpawnReason(); - GameEvent gameEvent = GameEventType.ATTEMPT_ENTITY_SPAWN_EVENT - .createEvent(attemptEntitySpawnEvent); - plugin.getGameEventsDispatcher().onGameEvent(gameEvent, priority); - if (gameEvent.isCancelled()) { - e.getEntity().remove(); - return null; - } - } - GameEventArgs.EntitySpawnEvent entitySpawnEvent = new GameEventArgs.EntitySpawnEvent(); entitySpawnEvent.entity = e.getEntity(); entitySpawnEvent.spawnReason = e.getSpawnReason(); @@ -955,19 +932,6 @@ public GameEvent execute(GameEventType { - - @Override - public GameEvent execute(GameEventType eventType, GameEventPriority priority, com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent e) { - GameEventArgs.AttemptEntitySpawnEvent attemptEntitySpawnEvent = new GameEventArgs.AttemptEntitySpawnEvent(); - attemptEntitySpawnEvent.entityType = e.getType(); - attemptEntitySpawnEvent.spawnLocation = e.getSpawnLocation(); - attemptEntitySpawnEvent.spawnReason = e.getReason(); - return eventType.createEvent(attemptEntitySpawnEvent); - } - - } - private class AsyncChatEventFunctions implements GameEventCreator, ApplyBukkitEventFunction { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java index 62f9d75c87..9b3a9843aa 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java @@ -67,8 +67,21 @@ private void onSpawnUpdate() { /* ENTITY SPAWNING */ - private void onAttemptEntitySpawn(GameEvent e) { - EntityType entityType = e.getArgs().entityType; + private void onEntitySpawn(GameEvent e) { + // We only check island flags in relevant worlds + if (shouldIgnoreWorldEvents(e.getArgs().entity.getWorld())) + return; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = e.getArgs().entity.getLocation(wrapper.getHandle()); + + if (checkPreventEntitySpawn(e, location) || checkPreventEggLay(e, location)) + e.setCancelled(); + } + } + + private boolean checkPreventEntitySpawn(GameEvent e, Location entityLocation) { + EntityType entityType = e.getArgs().entity.getType(); CreatureSpawnEvent.SpawnReason spawnReason = e.getArgs().spawnReason; IslandFlag actionFlag; @@ -83,7 +96,7 @@ private void onAttemptEntitySpawn(GameEvent e) { - if (e.getArgs().spawnReason != VILLAGE_INVASION) - return; + private boolean checkPreventEggLay(GameEvent e, Location entityLocation) { + if (!(e.getArgs().entity instanceof Item)) + return false; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location entityLocation = e.getArgs().entity.getLocation(wrapper.getHandle()); + Item item = (Item) e.getArgs().entity; - // We only check island flags in relevant worlds - if (shouldIgnoreWorldEvents(entityLocation.getWorld())) - return; + if (item.getItemStack().getType() != Material.EGG) + return false; - if (!preventAction(entityLocation, IslandFlags.NATURAL_MONSTER_SPAWN)) - return; + if (preventAction(entityLocation, IslandFlags.EGG_LAY)) { + for (Entity entity : item.getNearbyEntities(1, 1, 1)) { + if (entity instanceof Chicken) { + return true; + } + } } - Entity entity = e.getArgs().entity; - - // We should prevent the spawn of the entity - e.setCancelled(); - - BukkitExecutor.sync(() -> { - // The entity was not removed, let's remove it now - if (entity.isValid() || !entity.isDead()) - entity.remove(); - }, 1L); + return false; } /* ENTITY EXPLOSIONS */ @@ -342,32 +338,6 @@ private void onEndermanGrief(GameEvent e) } } - private void onEggLay(GameEvent e) { - if (!(e.getArgs().entity instanceof Item)) - return; - - Item item = (Item) e.getArgs().entity; - - if (item.getItemStack().getType() != Material.EGG) - return; - - // We only check island flags in relevant worlds - if (shouldIgnoreWorldEvents(item.getWorld())) { - return; - } - - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventAction(item.getLocation(wrapper.getHandle()), IslandFlags.EGG_LAY)) { - for (Entity entity : item.getNearbyEntities(1, 1, 1)) { - if (entity instanceof Chicken) { - e.setCancelled(); - return; - } - } - } - } - } - private void onPoisonAttack(GameEvent e) { Entity entity = e.getArgs().entity; EntityType entityType = entity.getType(); @@ -409,11 +379,9 @@ private boolean preventAction(Location location, IslandFlag islandFlag) { } private void registerListeners() { - registerCallback(GameEventType.ATTEMPT_ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onAttemptEntitySpawn); - if (VILLAGE_INVASION != null) - registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onEntitySpawnFromVillageSiege); registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.LOWEST, this::onEntityExplode); registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.LOWEST, this::onEntityChangeBlock); + registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onEntitySpawn); registerCallback(GameEventType.HANGING_BREAK_EVENT, GameEventPriority.LOWEST, this::onHangingBreakByEntity); registerCallback(GameEventType.ENTITY_DAMAGE_EVENT, GameEventPriority.MONITOR, this::onFireballDamage); registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.LOWEST, this::onBlockFlow); @@ -422,7 +390,6 @@ private void registerListeners() { registerCallback(GameEventType.BLOCK_BURN_EVENT, GameEventPriority.LOWEST, this::onFireSpread); registerCallback(GameEventType.BLOCK_IGNITE_EVENT, GameEventPriority.LOWEST, this::onBlockIgnite); registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.LOWEST, this::onEndermanGrief); - registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.LOWEST, this::onEggLay); registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.LOWEST, this::onPoisonAttack); plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SPAWN_UPDATE_EVENT, this::onSpawnUpdate); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java index 2340b936df..84c4b5354d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java @@ -41,7 +41,6 @@ public class GameEventType extends EventType WORLD_UNLOAD_EVENT = register(WorldUnloadEvent.class); // Entity Events - public static final GameEventType ATTEMPT_ENTITY_SPAWN_EVENT = register(AttemptEntitySpawnEvent.class); public static final GameEventType ENTITY_BLOCK_FORM_EVENT = register(EntityBlockFormEvent.class); public static final GameEventType ENTITY_CHANGE_BLOCK_EVENT = register(EntityChangeBlockEvent.class); public static final GameEventType ENTITY_COLLISION_EVENT = register(EntityCollisionEvent.class); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java index f21dcf618a..dcac9b0e60 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java @@ -12,7 +12,6 @@ import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; import org.bukkit.entity.Item; import org.bukkit.entity.Player; import org.bukkit.entity.Vehicle; @@ -30,14 +29,6 @@ private GameEventArgs() { } - public static class AttemptEntitySpawnEvent extends GameEventArgs { - - public EntityType entityType; - public Location spawnLocation; - public CreatureSpawnEvent.SpawnReason spawnReason; - - } - public static class BlockFromToEvent extends BlockEvent { public Block toBlock; From 4e5a3c9161c1b2379b37af71d769505ce0ad6776 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 14 Oct 2025 19:11:11 +0300 Subject: [PATCH 387/600] Fixed errors when using SSBProxyBridge to create islands due to recent commits --- .../superiorskyblock/island/GridManagerImpl.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index 0bc6d15c5c..6b2279e7db 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -25,6 +25,7 @@ import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SBlockPosition; +import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; @@ -330,11 +331,13 @@ private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Bi this.islandsContainer.addIsland(island); setLastIslandPosition(SBlockPosition.of(islandLocation)); + Dimension defaultDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); + try { island.getDatabaseBridge().setDatabaseBridgeMode(DatabaseBridgeMode.IDLE); island.setBiome(biome, false); - island.setSchematicGenerate(plugin.getSettings().getWorlds().getDefaultWorldDimension()); + island.setSchematicGenerate(defaultDimension); island.setCurrentlyActive(true); if (offset) { @@ -351,7 +354,7 @@ private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Bi if (spawnOffset != null) homeLocation = spawnOffset.applyToLocation(homeLocation); - island.setIslandHome(homeLocation); + island.setIslandHome(defaultDimension, SWorldPosition.of(homeLocation)); BukkitExecutor.sync(() -> builder.owner.runIfOnline(player -> { if (updateGameMode) @@ -380,8 +383,6 @@ private void createIslandInternalOnSuccessCallback(IslandBuilderImpl builder, Bi }, 10L); } - Dimension defaultDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); - if (defaultDimension.getEnvironment() == World.Environment.THE_END) { plugin.getNMSDragonFight().awardTheEndAchievement(player); this.dragonBattleService.get().resetEnderDragonBattle(island, defaultDimension); From aaff30d3a9c6d4f59aad581581bac65fdf58dafd Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 14 Oct 2025 19:32:22 +0300 Subject: [PATCH 388/600] Do not allow calling IslandWarp#getLocation for non-loaded worlds --- .../superiorskyblock/core/ChunkPosition.java | 7 ++++ .../superiorskyblock/core/IslandWorlds.java | 15 +++++++ .../button/impl/WarpManageLocationButton.java | 39 ++++++++++++------- .../island/warp/SIslandWarp.java | 19 +++++---- 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java index ca2f37a63b..a1edb1571b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ChunkPosition.java @@ -3,6 +3,8 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; @@ -30,6 +32,11 @@ public static ChunkPosition of(Location location) { return of(WorldInfo.of(world), location.getBlockX() >> 4, location.getBlockZ() >> 4).withBukkitWorld(world); } + public static ChunkPosition of(WorldInfo worldInfo, WorldPosition worldPosition) { + BlockPosition blockPosition = worldPosition.toBlockPosition(); + return of(worldInfo, blockPosition.getX() >> 4, blockPosition.getZ() >> 4); + } + public static ChunkPosition of(Chunk chunk) { return of(chunk, true); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java index 3adfd1d5b5..1471bf33b0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorlds.java @@ -81,6 +81,10 @@ public static void accessIslandWorldAsync(Island island, Dimension dimension, bo public static Location setWorldToLocation(Island island, Dimension dimension, WorldPosition worldPosition) { WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); + return setWorldToLocation(worldInfo, worldPosition); + } + + public static Location setWorldToLocation(WorldInfo worldInfo, WorldPosition worldPosition) { World world = Bukkit.getWorld(worldInfo.getName()); Location location; if (world != null) { @@ -92,6 +96,17 @@ public static Location setWorldToLocation(Island island, Dimension dimension, Wo return location; } + public static void ensureWorldLoaded(Island island, Dimension dimension) { + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); + ensureWorldLoaded(worldInfo); + } + + public static void ensureWorldLoaded(WorldInfo worldInfo) { + World world = Bukkit.getWorld(worldInfo.getName()); + if (world == null) + throw new IllegalStateException("You cannot call this method while the world is unloaded. Use Island#accessIslandWorld"); + } + private static void loadedWorldCallback(WorldInfo worldInfo, Consumer> consumer) { World world = Bukkit.getWorld(worldInfo.getName()); if (world != null) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java index 44e1f44612..f311700d91 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/WarpManageLocationButton.java @@ -2,8 +2,11 @@ import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; +import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; @@ -21,6 +24,8 @@ import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; +import java.util.Objects; + public class WarpManageLocationButton extends AbstractMenuViewButton { private WarpManageLocationButton(AbstractMenuTemplateButton templateButton, MenuWarpManage.View menuView) { @@ -32,7 +37,6 @@ public void onButtonClick(InventoryClickEvent clickEvent) { Player player = (Player) clickEvent.getWhoClicked(); IslandWarp islandWarp = menuView.getIslandWarp(); - PluginEvent event; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location playerLocation = player.getLocation(wrapper.getHandle()); @@ -41,29 +45,36 @@ public void onButtonClick(InventoryClickEvent clickEvent) { return; } - event = PluginEventsFactory.callIslandChangeWarpLocationEvent( + PluginEvent event = PluginEventsFactory.callIslandChangeWarpLocationEvent( islandWarp.getIsland(), player, islandWarp, playerLocation); - } - - if (event.isCancelled()) - return; + if (event.isCancelled()) + return; - Message.WARP_LOCATION_UPDATE.send(player); + Message.WARP_LOCATION_UPDATE.send(player); - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location warpLocation = islandWarp.getLocation(wrapper.getHandle()); + WorldPosition warpPosition = islandWarp.getPosition(); + WorldInfo warpWorld = plugin.getGrid().getIslandsWorldInfo(islandWarp.getIsland(), islandWarp.getPositionDimension()); - if (!warpLocation.equals(event.getArgs().location)) { - ChunksProvider.loadChunk(ChunkPosition.of(warpLocation), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { + if (!isSameLocation(event.getArgs().location, warpWorld, warpPosition)) { + ChunksProvider.loadChunk(ChunkPosition.of(warpWorld, warpPosition), ChunkLoadReason.WARP_SIGN_BREAK, chunk -> { SignWarp.trySignWarpBreak(islandWarp, player); }); } - } - islandWarp.setLocation(event.getArgs().location); + islandWarp.setLocation(event.getArgs().location); + + GameSoundImpl.playSound(player, Menus.MENU_WARP_MANAGE.getSuccessUpdateSound()); + } + } - GameSoundImpl.playSound(player, Menus.MENU_WARP_MANAGE.getSuccessUpdateSound()); + private static boolean isSameLocation(Location location, WorldInfo worldInfo, WorldPosition worldPosition) { + if (location.getX() != worldPosition.getX() || location.getY() != worldPosition.getY() || + location.getZ() != worldPosition.getZ() || location.getYaw() != worldPosition.getYaw() || + location.getPitch() != worldPosition.getPitch()) + return false; + String worldName = LazyWorldLocation.getWorldName(location); + return Objects.equals(worldName, worldInfo.getName()); } public static class Builder extends AbstractMenuTemplateButton.AbstractBuilder { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java index 8e5dcdf452..0556926be0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/warp/SIslandWarp.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; +import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; @@ -16,6 +17,7 @@ import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.google.common.base.Preconditions; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.inventory.ItemStack; @@ -67,24 +69,25 @@ public void setName(String name) { @Override public Location getLocation() { - return LazyWorldLocation.of(worldInfo, worldPosition); + return IslandWorlds.setWorldToLocation(this.worldInfo, this.worldPosition); } @Override public Location getLocation(Location location) { if (location != null) { - location.setX(this.worldPosition.getX()); - location.setY(this.worldPosition.getY()); - location.setZ(this.worldPosition.getZ()); - location.setYaw(this.worldPosition.getYaw()); - location.setPitch(this.worldPosition.getPitch()); - if (location instanceof LazyWorldLocation) { ((LazyWorldLocation) location).setWorldName(this.worldInfo.getName()); } else { - World world = plugin.getGrid().getIslandsWorld(getIsland(), this.worldInfo.getDimension()); + IslandWorlds.ensureWorldLoaded(this.worldInfo); + World world = Bukkit.getWorld(this.worldInfo.getName()); location.setWorld(world); } + + location.setX(this.worldPosition.getX()); + location.setY(this.worldPosition.getY()); + location.setZ(this.worldPosition.getZ()); + location.setYaw(this.worldPosition.getYaw()); + location.setPitch(this.worldPosition.getPitch()); } return location; From 2e98cc8d1bf6170ea9813fb6140dd7141637434c Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 17 Oct 2025 09:01:19 +0200 Subject: [PATCH 389/600] Fixed creating schematics with signs on 1.21.7+ (v2) (#2722) --- .../nms/v1_21_7/utils/NMSUtilsVersioned.java | 6 ++++-- .../nms/v1_21_9/utils/NMSUtilsVersioned.java | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java index db8305d81a..dc4ded1e59 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java @@ -352,8 +352,10 @@ private static void applySignTextLines(CompoundTag blockEntityCompound, String k } } - while (textLines.size() < 4) - textLines.add(Component.empty()); + for (int i = 0; i < 4; i++) { + if (textLines.get(i) == null) + textLines.set(i, Component.empty()); + } Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java index e0a468d15a..cb081c95ca 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java @@ -364,8 +364,10 @@ private static void applySignTextLines(CompoundTag blockEntityCompound, String k } } - while (textLines.size() < 4) - textLines.add(Component.empty()); + for (int i = 0; i < 4; i++) { + if (textLines.get(i) == null) + textLines.set(i, Component.empty()); + } Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); From 1ca4d6ad6d710df04c0f9be7054dd35076b83012 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 17 Oct 2025 15:41:41 +0300 Subject: [PATCH 390/600] Fixed NoSuchFieldError when using 1.21 (#2723) --- .../main/templates/AbstractNMSAlgorithms.java.template | 6 +++++- NMS/src/main/templates/AbstractNMSTags.java.template | 8 ++++---- .../superiorskyblock/nms/v1_17/NMSTagsImpl.java | 2 +- .../superiorskyblock/nms/v1_18/NMSTagsImpl.java | 2 +- .../superiorskyblock/nms/v1_19/NMSTagsImpl.java | 2 +- .../superiorskyblock/nms/v1_20_3/NMSTagsImpl.java | 2 +- .../superiorskyblock/nms/v1_20_4/NMSTagsImpl.java | 2 +- .../superiorskyblock/nms/v1_21/NMSTagsImpl.java | 2 +- .../superiorskyblock/nms/v1_21_3/NMSTagsImpl.java | 2 +- .../superiorskyblock/nms/v1_21_4/NMSTagsImpl.java | 2 +- .../superiorskyblock/nms/v1_21_5/NMSTagsImpl.java | 2 +- .../superiorskyblock/nms/v1_21_7/NMSTagsImpl.java | 2 +- .../superiorskyblock/nms/v1_21_9/NMSTagsImpl.java | 2 +- 13 files changed, 20 insertions(+), 16 deletions(-) diff --git a/NMS/src/main/templates/AbstractNMSAlgorithms.java.template b/NMS/src/main/templates/AbstractNMSAlgorithms.java.template index f938b92406..ba10d0b4ef 100644 --- a/NMS/src/main/templates/AbstractNMSAlgorithms.java.template +++ b/NMS/src/main/templates/AbstractNMSAlgorithms.java.template @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -76,6 +77,9 @@ public abstract class AbstractNMSAlgorithms implements NMSAlgorithms { } }; + static final int DATA_VERSION = ((CraftMagicNumbers) new ReflectField<>( + CraftMagicNumbers.class, Object.class, "INSTANCE").get(null)).getDataVersion(); + private static final EnumMap MENUS_HOLDER_CREATORS = new EnumMap<>(InventoryType.class); static { @@ -233,7 +237,7 @@ public abstract class AbstractNMSAlgorithms implements NMSAlgorithms { @Override public int getDataVersion() { - return CraftMagicNumbers.INSTANCE.getDataVersion(); + return DATA_VERSION; } @Override diff --git a/NMS/src/main/templates/AbstractNMSTags.java.template b/NMS/src/main/templates/AbstractNMSTags.java.template index be7735fc6a..247d6adb54 100644 --- a/NMS/src/main/templates/AbstractNMSTags.java.template +++ b/NMS/src/main/templates/AbstractNMSTags.java.template @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}; +import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.nms.NMSTags; import com.bgsoftware.superiorskyblock.tag.CompoundTag; @@ -22,7 +23,7 @@ public abstract class AbstractNMSTags implements NMSTags { @Override public CompoundTag serializeItem(org.bukkit.inventory.ItemStack bukkitItem) { ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); - return setTagAndGetCompoundTag(itemStack, "DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + return setTagAndGetCompoundTag(itemStack, "DataVersion", AbstractNMSAlgorithms.DATA_VERSION); } protected abstract CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value); @@ -36,11 +37,10 @@ public abstract class AbstractNMSTags implements NMSTags { net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) compoundTag.toNBT(); - int currentVersion = CraftMagicNumbers.INSTANCE.getDataVersion(); int itemVersion = getCompoundTagInt(tagCompound, "DataVersion", 0); - if (itemVersion < currentVersion) { + if (itemVersion < AbstractNMSAlgorithms.DATA_VERSION) { tagCompound = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ITEM_STACK, - new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, currentVersion).getValue(); + new Dynamic<>(NbtOps.INSTANCE, tagCompound), itemVersion, AbstractNMSAlgorithms.DATA_VERSION).getValue(); } ItemStack itemStack = parseItemStack(tagCompound); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java index 13cac1aebe..387f9becc3 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSTagsImpl.java @@ -18,7 +18,7 @@ public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.Abstr @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag()); - tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java index 1f0750dfc3..fb39f769a5 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSTagsImpl.java @@ -18,7 +18,7 @@ public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.Abstr @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag()); - tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java index 9c595fbc23..b680250d20 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSTagsImpl.java @@ -18,7 +18,7 @@ public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.Abstr @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag()); - tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java index 067fbd8963..31de3646ed 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSTagsImpl.java @@ -18,7 +18,7 @@ public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.Abs @Override protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = itemStack.save(new net.minecraft.nbt.CompoundTag()); - tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java index c36d3a821f..f6fe0c897c 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSTagsImpl.java @@ -41,7 +41,7 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) itemStack.save(MinecraftServer.getServer().registryAccess()); - tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java index 004a790970..0601fa9e93 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSTagsImpl.java @@ -41,7 +41,7 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) itemStack.save(MinecraftServer.getServer().registryAccess()); - tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java index 98090c483d..78b08ba5be 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSTagsImpl.java @@ -42,7 +42,7 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) itemStack.save(MinecraftServer.getServer().registryAccess()); - tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java index 140da89bb1..61d780b0a0 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSTagsImpl.java @@ -42,7 +42,7 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) itemStack.save(MinecraftServer.getServer().registryAccess()); - tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java index f4d4e0f8e6..f94670d3f9 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSTagsImpl.java @@ -42,7 +42,7 @@ public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.I protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) itemStack.save(MinecraftServer.getServer().registryAccess()); - tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java index 5949341885..19431741f3 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSTagsImpl.java @@ -51,7 +51,7 @@ protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, i net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow(); - tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java index b2476d3243..44ce8e6fc5 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSTagsImpl.java @@ -56,7 +56,7 @@ protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, i net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow(); - tagCompound.putInt("DataVersion", CraftMagicNumbers.INSTANCE.getDataVersion()); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms.DATA_VERSION); return CompoundTag.fromNBT(tagCompound); } From 3ef7e9c8c9ffb81493d9918d8f5370946e8c3600 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 17 Oct 2025 15:45:29 +0300 Subject: [PATCH 391/600] Fixed errors when using WildTools --- .../main/templates/AbstractNMSWorld.java.template | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/NMS/src/main/templates/AbstractNMSWorld.java.template b/NMS/src/main/templates/AbstractNMSWorld.java.template index 283ac25758..2b358d08d7 100644 --- a/NMS/src/main/templates/AbstractNMSWorld.java.template +++ b/NMS/src/main/templates/AbstractNMSWorld.java.template @@ -231,15 +231,23 @@ public abstract class AbstractNMSWorld implements NMSWorld { @Override public int getDefaultAmount(org.bukkit.block.Block bukkitBlock) { - return getDefaultAmount(((CraftBlock) bukkitBlock).getNMS()); + ServerLevel serverLevel = ((CraftWorld) bukkitBlock.getWorld()).getHandle(); + BlockState blockState; + try (ObjectsPools.Wrapper wrapper = NMSUtils.BLOCK_POS_POOL.obtain()) { + BlockPos.MutableBlockPos blockPos = wrapper.getHandle(); + blockPos.set(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ()); + + blockState = serverLevel.getBlockState(blockPos); + } + return getDefaultAmountInternal(blockState); } @Override public int getDefaultAmount(org.bukkit.block.BlockState bukkitBlockState) { - return getDefaultAmount(((CraftBlockState) bukkitBlockState).getHandle()); + return getDefaultAmountInternal(((CraftBlockState) bukkitBlockState).getHandle()); } - private int getDefaultAmount(BlockState blockState) { + private int getDefaultAmountInternal(BlockState blockState) { Block block = blockState.getBlock(); return NMSUtils.isDoubleBlock(block, blockState) ? 2 : 1; } From 54c9d228e2c6d05ec20753d00164fd55cd3723ee Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 17 Oct 2025 16:40:52 +0300 Subject: [PATCH 392/600] Fixed stacked blocks holograms do not appear in some cases --- .../core/stackedblocks/StackedBlock.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java index 1ea63b1f88..50369a5bda 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/stackedblocks/StackedBlock.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.service.hologram.HologramsService; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; @@ -82,8 +83,12 @@ public void updateName() { return; } - if (hologram == null) - hologram = hologramsService.get().createHologram(location.add(0.5, 1, 0.5)); + if (hologram == null) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = copyLocation(wrapper.getHandle()).add(0.5, 1, 0.5); + hologram = hologramsService.get().createHologram(location); + } + } hologram.setHologramName(plugin.getSettings().getStackedBlocks().getCustomName() .replace("{0}", String.valueOf(amount)) @@ -99,4 +104,14 @@ public void removeHologram() { } } + private Location copyLocation(Location location) { + location.setX(this.location.getX()); + location.setY(this.location.getY()); + location.setZ(this.location.getZ()); + location.setYaw(this.location.getYaw()); + location.setPitch(this.location.getPitch()); + location.setWorld(this.location.getWorld()); + return location; + } + } From dfeb1cbd1d172aa9b7ada1137c631e0b4ec1d74b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 17 Oct 2025 18:23:57 +0300 Subject: [PATCH 393/600] Fixed block counts are not loaded correctly, potentially causing incorrect counts --- .../api/island/IslandBlockFlags.java | 5 ++ .../superiorskyblock/island/SIsland.java | 61 ++++++++++++++----- .../DefaultIslandBlocksTrackerAlgorithm.java | 3 + 3 files changed, 53 insertions(+), 16 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandBlockFlags.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandBlockFlags.java index ba14385e5d..6a53ce2b2f 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandBlockFlags.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/IslandBlockFlags.java @@ -19,4 +19,9 @@ */ int UPDATE_LAST_TIME_STATUS = (1 << 1); + /** + * Indicates to update block counts only for the provided blocks, and do not count global keys, limit keys, etc. + */ + int RAW_BLOCKS = (1 << 2); + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 16c8f6191a..b1366e26a9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -357,7 +357,10 @@ public SIsland(IslandBuilderImpl builder) { }); if (!builder.blockCounts.isEmpty()) { plugin.getProviders().addPricesLoadCallback(() -> { - builder.blockCounts.forEach((block, count) -> handleBlockPlaceInternal(block, count, 0)); + accessBlocksTracker(true, unused -> { + builder.blockCounts.forEach((block, count) -> handleBlockPlaceInternal(block, count, 0)); + return null; + }); this.lastSavedBlockCounts = this.currentTotalBlockCounts.get(); }); } @@ -2427,7 +2430,10 @@ public BlockChangeResult handleBlockPlaceWithResult(Key key, @Size int amount, @ } private BlockChangeResult handleBlockPlaceInternal(Key key, @Size BigInteger amount, @IslandBlockFlags int flags) { - boolean trackedBlock = this.blocksTracker.trackBlock(key, amount); + boolean rawBlocks = (flags & IslandBlockFlags.RAW_BLOCKS) != 0; + + boolean trackedBlock = accessBlocksTracker(rawBlocks, + blocksTracker -> blocksTracker.trackBlock(key, amount)); if (!trackedBlock) return BlockChangeResult.MISSING_BLOCK_VALUE; @@ -2543,12 +2549,16 @@ public Map handleBlocksPlaceWithResult(Map BigDecimal oldWorth = getWorth(); BigDecimal oldLevel = getIslandLevel(); - KeyMap result = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); + boolean rawBlocks = (flags & IslandBlockFlags.RAW_BLOCKS) != 0; - blocks.forEach((blockKey, amount) -> { - BlockChangeResult blockResult = handleBlockPlaceWithResult(blockKey, amount, 0); - if (blockResult != BlockChangeResult.SUCCESS) - result.put(blockKey, blockResult); + KeyMap result = accessBlocksTracker(rawBlocks, blocksTracker -> { + KeyMap resultMap = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); + blocks.forEach((blockKey, amount) -> { + BlockChangeResult blockResult = handleBlockPlaceWithResult(blockKey, amount, 0); + if (blockResult != BlockChangeResult.SUCCESS) + resultMap.put(blockKey, blockResult); + }); + return resultMap.isEmpty() ? KeyMaps.createEmptyMap() : KeyMaps.unmodifiableKeyMap(resultMap); }); boolean saveBlockCounts = (flags & IslandBlockFlags.SAVE_BLOCK_COUNTS) != 0; @@ -2560,7 +2570,7 @@ public Map handleBlocksPlaceWithResult(Map if (updateLastTimeStatus) updateLastTime(); - return result.isEmpty() ? KeyMaps.createEmptyMap() : KeyMaps.unmodifiableKeyMap(result); + return result; } @Override @@ -2631,7 +2641,10 @@ public BlockChangeResult handleBlockBreakWithResult(Key key, @Size int amount, i BigInteger amountBig = BigInteger.valueOf(amount); - boolean untrackedBlocks = this.blocksTracker.untrackBlock(key, amountBig); + boolean rawBlocks = (flags & IslandBlockFlags.RAW_BLOCKS) != 0; + + boolean untrackedBlocks = accessBlocksTracker(rawBlocks, + blocksTracker -> blocksTracker.untrackBlock(key, amountBig)); if (!untrackedBlocks) return BlockChangeResult.MISSING_BLOCK_VALUE; @@ -2729,12 +2742,16 @@ public Map handleBlocksBreakWithResult(Map BigDecimal oldWorth = getWorth(); BigDecimal oldLevel = getIslandLevel(); - KeyMap result = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); + boolean rawBlocks = (flags & IslandBlockFlags.RAW_BLOCKS) != 0; - blocks.forEach((blockKey, amount) -> { - BlockChangeResult blockResult = handleBlockBreakWithResult(blockKey, amount, 0); - if (blockResult != BlockChangeResult.SUCCESS) - result.put(blockKey, blockResult); + KeyMap result = accessBlocksTracker(rawBlocks, blocksTracker -> { + KeyMap resultMap = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); + blocks.forEach((blockKey, amount) -> { + BlockChangeResult blockResult = handleBlockBreakWithResult(blockKey, amount, 0); + if (blockResult != BlockChangeResult.SUCCESS) + resultMap.put(blockKey, blockResult); + }); + return resultMap.isEmpty() ? KeyMaps.createEmptyMap() : KeyMaps.unmodifiableKeyMap(resultMap); }); boolean saveBlockCounts = (flags & IslandBlockFlags.SAVE_BLOCK_COUNTS) != 0; @@ -2746,7 +2763,7 @@ public Map handleBlocksBreakWithResult(Map if (updateLastTimeStatus) updateLastTime(); - return result.isEmpty() ? KeyMaps.createEmptyMap() : KeyMaps.unmodifiableKeyMap(result); + return result; } @Override @@ -3631,7 +3648,7 @@ public IslandWarp createWarp(String name, Location location, @Nullable WarpCateg WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(this, LazyWorldLocation.getWorldName(location)); WorldPosition worldPosition = SWorldPosition.of(location); - + return createIslandInternal(name, worldInfo, worldPosition, warpCategory); } @@ -5221,6 +5238,18 @@ private Location worldPositionToLocation(Dimension dimension, WorldPosition worl return IslandWorlds.setWorldToLocation(this, dimension, worldPosition); } + private R accessBlocksTracker(boolean rawBlocks, Function function) { + if (!rawBlocks) + return function.apply(this.blocksTracker); + + try { + this.blocksTracker.setLoadingDataMode(true); + return function.apply(this.blocksTracker); + } finally { + this.blocksTracker.setLoadingDataMode(false); + } + } + public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SIsland::onSettingsUpdate); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java index 045c8c7a5c..f9a3e2c614 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java @@ -87,6 +87,9 @@ public boolean untrackBlock(Key key, BigInteger amount) { Key valueKey = plugin.getBlockValues().getBlockKey(key); removeCounts(valueKey, amount); + if (loadingDataMode) + return true; + Key limitKey = island.getBlockLimitKey(valueKey); Key globalKey = ((BaseKey) valueKey).toGlobalKey(); boolean limitCount = false; From da8bf0716205017127c8b289a679a0ebc5f721e3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 17 Oct 2025 18:45:03 +0300 Subject: [PATCH 394/600] Add island active debug mode --- .../superiorskyblock/core/logging/Debug.java | 215 +++++++++--------- .../superiorskyblock/island/SIsland.java | 1 + 2 files changed, 109 insertions(+), 107 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java index fa2fc222d6..2ac38b66b8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Debug.java @@ -4,137 +4,138 @@ public enum Debug { + ADD_COOP, + ADD_MEMBER, + BAN_PLAYER, + BLOCK_BREAK, + BLOCK_COUNT_DECREASE, + BLOCK_COUNT_INCREASE, + BLOCK_PLACE, + CALCULATE_ALL_ISLANDS, + CALCULATE_ISLAND, + CHUNK_CALCULATION_BLOCKS, + CHUNK_CALCULATION_ENTITIES, + CLEAR_BLOCK_LIMITS, + CLEAR_ENTITY_LIMITS, + CLEAR_GENERATOR_RATES, + CLEAR_ISLAND_EFFECTS, CREATE_ISLAND, + CREATE_WARP, + CREATE_WARP_CATEGORY, + DATABASE_QUERY, DELETE_ISLAND, - SORT_ISLANDS, - CALCULATE_ALL_ISLANDS, - PURGE_ISLAND, - UNPURGE_ISLAND, - REGISTER_SORTING_TYPE, - SET_LAST_ISLAND, - SET_BLOCK_AMOUNT, - GET_VALUE, - SAVE_SCHEMATIC, - REWARD_MISSION, + DELETE_WARP, + DELETE_WARP_CATEGORY, + DEPOSIT_MONEY, + DISABLE_ISLAND_FLAG, + DISABLE_REDSTONE, + ENABLE_ISLAND_FLAG, + ENTER_ISLAND, + ENTITY_DESPAWN, + ENTITY_SPAWN, EXECUTE_COMMAND, + EXECUTE_ISLAND_COMMANDS, + FIND_SAFE_TELEPORT, + FIRE_EVENT, + GENERATE_BLOCK, + GET_VALUE, + GIVE_BANK_INTEREST, INVITE_MEMBER, - REVOKE_INVITE, - ADD_MEMBER, + ISLAND_ACTIVE, KICK_MEMBER, - BAN_PLAYER, - UNBAN_PLAYER, - ADD_COOP, - REMOVE_COOP, - SET_COOP_LIMIT, - ENTER_ISLAND, LEAVE_ISLAND, - SET_ISLAND_HOME, - SET_VISITOR_HOME, - SET_DIMENSION_ENABLED, - SET_PERMISSION, + LOAD_CHUNK, + MENU_CLICK, + OPEN_MENU, + PASTE_SCHEMATIC, + PERMISSION_LOOKUP, + PURGE_ISLAND, + REGISTER_SORTING_TYPE, + REMOVE_BLOCK_LIMIT, + REMOVE_COOP, + REMOVE_ENTITY_LIMIT, + REMOVE_GENERATOR_RATE, + REMOVE_ISLAND_EFFECT, + REMOVE_PLAYER_STATUS, + REMOVE_RATING, + REMOVE_RATINGS, + REMOVE_ROLE_LIMIT, + REPLACE_PLAYER, + RESET_ISLAND_FLAGS, RESET_PERMISSIONS, - SET_NAME, - SET_DESCRIPTION, - TRANSFER_ISLAND, - CALCULATE_ISLAND, - UPDATE_BORDER, - SET_SIZE, - SET_DISCORD, - SET_PAYPAL, - SET_BIOME, - SET_IGNORED, + REVOKE_INVITE, + REWARD_MISSION, + SAVE_SCHEMATIC, SEND_MESSAGE, SEND_TITLE, - SET_LOCKED, - EXECUTE_ISLAND_COMMANDS, - SET_ISLAND_LAST_TIME_UPDATED, + SET_ADMIN_BYPASS, + SET_ADMIN_SPY, SET_BANK_LIMIT, - GIVE_BANK_INTEREST, - SET_BONUS_WORTH, + SET_BIOME, + SET_BLOCK_AMOUNT, + SET_BLOCK_LIMIT, SET_BONUS_LEVEL, - SET_UPGRADE, + SET_BONUS_WORTH, + SET_BORDER_COLOR, + SET_COOP_LIMIT, SET_CROP_GROWTH, - SET_SPAWNER_RATES, - SET_MOB_DROPS, - CLEAR_BLOCK_LIMITS, - SET_BLOCK_LIMIT, - REMOVE_BLOCK_LIMIT, - CLEAR_ENTITY_LIMITS, + SET_DESCRIPTION, + SET_DIMENSION_ENABLED, + SET_DISBANDS, + SET_DISCORD, SET_ENTITY_LIMIT, - REMOVE_ENTITY_LIMIT, - SET_TEAM_LIMIT, - SET_WARPS_LIMIT, - SET_ISLAND_EFFECT, - REMOVE_ISLAND_EFFECT, - CLEAR_ISLAND_EFFECTS, - SET_ROLE_LIMIT, - REMOVE_ROLE_LIMIT, - CREATE_WARP_CATEGORY, - DELETE_WARP_CATEGORY, - CREATE_WARP, - DELETE_WARP, - SET_RATING, - REMOVE_RATING, - REMOVE_RATINGS, - ENABLE_ISLAND_FLAG, - DISABLE_ISLAND_FLAG, - RESET_ISLAND_FLAGS, SET_GENERATOR_PERCENTAGE, SET_GENERATOR_RATE, - REMOVE_GENERATOR_RATE, - CLEAR_GENERATOR_RATES, - GENERATE_BLOCK, - SET_SCHEMATIC, + SET_IGNORED, + SET_ISLAND_EFFECT, + SET_ISLAND_FLY, + SET_ISLAND_HOME, + SET_ISLAND_LAST_TIME_UPDATED, SET_ISLAND_MISSION_COMPLETED, - DATABASE_QUERY, - MENU_CLICK, - OPEN_MENU, - BLOCK_PLACE, - BLOCK_BREAK, - BLOCK_COUNT_INCREASE, - BLOCK_COUNT_DECREASE, - CHUNK_CALCULATION_BLOCKS, - CHUNK_CALCULATION_ENTITIES, - ENTITY_SPAWN, - ENTITY_DESPAWN, - DEPOSIT_MONEY, - WITHDRAW_MONEY, - SET_TEXTURE_VALUE, - SET_PLAYER_LAST_TIME_UPDATED, + SET_LANGUAGE, + SET_LAST_ISLAND, + SET_LOCKED, + SET_MOB_DROPS, + SET_NAME, + SET_PAYPAL, + SET_PERMISSION, SET_PLAYER_ISLAND, + SET_PLAYER_LAST_TIME_UPDATED, + SET_PLAYER_MISSION_COMPLETED, SET_PLAYER_ROLE, - SET_DISBANDS, - SET_LANGUAGE, - SET_TOGGLED_BORDER, - SET_TOGGLED_STACKER, - SET_TOGGLED_SCHEMATIC, + SET_PLAYER_STATUS, + SET_RATING, + SET_ROLE_LIMIT, + SET_SCHEMATIC, + SET_SCHEMATIC_POSITION, + SET_SIZE, + SET_SPAWNER_RATES, SET_TEAM_CHAT, - SET_ADMIN_BYPASS, + SET_TEAM_LIMIT, + SET_TEXTURE_VALUE, + SET_TOGGLED_BORDER, SET_TOGGLED_PANEL, - SET_ISLAND_FLY, - SET_ADMIN_SPY, - SET_BORDER_COLOR, - SET_SCHEMATIC_POSITION, - SET_PLAYER_STATUS, - REMOVE_PLAYER_STATUS, - SET_PLAYER_MISSION_COMPLETED, - SET_WARP_NAME, - SET_WARP_LOCATION, - SET_WARP_PRIVATE, - SET_WARP_ICON, - SET_WARP_CATEGORY_NAME, + SET_TOGGLED_SCHEMATIC, + SET_TOGGLED_STACKER, + SET_UPGRADE, + SET_VISITOR_HOME, + SET_WARPS_LIMIT, SET_WARP_CATEGORY_ICON, + SET_WARP_CATEGORY_NAME, SET_WARP_CATEGORY_SLOT, - VOID_TELEPORT, + SET_WARP_ICON, + SET_WARP_LOCATION, + SET_WARP_NAME, + SET_WARP_PRIVATE, + SORT_ISLANDS, TELEPORT_PLAYER, - LOAD_CHUNK, - PASTE_SCHEMATIC, - FIRE_EVENT, - FIND_SAFE_TELEPORT, - PERMISSION_LOOKUP, - REPLACE_PLAYER, TRACK_TASK, - DISABLE_REDSTONE, + TRANSFER_ISLAND, + UNBAN_PLAYER, + UNPURGE_ISLAND, + UPDATE_BORDER, + VOID_TELEPORT, + WITHDRAW_MONEY, SHOW_STACKTRACE, PROFILER; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index b1366e26a9..546fbc0ee3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -2211,6 +2211,7 @@ public void setCurrentlyActive() { @Override public void setCurrentlyActive(boolean active) { + Log.debug(Debug.ISLAND_ACTIVE, getOwner().getName(), active); this.currentlyActive = active; } From e7992425f6f74b14cc2621ae47c1b699794e96a8 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 17 Oct 2025 17:49:57 +0200 Subject: [PATCH 395/600] Added option to create a separate item for locked missions (#2707) --- .../impl/MissionsPagedObjectButton.java | 85 +++++++++++++------ .../core/menu/impl/MenuMissionsCategory.java | 4 +- .../superiorskyblock/mission/MissionData.java | 11 +++ .../mission/MissionsManagerImpl.java | 13 ++- .../resources/menus/missions-category.yml | 4 + .../resources/menus/missions-category1_12.yml | 4 + .../resources/menus/missions-category1_13.yml | 4 + .../categories/explorer/explorer_2.yml | 10 +++ .../missions/categories/farmer/farmer_2.yml | 19 +++++ .../categories/farmer/farmer_21_12.yml | 21 +++++ .../missions/categories/farmer/farmer_3.yml | 17 ++++ .../categories/farmer/farmer_31_12.yml | 17 ++++ .../missions/categories/farmer/farmer_4.yml | 24 ++++++ .../categories/farmer/farmer_41_12.yml | 25 ++++++ .../missions/categories/farmer/farmer_5.yml | 24 ++++++ .../categories/farmer/farmer_51_12.yml | 25 ++++++ .../categories/fisherman/fisherman_2.yml | 16 ++++ .../categories/fisherman/fisherman_21_13.yml | 16 ++++ .../categories/fisherman/fisherman_3.yml | 16 ++++ .../categories/fisherman/fisherman_31_13.yml | 16 ++++ .../missions/categories/miner/miner_2.yml | 21 +++++ .../missions/categories/miner/miner_3.yml | 18 ++++ .../missions/categories/miner/miner_4.yml | 18 ++++ .../missions/categories/miner/miner_5.yml | 16 ++++ .../missions/categories/slayer/slayer_2.yml | 23 +++++ .../missions/categories/slayer/slayer_3.yml | 20 +++++ .../missions/categories/slayer/slayer_4.yml | 26 +++++- 27 files changed, 473 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MissionsPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MissionsPagedObjectButton.java index 02fb9dc8fb..fec2653f95 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MissionsPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/MissionsPagedObjectButton.java @@ -1,6 +1,5 @@ package com.bgsoftware.superiorskyblock.core.menu.button.impl; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; import com.bgsoftware.superiorskyblock.api.missions.IMissionsHolder; @@ -8,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.GameSoundImpl; +import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; @@ -34,27 +34,44 @@ public Template getTemplate() { @Override public void onButtonClick(InventoryClickEvent clickEvent) { - SuperiorPlayer clickedPlayer = menuView.getInventoryViewer(); - Island island = clickedPlayer.getIsland(); + Mission mission = pagedObject.getMission(); - if (island == null) + if (mission == null) return; - Mission mission = pagedObject.getMission(); - if (mission == null) + Optional missionDataOptional = plugin.getMissions().getMissionData(mission); + + if (!missionDataOptional.isPresent()) return; - boolean completed = !island.canCompleteMissionAgain(mission); - boolean canComplete = plugin.getMissions().canComplete(clickedPlayer, mission); + SuperiorPlayer inventoryViewer = menuView.getInventoryViewer(); - GameSound soundToPlay = completed ? getTemplate().completedSound : canComplete ? - getTemplate().canCompleteSound : getTemplate().notCompletedSound; - GameSoundImpl.playSound(clickEvent.getWhoClicked(), soundToPlay); + MissionData missionData = missionDataOptional.get(); + IMissionsHolder missionsHolder = mission.getIslandMission() ? inventoryViewer.getIsland() : inventoryViewer; - if (!canComplete || !plugin.getMissions().hasAllRequiredMissions(clickedPlayer, mission)) + if (missionsHolder == null) return; - plugin.getMissions().rewardMission(mission, clickedPlayer, false, false, result -> { + boolean canComplete = plugin.getMissions().canComplete(inventoryViewer, mission); + + GameSound gameSound; + + if (!missionsHolder.canCompleteMissionAgain(mission)) + gameSound = getTemplate().completedSound; + else if (getTemplate().lockedSound != null && missionData.hasLocked() + && !plugin.getMissions().hasAllRequirements(mission, inventoryViewer)) + gameSound = getTemplate().lockedSound; + else if (canComplete) + gameSound = getTemplate().canCompleteSound; + else + gameSound = getTemplate().notCompletedSound; + + GameSoundImpl.playSound(clickEvent.getWhoClicked(), gameSound); + + if (!canComplete) + return; + + plugin.getMissions().rewardMission(mission, inventoryViewer, false, false, result -> { if (result) menuView.refreshView(); }); @@ -63,6 +80,7 @@ public void onButtonClick(InventoryClickEvent clickEvent) { @Override public ItemStack modifyViewItem(ItemStack buttonItem) { Mission mission = pagedObject.getMission(); + if (mission == null) return buttonItem; @@ -79,23 +97,26 @@ public ItemStack modifyViewItem(ItemStack buttonItem) { if (missionsHolder == null) return new ItemStack(Material.AIR); - boolean completed = !missionsHolder.canCompleteMissionAgain(mission); int percentage = calculatePercentage(mission.getProgress(inventoryViewer)); int progressValue = mission.getProgressValue(inventoryViewer); int amountCompleted = missionsHolder.getAmountMissionCompleted(mission); - ItemStack itemStack = completed ? missionData.getCompleted().build(inventoryViewer) : - plugin.getMissions().canComplete(inventoryViewer, mission) ? - missionData.getCanComplete() - .replaceAll("{0}", percentage + "") - .replaceAll("{1}", progressValue + "") - .replaceAll("{2}", amountCompleted + "") - .build(inventoryViewer) : - missionData.getNotCompleted() - .replaceAll("{0}", percentage + "") - .replaceAll("{1}", progressValue + "") - .replaceAll("{2}", amountCompleted + "") - .build(inventoryViewer); + ItemBuilder itemBuilder; + + if (!missionsHolder.canCompleteMissionAgain(mission)) + itemBuilder = missionData.getCompleted(); + else if (missionData.hasLocked() && !plugin.getMissions().hasAllRequirements(mission, inventoryViewer)) + itemBuilder = missionData.getLocked(); + else if (plugin.getMissions().canComplete(inventoryViewer, mission)) + itemBuilder = missionData.getCanComplete(); + else + itemBuilder = missionData.getNotCompleted(); + + ItemStack itemStack = itemBuilder + .replaceAll("{0}", percentage + "") + .replaceAll("{1}", progressValue + "") + .replaceAll("{2}", amountCompleted + "") + .build(inventoryViewer); mission.formatItem(inventoryViewer, itemStack); @@ -110,6 +131,7 @@ public static class Builder extends PagedMenuTemplateButtonImpl.AbstractBuilder< private GameSound notCompletedSound = null; private GameSound canCompleteSound = null; + private GameSound lockedSound = null; public Builder setCompletedSound(GameSound completedSound) { this.clickSound = completedSound; @@ -126,10 +148,15 @@ public Builder setCanCompleteSound(GameSound canCompleteSound) { return this; } + public Builder setLockedSound(GameSound lockedSound) { + this.lockedSound = lockedSound; + return this; + } + @Override public PagedMenuTemplateButton build() { return new Template(buttonItem, commands, requiredPermission, lackPermissionSound, nullItem, - getButtonIndex(), clickSound, notCompletedSound, canCompleteSound); + getButtonIndex(), clickSound, notCompletedSound, canCompleteSound, lockedSound); } } @@ -139,15 +166,17 @@ public static class Template extends PagedMenuTemplateButtonImpl commands, String requiredPermission, GameSound lackPermissionSound, TemplateItem nullItem, int buttonIndex, - GameSound completedSound, GameSound notCompletedSound, GameSound canCompleteSound) { + GameSound completedSound, GameSound notCompletedSound, GameSound canCompleteSound, GameSound lockedSound) { super(buttonItem, null, commands, requiredPermission, lackPermissionSound, nullItem, buttonIndex, MissionsPagedObjectButton.class, MissionsPagedObjectButton::new); this.completedSound = completedSound; this.notCompletedSound = notCompletedSound; this.canCompleteSound = canCompleteSound; + this.lockedSound = lockedSound; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMissionsCategory.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMissionsCategory.java index 5af19153b7..d7dd2dc570 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMissionsCategory.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuMissionsCategory.java @@ -74,11 +74,13 @@ public static MenuMissionsCategory createInstance() { GameSound completedSound = MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("completed")); GameSound notCompletedSound = MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("not-completed")); GameSound canCompleteSound = MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("can-complete")); + GameSound lockedSound = MenuParserImpl.getInstance().getSound(soundSection.getConfigurationSection("locked")); patternBuilder.setPagedObjectSlots(menuPatternSlots.getSlots(slotChar), new MissionsPagedObjectButton.Builder() .setCompletedSound(completedSound) .setNotCompletedSound(notCompletedSound) - .setCanCompleteSound(canCompleteSound)); + .setCanCompleteSound(canCompleteSound) + .setLockedSound(lockedSound)); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java index f6ca014c24..9aeaf594e0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java @@ -29,6 +29,8 @@ public class MissionData { @Nullable private final TemplateItem canComplete; @Nullable + private final TemplateItem locked; + @Nullable private final TemplateItem completed; private final int resetAmount; @@ -58,6 +60,7 @@ public class MissionData { this.notCompleted = MenuParserImpl.getInstance().getItemStack(missionFilePath, section.getConfigurationSection("icons.not-completed")); this.canComplete = MenuParserImpl.getInstance().getItemStack(missionFilePath, section.getConfigurationSection("icons.can-complete")); + this.locked = MenuParserImpl.getInstance().getItemStack(missionFilePath, section.getConfigurationSection("icons.locked")); this.completed = MenuParserImpl.getInstance().getItemStack(missionFilePath, section.getConfigurationSection("icons.completed")); } @@ -97,10 +100,18 @@ public int getResetAmount() { return resetAmount; } + public boolean hasLocked() { + return locked != null; + } + public ItemBuilder getCompleted() { return (completed == null ? TemplateItem.AIR : completed).getBuilder(); } + public ItemBuilder getLocked() { + return (locked == null ? TemplateItem.AIR : locked).getBuilder(); + } + public ItemBuilder getCanComplete() { return (canComplete == null ? TemplateItem.AIR : canComplete).getBuilder(); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java index 793eac8cee..1557ae7959 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java @@ -478,14 +478,13 @@ public void loadMissionCategory(MissionCategory missionCategory) { this.missionsContainer.addMissionCategory(missionCategory); } - public boolean canDisplayMission(Mission mission, SuperiorPlayer superiorPlayer, boolean removeCompleted) { - if (mission.isOnlyShowIfRequiredCompleted()) { - if (!hasAllRequiredMissions(superiorPlayer, mission)) - return false; + public boolean hasAllRequirements(Mission mission, SuperiorPlayer superiorPlayer) { + return hasAllRequiredMissions(superiorPlayer, mission) && canPassAllChecks(superiorPlayer, mission); + } - if (!canPassAllChecks(superiorPlayer, mission)) - return false; - } + public boolean canDisplayMission(Mission mission, SuperiorPlayer superiorPlayer, boolean removeCompleted) { + if (mission.isOnlyShowIfRequiredCompleted() && !hasAllRequirements(mission, superiorPlayer)) + return false; if (removeCompleted) { if (mission.getIslandMission() ? superiorPlayer.getIsland() != null && diff --git a/src/main/resources/menus/missions-category.yml b/src/main/resources/menus/missions-category.yml index dcc6755c0f..08968e0d7a 100644 --- a/src/main/resources/menus/missions-category.yml +++ b/src/main/resources/menus/missions-category.yml @@ -33,6 +33,10 @@ items: sounds: '@': + locked: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 completed: type: ANVIL_LAND volume: 0.2 diff --git a/src/main/resources/menus/missions-category1_12.yml b/src/main/resources/menus/missions-category1_12.yml index d93cd3b3eb..f2cd651268 100644 --- a/src/main/resources/menus/missions-category1_12.yml +++ b/src/main/resources/menus/missions-category1_12.yml @@ -33,6 +33,10 @@ items: sounds: '@': + locked: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 completed: type: BLOCK_ANVIL_PLACE volume: 0.2 diff --git a/src/main/resources/menus/missions-category1_13.yml b/src/main/resources/menus/missions-category1_13.yml index 75a9f5268b..b8da0e9494 100644 --- a/src/main/resources/menus/missions-category1_13.yml +++ b/src/main/resources/menus/missions-category1_13.yml @@ -32,6 +32,10 @@ items: sounds: '@': + locked: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 completed: type: BLOCK_ANVIL_PLACE volume: 0.2 diff --git a/src/main/resources/modules/missions/categories/explorer/explorer_2.yml b/src/main/resources/modules/missions/categories/explorer/explorer_2.yml index 389d356687..277f72f096 100644 --- a/src/main/resources/modules/missions/categories/explorer/explorer_2.yml +++ b/src/main/resources/modules/missions/categories/explorer/explorer_2.yml @@ -31,6 +31,16 @@ required-missions: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aThe-End Explorer' + lore: + - '&7Go to The-End.' + - '' + - '&6Rewards:' + - '&8 - &7$150,000' + - '' + - '&c&l ✘ &7Locked' not-completed: type: PAPER name: '&aThe-End Explorer' diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_2.yml b/src/main/resources/modules/missions/categories/farmer/farmer_2.yml index 789f0e59ff..559529946b 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_2.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_2.yml @@ -44,6 +44,25 @@ required-plants: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aFarmer II' + lore: + - '&7Expand your farm with pumpkins and melons.' + - '' + - '&6Required Plants:' + - '&8 - &7x10 Pumpkins' + - '&8 - &7x10 Melons' + - '' + - '&6Rewards:' + - '&8 - &7x1 Sugar Cane' + - '&8 - &7x1 Cactus' + - '&8 - &7$5,000' + - '' + - '&6Grown Pumpkins: &7{value_pumpkin}/10' + - '&6Grown Melons: &7{value_melon}/10' + - '&c&l ✘ &7Locked' + amount: 2 not-completed: type: PAPER name: '&aFarmer II' diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_21_12.yml b/src/main/resources/modules/missions/categories/farmer/farmer_21_12.yml index 700e599b98..220061ba2b 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_21_12.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_21_12.yml @@ -48,6 +48,27 @@ required-plants: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aFarmer II' + lore: + - '&7Expand your farm with beetroots, pumpkins and melons.' + - '' + - '&6Required Plants:' + - '&8 - &7x10 Beetroots' + - '&8 - &7x10 Pumpkins' + - '&8 - &7x10 Melons' + - '' + - '&6Rewards:' + - '&8 - &7x1 Sugar Cane' + - '&8 - &7x1 Cactus' + - '&8 - &7$5,000' + - '' + - '&6Grown Beetroots: &7{value_beetroot}/10' + - '&6Grown Pumpkins: &7{value_pumpkin}/10' + - '&6Grown Melons: &7{value_melon}/10' + - '&c&l ✘ &7Locked' + amount: 2 not-completed: type: PAPER name: '&aFarmer II' diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_3.yml b/src/main/resources/modules/missions/categories/farmer/farmer_3.yml index 3af54aad28..bb94068fcf 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_3.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_3.yml @@ -38,6 +38,23 @@ required-plants: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aFarmer III' + lore: + - '&7Expand your farm with sugar canes and cactus.' + - '' + - '&6Required Plants:' + - '&8 - &7x10 Sugar Canes' + - '&8 - &7x10 Cactus' + - '' + - '&6Rewards:' + - '&8 - &7Crops Upgrade' + - '' + - '&6Grown Sugar Canes: &7{value_sugar_cane}/10' + - '&6Grown Cactus: &7{value_cactus}/10' + - '&c&l ✘ &7Locked' + amount: 3 not-completed: type: PAPER name: '&aFarmer III' diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_31_12.yml b/src/main/resources/modules/missions/categories/farmer/farmer_31_12.yml index 3af54aad28..bb94068fcf 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_31_12.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_31_12.yml @@ -38,6 +38,23 @@ required-plants: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aFarmer III' + lore: + - '&7Expand your farm with sugar canes and cactus.' + - '' + - '&6Required Plants:' + - '&8 - &7x10 Sugar Canes' + - '&8 - &7x10 Cactus' + - '' + - '&6Rewards:' + - '&8 - &7Crops Upgrade' + - '' + - '&6Grown Sugar Canes: &7{value_sugar_cane}/10' + - '&6Grown Cactus: &7{value_cactus}/10' + - '&c&l ✘ &7Locked' + amount: 3 not-completed: type: PAPER name: '&aFarmer III' diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_4.yml b/src/main/resources/modules/missions/categories/farmer/farmer_4.yml index 52b4e0fdde..2faaddd0f7 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_4.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_4.yml @@ -59,6 +59,30 @@ required-plants: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aFarmer IV' + lore: + - '&7Now that you are a professional farmer,' + - '&7let''s get the hands dirty.' + - '&7Plant x64 of each crop.' + - '' + - '&6Required Plants:' + - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins' + - '&8 - &7Melons, Sugar Canes, Cactus' + - '' + - '&6Rewards:' + - '&8 - &7$25,000' + - '' + - '&6Grown Carrots: &7{value_carrot}/64' + - '&6Grown Potatoes: &7{value_potato}/64' + - '&6Grown Wheat: &7{value_wheat}/64' + - '&6Grown Pumpkins: &7{value_pumpkin}/64' + - '&6Grown Melons: &7{value_melon}/64' + - '&6Grown Sugar Canes: &7{value_sugar_cane}/64' + - '&6Grown Cactus: &7{value_cactus}/64' + - '&c&l ✘ &7Locked' + amount: 4 not-completed: type: PAPER name: '&aFarmer IV' diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_41_12.yml b/src/main/resources/modules/missions/categories/farmer/farmer_41_12.yml index 429280c1cf..5d49eb8749 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_41_12.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_41_12.yml @@ -63,6 +63,31 @@ required-plants: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aFarmer IV' + lore: + - '&7Now that you are a professional farmer,' + - '&7let''s get the hands dirty.' + - '&7Plant x64 of each crop.' + - '' + - '&6Required Plants:' + - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' + - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' + - '' + - '&6Rewards:' + - '&8 - &7$25,000' + - '' + - '&6Grown Carrots: &7{value_carrot}/64' + - '&6Grown Potatoes: &7{value_potato}/64' + - '&6Grown Wheat: &7{value_wheat}/64' + - '&6Grown Beetroots: &7{value_beetroot}/64' + - '&6Grown Pumpkins: &7{value_pumpkin}/64' + - '&6Grown Melons: &7{value_melon}/64' + - '&6Grown Sugar Canes: &7{value_sugar_cane}/64' + - '&6Grown Cactus: &7{value_cactus}/64' + - '&c&l ✘ &7Locked' + amount: 4 not-completed: type: PAPER name: '&aFarmer IV' diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_5.yml b/src/main/resources/modules/missions/categories/farmer/farmer_5.yml index f79386b302..d1cd21ac35 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_5.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_5.yml @@ -63,6 +63,30 @@ required-plants: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aFarmer V' + lore: + - '&7Let''s go one step further,' + - '&7Plant 5 stacks of each crop.' + - '' + - '&6Required Plants:' + - '&8 - &7Carrots, Potatoes, Wheat, Pumpkins' + - '&8 - &7Melons, Sugar Canes, Cactus' + - '' + - '&6Rewards:' + - '&8 - &7$1,000,000' + - '&8 - &7Crops Upgrade' + - '' + - '&6Grown Carrots: &7{value_carrot}/320' + - '&6Grown Potatoes: &7{value_potato}/320' + - '&6Grown Wheat: &7{value_wheat}/320' + - '&6Grown Pumpkins: &7{value_pumpkin}/320' + - '&6Grown Melons: &7{value_melon}/320' + - '&6Grown Sugar Canes: &7{value_sugar_cane}/320' + - '&6Grown Cactus: &7{value_cactus}/320' + - '&c&l ✘ &7Locked' + amount: 5 not-completed: type: PAPER name: '&aFarmer V' diff --git a/src/main/resources/modules/missions/categories/farmer/farmer_51_12.yml b/src/main/resources/modules/missions/categories/farmer/farmer_51_12.yml index 1f70e014a1..b54d940578 100644 --- a/src/main/resources/modules/missions/categories/farmer/farmer_51_12.yml +++ b/src/main/resources/modules/missions/categories/farmer/farmer_51_12.yml @@ -67,6 +67,31 @@ required-plants: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aFarmer V' + lore: + - '&7Let''s go one step further,' + - '&7Plant 5 stacks of each crop.' + - '' + - '&6Required Plants:' + - '&8 - &7Carrots, Potatoes, Wheat, Beetroots,' + - '&8 - &7Pumpkins, Melons, Sugar Canes, Cactus' + - '' + - '&6Rewards:' + - '&8 - &7$1,000,000' + - '&8 - &7Crops Upgrade' + - '' + - '&6Grown Carrots: &7{value_carrot}/320' + - '&6Grown Potatoes: &7{value_potato}/320' + - '&6Grown Wheat: &7{value_wheat}/320' + - '&6Grown Beetroots: &7{value_beetroot}/320' + - '&6Grown Pumpkins: &7{value_pumpkin}/320' + - '&6Grown Melons: &7{value_melon}/320' + - '&6Grown Sugar Canes: &7{value_sugar_cane}/320' + - '&6Grown Cactus: &7{value_cactus}/320' + - '&c&l ✘ &7Locked' + amount: 5 not-completed: type: PAPER name: '&aFarmer V' diff --git a/src/main/resources/modules/missions/categories/fisherman/fisherman_2.yml b/src/main/resources/modules/missions/categories/fisherman/fisherman_2.yml index 1f1b69fa78..1cc7ef4ebc 100644 --- a/src/main/resources/modules/missions/categories/fisherman/fisherman_2.yml +++ b/src/main/resources/modules/missions/categories/fisherman/fisherman_2.yml @@ -47,6 +47,22 @@ required-caughts: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aFisherman II' + lore: + - '&7Cleaning the ocean from junk can be messy, but fun!' + - '&7Catch 5 items.' + - '' + - '&6Required Caughts:' + - '&8 - &7x5 Items' + - '' + - '&6Rewards:' + - '&8 - &7$15,000' + - '' + - '&6Items: &7{1}/5' + - '&c&l ✘ &7Locked' + amount: 2 not-completed: type: PAPER name: '&aFisherman II' diff --git a/src/main/resources/modules/missions/categories/fisherman/fisherman_21_13.yml b/src/main/resources/modules/missions/categories/fisherman/fisherman_21_13.yml index 0156f0fe97..9b9fdbd567 100644 --- a/src/main/resources/modules/missions/categories/fisherman/fisherman_21_13.yml +++ b/src/main/resources/modules/missions/categories/fisherman/fisherman_21_13.yml @@ -48,6 +48,22 @@ required-caughts: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aFisherman II' + lore: + - '&7Cleaning the ocean from junk can be messy, but fun!' + - '&7Catch 5 items.' + - '' + - '&6Required Caughts:' + - '&8 - &7x5 Items' + - '' + - '&6Rewards:' + - '&8 - &7$15,000' + - '' + - '&6Items: &7{1}/5' + - '&c&l ✘ &7Locked' + amount: 2 not-completed: type: PAPER name: '&aFisherman II' diff --git a/src/main/resources/modules/missions/categories/fisherman/fisherman_3.yml b/src/main/resources/modules/missions/categories/fisherman/fisherman_3.yml index 14519920fb..1ac8d1a635 100644 --- a/src/main/resources/modules/missions/categories/fisherman/fisherman_3.yml +++ b/src/main/resources/modules/missions/categories/fisherman/fisherman_3.yml @@ -37,6 +37,22 @@ required-caughts: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aFisherman III' + lore: + - '&7It''s possible to catch treasure in the ocean.' + - '&7Catch 3 treasure items.' + - '' + - '&6Required Caughts:' + - '&8 - &7x3 Treasure Items' + - '' + - '&6Rewards:' + - '&8 - &7$50,000' + - '' + - '&6Treasure Items: &7{1}/3' + - '&c&l ✘ &7Locked' + amount: 3 not-completed: type: PAPER name: '&aFisherman III' diff --git a/src/main/resources/modules/missions/categories/fisherman/fisherman_31_13.yml b/src/main/resources/modules/missions/categories/fisherman/fisherman_31_13.yml index 869bc15cfd..5004f4b051 100644 --- a/src/main/resources/modules/missions/categories/fisherman/fisherman_31_13.yml +++ b/src/main/resources/modules/missions/categories/fisherman/fisherman_31_13.yml @@ -38,6 +38,22 @@ required-caughts: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aFisherman III' + lore: + - '&7It''s possible to catch treasure in the ocean.' + - '&7Catch 3 treasure items.' + - '' + - '&6Required Caughts:' + - '&8 - &7x3 Treasure Items' + - '' + - '&6Rewards:' + - '&8 - &7$50,000' + - '' + - '&6Treasure Items: &7{1}/3' + - '&c&l ✘ &7Locked' + amount: 3 not-completed: type: PAPER name: '&aFisherman III' diff --git a/src/main/resources/modules/missions/categories/miner/miner_2.yml b/src/main/resources/modules/missions/categories/miner/miner_2.yml index 66cc5a7748..d1b89fad35 100644 --- a/src/main/resources/modules/missions/categories/miner/miner_2.yml +++ b/src/main/resources/modules/missions/categories/miner/miner_2.yml @@ -48,6 +48,27 @@ required-blocks: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aMiner II' + lore: + - '&7Continue mining for ores!' + - '&7Mine x96 cobblestone, x32 coal ore and x16 iron ore.' + - '' + - '&6Required Blocks:' + - '&8 - &7x96 Cobblestone' + - '&8 - &7x32 Coal Ore' + - '&8 - &7x16 Iron Ore' + - '' + - '&6Rewards:' + - '&8 - &7$5,000' + - '&8 - &7Generator Upgrade' + - '' + - '&6Cobblestone Mined: &7{value_cobblestone}/96' + - '&6Coal Ore Mined: &7{value_coal_ore}/32' + - '&6Iron Ore Mined: &7{value_iron_ore}/16' + - '&c&l ✘ &7Locked' + amount: 2 not-completed: type: PAPER name: '&aMiner II' diff --git a/src/main/resources/modules/missions/categories/miner/miner_3.yml b/src/main/resources/modules/missions/categories/miner/miner_3.yml index fa82b30dab..c027d04949 100644 --- a/src/main/resources/modules/missions/categories/miner/miner_3.yml +++ b/src/main/resources/modules/missions/categories/miner/miner_3.yml @@ -43,6 +43,24 @@ required-blocks: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aMiner III' + lore: + - '&7I am willing to buy iron and coal from you.' + - '&7Mine x64 coal ore and x64 iron ore.' + - '' + - '&6Required Blocks:' + - '&8 - &7x64 Coal Ore' + - '&8 - &7x64 Iron Ore' + - '' + - '&6Rewards:' + - '&8 - &7$25,000' + - '' + - '&6Coal Ore Mined: &7{value_coal_ore}/64' + - '&6Iron Ore Mined: &7{value_iron_ore}/64' + - '&c&l ✘ &7Locked' + amount: 3 not-completed: type: PAPER name: '&aMiner III' diff --git a/src/main/resources/modules/missions/categories/miner/miner_4.yml b/src/main/resources/modules/missions/categories/miner/miner_4.yml index c8cad70682..a347f4e240 100644 --- a/src/main/resources/modules/missions/categories/miner/miner_4.yml +++ b/src/main/resources/modules/missions/categories/miner/miner_4.yml @@ -44,6 +44,24 @@ required-blocks: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aMiner IV' + lore: + - '&7I have more customers, I need more materials!' + - '&7Mine x192 coal ore and x320 iron ore.' + - '' + - '&6Required Blocks:' + - '&8 - &7x192 Coal Ore' + - '&8 - &7x320 Iron Ore' + - '' + - '&6Rewards:' + - '&8 - &7$125,000' + - '' + - '&6Coal Ore Mined: &7{value_coal_ore}/192' + - '&6Iron Ore Mined: &7{value_iron_ore}/320' + - '&c&l ✘ &7Locked' + amount: 4 not-completed: type: PAPER name: '&aMiner IV' diff --git a/src/main/resources/modules/missions/categories/miner/miner_5.yml b/src/main/resources/modules/missions/categories/miner/miner_5.yml index 69009a1981..e713349152 100644 --- a/src/main/resources/modules/missions/categories/miner/miner_5.yml +++ b/src/main/resources/modules/missions/categories/miner/miner_5.yml @@ -41,6 +41,22 @@ required-blocks: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aMiner V' + lore: + - '&7It''s time to buy the best goodies.' + - '&7Mine x32 diamond ores.' + - '' + - '&6Required Blocks:' + - '&8 - &7x32 Diamond Ore' + - '' + - '&6Rewards:' + - '&8 - &7$250,000' + - '' + - '&6Diamond Ore Mined: &7{1}/32' + - '&c&l ✘ &7Locked' + amount: 5 not-completed: type: PAPER name: '&aMiner V' diff --git a/src/main/resources/modules/missions/categories/slayer/slayer_2.yml b/src/main/resources/modules/missions/categories/slayer/slayer_2.yml index 2699cffed7..274f2951c9 100644 --- a/src/main/resources/modules/missions/categories/slayer/slayer_2.yml +++ b/src/main/resources/modules/missions/categories/slayer/slayer_2.yml @@ -48,6 +48,29 @@ required-entities: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aSlayer II' + lore: + - '&7It is time you build a farm.' + - '&7Kill 120 hostile mobs.' + - '' + - '&6Required Kills:' + - '&8 - &7x32 Skeletons' + - '&8 - &7x32 Zombies' + - '&8 - &7x32 Spiders' + - '&8 - &7x24 Creepers' + - '' + - '&6Rewards:' + - '&8 - &7$15,000' + - '&8 - &7Unlock Nether' + - '' + - '&6Skeletons Killed: &7{value_skeleton}/32' + - '&6Zombies Killed: &7{value_zombie}/32' + - '&6Spiders Killed: &7{value_spider}/32' + - '&6Creepers Killed: &7{value_creeper}/24' + - '&c&l ✘ &7Locked' + amount: 2 not-completed: type: PAPER name: '&aSlayer II' diff --git a/src/main/resources/modules/missions/categories/slayer/slayer_3.yml b/src/main/resources/modules/missions/categories/slayer/slayer_3.yml index 718477cd69..eb6762baac 100644 --- a/src/main/resources/modules/missions/categories/slayer/slayer_3.yml +++ b/src/main/resources/modules/missions/categories/slayer/slayer_3.yml @@ -44,6 +44,26 @@ required-entities: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aSlayer III' + lore: + - '&7It is time to prepare for the boss fights.' + - '&7Kill 12 blazes, 12 wither skeletons and 24 enderman.' + - '' + - '&6Required Kills:' + - '&8 - &7x12 Blazes' + - '&8 - &7x12 Wither Skeletons' + - '&8 - &7x24 Endermans' + - '' + - '&6Rewards:' + - '&8 - &7$75,000' + - '' + - '&6Blazes Killed: &7{value_blaze}/12' + - '&6Wither Skeletons Killed: &7{value_wither_skeleton}/12' + - '&6Endermans Killed: &7{value_enderman}/24' + - '&c&l ✘ &7Locked' + amount: 3 not-completed: type: PAPER name: '&aSlayer III' diff --git a/src/main/resources/modules/missions/categories/slayer/slayer_4.yml b/src/main/resources/modules/missions/categories/slayer/slayer_4.yml index aac8ab46a1..8e780551ef 100644 --- a/src/main/resources/modules/missions/categories/slayer/slayer_4.yml +++ b/src/main/resources/modules/missions/categories/slayer/slayer_4.yml @@ -38,6 +38,23 @@ required-entities: # Icons used in the menus. icons: + locked: + type: PAPER + name: '&aSlayer IV' + lore: + - '&7Before the end, there is one mission left.' + - '&7Kill the wither.' + - '' + - '&6Required Kills:' + - '&8 - &7x1 Wither' + - '' + - '&6Rewards:' + - '&8 - &7$250,000' + - '&8 - &7Unlock The End' + - '' + - '&6Wither Killed: &c&l✘' + - '&c&l ✘ &7Locked' + amount: 4 not-completed: type: PAPER name: '&aSlayer IV' @@ -52,7 +69,8 @@ icons: - '&8 - &7$250,000' - '&8 - &7Unlock The End' - '' - - '&6Wither Killed: &c&l ✘' + - '&6Wither Killed: &c&l✘' + - '&c&l ✘ &7Not Completed' amount: 4 can-complete: type: PAPER @@ -68,7 +86,7 @@ icons: - '&8 - &7$250,000' - '&8 - &7Unlock The End' - '' - - '&6Wither Killed: &a&l ✔' + - '&6Wither Killed: &a&l✔' - '&a&l ✔ &7Click to redeem your reward.' amount: 4 glow: true @@ -83,6 +101,6 @@ icons: - '&8 - &7$250,000' - '&8 - &7Unlock The End' - '' - - '&6Wither Killed: &a&l ✔' - - '&a&l ✔ &7Click to redeem your reward.' + - '&6Wither Killed: &a&l✔' + - '&a&l ✔ &7Already Claimed.' amount: 4 \ No newline at end of file From 9bcb2ee28ca8db2d27d2338d3c70d30dbac5a160 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 18 Oct 2025 08:57:13 +0200 Subject: [PATCH 396/600] Fixed /is admin addbonus and /is admin setbonus commands (#2728) --- .../commands/admin/CmdAdminAddBonus.java | 30 +++++++++++++++++-- .../commands/admin/CmdAdminSetBonus.java | 30 +++++++++++++++++-- .../core/messages/Message.java | 7 ++++- src/main/resources/lang/de-DE.yml | 7 ++++- src/main/resources/lang/en-US.yml | 7 ++++- src/main/resources/lang/es-ES.yml | 7 ++++- src/main/resources/lang/fr-FR.yml | 7 ++++- src/main/resources/lang/it-IT.yml | 7 ++++- src/main/resources/lang/iw-IL.yml | 7 ++++- src/main/resources/lang/pl-PL.yml | 7 ++++- src/main/resources/lang/pt-BR.yml | 7 ++++- src/main/resources/lang/ru-RU.yml | 7 ++++- src/main/resources/lang/tr-TR.yml | 7 ++++- src/main/resources/lang/vi-VN.yml | 7 ++++- src/main/resources/lang/zh-CN.yml | 7 ++++- 15 files changed, 134 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBonus.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBonus.java index d35b49c1ec..0a8543a131 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBonus.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBonus.java @@ -13,11 +13,13 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.Collections; import java.util.List; +import java.util.Locale; public class CmdAdminAddBonus implements IAdminIslandCommand { @@ -67,7 +69,17 @@ public boolean supportMultipleIslands() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { - boolean isWorthBonus = !args[3].equalsIgnoreCase("level"); + boolean isWorthBonus; + + if (args[3].equalsIgnoreCase("worth")) { + isWorthBonus = true; + } else if (args[3].equalsIgnoreCase("level")) { + isWorthBonus = false; + } else { + Locale locale = PlayerLocales.getLocale(sender); + Message.COMMAND_USAGE.send(sender, locale, plugin.getCommands().getLabel() + " " + getUsage(locale)); + return; + } BigDecimal bonus = CommandArguments.getBigDecimalAmount(sender, args[4]); @@ -97,7 +109,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (islandsChangedCount <= 0) return; - Message.BONUS_SET_SUCCESS.send(sender, bonus.toString()); + if (isWorthBonus) { + if (islandsChangedCount > 1) + Message.CHANGED_BONUS_WORTH_ALL.send(sender); + else if (targetPlayer == null) + Message.CHANGED_BONUS_WORTH_NAME.send(sender, islands.get(0).getName()); + else + Message.CHANGED_BONUS_WORTH.send(sender, targetPlayer.getName()); + } else { + if (islandsChangedCount > 1) + Message.CHANGED_BONUS_LEVEL_ALL.send(sender); + else if (targetPlayer == null) + Message.CHANGED_BONUS_LEVEL_NAME.send(sender, islands.get(0).getName()); + else + Message.CHANGED_BONUS_LEVEL.send(sender, targetPlayer.getName()); + } } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBonus.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBonus.java index f856daabfc..4122ac741f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBonus.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBonus.java @@ -13,12 +13,14 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.player.PlayerLocales; import org.bukkit.command.CommandSender; import java.math.BigDecimal; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Locale; public class CmdAdminSetBonus implements IAdminIslandCommand { @@ -68,7 +70,17 @@ public boolean supportMultipleIslands() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { - boolean isWorthBonus = !args[3].equalsIgnoreCase("level"); + boolean isWorthBonus; + + if (args[3].equalsIgnoreCase("worth")) { + isWorthBonus = true; + } else if (args[3].equalsIgnoreCase("level")) { + isWorthBonus = false; + } else { + Locale locale = PlayerLocales.getLocale(sender); + Message.COMMAND_USAGE.send(sender, locale, plugin.getCommands().getLabel() + " " + getUsage(locale)); + return; + } BigDecimal bonus = CommandArguments.getBigDecimalAmount(sender, args[4]); @@ -98,7 +110,21 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (islandsChangedCount <= 0) return; - Message.BONUS_SET_SUCCESS.send(sender, bonus.toString()); + if (isWorthBonus) { + if (islandsChangedCount > 1) + Message.CHANGED_BONUS_WORTH_ALL.send(sender); + else if (targetPlayer == null) + Message.CHANGED_BONUS_WORTH_NAME.send(sender, islands.get(0).getName()); + else + Message.CHANGED_BONUS_WORTH.send(sender, targetPlayer.getName()); + } else { + if (islandsChangedCount > 1) + Message.CHANGED_BONUS_LEVEL_ALL.send(sender); + else if (targetPlayer == null) + Message.CHANGED_BONUS_LEVEL_NAME.send(sender, islands.get(0).getName()); + else + Message.CHANGED_BONUS_LEVEL.send(sender, targetPlayer.getName()); + } } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 86752f7c71..0639369be1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -71,7 +71,6 @@ public enum Message { BLOCK_LEVEL_WORTHLESS, BLOCK_VALUE, BLOCK_VALUE_WORTHLESS, - BONUS_SET_SUCCESS, BONUS_SYNC_ALL, BONUS_SYNC_NAME, BONUS_SYNC, @@ -92,6 +91,12 @@ public enum Message { CHANGED_BLOCK_LIMIT, CHANGED_BLOCK_LIMIT_ALL, CHANGED_BLOCK_LIMIT_NAME, + CHANGED_BONUS_LEVEL, + CHANGED_BONUS_LEVEL_ALL, + CHANGED_BONUS_LEVEL_NAME, + CHANGED_BONUS_WORTH, + CHANGED_BONUS_WORTH_ALL, + CHANGED_BONUS_WORTH_NAME, CHANGED_CHEST_SIZE, CHANGED_CHEST_SIZE_ALL, CHANGED_CHEST_SIZE_NAME, diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 70feaf1355..92fcc0c832 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -44,7 +44,6 @@ BLOCK_LEVEL: '&e&lLevel | &7Die Ebene des Blocks {0} ist {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lLevel | &7Der Block {0} ist wertlos.' BLOCK_VALUE: '&e&lWert | &7Der Block {0} im Wert von {1}.' BLOCK_VALUE_WORTHLESS: '&e&lWert | &7Der Block {0} ist wertlos.' -BONUS_SET_SUCCESS: '&e&lInsel | &7Der Inselbonus wurde erfolgreich auf {0} aktualisiert.' BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' @@ -77,6 +76,12 @@ CHANGED_BLOCK_LIMIT_ALL: '&e&lUpgrades | &7Das {0} Blocklimit aller Inseln wurde aktualisiert.' CHANGED_BLOCK_LIMIT_NAME: '&e&lUpgrades | &7Das {0} Blocklimit von {1} wurde erfolgreich aktualisiert.' +CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' +CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' +CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' +CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' +CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' +CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lChest | &7Die Zeilen von Seite #{0} wurden erfolgreich auf {1} für die Insel von {2} aktualisiert.' CHANGED_CHEST_SIZE_ALL: '&e&lChest | &7Die Zeilen der Seite #{0} wurden für alle Inseln diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 3a61931151..15e83f0485 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -39,7 +39,6 @@ BLOCK_LEVEL: '&e&lLevel | &7The block {0}''s level is {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lLevel | &7The block {0} is worthless.' BLOCK_VALUE: '&e&lWorth | &7The block {0} worth {1}.' BLOCK_VALUE_WORTHLESS: '&e&lWorth | &7The block {0} is worthless.' -BONUS_SET_SUCCESS: '&e&lIsland | &7Successfully updated the island bonus to {0}.' BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' @@ -61,6 +60,12 @@ CHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7Successfully changed the block amount at { CHANGED_BLOCK_LIMIT: '&e&lUpgrades | &7Successfully updated the {0} Block limit of {1}''s island.' CHANGED_BLOCK_LIMIT_ALL: '&e&lUpgrades | &7Successfully updated the {0} Block limit of all the islands.' CHANGED_BLOCK_LIMIT_NAME: '&e&lUpgrades | &7Successfully updated the {0} Block limit of {1}.' +CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' +CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' +CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' +CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' +CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' +CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for {2}''s island.' CHANGED_CHEST_SIZE_ALL: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for all the islands.' CHANGED_CHEST_SIZE_NAME: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for {2}.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 6dd0c21ec7..03d3626305 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -39,7 +39,6 @@ BLOCK_LEVEL: '&e&lNivel | &7El nivel del bloque {0} es {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lNivel | &7El bloque {0} no tiene valor.' BLOCK_VALUE: '&e&lValor | &7El bloque {0} vale {1}.' BLOCK_VALUE_WORTHLESS: '&e&lValor | &7El bloque {0} no tiene valor.' -BONUS_SET_SUCCESS: '&e&lIsla | &7Se actualizó con éxito la bonificación de la isla a {0}.' BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' @@ -61,6 +60,12 @@ CHANGED_BLOCK_AMOUNT: '&e&lBloques | &7Cambió correctamente la cantidad de bloq CHANGED_BLOCK_LIMIT: '&e&lMejoras| &Se actualizó correctamente el límitede bloques de {1} a {0}.' CHANGED_BLOCK_LIMIT_ALL: '&e&lMejoras| &7Se actualizó correctamente el límitede bloques de todas las islas a {0}.' CHANGED_BLOCK_LIMIT_NAME: '&e&lMejoras| &7Se actualizó correctamente el límite de bloques de {1} a {0}.' +CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' +CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' +CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' +CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' +CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' +CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lChest | &7Se actualizaron correctamente las filas de la página n.º {0} a {1} para la isla de {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lChest | &7Se actualizaron correctamente las filas de la página n.º {0} a {1} para todas las islas.' CHANGED_CHEST_SIZE_NAME: '&e&lChest | &7Se actualizaron correctamente las filas de la página n.º {0} a {1} para {2}.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 1494cc53fe..322a00fb83 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -39,7 +39,6 @@ BLOCK_LEVEL: '&e&lNiveau | &7Le le niveau du bloc {0} est de {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lNiveau | &7Le bloc {0} n''a pas de valeur.' BLOCK_VALUE: '&e&lValeur | &7La valeur du bloc {0} est de {1}.' BLOCK_VALUE_WORTHLESS: '&e&lValeur | &7Le bloc {0} n''a pas de valeur.' -BONUS_SET_SUCCESS: '&e&lIle | &7Bonus de l''île mit à jour sur {0}.' BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' @@ -61,6 +60,12 @@ CHANGED_BLOCK_AMOUNT: '&e&lBlocs | &7La quantité de blocs aux coordonnées {0} CHANGED_BLOCK_LIMIT: '&e&lAméliorations | &7Vous avez changé la limite de blocs de {0} pour l''île de {1}.' CHANGED_BLOCK_LIMIT_ALL: '&e&lAméliorations | &7Vous avez changé la limite de blocs de {0} pour toutes les îles.' CHANGED_BLOCK_LIMIT_NAME: '&e&lAméliorations | &7Vous avez changé la limite de blocs de {0} pour {1}.' +CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' +CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' +CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' +CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' +CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' +CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lStockage | &7Mise à jour des lignes de la page #{0} sur {1} pour l''île de {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lStockage | &7Mise à jour des lignes de la page #{0} sur {1} pour toutes les îles.' CHANGED_CHEST_SIZE_NAME: '&e&lStockage | &7Mise à jour des lignes de la page #{0} sur {1} pour {2}.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index c5c9e394ce..d79f916633 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -42,7 +42,6 @@ BLOCK_LEVEL: '&e&lLivello | &7Il blocco {0} vale {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lLivello | &7Il blocco {0} non ha valore.' BLOCK_VALUE: '&e&lWorth | &7Il blocco {0} vale {1}.' BLOCK_VALUE_WORTHLESS: '&e&lWorth | &7Il blocco {0} non ha valore.' -BONUS_SET_SUCCESS: '&e&lIsola | &7Aggiornato con successo il bonus isola a {0}.' BONUS_SYNC_ALL: '&e&lIsola | &7SAggiornato con successo il bonus a tutte le isole.' BONUS_SYNC_NAME: '&e&lIsola | &7Aggiornato con successo il bonus per l''isola di {0}.' BONUS_SYNC: '&e&lIsola | &7Aggiornato con successo il bonus per l''isola di {0}.' @@ -64,6 +63,12 @@ CHANGED_BLOCK_AMOUNT: '&e&lBlocchi | &7Aggiornato con successo il numero di bloc CHANGED_BLOCK_LIMIT: '&e&lAggiornamenti | &7Aggiornato il limite del blocco {0} dell''isola {1}.' CHANGED_BLOCK_LIMIT_ALL: '&e&lAggiornamenti | &7Aggiornato il limite del blocco {0} in tutte le isole.' CHANGED_BLOCK_LIMIT_NAME: '&e&lAggiornamenti | &7Aggiornato il limite del blocco {0} nell''isola di {1}.' +CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' +CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' +CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' +CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' +CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' +CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lBaule | &7Aggiornate con successo le righe della pagina #{0} a {1} per l''isola di {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lBaule | &7Aggiornate con successo le righe della pagina #{0} a {1} per tutte le isole.' CHANGED_CHEST_SIZE_NAME: '&e&lBaule | &7Aggiornate con successo le righe della pagina #{0} a {1} per {2}.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index d4b954efa9..e884029810 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -40,7 +40,6 @@ BLOCK_LEVEL: '&e&lתודוקנ | &7{1} אוה {0} קולבה לש תודוקנה BLOCK_LEVEL_WORTHLESS: '&e&lתודוקנ | &7םולכ הווש אל {0} קולבה.' BLOCK_VALUE: '&e&lיווש | &7{1} אוה {0} קולבה לש יוושה.' BLOCK_VALUE_WORTHLESS: '&e&lיווש | &7םולכ הווש אל {0} קולבה.' -BONUS_SET_SUCCESS: '&e&lיא | &7{0} ל החלצהב ןכדוע יאה לש סונובה.' BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' @@ -64,6 +63,12 @@ CHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7Successfully changed the block amount at { CHANGED_BLOCK_LIMIT: '&e&lםיגורדש | &7{1} לש יאל החלצהב הנכדוע {0} קולבה תלבגה.' CHANGED_BLOCK_LIMIT_ALL: '&e&lםיגורדש | &7םייאה לכל החלצהב הנכדוע {0} קולבה תלבגה.' CHANGED_BLOCK_LIMIT_NAME: '&e&lםיגורדש | &7{1} יאל החלצהב הנכדוע {0} קולבה תלבגה.' +CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' +CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' +CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' +CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' +CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' +CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for {2}''s island.' CHANGED_CHEST_SIZE_ALL: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for all the islands.' CHANGED_CHEST_SIZE_NAME: '&e&lChest | &7Successfully updated the rows of page #{0} to {1} for {2}.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 50f064e023..e5995a795a 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -39,7 +39,6 @@ BLOCK_LEVEL: '&e&lLevel | &7Poziom bloku {0} to {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lLevel | &7Blok {0} jest bezwartosciowy.' BLOCK_VALUE: '&e&lWartosc | &7Blok {0} o wartosci {1}.' BLOCK_VALUE_WORTHLESS: '&e&lWartosc | &7Blok {0} jest bezwartosciowy.' -BONUS_SET_SUCCESS: '&e&lWyspa | &7Pomyslnie zaktualizowano premie za wyspe do {0}.' BONUS_SYNC_ALL: '&e&lIsland | &7Successfully synced the island bonus to all the islands' BONUS_SYNC_NAME: '&e&lIsland | &7Successfully synced the island bonus to {0}.' BONUS_SYNC: '&e&lIsland | &7Successfully synced the island bonus to {0}''s island.' @@ -61,6 +60,12 @@ CHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7Pomyslnie zmieniono wielkosc bloku z {0} n CHANGED_BLOCK_LIMIT: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit bloków {0} wyspy {1}.' CHANGED_BLOCK_LIMIT_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit {0} blokowania wszystkich wysp.' CHANGED_BLOCK_LIMIT_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano limit blokowania {0} {1}.' +CHANGED_BONUS_LEVEL: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus poziomu wyspy {0}.' +CHANGED_BONUS_LEVEL_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus poziomu wszystkich wysp.' +CHANGED_BONUS_LEVEL_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus poziomu {0}.' +CHANGED_BONUS_WORTH: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus wartosci wyspy {0}.' +CHANGED_BONUS_WORTH_ALL: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus wartosci wszystkich wysp.' +CHANGED_BONUS_WORTH_NAME: '&e&lWyspa | &7Pomyslnie zaktualizowano bonus wartosci {0}.' CHANGED_CHEST_SIZE: '&e&lKlatka | &7Pomyslnie zaktualizowano wiersze strony nr {0} na {1} dla wyspy {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lKlatka | &7Pomyslnie zaktualizowano wiersze na stronie nr {0} do {1} dla wszystkich wysp.' CHANGED_CHEST_SIZE_NAME: '&e&lSkrzynia | &7Pomyslnie zaktualizowano wiersze strony nr {0} do {1} dla {2}.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index c2e3014df8..47382cf44d 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -39,7 +39,6 @@ BLOCK_LEVEL: '&e&lNível | &7O nível do bloco {0} é {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lNível | &7O bloco {0} não possui valor.' BLOCK_VALUE: '&e&lValor | &7O bloco {0} vale {1}.' BLOCK_VALUE_WORTHLESS: '&e&lValor | &7O bloco {0} não possui valor.' -BONUS_SET_SUCCESS: '&e&lIlha | &7Bônus da ilha atualizado com sucesso para {0}.' BONUS_SYNC_ALL: '&e&lIlha | &7Bônus sincronizado com sucesso para todas as ilhas.' BONUS_SYNC_NAME: '&e&lIlha | &7Bônus sincronizado com sucesso para {0}.' BONUS_SYNC: '&e&lIlha | &7Bônus sincronizado com sucesso para a ilha de {0}.' @@ -61,6 +60,12 @@ CHANGED_BLOCK_AMOUNT: '&e&lBlocos | &7Quantidade de blocos em {0} alterada para CHANGED_BLOCK_LIMIT: '&e&lMelhorias | &7Limite de blocos {0} atualizado na ilha de {1}.' CHANGED_BLOCK_LIMIT_ALL: '&e&lMelhorias | &7Limite de blocos {0} atualizado em todas as ilhas.' CHANGED_BLOCK_LIMIT_NAME: '&e&lMelhorias | &7Limite de blocos {0} atualizado em {1}.' +CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' +CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' +CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' +CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' +CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' +CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lBaú | &7As linhas da página #{0} foram atualizadas para {1} na ilha de {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lBaú | &7As linhas da página #{0} foram atualizadas para {1} em todas as ilhas.' CHANGED_CHEST_SIZE_NAME: '&e&lBaú | &7As linhas da página #{0} foram atualizadas para {1} de {2}.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 7814bbaaf7..3f544f4f7f 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -39,7 +39,6 @@ BLOCK_LEVEL: '&e&lУровень | &7Уровень блока {0} состав BLOCK_LEVEL_WORTHLESS: '&e&lУровень | &7Блок {0} бесполезен.' BLOCK_VALUE: '&e&lЦена | &7Блок {0} стоит {1}.' BLOCK_VALUE_WORTHLESS: '&e&lЦена | &7Блок {0} бесполезен.' -BONUS_SET_SUCCESS: '&e&lОстров | &7Успешно обновлен бонус острова до {0}.' BONUS_SYNC_ALL: '&e&lОстров | &7Успешно синхронизирован бонус острова для всех островов.' BONUS_SYNC_NAME: '&e&lОстров | &7Успешно синхронизирован бонус острова для {0}.' BONUS_SYNC: '&e&lОстров | &7Успешно синхронизирован бонус острова для острова {0}.' @@ -61,6 +60,12 @@ CHANGED_BLOCK_AMOUNT: '&e&lБлоки | &7Успешно изменено кол CHANGED_BLOCK_LIMIT: '&e&lУлучшения | &7Успешно обновлен лимит {0} блоков для острова {1}.' CHANGED_BLOCK_LIMIT_ALL: '&e&lУлучшения | &7Успешно обновлен лимит {0} блоков для всех островов.' CHANGED_BLOCK_LIMIT_NAME: '&e&lУлучшения | &7Успешно обновлен лимит {0} блоков для {1}.' +CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' +CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' +CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' +CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' +CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' +CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lСундук | &7Успешно обновлено количество строк на странице #{0} до {1} для острова {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lСундук | &7Успешно обновлено количество строк на странице #{0} до {1} для всех островов.' CHANGED_CHEST_SIZE_NAME: '&e&lСундук | &7Успешно обновлено количество строк на странице #{0} до {1} для {2}.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 1bd495129f..c310d297f4 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -41,7 +41,6 @@ BLOCK_LEVEL: '&e&lSeviye | &7{0} bloğunun seviyesi {1}.' BLOCK_LEVEL_WORTHLESS: '&e&lSeviye | &7{0} bloğu değersiz.' BLOCK_VALUE: '&e&lDeğer | &7{0} bloğunun değeri {1}.' BLOCK_VALUE_WORTHLESS: '&e&lDeğer | &7{0} bloğu değersiz.' -BONUS_SET_SUCCESS: '&e&lAda | &7Ada bonusu başarıyla {0} olarak güncellendi.' BONUS_SYNC_ALL: '&e&lAda | &7Ada bonusu tüm adalarla başarıyla senkronize edildi.' BONUS_SYNC_NAME: '&e&lAda | &7Ada bonusu {0} ile başarıyla senkronize edildi.' BONUS_SYNC: '&e&lAda | &7Ada bonusu {0}''ın adasıyla başarıyla senkronize edildi.' @@ -73,6 +72,12 @@ CHANGED_BLOCK_LIMIT_ALL: '&e&lYükseltmeler | &7{0} Bloğunun tüm adalar için başarıyla güncellendi.' CHANGED_BLOCK_LIMIT_NAME: '&e&lYükseltmeler | &7{0} Bloğunun {1} adası için limiti başarıyla güncellendi.' +CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' +CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' +CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' +CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' +CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' +CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lSandık | &7{2}''in adası için #{0} sayfasının satırları başarıyla {1} olarak güncellendi.' CHANGED_CHEST_SIZE_ALL: '&e&lSandık | &7Tüm adalar için #{0} sayfasının satırları diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 76e7c3ba11..4e857ad445 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -43,7 +43,6 @@ BLOCK_LEVEL: '&e&lCấp Độ | &7Khối {0} có giá trị cấp độ là {1}. BLOCK_LEVEL_WORTHLESS: '&e&lCấp Độ | &7Khối {0} vô giá trị.' BLOCK_VALUE: '&e&lĐáng giá | &7Khối {0} được đánh giá với {1}.' BLOCK_VALUE_WORTHLESS: '&e&lĐáng giá | &7Khối {0} vô giá trị.' -BONUS_SET_SUCCESS: '&e&lĐảo | &7Cập nhật thành công phần thưởng đảo đến {0}.' BONUS_SYNC_ALL: '&e&lĐảo | &7Đồng bộ thành công phần thưởng đảo đến tất cả các đảo.' BONUS_SYNC_NAME: '&e&lĐảo | &7Đồng bộ thành công phần thưởng đảo đến {0}.' BONUS_SYNC: '&e&lĐảo | &7Đồng bộ thành công phần thưởng đảo của {0}.' @@ -71,6 +70,12 @@ CHANGED_BLOCK_LIMIT: '&e&lNâng Cấp | &7Thay đổi thành công giới hạn CHANGED_BLOCK_LIMIT_ALL: '&e&lNâng Cấp | &7Thành công nâng cấp {0} giới hạn khối của tất cả các đảo.' CHANGED_BLOCK_LIMIT_NAME: '&e&lNâng Cấp | &7Thay đổi thành công giới hạn khối {0} đảo của {1}.' +CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' +CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' +CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' +CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' +CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' +CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lRương | &7Thành công nâng cấp số dòng của trang #{0} thành {1} cho đảo của {2}.' CHANGED_CHEST_SIZE_ALL: '&e&lRương | &7Thành công nâng cấp số dòng của trang #{0} thành {1} cho tất cả các đảo.' CHANGED_CHEST_SIZE_NAME: '&e&lRương | &7Thành công nâng cấp số dòng của trang #{0} thành {1} cho đảo {2}.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index c503f76823..b74dba49d0 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -39,7 +39,6 @@ BLOCK_LEVEL: '&e&l等级 | &7方块 {0} 的等级为 {1}.' BLOCK_LEVEL_WORTHLESS: '&e&l等级 | &7方块 {0} 没有价格.' BLOCK_VALUE: '&e&l价值 | &7方块 {0} 的价值为 {1}.' BLOCK_VALUE_WORTHLESS: '&e&l价值 | &7方块 {0} 没有价格.' -BONUS_SET_SUCCESS: '&e&l岛屿 | &7成功将岛屿奖励更新为 {0}.' BONUS_SYNC_ALL: '&e&l岛屿 | &7成功将该岛屿奖励同步至所有岛屿' BONUS_SYNC_NAME: '&e&l岛屿 | &7成功将该岛屿奖励同步为 {0}.' BONUS_SYNC: '&e&l岛屿 | &7成功将该岛屿奖励同步至了玩家 {0} 的岛屿.' @@ -61,6 +60,12 @@ CHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7成功将 {0} 的方块数量设置为了 CHANGED_BLOCK_LIMIT: '&e&l升级 | &7成功更新了岛屿 {1} 的方块 {0} 限制.' CHANGED_BLOCK_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的方块 {0} 限制.' CHANGED_BLOCK_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的方块 {0} 限制.' +CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' +CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' +CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' +CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' +CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' +CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' CHANGED_CHEST_SIZE: '&e&lChest | &7成功将玩家 {2} 的岛屿仓库 #{0} 的行数更新为了 {1}.' CHANGED_CHEST_SIZE_ALL: '&e&lChest | &7成功将所有岛屿的岛屿仓库 #{0} 的行数更新为了 {1}.' CHANGED_CHEST_SIZE_NAME: '&e&lChest | &7成功将岛屿 {2} 的岛屿仓库 #{0} 的行数更新为了 {1}.' From e212a50cecb29397a525d9c4711df2841c9e0594 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 18 Oct 2025 09:03:32 +0200 Subject: [PATCH 397/600] Fixed tab completes of /is admin data command (#2727) --- .../superiorskyblock/commands/admin/CmdAdminData.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminData.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminData.java index 61b60efb13..ed36ed7cdd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminData.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminData.java @@ -110,9 +110,12 @@ public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sen } case 5: { SubCommand subCommand = subCommands.get(args[2].toLowerCase(Locale.ENGLISH)); - return subCommand == null ? Collections.emptyList() : args[3].equalsIgnoreCase("island") ? - CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[4], false, null) : - CommandTabCompletes.getOnlinePlayers(plugin, args[4], false); + if (subCommand != null && args[3].equalsIgnoreCase("island")) + return CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[4], false, null); + else if (subCommand != null && args[3].equalsIgnoreCase("player")) + CommandTabCompletes.getOnlinePlayers(plugin, args[4], false); + else + return Collections.emptyList(); } default: { return Collections.emptyList(); From 969ea850b36778edf5f5268df53e0eb7a92e4ff9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 18 Oct 2025 10:53:22 +0300 Subject: [PATCH 398/600] Removed debug messages when connecting to database --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6585a2e3a7..edce232615 100644 --- a/build.gradle +++ b/build.gradle @@ -73,7 +73,7 @@ dependencies { implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b16' - implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b1' + implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b2' implementation 'org.bstats:bstats-bukkit:3.0.0' From 605793182ad18015edd35145246978ed33907b92 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Mon, 27 Oct 2025 21:44:12 +0100 Subject: [PATCH 399/600] Added message-delays option (#2731) --- .../api/config/SettingsManager.java | 13 ++- .../StackedBlocksProvider_WildStacker.java | 3 +- .../commands/admin/CmdAdminTeleport.java | 3 +- .../config/SettingsContainer.java | 10 ++- .../config/SettingsManagerImpl.java | 18 ++++- .../config/section/GlobalSection.java | 4 +- .../core/messages/Message.java | 80 +++---------------- .../portals/PortalsManagerServiceImpl.java | 19 ++--- .../service/region/ProtectionHelper.java | 37 ++++++++- src/main/resources/config.yml | 13 ++- src/main/resources/lang/de-DE.yml | 3 +- src/main/resources/lang/en-US.yml | 3 +- src/main/resources/lang/es-ES.yml | 3 +- src/main/resources/lang/fr-FR.yml | 3 +- src/main/resources/lang/it-IT.yml | 3 +- src/main/resources/lang/iw-IL.yml | 3 +- src/main/resources/lang/pl-PL.yml | 3 +- src/main/resources/lang/pt-BR.yml | 3 +- src/main/resources/lang/ru-RU.yml | 3 +- src/main/resources/lang/tr-TR.yml | 3 +- src/main/resources/lang/vi-VN.yml | 3 +- src/main/resources/lang/zh-CN.yml | 3 +- 22 files changed, 130 insertions(+), 106 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 26614267a2..267f52c040 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -636,11 +636,20 @@ public interface SettingsManager { boolean isDropsUpgradePlayersMultiply(); /** - * The delay between protect messages, in ticks. - * Config-path: protected-message-delay + * The delay set for the ISLAND_PROTECTED message. + * + * @deprecated See {@link #getMessageDelays()} */ + @Deprecated long getProtectedMessageDelay(); + /** + * A list of messages that should have a delay, in milliseconds. + * Represented by a map with string as the message name, and values as the delays. + * Config-path: message-delays + */ + Map getMessageDelays(); + /** * Whether the warp categories system is enabled or not. * Config-path: warp-categories diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java index 52c0010f0c..4d0201cffc 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java @@ -15,6 +15,7 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.external.WildStackerSnapshotsContainer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.wildstacker.api.WildStackerAPI; import com.bgsoftware.wildstacker.api.events.BarrelPlaceEvent; import com.bgsoftware.wildstacker.api.events.BarrelPlaceInventoryEvent; @@ -153,7 +154,7 @@ public void onBarrelUnstackOnOtherIsland(BarrelUnstackEvent e) { if (!island.hasPermission(player, IslandPrivileges.BREAK)) { e.setCancelled(true); - Message.PROTECTION.send(player); + ProtectionHelper.sendProtectionMessage(player); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java index 2b936953d7..7cf9a48dce 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.Location; import org.bukkit.PortalType; @@ -89,7 +90,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab } if (plugin.getGrid().getIslandsWorldInfo(island, dimension) == null) { - Message.WORLD_NOT_ENABLED.send(sender); + Message.WORLD_NOT_ENABLED.send(sender, Formatters.CAPITALIZED_FORMATTER.format(dimension.getName())); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index ad4bfdb5cd..9fcbb57de3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -216,7 +216,7 @@ public class SettingsContainer { public final Map islandPreviewsLocations; public final boolean tabCompleteHideVanished; public final boolean dropsUpgradePlayersMultiply; - public final long protectedMessageDelay; + public final Map messageDelays; public final boolean warpCategories; public final boolean physicsListener; public final double chargeOnWarp; @@ -561,7 +561,13 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config this.islandPreviewsLocations = Collections.unmodifiableMap(islandPreviewsLocations); tabCompleteHideVanished = config.getBoolean("tab-complete-hide-vanished", true); dropsUpgradePlayersMultiply = config.getBoolean("drops-upgrade-players-multiply", false); - protectedMessageDelay = config.getLong("protected-message-delay", 60L); + Map messageDelays = new HashMap<>(); + if (config.isConfigurationSection("message-delays")) { + for (String message : config.getConfigurationSection("message-delays").getKeys(false)) { + messageDelays.put(message.toUpperCase(Locale.ENGLISH), config.getLong("message-delays." + message)); + } + } + this.messageDelays = Collections.unmodifiableMap(messageDelays); warpCategories = config.getBoolean("warp-categories", true); physicsListener = config.getBoolean("physics-listener", true); chargeOnWarp = config.getDouble("charge-on-warp", 0D); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index e6dee4c08d..0a09aea9f1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -48,7 +48,7 @@ public class SettingsManagerImpl extends Manager implements SettingsManager { private static final String[] IGNORED_SECTIONS = new String[]{ "config.yml", "ladder", "commands-cooldown", "containers", "event-commands", "command-aliases", "island-previews.locations", "default-values.block-limits", "default-values.entity-limits", - "default-values.role-limits", "stacked-blocks.limits", "default-values.generator" + "default-values.role-limits", "stacked-blocks.limits", "default-values.generator", "message-delays" }; private final GlobalSection global = new GlobalSection(); @@ -581,8 +581,14 @@ public boolean isDropsUpgradePlayersMultiply() { } @Override + @Deprecated public long getProtectedMessageDelay() { - return this.global.getProtectedMessageDelay(); + return this.global.getMessageDelays().getOrDefault("ISLAND_PROTECTED", 0L); + } + + @Override + public Map getMessageDelays() { + return this.global.getMessageDelays(); } @Override @@ -705,6 +711,14 @@ private void loadContainerFromConfig(YamlConfiguration cfg) throws ManagerLoadEx } private void convertData(YamlConfiguration cfg) { + if (cfg.get("protected-message-delay") instanceof Number) { + long delay = cfg.getLong("protected-message-delay") * 50; + cfg.set("message-delays.ISLAND_PROTECTED", delay); + cfg.set("message-delays.ISLAND_PROTECTED_OPPED", delay); + cfg.set("message-delays.SPAWN_PROTECTED", delay); + cfg.set("message-delays.SPAWN_PROTECTED_OPPED", delay); + cfg.set("protected-message-delay", null); + } if (cfg.isConfigurationSection("preview-islands")) { cfg.set("island-previews.locations", cfg.getConfigurationSection("preview-islands")); cfg.set("preview-islands", null); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index 29528e5108..aa7c05db99 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -341,8 +341,8 @@ public boolean isDropsUpgradePlayersMultiply() { return getContainer().dropsUpgradePlayersMultiply; } - public long getProtectedMessageDelay() { - return getContainer().protectedMessageDelay; + public Map getMessageDelays() { + return getContainer().messageDelays; } public boolean isWarpCategories() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 0639369be1..f1a60f761b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -3,14 +3,10 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.message.IMessageComponent; import com.bgsoftware.superiorskyblock.api.service.message.MessagesService; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.commands.CommandsHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; -import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.AutoRemovalCollection; @@ -30,7 +26,6 @@ import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.chat.HoverEvent; import net.md_5.bungee.api.chat.TextComponent; -import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -78,7 +73,7 @@ public enum Message { BORDER_PLAYER_COLOR_NAME_GREEN, BORDER_PLAYER_COLOR_NAME_RED, BORDER_PLAYER_COLOR_UPDATED, - BUILD_OUTSIDE_ISLAND(3, TimeUnit.SECONDS), + BUILD_OUTSIDE_ISLAND, CANNOT_SET_ROLE, CHANGED_BANK_LIMIT, CHANGED_BANK_LIMIT_ALL, @@ -479,7 +474,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { ISLAND_BANK_SHOW, ISLAND_BANK_SHOW_OTHER, ISLAND_BANK_SHOW_OTHER_NAME, - ISLAND_BEING_CALCULATED(3, TimeUnit.SECONDS), + ISLAND_BEING_CALCULATED, ISLAND_CLOSED, ISLAND_CREATE_PROCCESS_REQUEST, ISLAND_CREATE_PROCESS_FAIL, @@ -708,6 +703,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { REVOKE_INVITE_ANNOUNCEMENT, SAME_NAME_CHANGE, SCHEMATIC_LEFT_SELECT, + SCHEMATIC_NOT_ADDED, SCHEMATIC_NOT_READY, SCHEMATIC_PROCCESS_REQUEST, SCHEMATIC_READY_TO_CREATE, @@ -814,60 +810,6 @@ public void send(CommandSender sender, Locale locale, Object... args) { WORLD_NOT_ENABLED, WORLD_NOT_UNLOCKED, - SCHEMATICS(true) { - - private final Collection noSchematicMessages = AutoRemovalCollection.newHashSet(3, TimeUnit.SECONDS); - - @Override - public void send(CommandSender sender, Locale locale, Object... objects) { - if (!(sender instanceof Player) || objects.length != 1 || !(objects[0] instanceof String)) - return; - - UUID playerUUID = ((Player) sender).getUniqueId(); - String message = (String) objects[0]; - - if (noSchematicMessages.add(playerUUID)) { - Message.CUSTOM.send(sender, locale, message, false); - } - } - }, - - PROTECTION(true) { - @Override - public void send(CommandSender sender, Locale locale, Object... args) { - if (!(sender instanceof Player)) - return; - - if (plugin.getSettings().getProtectedMessageDelay() > 0) { - if (noInteractMessages == null) - noInteractMessages = AutoRemovalCollection.newHashSet(plugin.getSettings().getProtectedMessageDelay() * 50, TimeUnit.MILLISECONDS); - - UUID playerUUID = ((Player) sender).getUniqueId(); - - if (!noInteractMessages.add(playerUUID)) - return; - } - - boolean isSpawnIsland; - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Island island = plugin.getGrid().getIslandAt(((Player) sender).getLocation(wrapper.getHandle())); - isSpawnIsland = island != null && island.isSpawn(); - } - - if (!isSpawnIsland) - Message.ISLAND_PROTECTED.send(sender, locale, args); - else - Message.SPAWN_PROTECTED.send(sender, locale, args); - - SuperiorCommand bypassCommand = plugin.getCommands().getAdminCommand("bypass"); - if (CommandsHelper.hasCommandAccess(bypassCommand, sender)) - if (!isSpawnIsland) - Message.ISLAND_PROTECTED_OPPED.send(sender, locale, args); - else - Message.SPAWN_PROTECTED_OPPED.send(sender, locale, args); - } - }, - CUSTOM(true) { @Override public void send(CommandSender sender, Locale locale, Object... args) { @@ -905,9 +847,6 @@ protected MessagesServiceImpl create() { } }; - @Nullable - private static Collection noInteractMessages; - private final String defaultMessage; private final boolean isCustom; private final Map messages = new ArrayMap<>(); @@ -926,10 +865,6 @@ protected MessagesServiceImpl create() { this(defaultMessage, false, 0L, null); } - Message(long delay, TimeUnit delayUnit) { - this(null, false, delay, delayUnit); - } - Message(String defaultMessage, boolean isCustom, long delay, @Nullable TimeUnit delayUnit) { this.defaultMessage = defaultMessage; this.isCustom = isCustom; @@ -1094,7 +1029,14 @@ public static void registerListeners(PluginEventsDispatcher dispatcher) { } private static void onSettingsUpdate() { - noInteractMessages = null; + for (Message message : values()) { + long delay = plugin.getSettings().getMessageDelays().getOrDefault(message.name(), 0L); + + if (delay > 0L) + message.delayedMessages = AutoRemovalCollection.newHashSet(delay, TimeUnit.MILLISECONDS); + else + message.delayedMessages = null; + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java index e5df2639fb..9d63d7cc53 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java @@ -26,7 +26,6 @@ import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import com.google.common.base.Preconditions; -import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.PortalType; import org.bukkit.World; @@ -130,14 +129,12 @@ private EntityPortalResult handlePlayerPortalInternal(SuperiorPlayer superiorPla EntityPortalResult portalResult = simulateEntityPortalFromIsland(superiorPlayer.asPlayer(), island, portalLocation, portalType); - if (portalResult == EntityPortalResult.WORLD_NOT_UNLOCKED && !Message.WORLD_NOT_UNLOCKED.isEmpty(superiorPlayer.getUserLocale())) { + if (portalResult == EntityPortalResult.WORLD_NOT_UNLOCKED) { Dimension originalDestination = getTargetWorld(portalLocation, portalType); - Message.SCHEMATICS.send(superiorPlayer, Message.WORLD_NOT_UNLOCKED.getMessage( - superiorPlayer.getUserLocale(), Formatters.CAPITALIZED_FORMATTER.format(originalDestination.getName()))); - } - - if (portalResult == EntityPortalResult.DESTINATION_WORLD_DISABLED && !Message.WORLD_NOT_ENABLED.isEmpty(superiorPlayer.getUserLocale())) { - Message.SCHEMATICS.send(superiorPlayer, Message.WORLD_NOT_ENABLED.getMessage(superiorPlayer.getUserLocale())); + Message.WORLD_NOT_UNLOCKED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(originalDestination.getName())); + } else if (portalResult == EntityPortalResult.DESTINATION_WORLD_DISABLED) { + Dimension originalDestination = getTargetWorld(portalLocation, portalType); + Message.WORLD_NOT_ENABLED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(originalDestination.getName())); } return portalResult; @@ -210,10 +207,8 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island if (schematic == null && !ignoreInvalidSchematic) { if (superiorPlayer != null) { - Message.SCHEMATICS.send(superiorPlayer, ChatColor.RED + "The server hasn't added a " + - destinationEnvironmentName + " schematic. Please contact administrator to solve the problem. " + - "The format for " + destinationEnvironmentName + " schematic is \"" + - islandSchematic + "_" + destinationEnvironmentName + "\"."); + String schematicName = islandSchematic + "_" + destinationEnvironmentName; + Message.SCHEMATIC_NOT_ADDED.send(superiorPlayer, destinationEnvironmentName, schematicName); } return EntityPortalResult.INVALID_SCHEMATIC; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/ProtectionHelper.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/ProtectionHelper.java index 099e6e6f63..a5fedf9636 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/ProtectionHelper.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/ProtectionHelper.java @@ -1,12 +1,25 @@ package com.bgsoftware.superiorskyblock.service.region; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; +import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandsHelper; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.player.PlayerLocales; +import org.bukkit.Location; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.Locale; public class ProtectionHelper { + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private ProtectionHelper() { } @@ -20,7 +33,7 @@ public static boolean shouldPreventInteraction(InteractionResult interactionResu return true; case MISSING_PRIVILEGE: if (sendMessages && superiorPlayer != null) - Message.PROTECTION.send(superiorPlayer); + sendProtectionMessage(superiorPlayer.asPlayer()); return true; case OUTSIDE_ISLAND: if (sendMessages && superiorPlayer != null) @@ -33,4 +46,26 @@ public static boolean shouldPreventInteraction(InteractionResult interactionResu throw new IllegalStateException("No handling for result " + interactionResult); } + public static void sendProtectionMessage(CommandSender sender) { + boolean isSpawnIsland; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Island island = plugin.getGrid().getIslandAt(((Player) sender).getLocation(wrapper.getHandle())); + isSpawnIsland = island != null && island.isSpawn(); + } + + Locale locale = PlayerLocales.getLocale(sender); + + if (!isSpawnIsland) + Message.ISLAND_PROTECTED.send(sender, locale); + else + Message.SPAWN_PROTECTED.send(sender, locale); + + SuperiorCommand bypassCommand = plugin.getCommands().getAdminCommand("bypass"); + if (CommandsHelper.hasCommandAccess(bypassCommand, sender)) + if (!isSpawnIsland) + Message.ISLAND_PROTECTED_OPPED.send(sender, locale); + else + Message.SPAWN_PROTECTED_OPPED.send(sender, locale); + } + } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 45b090b1bb..ade5b54526 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -843,8 +843,17 @@ tab-complete-hide-vanished: true # When enabled, the drops multiplier will only multiply drops of entities that were killed by players. drops-upgrade-players-multiply: false -# The delay between protected messages (in ticks) -protected-message-delay: 60 +# List of messages that should have a delay. (in milliseconds) +message-delays: + BUILD_OUTSIDE_ISLAND: 3000 + ISLAND_BEING_CALCULATED: 3000 + ISLAND_PROTECTED: 3000 + ISLAND_PROTECTED_OPPED: 3000 + SCHEMATIC_NOT_ADDED: 3000 + SPAWN_PROTECTED: 3000 + SPAWN_PROTECTED_OPPED: 3000 + WORLD_NOT_ENABLED: 3000 + WORLD_NOT_UNLOCKED: 3000 # Should players be able to create warp categories? warp-categories: true diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 92fcc0c832..45c1371b33 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -869,6 +869,7 @@ RESET_WORLD_SUCCEED_NAME: '&e&lInsel | &7Die Welt {0} für {1} erfolgreich zurü SAME_NAME_CHANGE: '&c&lError | &7Du musst einen anderen Namen als dein aktuellen Inselnamen eingeben.' SCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Ausgewählte Position #2 ({0})' +SCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is "{1}".' SCHEMATIC_NOT_READY: '&c&lError | &7Du hast keine zwei Stellen ausgewählt.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Deine Anfrage wird bearbeitet...' SCHEMATIC_READY_TO_CREATE: | @@ -1020,5 +1021,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&lBank | &7{0} withdrawn ${1} from the island bank!' WITHDRAW_ERROR: '&c&lError | &7{0}.' WITHDRAWN_MONEY: '&e&lBank | &7You withdrawn ${0} from {1}''s island bank!' WITHDRAWN_MONEY_NAME: '&e&lBank | &7Du hast ${0} von der Inselbank von {1} abgehoben!' -WORLD_NOT_ENABLED: '&e&lWorlds | &7This world is not enabled on the server.' +WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lWorlds | &7Die Welt {0} ist noch nicht freigeschaltet!' \ No newline at end of file diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 15e83f0485..f30bc98bc5 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -690,6 +690,7 @@ RESET_WORLD_SUCCEED_ALL: '&e&lIsland | &7Successfully reset the world {0} for al RESET_WORLD_SUCCEED_NAME: '&e&lIsland | &7Successfully reset the world {0} for {1}.' SAME_NAME_CHANGE: '&c&lError | &7You must enter a different name from your current island name.' SCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Selected position #2 ({0})' +SCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is "{1}".' SCHEMATIC_NOT_READY: '&c&lError | &7You haven''t selected two positions.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Processing your request...' SCHEMATIC_READY_TO_CREATE: | @@ -803,5 +804,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&lBank | &7{0} withdrawn ${1} from the island bank!' WITHDRAW_ERROR: '&c&lError | &7{0}.' WITHDRAWN_MONEY: '&e&lBank | &7You withdrawn ${0} from {1}''s island bank!' WITHDRAWN_MONEY_NAME: '&e&lBank | &7You withdrawn ${0} from the island bank of {1}!' -WORLD_NOT_ENABLED: '&e&lWorlds | &7This world is not enabled on the server.' +WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lWorlds | &7The {0} world is not unlocked yet!' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 03d3626305..03cdbef83c 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -687,6 +687,7 @@ RESET_WORLD_SUCCEED_ALL: '&e&lIsland | &7Successfully reset the world {0} for al RESET_WORLD_SUCCEED_NAME: '&e&lIsland | &7Successfully reset the world {0} for {1}.' SAME_NAME_CHANGE: '&c&lError | &7Debes ingresar un nombre diferente al nombre de tu isla actual.' SCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Posición seleccionada #2 ({0})' +SCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is "{1}".' SCHEMATIC_NOT_READY: '&c&lError | &7No ha seleccionado dos posiciones.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Procesando su solicitud...' SCHEMATIC_READY_TO_CREATE: | @@ -800,5 +801,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&lBanco | &7{0} esta retirado ${1} del banco de la isl WITHDRAW_ERROR: '&c&lError | &7{0}.' WITHDRAWN_MONEY: '&e&lBanco | &7¡Retiraste ${0} del banco de la isla de {1}!' WITHDRAWN_MONEY_NAME: '&e&lBanco | &7¡Retiraste ${0} del banco de la isla de {1}!' -WORLD_NOT_ENABLED: '&e&lWorlds | &7This world is not enabled on the server.' +WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lMundos | &7¡El mundo {0} aún no está desbloqueado!' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 322a00fb83..39d064ee43 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -689,6 +689,7 @@ RESET_WORLD_SUCCEED_ALL: '&e&lIle | &7Réinitialisation du monde {0} pour toutes RESET_WORLD_SUCCEED_NAME: '&e&lIle | &7Réinitialisation du monde {0} pour l''île de {1}.' SAME_NAME_CHANGE: '&c&lErreur | &7Vous devez entrer un nom différent de celui actuel.' SCHEMATIC_LEFT_SELECT: '&e&lSchémas | &7Position #2 séléctionnée ({0})' +SCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is "{1}".' SCHEMATIC_NOT_READY: '&c&lErreur | &7Vous n''avez pas séléctionné deux positionss.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchémas | &7Traitement de votre requête...' SCHEMATIC_READY_TO_CREATE: | @@ -802,5 +803,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&lBanque | &7{0} a retiré {1}$ du compte de l''île ! WITHDRAW_ERROR: '&c&lErreur | &7{0}.' WITHDRAWN_MONEY: '&e&lBanque | &7Vous avez retiré {0}$ du compte de l''île de {1} !' WITHDRAWN_MONEY_NAME: '&e&lBanque | &7Vous avez retiré {0}$ du compte de l''île {1} !' -WORLD_NOT_ENABLED: '&e&lWorlds | &7This world is not enabled on the server.' +WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lMondes | &7Le monde {0} n''a pas encore été dévérouillé !' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index d79f916633..b6463be04b 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -695,6 +695,7 @@ RESET_WORLD_SUCCEED_ALL: '&e&lIsola | &7Ripristinato il mondo {0} con successo p RESET_WORLD_SUCCEED_NAME: '&e&lIsola | &7Ripristinato il mondo {0} con successo per {1}.' SAME_NAME_CHANGE: '&c&lErrore | &7Devi inserire un nome diverso dal tuo attuale nome dell''isola.' SCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Posizione selezionata #2 ({0})' +SCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is "{1}".' SCHEMATIC_NOT_READY: '&c&lErrore | &7Non hai selezionato due posizioni.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Elaborazione della richiesta...' SCHEMATIC_READY_TO_CREATE: | @@ -808,5 +809,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&lBanca | &7{0} ha prelevato ${1} dalla banca dell''is WITHDRAW_ERROR: '&c&lErrore | &7{0}.' WITHDRAWN_MONEY: '&e&lBanca | &7Hai ritirato ${0} dalla banca dell''isola di {1}!' WITHDRAWN_MONEY_NAME: '&e&lBanca | &7Hai ritirato ${0} dalla riva dell''isola {1}!' -WORLD_NOT_ENABLED: '&e&lWorlds | &7This world is not enabled on the server.' +WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lMondi | &7Il mondo {0} non è ancora stato sbloccato!' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index e884029810..9795cd8d40 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -709,6 +709,7 @@ RESET_WORLD_SUCCEED_ALL: '&e&lIsland | &7Successfully reset the world {0} for al RESET_WORLD_SUCCEED_NAME: '&e&lIsland | &7Successfully reset the world {0} for {1}.' SAME_NAME_CHANGE: '&c&lהאיגש | &7ךלש יאה לש יוושכעה םשהמ רחא םש סינכהל ךירצ התא.' SCHEMATIC_LEFT_SELECT: '&e&lםינבמ רצוי | &7היינש הדוקנ תנמיס ({0})' +SCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is "{1}".' SCHEMATIC_NOT_READY: '&c&lהאיגש | &7תודוקנ ינש תרחב אל.' SCHEMATIC_PROCCESS_REQUEST: '&e&lםינבמ רצוי | &7ךתשקב תא דבעמ...' SCHEMATIC_READY_TO_CREATE: | @@ -822,5 +823,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&lקנב | &7יאה לש קנבהמ ${1} ךשמ {0}!' WITHDRAW_ERROR: '&c&lError | &7{0}.' WITHDRAWN_MONEY: '&e&lקנב | &7{1} לש יאה לש קנבהמ ${0} תכשמ!' WITHDRAWN_MONEY_NAME: '&e&lקנב | &7{1} יאה לש קנבהמ ${0} תכשמ!' -WORLD_NOT_ENABLED: '&e&lWorlds | &7This world is not enabled on the server.' +WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lתומלוע | &7הזה יאב חותפ אל ןיידע {0} םלועה.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index e5995a795a..9c886c1945 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -687,6 +687,7 @@ RESET_WORLD_SUCCEED_ALL: '&e&lWyspa | &7Pomyslnie zresetuj swiat {0} dla wszystk RESET_WORLD_SUCCEED_NAME: '&e&lWyspa | &7Pomyslnie zresetuj swiat {0} dla {1}.' SAME_NAME_CHANGE: '&c&lBlad | &7Musisz wprowadzic inna nazwe niz obecna nazwa wyspy.' SCHEMATIC_LEFT_SELECT: '&e&lSchematy | &7Wybrana pozycja #2 ({0})' +SCHEMATIC_NOT_ADDED: '&c&lBlad | &7Serwer nie dodal schematu {0}. Skontaktuj sie z administratorem, aby rozwiazac problem. Format dla schematu {0} to "{1}".' SCHEMATIC_NOT_READY: '&c&lBlad | &7Nie wybrales dwóch pozycji.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchematy | &7Przetwarzanie zadania...' SCHEMATIC_READY_TO_CREATE: | @@ -800,5 +801,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&lBank | &7{0} wyplaciles {1}$ z banku wyspy!' WITHDRAW_ERROR: '&c&lBlad | &7{0}.' WITHDRAWN_MONEY: '&e&lBank | &7Wyplaciles {0}$ z banku wysp {1}!' WITHDRAWN_MONEY_NAME: '&e&lBank | &7Wyplaciles {0}$ z banku wyspy {1}!' -WORLD_NOT_ENABLED: '&e&lWorlds | &7This world is not enabled on the server.' +WORLD_NOT_ENABLED: '&e&lWorlds | &7Swiat {0} nie jest wlaczony na serwerze.' WORLD_NOT_UNLOCKED: '&e&lSwiaty | &7swiat {0} nie jest jeszcze odblokowany!' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 47382cf44d..742285f7e9 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -687,6 +687,7 @@ RESET_WORLD_SUCCEED_ALL: '&e&lIlha | &7Redefinido com sucesso o mundo {0} para t RESET_WORLD_SUCCEED_NAME: '&e&lIlha | &7Redefinido com sucesso o mundo {0} para {1}.' SAME_NAME_CHANGE: '&c&lErro | &7Você deve digitar um nome diferente do nome atual da sua ilha.' SCHEMATIC_LEFT_SELECT: '&e&lEsquemas | &7Posição selecionada nº 2 ({0})' +SCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is "{1}".' SCHEMATIC_NOT_READY: '&c&lErro | &7Você não selecionou duas posições.' SCHEMATIC_PROCCESS_REQUEST: '&e&lEsquemas | &7Processando sua solicitação...' SCHEMATIC_READY_TO_CREATE: | @@ -800,5 +801,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&lBanco | &7{0} retirou ${1} do banco da ilha!' WITHDRAW_ERROR: '&c&lErro | &7{0}.' WITHDRAWN_MONEY: '&e&lBanco | &7Você sacou ${0} do banco da ilha de {1}!' WITHDRAWN_MONEY_NAME: '&e&lBanco | &7Você sacou ${0} do banco da ilha de {1}!' -WORLD_NOT_ENABLED: '&e&lWorlds | &7Este mundo não está habilitado no servidor.' +WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lWorlds | &7O mundo {0} ainda não está desbloqueado!' \ No newline at end of file diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 3f544f4f7f..be4b97b972 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -687,6 +687,7 @@ RESET_WORLD_SUCCEED_ALL: '&e&lОстров | &7Успешно сброшен м RESET_WORLD_SUCCEED_NAME: '&e&lОстров | &7Успешно сброшен мир {0} для {1}.' SAME_NAME_CHANGE: '&c&lОшибка | &7Вы должны ввести другое имя, отличное от текущего имени острова.' SCHEMATIC_LEFT_SELECT: '&e&lСхемы | &7Выбрана позиция #2 ({0})' +SCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is "{1}".' SCHEMATIC_NOT_READY: '&c&lОшибка | &7Вы не выбрали две позиции.' SCHEMATIC_PROCCESS_REQUEST: '&e&lСхемы | &7Обработка вашего запроса...' SCHEMATIC_READY_TO_CREATE: | @@ -800,5 +801,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&lБанк | &7{0} снял ${1} из банка ос WITHDRAW_ERROR: '&c&lОшибка | &7{0}.' WITHDRAWN_MONEY: '&e&lБанк | &7Вы сняли ${0} из банка острова {1}!' WITHDRAWN_MONEY_NAME: '&e&lБанк | &7Вы сняли ${0} из банка острова {1}!' -WORLD_NOT_ENABLED: '&e&lМиры | &7Этот мир не включен на сервере.' +WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lМиры | &7Мир {0} еще не разблокирован!' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index c310d297f4..e3a009f3f9 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -815,6 +815,7 @@ RESET_WORLD_SUCCEED_ALL: '&e&lAda | &7Tüm adalar için {0} dünyası başarıyl RESET_WORLD_SUCCEED_NAME: '&e&lAda | &7{1} adası için {0} dünyası başarıyla sıfırlandı.' SAME_NAME_CHANGE: '&c&lHata | &7Mevcut ada adından farklı bir ad girmelisin.' SCHEMATIC_LEFT_SELECT: '&e&lŞematikler | &7Konum #2 ({0}) seçildi.' +SCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is "{1}".' SCHEMATIC_NOT_READY: '&c&lHata | &7İki konum seçmedin.' SCHEMATIC_PROCCESS_REQUEST: '&e&lŞematikler | &7İsteğiniz işleniyor...' SCHEMATIC_READY_TO_CREATE: | @@ -950,5 +951,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&lBanka | &7{0} ada bankasından ${1} çekti!' WITHDRAW_ERROR: '&c&lHata | &7{0}.' WITHDRAWN_MONEY: '&e&lBanka | &7{1}''in ada bankasından ${0} çektin!' WITHDRAWN_MONEY_NAME: '&e&lBanka | &7{1} adasının bankasından ${0} çektin!' -WORLD_NOT_ENABLED: '&e&lDünyalar | &7Bu dünya sunucuda etkin değil.' +WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lDünyalar | &7{0} dünyası henüz kilitli değil!' \ No newline at end of file diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 4e857ad445..108e7573ae 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -771,6 +771,7 @@ RESET_WORLD_SUCCEED_NAME: '&e&lĐảo | &7Thành công đặt lại thế giới SAME_NAME_CHANGE: '&c&lLỗi | &7Bạn phải nhập một tên khác với tên đảo hiện tại của bạn.' SCHEMATIC_LEFT_SELECT: '&e&lSchematics | &7Đã chọn vị trí #2 ({0})' +SCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is "{1}".' SCHEMATIC_NOT_READY: '&c&lLỗi | &7Bạn chưa chọn hai vị trí.' SCHEMATIC_PROCCESS_REQUEST: '&e&lSchematics | &7Đang xử lý yêu cầu của bạn...' SCHEMATIC_READY_TO_CREATE: | @@ -898,5 +899,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&lNgân Hàng | &7{0} rút {1}$ từ ngân hàng của WITHDRAW_ERROR: '&c&lLỗi | &7{0}.' WITHDRAWN_MONEY: '&e&lNgân Hàng | &7Bạn đã rút ${0} từ đảo của {1}!' WITHDRAWN_MONEY_NAME: '&e&lNgân Hàng | &7Bạn đã rút ${0} từ đảo {1}!' -WORLD_NOT_ENABLED: '&e&lThế giới | &7Thế giới này không được bật trên máy chủ.' +WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&lThế Giới | &7Thế giới {0} hiện chưa được mở khóa!' \ No newline at end of file diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index b74dba49d0..02ee975c13 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -687,6 +687,7 @@ RESET_WORLD_SUCCEED_ALL: '&e&l岛屿 | &7成功为所有岛屿重置了世界 {0 RESET_WORLD_SUCCEED_NAME: '&e&l岛屿 | &7成功为岛屿 {1} 重置了世界 {0}.' SAME_NAME_CHANGE: '&c&l错误 | &7你必须输入一个不与当前岛屿名称重复的名称.' SCHEMATIC_LEFT_SELECT: '&e&l结构 | &7已选中 #2 位点 ({0})' +SCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is "{1}".' SCHEMATIC_NOT_READY: '&c&l错误 | &7你尚未选中两点.' SCHEMATIC_PROCCESS_REQUEST: '&e&l结构 | &7正在处理你的请求...' SCHEMATIC_READY_TO_CREATE: | @@ -800,5 +801,5 @@ WITHDRAW_ANNOUNCEMENT: '&e&l银行 | &7玩家 {0} 从岛屿银行中取出了 ${ WITHDRAW_ERROR: '&c&l错误 | &7{0}.' WITHDRAWN_MONEY: '&e&l银行 | &7你从玩家 {1} 的岛屿银行中取出 ${0}!' WITHDRAWN_MONEY_NAME: '&e&l银行 | &7你从岛屿 {1} 的银行中取出 ${0} {1}!' -WORLD_NOT_ENABLED: '&e&l世界 | &7该服务器尚未启用该世界.' +WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' WORLD_NOT_UNLOCKED: '&e&l世界 | &7世界 {0} 尚未解锁!' From ce09493cbc90b33ddf5ba4cf342085553812c5bd Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 30 Oct 2025 13:40:01 +0200 Subject: [PATCH 400/600] Fix when loading entities in unloaded chunks may cause warnings in console (#2717) --- .../nms/v1_17/NMSChunksImpl.java | 23 +++++++++---------- .../nms/v1_18/NMSChunksImpl.java | 23 ++++++++----------- .../nms/v1_19/NMSChunksImpl.java | 23 ++++++++----------- .../nms/v1_20_3/NMSChunksImpl.java | 20 ++++++++-------- .../nms/v1_20_4/NMSChunksImpl.java | 19 +++++++-------- .../nms/v1_21/NMSChunksImpl.java | 19 +++++++-------- .../nms/v1_21_3/NMSChunksImpl.java | 19 +++++++-------- .../nms/v1_21_4/NMSChunksImpl.java | 19 +++++++-------- .../nms/v1_21_5/NMSChunksImpl.java | 19 +++++++-------- .../nms/v1_21_7/NMSChunksImpl.java | 18 ++++++++------- .../nms/v1_21_9/NMSChunksImpl.java | 18 ++++++++------- 11 files changed, 111 insertions(+), 109 deletions(-) diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java index 71279a172a..712c5bd6d8 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java @@ -1,36 +1,31 @@ package com.bgsoftware.superiorskyblock.nms.v1_17; import com.bgsoftware.common.reflection.ReflectField; -import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; -import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; -import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_17.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.nms.v1_17.world.KeyBlocksCache; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; +import net.minecraft.nbt.NbtOps; import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; @@ -39,14 +34,11 @@ import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.craftbukkit.v1_17_R1.CraftChunk; import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; -import org.bukkit.craftbukkit.v1_17_R1.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; @@ -291,6 +283,13 @@ public void onFinish() { @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getInt("DataVersion"); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + return EntityType.create(compoundTag, serverLevel); } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java index 4bb11e214c..e188f37f06 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java @@ -1,24 +1,18 @@ package com.bgsoftware.superiorskyblock.nms.v1_18; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_18.utils.NMSUtilsVersioned; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -30,7 +24,8 @@ import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; @@ -40,22 +35,17 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.craftbukkit.v1_18_R2.CraftChunk; import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator; -import org.bukkit.craftbukkit.v1_18_R2.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -367,6 +357,13 @@ public void onFinish() { @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getInt("DataVersion"); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + return EntityType.create(compoundTag, serverLevel); } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java index 37c3cbfdc9..5dac3811f8 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java @@ -1,24 +1,18 @@ package com.bgsoftware.superiorskyblock.nms.v1_19; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_19.utils.NMSUtilsVersioned; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -31,7 +25,8 @@ import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; @@ -41,23 +36,18 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.craftbukkit.v1_19_R3.CraftChunk; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_19_R3.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; -import org.bukkit.craftbukkit.v1_19_R3.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.CompletableFuture; @@ -370,6 +360,13 @@ public void onFinish() { @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getInt("DataVersion"); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + return EntityType.create(compoundTag, serverLevel); } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java index 44b05900a7..d2eabe95e4 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java @@ -1,24 +1,18 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_3; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_3.utils.NMSUtilsVersioned; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -31,6 +25,8 @@ import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; @@ -46,11 +42,8 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.craftbukkit.v1_20_R3.CraftChunk; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome; -import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_20_R3.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; @@ -366,6 +359,13 @@ public void onFinish() { @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getInt("DataVersion"); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + return EntityType.create(compoundTag, serverLevel); } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java index 8e905fb283..b63a38dacf 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java @@ -1,24 +1,18 @@ package com.bgsoftware.superiorskyblock.nms.v1_20_4; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_4.utils.NMSUtilsVersioned; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -32,6 +26,8 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; @@ -47,10 +43,8 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.craftbukkit.CraftChunk; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; @@ -361,6 +355,13 @@ public void onFinish() { @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getInt("DataVersion"); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + return EntityType.create(compoundTag, serverLevel); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java index 886ae4f8f6..e9a0ced091 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java @@ -1,24 +1,18 @@ package com.bgsoftware.superiorskyblock.nms.v1_21; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21.utils.NMSUtilsVersioned; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -32,6 +26,8 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.level.ChunkPos; @@ -47,10 +43,8 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.craftbukkit.CraftChunk; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; @@ -361,6 +355,13 @@ public void onFinish() { @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getInt("DataVersion"); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + return EntityType.create(compoundTag, serverLevel); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java index d38baa3370..10eadc8087 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java @@ -1,24 +1,18 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_3; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_3.utils.NMSUtilsVersioned; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -32,6 +26,8 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; @@ -48,10 +44,8 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.craftbukkit.CraftChunk; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; @@ -362,6 +356,13 @@ public void onFinish() { @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getInt("DataVersion"); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + return EntityType.create(compoundTag, serverLevel, EntitySpawnReason.NATURAL); } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java index 40700d061b..a11517a25c 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -1,24 +1,18 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_4; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_4.utils.NMSUtilsVersioned; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -32,6 +26,8 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; @@ -48,10 +44,8 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.craftbukkit.CraftChunk; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; @@ -362,6 +356,13 @@ public void onFinish() { @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getInt("DataVersion"); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + return EntityType.create(compoundTag, serverLevel, EntitySpawnReason.NATURAL); } private static void removeBlocks(ChunkAccess chunk) { diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java index eb386bfc31..1c417f8d18 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java @@ -1,24 +1,18 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_5; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_5.utils.NMSUtilsVersioned; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -32,6 +26,8 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; @@ -48,10 +44,8 @@ import net.minecraft.world.level.chunk.PalettedContainerRO; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.lighting.LevelLightEngine; -import org.bukkit.craftbukkit.CraftChunk; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; @@ -364,6 +358,13 @@ public void onFinish() { @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getIntOr("DataVersion", 0); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + return EntityType.create(compoundTag, serverLevel, EntitySpawnReason.NATURAL); } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java index d6a6492944..ef6f7b5603 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java @@ -1,23 +1,19 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_7; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_7.utils.NMSUtilsVersioned; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.Registry; @@ -32,6 +28,8 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.ProblemReporter; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; @@ -50,11 +48,8 @@ import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.ValueInput; -import org.bukkit.craftbukkit.CraftChunk; import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.entity.CraftEntityType; import org.bukkit.craftbukkit.entity.CraftPlayer; -import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; import org.slf4j.Logger; @@ -370,6 +365,13 @@ public void onFinish() { @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getIntOr("DataVersion", 0); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) { ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag); diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java index 6a0d83e4ce..5378e7e18e 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java @@ -2,23 +2,19 @@ import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.core.CalculatedChunk; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; -import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.v1_21_9.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_9.utils.NMSUtilsVersioned; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.mojang.logging.LogUtils; import com.mojang.serialization.Codec; import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.nbt.CompoundTag; @@ -31,6 +27,8 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.ProblemReporter; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; @@ -43,13 +41,10 @@ import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainerFactory; import net.minecraft.world.level.chunk.ProtoChunk; -import net.minecraft.world.level.chunk.Strategy; import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.storage.TagValueInput; import net.minecraft.world.level.storage.ValueInput; -import org.bukkit.craftbukkit.CraftChunk; import org.bukkit.craftbukkit.block.CraftBiome; -import org.bukkit.craftbukkit.entity.CraftEntityType; import org.bukkit.craftbukkit.entity.CraftPlayer; import org.bukkit.entity.Player; import org.bukkit.generator.ChunkGenerator; @@ -332,6 +327,13 @@ public void onFinish() { @Override protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getIntOr("DataVersion", 0); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (net.minecraft.nbt.CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) { ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag); From ccca7b52f9819d18ca6eb857cafa5351beb9bbd4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 30 Oct 2025 14:20:57 +0200 Subject: [PATCH 401/600] Adds support to "vanished" metadata key check (#2740) --- .../external/ProvidersManagerImpl.java | 3 ++- .../external/vanish/VanishProvider_Default.java | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Default.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java index 7b6e42796e..472c152ca6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java @@ -48,6 +48,7 @@ import com.bgsoftware.superiorskyblock.external.spawners.SpawnersProvider_Default; import com.bgsoftware.superiorskyblock.external.stackedblocks.StackedBlocksProvider_AutoDetect; import com.bgsoftware.superiorskyblock.external.stackedblocks.StackedBlocksProvider_Default; +import com.bgsoftware.superiorskyblock.external.vanish.VanishProvider_Default; import com.bgsoftware.superiorskyblock.external.worlds.WorldsProvider_Default; import com.bgsoftware.superiorskyblock.service.placeholders.PlaceholdersServiceImpl; import com.google.common.base.Preconditions; @@ -83,7 +84,7 @@ public class ProvidersManagerImpl extends Manager implements ProvidersManager { private EconomyProvider bankEconomyProvider = new EconomyProvider_Default(); private PermissionsProvider permissionsProvider = new PermissionsProvider_Default(); private PricesProvider pricesProvider = new PricesProvider_Default(); - private VanishProvider vanishProvider = player -> false; + private VanishProvider vanishProvider = new VanishProvider_Default(); private AsyncProvider asyncProvider = new AsyncProvider_Default(); private WorldsProvider worldsProvider; private ChunksProvider chunksProvider = new ChunksProvider_Default(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Default.java b/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Default.java new file mode 100644 index 0000000000..e455f82e49 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Default.java @@ -0,0 +1,12 @@ +package com.bgsoftware.superiorskyblock.external.vanish; + +import com.bgsoftware.superiorskyblock.api.hooks.VanishProvider; +import org.bukkit.entity.Player; + +public class VanishProvider_Default implements VanishProvider { + + @Override + public boolean isVanished(Player player) { + return player.hasMetadata("vanished"); + } +} From 587ef10296150d4eb3a4e86d7a63fb343f22e482 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 30 Oct 2025 14:27:51 +0200 Subject: [PATCH 402/600] Removed schematics-cache from default config file as it is currently does not work, and no expected fix --- src/main/resources/config.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index ade5b54526..7082c7834c 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -926,9 +926,4 @@ chat-signing-support: true # Amount of commands to be listed in the `/is help` and `/is admin` commands. # Setting this to 0 or below will result all commands to be shown in a single page. -commands-per-page: 7 - -# Whether the plugin should cache schematics for faster placement of schematics. -# This may consume more RAM usage, but will place schematics much faster. -# This will only work if max-island-size is divisible by 4 with no remainder. -cache-schematics: true \ No newline at end of file +commands-per-page: 7 \ No newline at end of file From cfdfe2068a0d1984ec2a41b33ba7284bb70bd673 Mon Sep 17 00:00:00 2001 From: nivcoo <36514752+nivcoo@users.noreply.github.com> Date: Thu, 30 Oct 2025 19:44:54 +0100 Subject: [PATCH 403/600] improv. fix vanished check (#2743) --- .../external/vanish/VanishProvider_Default.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Default.java b/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Default.java index e455f82e49..63b28eae15 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Default.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Default.java @@ -2,11 +2,13 @@ import com.bgsoftware.superiorskyblock.api.hooks.VanishProvider; import org.bukkit.entity.Player; +import org.bukkit.metadata.MetadataValue; public class VanishProvider_Default implements VanishProvider { @Override public boolean isVanished(Player player) { - return player.hasMetadata("vanished"); + return player.getMetadata("vanished").stream() + .anyMatch(MetadataValue::asBoolean); } } From c71faa98fcf158720a778ec103b5275755508a44 Mon Sep 17 00:00:00 2001 From: Ome_R Date: Thu, 30 Oct 2025 22:25:19 +0200 Subject: [PATCH 404/600] Custom entity categories (#2747) --- .../api/config/SettingsManager.java | 7 + .../SuperiorSkyblockPlugin.java | 1 + .../config/SettingsContainer.java | 17 ++ .../config/SettingsManagerImpl.java | 9 + .../config/section/GlobalSection.java | 5 + .../events/plugin/PluginEventsDispatcher.java | 2 + .../listener/IslandFlagsListener.java | 36 +--- .../listener/ProtectionListener.java | 11 +- .../region/RegionManagerServiceImpl.java | 23 +- .../world/BukkitEntities.java | 19 -- .../world/EntityCategory.java | 138 ------------ .../world/entity/EntityCategories.java | 196 ++++++++++++++++++ .../world/entity/EntityCategory.java | 78 +++++++ src/main/resources/config.yml | 16 +- 14 files changed, 371 insertions(+), 187 deletions(-) delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/EntityCategory.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategories.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategory.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 267f52c040..6bbad68728 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; @@ -748,6 +749,12 @@ public interface SettingsManager { */ boolean isCacheSchematics(); + /** + * Custom entity categories to be used by the plugin. + * Config-path: entity-categories + */ + Map getEntityCategories(); + interface Database { /** diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index a837a54e43..2dcaf09291 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -82,6 +82,7 @@ import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.WorldGenerator; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; +import com.bgsoftware.superiorskyblock.world.entity.EntityCategories; import com.bgsoftware.superiorskyblock.world.schematic.SchematicsManagerImpl; import com.bgsoftware.superiorskyblock.world.schematic.container.DefaultSchematicsContainer; import org.bstats.bukkit.Metrics; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 9fcbb57de3..56db039528 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -233,6 +233,7 @@ public class SettingsContainer { public final boolean chatSigningSupport; public final int commandsPerPage; public final boolean cacheSchematics; + public final Map entityCategories; public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config) throws ManagerLoadException { databaseType = config.getString("database.type").toUpperCase(Locale.ENGLISH); @@ -594,6 +595,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config chatSigningSupport = config.getBoolean("chat-signing-support", true); commandsPerPage = config.getInt("commands-per-page", 7); cacheSchematics = config.getBoolean("cache-schematics", true); + entityCategories = parseEntityCategories(config.getConfigurationSection("entity-categories")); } private List loadClearActions(List clearActionsNames) { @@ -670,6 +672,21 @@ private void loadGenerator(YamlConfiguration config, String path, Dimension dime this.defaultGenerator.put(dimension, KeyMaps.unmodifiableKeyMap(defaultGenerator)); } + private static Map parseEntityCategories(ConfigurationSection section) { + Map entityCategories = new HashMap<>(); + + for (String categoryName : section.getKeys(false)) { + KeySet entityTypes = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); + for (String entityType : section.getStringList(categoryName)) { + entityTypes.add(Keys.ofEntityType(entityType)); + } + if (!entityTypes.isEmpty()) + entityCategories.put(categoryName, KeySets.unmodifiableKeySet(entityTypes)); + } + + return entityCategories.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(entityCategories); + } + private static void loadListOrSection(YamlConfiguration config, String path, String parseName, BiConsumer consumer) { Object value = config.get(path); if (value == null) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index 0a09aea9f1..4ee1b7829b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; @@ -671,6 +672,11 @@ public boolean isCacheSchematics() { return this.global.isCacheSchematics(); } + @Override + public Map getEntityCategories() { + return this.global.getEntityCategories(); + } + public void updateValue(String path, Object value) throws IOException { File file = new File(plugin.getDataFolder(), "config.yml"); @@ -711,6 +717,9 @@ private void loadContainerFromConfig(YamlConfiguration cfg) throws ManagerLoadEx } private void convertData(YamlConfiguration cfg) { + if (!cfg.isConfigurationSection("entity-categories")) { + cfg.createSection("entity-categories"); + } if (cfg.get("protected-message-delay") instanceof Number) { long delay = cfg.getLong("protected-message-delay") * 50; cfg.set("message-delays.ISLAND_PROTECTED", delay); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index aa7c05db99..bfed81f321 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -3,6 +3,7 @@ import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; @@ -409,4 +410,8 @@ public boolean isCacheSchematics() { return getContainer().cacheSchematics; } + public Map getEntityCategories() { + return getContainer().entityCategories; + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java index 6bde85cefc..72d05b411e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java @@ -15,6 +15,7 @@ import com.bgsoftware.superiorskyblock.island.SpawnIsland; import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; +import com.bgsoftware.superiorskyblock.world.entity.EntityCategories; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; @@ -41,6 +42,7 @@ public void registerDefaultListeners() { CmdAdmin.registerCallbacks(this); Message.registerListeners(this); SSuperiorPlayer.registerListeners(this); + EntityCategories.registerListeners(this); } public void registerCallback(PluginEventType type, Runnable callback) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java index 9b3a9843aa..a29825b278 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; @@ -16,6 +17,7 @@ import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.entity.EntityCategory; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -43,9 +45,6 @@ public class IslandFlagsListener extends AbstractGameEventListener { private static final EnumSet NATURAL_SPAWN_REASONS = initializeNaturalSpawnReasons(); - @Nullable - private static final CreatureSpawnEvent.SpawnReason VILLAGE_INVASION = EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "VILLAGE_INVASION"); - private final Int2ObjectMapView originalFireballsDamager = CollectionsFactory.createInt2ObjectArrayMap(); private World spawnIslandWorld; @@ -81,39 +80,26 @@ private void onEntitySpawn(GameEvent e) { } private boolean checkPreventEntitySpawn(GameEvent e, Location entityLocation) { - EntityType entityType = e.getArgs().entity.getType(); CreatureSpawnEvent.SpawnReason spawnReason = e.getArgs().spawnReason; IslandFlag actionFlag; if (spawnReason == CreatureSpawnEvent.SpawnReason.SPAWNER || spawnReason == CreatureSpawnEvent.SpawnReason.SPAWNER_EGG) { - switch (BukkitEntities.getCategory(entityType)) { - case ANIMAL: - actionFlag = IslandFlags.SPAWNER_ANIMALS_SPAWN; - break; - case MONSTER: - actionFlag = IslandFlags.SPAWNER_MONSTER_SPAWN; - break; - default: - return false; - } + EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(e.getArgs().entity)); + if (entityCategory == null) + return false; + actionFlag = entityCategory.getSpawnerSpawnFlag(); } else if (NATURAL_SPAWN_REASONS.contains(spawnReason)) { - switch (BukkitEntities.getCategory(entityType)) { - case ANIMAL: - actionFlag = IslandFlags.NATURAL_ANIMALS_SPAWN; - break; - case MONSTER: - actionFlag = IslandFlags.NATURAL_MONSTER_SPAWN; - break; - default: - return false; - } + EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(e.getArgs().entity)); + if (entityCategory == null) + return false; + actionFlag = entityCategory.getNaturalSpawnFlag(); } else { return false; } - return preventAction(entityLocation, actionFlag); + return actionFlag != null && preventAction(entityLocation, actionFlag); } private boolean checkPreventEggLay(GameEvent e, Location entityLocation) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 5806ea933a..27cdc5cfcb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; +import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; @@ -21,6 +22,7 @@ import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.superiorskyblock.world.BukkitEntities; +import com.bgsoftware.superiorskyblock.world.entity.EntityCategory; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -499,8 +501,12 @@ private void onProjectileHit(GameEvent e) { if (hitEntity == null) return; + EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(entity)); + if (entityCategory == null) + return; + location = hitEntity.getLocation(wrapper.getHandle()); - islandPrivilege = BukkitEntities.getCategory(entity.getType()).getDamagePrivilege(); + islandPrivilege = entityCategory.getDamagePrivilege(); hitBlock = null; } else { hitBlock = e.getArgs().hitBlock; @@ -511,6 +517,9 @@ private void onProjectileHit(GameEvent e) { islandPrivilege = IslandPrivileges.BREAK; } + if (islandPrivilege == null) + return; + interactionResult = this.protectionManager.get().handleCustomInteraction(shooterPlayer, location, islandPrivilege); } if (ProtectionHelper.shouldPreventInteraction(interactionResult, shooterPlayer, true)) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 76bc6f617f..f623300fe9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -35,6 +35,7 @@ import com.bgsoftware.superiorskyblock.service.IService; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.BukkitItems; +import com.bgsoftware.superiorskyblock.world.entity.EntityCategory; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.Material; @@ -204,7 +205,12 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc IslandPrivilege islandPrivilege; if (spawnType != EntityType.UNKNOWN) { - islandPrivilege = BukkitEntities.getCategory(spawnType).getSpawnPrivilege(); + EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(spawnType)); + if (entityCategory == null) + return InteractionResult.SUCCESS; + islandPrivilege = entityCategory.getSpawnPrivilege(); + if (islandPrivilege == null) + return InteractionResult.SUCCESS; } else if (usedItem != null && Materials.isMinecart(usedItem.getType()) ? Materials.isRail(blockType) : Materials.isBoat(blockType)) { islandPrivilege = IslandPrivileges.MINECART_PLACE; } else if (Materials.isChest(blockType)) { @@ -350,8 +356,19 @@ public InteractionResult handleEntityDamage(Entity damager, Entity entity) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); - IslandPrivilege islandPrivilege = BukkitEntities.isTameable(entity) ? IslandPrivileges.TAMED_ANIMAL_DAMAGE : - BukkitEntities.getCategory(entity.getType()).getDamagePrivilege(); + + IslandPrivilege islandPrivilege; + if (BukkitEntities.isTameable(entity)) { + islandPrivilege = IslandPrivileges.TAMED_ANIMAL_DAMAGE; + } else { + EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(entity)); + if (entityCategory == null) + return InteractionResult.SUCCESS; + islandPrivilege = entityCategory.getDamagePrivilege(); + } + + if (islandPrivilege == null) + return InteractionResult.SUCCESS; interactionResult = handleInteractionInternal(damagerSource.get(), entityLocation, islandPrivilege, 0, true, false); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java index 43cba76f9b..bf019c58c1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java @@ -32,7 +32,6 @@ import java.util.Arrays; import java.util.Collections; -import java.util.EnumMap; import java.util.LinkedList; import java.util.List; import java.util.Optional; @@ -44,20 +43,6 @@ public class BukkitEntities { @Nullable private static final EntityType CAMEL_TYPE = EnumHelper.getEnum(EntityType.class, "CAMEL"); - private static final EnumMap ENTITY_CATEGORIES_CACHE = new EnumMap<>(EntityType.class); - - static { - outerLoop: - for (EntityType entityType : EntityType.values()) { - for (EntityCategory entityCategory : EntityCategory.values()) { - if (entityCategory.isFromCategory(entityType)) { - ENTITY_CATEGORIES_CACHE.put(entityType, entityCategory); - continue outerLoop; - } - } - } - } - private BukkitEntities() { } @@ -163,10 +148,6 @@ public static boolean canBypassEntityLimit(Entity entity, boolean checkProviders return false; } - public static EntityCategory getCategory(EntityType entityType) { - return ENTITY_CATEGORIES_CACHE.getOrDefault(entityType, EntityCategory.UNKNOWN); - } - public static boolean isTameable(Entity entity) { return entity instanceof Tameable && ((Tameable) entity).isTamed(); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityCategory.java b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityCategory.java deleted file mode 100644 index 1245d20f9d..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityCategory.java +++ /dev/null @@ -1,138 +0,0 @@ -package com.bgsoftware.superiorskyblock.world; - -import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; -import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import org.bukkit.entity.Ambient; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Flying; -import org.bukkit.entity.Monster; -import org.bukkit.entity.Slime; -import org.bukkit.entity.Vehicle; - -import java.util.EnumSet; -import java.util.function.Predicate; - -public enum EntityCategory { - - MONSTER(IslandPrivileges.MONSTER_DAMAGE, IslandPrivileges.MONSTER_SPAWN) { - - private final EnumSet MONSTER_TYPES = createEntityTypesSet(EntityCategory::isMonsterType); - - @Override - boolean isFromCategory(EntityType entityType) { - return MONSTER_TYPES.contains(entityType); - } - }, - // !!!Never put this above Monster category!!! - ANIMAL(IslandPrivileges.ANIMAL_DAMAGE, IslandPrivileges.ANIMAL_SPAWN) { - - private final EnumSet ANIMAL_TYPES = createEntityTypesSet(EntityCategory::isAnimalType); - - @Override - boolean isFromCategory(EntityType entityType) { - return ANIMAL_TYPES.contains(entityType); - } - }, - PAINTING(IslandPrivileges.PAINTING, IslandPrivileges.BUILD) { - @Override - boolean isFromCategory(EntityType entityType) { - return entityType == EntityType.PAINTING; - } - }, - ITEM_FRAME(IslandPrivileges.ITEM_FRAME, IslandPrivileges.BUILD) { - @Override - boolean isFromCategory(EntityType entityType) { - return entityType == EntityType.ITEM_FRAME; - } - }, - VEHICLE(IslandPrivileges.MINECART_DAMAGE, IslandPrivileges.MINECART_PLACE) { - - private final EnumSet VEHICLE_TYPES = createEntityTypesSet(entityType -> { - Class entityClass = entityType.getEntityClass(); - return entityClass != null && Vehicle.class.isAssignableFrom(entityClass); - }); - - @Override - boolean isFromCategory(EntityType entityType) { - return VEHICLE_TYPES.contains(entityType); - } - }, - UNKNOWN(IslandPrivileges.BREAK, IslandPrivileges.BUILD) { - @Override - boolean isFromCategory(EntityType entityType) { - return true; - } - }; - - private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); - private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); - private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); - - private final IslandPrivilege damagePrivilege; - private final IslandPrivilege spawnPrivilege; - - EntityCategory(IslandPrivilege damagePrivilege, IslandPrivilege spawnPrivilege) { - this.damagePrivilege = damagePrivilege; - this.spawnPrivilege = spawnPrivilege; - } - - public IslandPrivilege getDamagePrivilege() { - return damagePrivilege; - } - - public IslandPrivilege getSpawnPrivilege() { - return spawnPrivilege; - } - - abstract boolean isFromCategory(EntityType entityType); - - private static boolean isAnimalType(EntityType entityType) { - Class entityClass = entityType.getEntityClass(); - // This call is done after Monster category is checked. - // Therefore, the checks below are enough. - return entityClass != null && - // We check that the entity type is whether a Creature or an Ambient - (Creature.class.isAssignableFrom(entityClass) || Ambient.class.isAssignableFrom(entityClass)) && - // We make sure this is not Hoglin; In Bukkit, they are considered Animals. - entityClass != HOGLIN_CLASS && - // We make sure this is not Skeleton/Zombie horses; In Bukkit, they are considered Animals. - entityClass != SKELETON_HORSE_CLASS && entityClass != ZOMBIE_HORSE_CLASS; - } - - private static boolean isMonsterType(EntityType entityType) { - Class entityClass = entityType.getEntityClass(); - return entityClass != null && (Monster.class.isAssignableFrom(entityClass) || - // Checks for slimes & magma cubes - Slime.class.isAssignableFrom(entityClass) || - // Checks for ghasts and phantoms - Flying.class.isAssignableFrom(entityClass) || - // In Bukkit, Hoglins are considered as Animals for no reason. - // We want to explicitly tell the plugin its monster type. - entityClass == HOGLIN_CLASS || - // In Bukkit, Skeleton and Zombie horses are considered Horses, - // and therefore they are animals. We want to explicit tell the plugin - // they are monsters. - entityClass == SKELETON_HORSE_CLASS || entityClass == ZOMBIE_HORSE_CLASS - ); - } - - private static EnumSet createEntityTypesSet(Predicate predicate) { - EnumSet entityTypes = EnumSet.noneOf(EntityType.class); - for (EntityType entityType : EntityType.values()) { - if (predicate.test(entityType)) - entityTypes.add(entityType); - } - return entityTypes; - } - - private static Class getEntityTypeClass(String clazz) { - try { - return Class.forName(clazz); - } catch (ClassNotFoundException error) { - return null; - } - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategories.java b/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategories.java new file mode 100644 index 0000000000..3224929ef7 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategories.java @@ -0,0 +1,196 @@ +package com.bgsoftware.superiorskyblock.world.entity; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.IslandFlag; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.set.KeySets; +import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import org.bukkit.entity.Ambient; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Flying; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Slime; +import org.bukkit.entity.Vehicle; + +import java.util.Map; +import java.util.function.Predicate; + +public class EntityCategories { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); + private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); + private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); + + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, EntityCategories::onSettingsUpdate); + } + + private static void onSettingsUpdate() { + EntityCategory.clear(); + + // Load built-in categories with low priority + new Builder("ANIMAL", createEntityTypesSet(EntityCategories::isAnimalType)) + .spawnerSpawnFlag(IslandFlags.SPAWNER_ANIMALS_SPAWN).naturalSpawnFlag(IslandFlags.NATURAL_ANIMALS_SPAWN).build(); + new Builder("MONSTER", createEntityTypesSet(EntityCategories::isMonsterType)).build(); + + // Load config categories, which can override the categories above + Map entityCategories = plugin.getSettings().getEntityCategories(); + entityCategories.forEach((name, entityTypes) -> { + new Builder(name, entityTypes).build(); + }); + + // Register built-in categories with high priority + new Builder("PAINTING", createEntityTypesSet(EntityType.PAINTING)) + .damagePrivilege(IslandPrivileges.PAINTING).spawnPrivilege(IslandPrivileges.BUILD) + .naturalSpawnFlag(null).spawnerSpawnFlag(null).build(); + new Builder("ITEM_FRAME", createEntityTypesSet(EntityType.ITEM_FRAME)) + .damagePrivilege(IslandPrivileges.ITEM_FRAME).spawnPrivilege(IslandPrivileges.BUILD) + .naturalSpawnFlag(null).spawnerSpawnFlag(null).build(); + new Builder("VEHICLE", createEntityTypesSet(EntityCategories::isVehicleType)) + .damagePrivilege(IslandPrivileges.MINECART_DAMAGE).spawnPrivilege(IslandPrivileges.MINECART_PLACE) + .naturalSpawnFlag(null).spawnerSpawnFlag(null).build(); + } + + private EntityCategories() { + + } + + private static boolean isAnimalType(EntityType entityType) { + Class entityClass = entityType.getEntityClass(); + // This call is done after Monster category is checked. + // Therefore, the checks below are enough. + return entityClass != null && + // We check that the entity type is whether a Creature or an Ambient + (Creature.class.isAssignableFrom(entityClass) || Ambient.class.isAssignableFrom(entityClass)) && + // We make sure this is not Hoglin; In Bukkit, they are considered Animals. + entityClass != HOGLIN_CLASS && + // We make sure this is not Skeleton/Zombie horses; In Bukkit, they are considered Animals. + entityClass != SKELETON_HORSE_CLASS && entityClass != ZOMBIE_HORSE_CLASS; + } + + private static boolean isMonsterType(EntityType entityType) { + Class entityClass = entityType.getEntityClass(); + return entityClass != null && (Monster.class.isAssignableFrom(entityClass) || + // Checks for slimes & magma cubes + Slime.class.isAssignableFrom(entityClass) || + // Checks for ghasts and phantoms + Flying.class.isAssignableFrom(entityClass) || + // In Bukkit, Hoglins are considered as Animals for no reason. + // We want to explicitly tell the plugin its monster type. + entityClass == HOGLIN_CLASS || + // In Bukkit, Skeleton and Zombie horses are considered Horses, + // and therefore they are animals. We want to explicit tell the plugin + // they are monsters. + entityClass == SKELETON_HORSE_CLASS || entityClass == ZOMBIE_HORSE_CLASS + ); + } + + private static boolean isVehicleType(EntityType entityType) { + Class entityClass = entityType.getEntityClass(); + return entityClass != null && Vehicle.class.isAssignableFrom(entityClass) && !Creature.class.isAssignableFrom(entityClass); + } + + private static KeySet createEntityTypesSet(Predicate predicate) { + KeySet entityTypes = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); + for (EntityType entityType : EntityType.values()) { + if (predicate.test(entityType)) + entityTypes.add(Keys.of(entityType)); + } + return entityTypes; + } + + private static KeySet createEntityTypesSet(EntityType entityType) { + KeySet entityTypes = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); + entityTypes.add(Keys.of(entityType)); + return entityTypes; + } + + private static Class getEntityTypeClass(String clazz) { + try { + return Class.forName(clazz); + } catch (ClassNotFoundException error) { + return null; + } + } + + private static IslandPrivilege getOrRegisterPrivilege(@Nullable String name) { + if (name == null) + return null; + + try { + return IslandPrivilege.getByName(name); + } catch (NullPointerException error) { + IslandPrivilege.register(name); + return IslandPrivilege.getByName(name); + } + } + + private static IslandFlag getOrRegisterFlag(@Nullable String name) { + if (name == null) + return null; + + try { + return IslandFlag.getByName(name); + } catch (NullPointerException error) { + IslandFlag.register(name); + return IslandFlag.getByName(name); + } + } + + private static class Builder { + + private final KeySet entityTypes; + + private String damagePrivilege; + private String spawnPrivilege; + private String spawnerSpawnFlag; + private String naturalSpawnFlag; + + public Builder(String name, KeySet entityTypes) { + this.entityTypes = entityTypes; + this.damagePrivilege = name + "_DAMAGE"; + this.spawnPrivilege = name + "_SPAWN"; + this.spawnerSpawnFlag = "SPAWNER_" + name + "_SPAWN"; + this.naturalSpawnFlag = "NATURAL_" + name + "_SPAWN"; + } + + public Builder damagePrivilege(@Nullable IslandPrivilege damagePrivilege) { + this.damagePrivilege = damagePrivilege == null ? null : damagePrivilege.getName(); + return this; + } + + public Builder spawnPrivilege(@Nullable IslandPrivilege spawnPrivilege) { + this.spawnPrivilege = spawnPrivilege == null ? null : spawnPrivilege.getName(); + return this; + } + + public Builder spawnerSpawnFlag(@Nullable IslandFlag spawnerSpawnFlag) { + this.spawnerSpawnFlag = spawnerSpawnFlag == null ? null : spawnerSpawnFlag.getName(); + return this; + } + + public Builder naturalSpawnFlag(@Nullable IslandFlag naturalSpawnFlag) { + this.naturalSpawnFlag = naturalSpawnFlag == null ? null : naturalSpawnFlag.getName(); + return this; + } + + public EntityCategory build() { + return EntityCategory.register(this.entityTypes, + getOrRegisterPrivilege(this.damagePrivilege), getOrRegisterPrivilege(this.spawnPrivilege), + getOrRegisterFlag(this.spawnerSpawnFlag), getOrRegisterFlag(this.naturalSpawnFlag)); + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategory.java b/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategory.java new file mode 100644 index 0000000000..424cf8fd29 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategory.java @@ -0,0 +1,78 @@ +package com.bgsoftware.superiorskyblock.world.entity; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.island.IslandFlag; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.google.common.base.Preconditions; + +public class EntityCategory { + + private static final KeyMap entityToCategories = KeyMaps.createHashMap(KeyIndicator.ENTITY_TYPE); + + @Nullable + private final IslandPrivilege damagePrivilege; + @Nullable + private final IslandPrivilege spawnPrivilege; + @Nullable + private final IslandFlag spawnerSpawnFlag; + @Nullable + private final IslandFlag naturalSpawnFlag; + + private EntityCategory(KeySet entityTypes, @Nullable IslandPrivilege damagePrivilege, + @Nullable IslandPrivilege spawnPrivilege, @Nullable IslandFlag spawnerSpawnFlag, + @Nullable IslandFlag naturalSpawnFlag) { + this.damagePrivilege = damagePrivilege; + this.spawnPrivilege = spawnPrivilege; + this.spawnerSpawnFlag = spawnerSpawnFlag; + this.naturalSpawnFlag = naturalSpawnFlag; + setCategoryForEntities(entityTypes); + } + + private void setCategoryForEntities(KeySet entityTypes) { + for (Key entityType : entityTypes) { + entityToCategories.put(entityType, this); + } + } + + @Nullable + public IslandPrivilege getDamagePrivilege() { + return damagePrivilege; + } + + @Nullable + public IslandPrivilege getSpawnPrivilege() { + return spawnPrivilege; + } + + @Nullable + public IslandFlag getSpawnerSpawnFlag() { + return spawnerSpawnFlag; + } + + @Nullable + public IslandFlag getNaturalSpawnFlag() { + return naturalSpawnFlag; + } + + @Nullable + public static EntityCategory getEntityCategory(Key entityType) { + return entityToCategories.get(entityType); + } + + public static EntityCategory register(KeySet entityTypes, @Nullable IslandPrivilege damagePrivilege, + @Nullable IslandPrivilege spawnPrivilege, @Nullable IslandFlag spawnerSpawnFlag, + @Nullable IslandFlag naturalSpawnFlag) { + Preconditions.checkNotNull(entityTypes, "entityTypes parameter cannot be null."); + return new EntityCategory(entityTypes, damagePrivilege, spawnPrivilege, spawnerSpawnFlag, naturalSpawnFlag); + } + + public static void clear() { + entityToCategories.clear(); + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 7082c7834c..24d9aba519 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -926,4 +926,18 @@ chat-signing-support: true # Amount of commands to be listed in the `/is help` and `/is admin` commands. # Setting this to 0 or below will result all commands to be shown in a single page. -commands-per-page: 7 \ No newline at end of file +commands-per-page: 7 + +# Configure custom entity categories. +# By default, there are two entity categories - ANIMALS and MONSTER +# You can add your own custom categories in here, and configure which entities are part of the category. +# Entities in the custom categories will have custom privileges and flags for damaging and spawning them. +# You can add the custom privileges and island flags manually to the menus. +# For example: +# entity-categories: +# VILLAGERS: +# - VILLAGER +# The `VILLAGERS` category will have VILLAGER entities in it. +# The privileges `VILLAGERS_SPAWN` and `VILLAGERS_DAMAGE` will be required by players, and the island flags +# `SPAWNER_VILLAGERS_SPAWN` and `NATURAL_VILLAGERS_SPAWN` will be required to be enabled for the island. +entity-categories: { } \ No newline at end of file From 15c800aa09be7a1a9a2944e3b18ab835bd0dd5cb Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Thu, 30 Oct 2025 21:37:38 +0100 Subject: [PATCH 405/600] Added the ability to create infinite missions (#2738) --- .../com/bgsoftware/superiorskyblock/island/SIsland.java | 9 +++++++-- .../superiorskyblock/player/SSuperiorPlayer.java | 9 +++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 546fbc0ee3..7a417c989b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -4760,8 +4760,13 @@ public boolean canCompleteMissionAgain(Mission mission) { return false; Optional missionDataOptional = plugin.getMissions().getMissionData(mission); - return missionDataOptional.isPresent() && getAmountMissionCompleted(mission) < - missionDataOptional.get().getResetAmount(); + + if (missionDataOptional.isPresent()) { + int resetAmount = missionDataOptional.get().getResetAmount(); + return resetAmount <= 0 || getAmountMissionCompleted(mission) < resetAmount; + } + + return false; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index b784628e3b..959a162f94 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -1047,8 +1047,13 @@ public boolean canCompleteMissionAgain(Mission mission) { return false; Optional missionDataOptional = plugin.getMissions().getMissionData(mission); - return missionDataOptional.isPresent() && getAmountMissionCompleted(mission) < - missionDataOptional.get().getResetAmount(); + + if (missionDataOptional.isPresent()) { + int resetAmount = missionDataOptional.get().getResetAmount(); + return resetAmount <= 0 || getAmountMissionCompleted(mission) < resetAmount; + } + + return false; } @Override From fe9d72ed3ca8d59287588103a72a4b8c28627ada Mon Sep 17 00:00:00 2001 From: nivcoo <36514752+nivcoo@users.noreply.github.com> Date: Fri, 31 Oct 2025 10:38:57 +0100 Subject: [PATCH 406/600] improv. add more variables on the global warps menu (#2746) --- .../impl/GlobalWarpsPagedObjectButton.java | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java index ec0401a4d1..c034cdc29d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java @@ -3,6 +3,9 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; import com.bgsoftware.superiorskyblock.core.menu.button.AbstractPagedMenuButton; @@ -12,8 +15,13 @@ import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; +import java.util.Locale; +import java.util.Map; + public class GlobalWarpsPagedObjectButton extends AbstractPagedMenuButton { + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + private GlobalWarpsPagedObjectButton(MenuTemplateButton templateButton, MenuGlobalWarps.View menuView) { super(templateButton, menuView); } @@ -32,11 +40,42 @@ public void onButtonClick(InventoryClickEvent clickEvent) { @Override public ItemStack modifyViewItem(ItemStack buttonItem) { + final SuperiorPlayer viewer = menuView.getInventoryViewer(); + final SuperiorPlayer owner = pagedObject.getOwner(); + final String ownerName = owner.getName(); + String islandName = pagedObject.getName(); + if (Text.isBlank(islandName)) islandName = ownerName; + + final int warpsCount = pagedObject.getIslandWarps().size(); + + Locale userLocale = viewer.getUserLocale(); + String levelNum = Formatters.NUMBER_FORMATTER.format(pagedObject.getIslandLevel()); + String worthNum = Formatters.NUMBER_FORMATTER.format(pagedObject.getWorth()); + String levelFancy = Formatters.FANCY_NUMBER_FORMATTER.format(pagedObject.getIslandLevel(), userLocale); + String worthFancy = Formatters.FANCY_NUMBER_FORMATTER.format(pagedObject.getWorth(), userLocale); + + int ratingCount = pagedObject.getRatingAmount(); + + String ratingAvgNum = Formatters.NUMBER_FORMATTER.format(pagedObject.getTotalRating()); + String ratingAvgFancy = Formatters.RATING_FORMATTER.format(pagedObject.getTotalRating(), userLocale); + + String[] descLines = Text.isBlank(pagedObject.getDescription()) + ? EMPTY_STRING_ARRAY + : pagedObject.getDescription().split("\n"); + return new ItemBuilder(buttonItem) .asSkullOf(pagedObject.getOwner()) - .replaceAll("{0}", pagedObject.getOwner().getName()) - .replaceLoreWithLines("{1}", pagedObject.getDescription().split("\n")) - .replaceAll("{2}", pagedObject.getIslandWarps().size() + "") + .replaceAll("{0}", ownerName) + .replaceLoreWithLines("{1}", descLines) + .replaceAll("{2}", String.valueOf(warpsCount)) + .replaceAll("{3}", islandName) + .replaceAll("{4}", levelNum) + .replaceAll("{5}", levelFancy) + .replaceAll("{6}", worthNum) + .replaceAll("{7}", worthFancy) + .replaceAll("{8}", ratingAvgNum) + .replaceAll("{9}", ratingAvgFancy) + .replaceAll("{10}", String.valueOf(ratingCount)) .build(pagedObject.getOwner()); } From 60fcce25295df93db5cee235b26807f94dfad767 Mon Sep 17 00:00:00 2001 From: Ome_R Date: Sat, 1 Nov 2025 16:10:53 +0200 Subject: [PATCH 407/600] Log messages to log files (#2751) --- .../api/modules/ModuleInitializeData.java | 27 +++ .../api/modules/ModuleLogger.java | 48 ++++ .../api/modules/PluginModule.java | 49 +++- .../superiorskyblock/core/logging/Log.java | 46 ++-- .../module/BuiltinModule.java | 6 +- .../container/DefaultModulesContainer.java | 42 +++- .../logging/ModuleLoggerFileHandler.java | 212 ++++++++++++++++++ .../module/missions/MissionsModule.java | 19 +- .../module/upgrades/UpgradesModule.java | 6 +- .../module/upgrades/commands/CmdRankup.java | 4 +- 10 files changed, 413 insertions(+), 46 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleInitializeData.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/module/logging/ModuleLoggerFileHandler.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleInitializeData.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleInitializeData.java new file mode 100644 index 0000000000..83c0973a0a --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleInitializeData.java @@ -0,0 +1,27 @@ +package com.bgsoftware.superiorskyblock.api.modules; + +import java.io.File; + +/** + * All the data needed for a {@link PluginModule} to be initialized correctly. + */ +public interface ModuleInitializeData { + + /** + * The data folder of the module. + * Should return plugins/SuperiorSkyblock2/datastore/modules/{module-name} + */ + File getDataFolder(); + + /** + * The folder of the module. + * Should return plugins/SuperiorSkyblock2/modules/{module-name} + */ + File getModuleFolder(); + + /** + * The logger of the module. + */ + ModuleLogger getLogger(); + +} diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleLogger.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleLogger.java index 4b27618486..7a12ae93a2 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleLogger.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleLogger.java @@ -2,7 +2,12 @@ import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.logging.FileHandler; +import java.util.logging.Handler; import java.util.logging.Level; +import java.util.logging.LogRecord; import java.util.logging.Logger; /** @@ -10,6 +15,8 @@ */ public class ModuleLogger extends Logger { + private boolean debugMode = false; + /** * Constructor for the logger. * @@ -21,4 +28,45 @@ public ModuleLogger(PluginModule pluginModule) { this.setLevel(Level.ALL); } + public void setDebugMode(boolean debugMode) { + this.debugMode = debugMode; + } + + public void i(String message) { + super.info(message); + } + + public void w(String message) { + super.warning(message); + } + + public void e(String message) { + super.severe(message); + } + + public void e(String message, Throwable error) { + super.severe(message); + logError(error); + } + + public void d(String message) { + if (this.debugMode) { + this.info(message); + } else { + LogRecord logRecord = new LogRecord(Level.INFO, message); + for (Handler handler : getHandlers()) { + if (handler instanceof FileHandler) { + handler.publish(logRecord); + } + } + } + } + + private void logError(Throwable error) { + StringWriter buffer = new StringWriter(); + PrintWriter pw = new PrintWriter(buffer); + error.printStackTrace(pw); + super.severe(buffer.toString()); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/PluginModule.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/PluginModule.java index fab2ae8a08..f7787bda79 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/PluginModule.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/PluginModule.java @@ -7,7 +7,6 @@ import java.io.File; import java.io.InputStream; -import java.util.logging.Logger; /** * Plugin modules are similar to plugins. The difference between them and regular plugins is that the modules are @@ -25,7 +24,7 @@ public abstract class PluginModule { private File moduleFile; private File moduleFolder; private ClassLoader classLoader; - private Logger logger; + private ModuleLogger logger; private ModuleResources moduleResources; private boolean initialized = false; @@ -195,7 +194,7 @@ public final ClassLoader getClassLoader() { /** * Get the logger of the module {@link ModuleLogger} */ - public final Logger getLogger() { + public final ModuleLogger getLogger() { return logger; } @@ -251,21 +250,49 @@ public final void initModule(SuperiorSkyblock plugin, File dataFolder) { * @param dataFolder The database folder of the module. * @param moduleFolder The folder of the module. */ + @Deprecated public final void initModule(SuperiorSkyblock plugin, File moduleFolder, File dataFolder) { - if (initialized) - throw new RuntimeException("The module " + moduleName + " was already initialized."); + ModuleLogger moduleLogger = new ModuleLogger(this); + this.initModule(plugin, new ModuleInitializeData() { + @Override + public File getDataFolder() { + return dataFolder; + } + + @Override + public File getModuleFolder() { + return moduleFolder; + } + + @Override + public ModuleLogger getLogger() { + return moduleLogger; + } + }); + } - initialized = true; + /** + * Initialize the module. + * This method cannot be called twice - do not call it unless you know what you are doing. + * + * @param plugin An instance to the plugin. + * @param context The initialize context. + */ + public final void initModule(SuperiorSkyblock plugin, ModuleInitializeData context) { + if (this.initialized) + throw new RuntimeException("The module " + this.moduleName + " was already initialized."); - this.dataFolder = dataFolder; - this.moduleFolder = moduleFolder; + this.initialized = true; + File moduleFolder = context.getModuleFolder(); if (!moduleFolder.exists() && !moduleFolder.mkdirs()) - throw new RuntimeException("Cannot create module folder for " + moduleName + "."); + throw new RuntimeException("Cannot create module folder for " + this.moduleName + "."); - this.logger = new ModuleLogger(this); + this.dataFolder = context.getDataFolder(); + this.moduleFolder = moduleFolder; + this.logger = context.getLogger(); - if (moduleFile != null && classLoader != null) + if (this.moduleFile != null && this.classLoader != null) this.moduleResources = new ModuleResources(this.moduleFile, this.moduleFolder, this.classLoader); onPluginInit(plugin); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Log.java b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Log.java index ffcd428496..d921d5a12c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Log.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/logging/Log.java @@ -2,28 +2,40 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.module.logging.ModuleLoggerFileHandler; +import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.EnumSet; import java.util.logging.Level; +import java.util.logging.Logger; public class Log { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final Logger LOGGER = initializeLogger(); private static final EnumSet DEBUG_FILTERS = EnumSet.noneOf(Debug.class); private static boolean debugMode = false; - private static final ThreadLocal originalStackTrace = new ThreadLocal<>(); - private Log() { + private static Logger initializeLogger() { + Logger logger = Logger.getLogger("SuperiorSkyblock2"); - } + logger.setParent(plugin.getLogger()); + logger.setUseParentHandlers(true); + + File logsFolder = new File(plugin.getDataFolder(), "logs"); + File archiveLogsFile = new File(logsFolder, "archive"); + + ModuleLoggerFileHandler.addToLogger(logsFolder, archiveLogsFile, logger); - public static void attachStackTrace(StackTrace stackTrace) { - originalStackTrace.set(stackTrace); + return logger; } - public static void detachStackTrace() { - originalStackTrace.set(null); + private Log() { + } public static void info(Object first, Object... parts) { @@ -44,7 +56,7 @@ public static void error(Object first, Object... parts) { public static void error(Throwable error, Object first, Object... parts) { error(first, parts); - error.printStackTrace(); + printStackTrace(error); } public static void errorFromFile(String fileName, Object first, Object... parts) { @@ -53,7 +65,7 @@ public static void errorFromFile(String fileName, Object first, Object... parts) public static void errorFromFile(Throwable error, String fileName, Object first, Object... parts) { errorFromFile(fileName, first, parts); - error.printStackTrace(); + printStackTrace(error); } public static void profile(String[] profiledDataLines) { @@ -117,11 +129,11 @@ private static void enteringInternal(Level level, String clazz, String method, @ } private static void logInternalWithFile(Level level, String fileName, Object first, Object... parts) { - plugin.getLogger().log(level, buildFromPartsWithFile(fileName, first, parts)); + LOGGER.log(level, buildFromPartsWithFile(fileName, first, parts)); } private static void logInternal(Level level, Object first, Object... parts) { - plugin.getLogger().log(level, buildFromParts(first, parts)); + LOGGER.log(level, buildFromParts(first, parts)); } private static String buildFromParts(Object first, Object... parts) { @@ -152,10 +164,14 @@ private static String[] getClassAndMethodNames() { } private static void printStackTrace() { - Thread.dumpStack(); - StackTrace originalStackTrace = Log.originalStackTrace.get(); - if (originalStackTrace != null) - originalStackTrace.dump(); + printStackTrace(new Exception("Stack trace")); + } + + private static void printStackTrace(Throwable error) { + StringWriter buffer = new StringWriter(); + PrintWriter pw = new PrintWriter(buffer); + error.printStackTrace(pw); + LOGGER.log(Level.SEVERE, buffer.toString()); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java index 8c2e2fed97..42e1a7902b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java @@ -6,7 +6,6 @@ import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import com.bgsoftware.superiorskyblock.core.io.Resources; -import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.event.Listener; import java.io.File; @@ -96,7 +95,7 @@ protected void onPluginInit(SuperiorSkyblockPlugin plugin) { try { config.save(configFile); } catch (Exception error) { - Log.error(error, "An error occurred while saving config file for module " + getName() + ":"); + getLogger().e("An error occurred while saving config file for module " + getName() + ":", error); } } @@ -105,8 +104,7 @@ protected void onPluginInit(SuperiorSkyblockPlugin plugin) { Resources.getResource("modules/" + getName() + "/config.yml"), getIgnoredSections()); } catch (Exception error) { - Log.entering(getClass().getName(), "onPluginInit", "ENTER", ""); - Log.error(error, "An error occurred while loading config file:"); + getLogger().e("An error occurred while loading config file:", error); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java index 90c16afe4e..1d08ae740b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java @@ -2,11 +2,14 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.modules.ModuleInitializeData; +import com.bgsoftware.superiorskyblock.api.modules.ModuleLogger; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.module.ModuleData; +import com.bgsoftware.superiorskyblock.module.logging.ModuleLoggerFileHandler; import com.google.common.base.Preconditions; import org.bukkit.event.HandlerList; @@ -23,9 +26,13 @@ public class DefaultModulesContainer implements ModulesContainer { private final Map modulesData = new ArrayMap<>(); private final SuperiorSkyblockPlugin plugin; + private final File globalLogsFolder; + private final File globalArchiveLogsFolder; public DefaultModulesContainer(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; + this.globalLogsFolder = new File(plugin.getDataFolder(), "logs" + File.separator + "modules"); + this.globalArchiveLogsFolder = new File(plugin.getDataFolder(), "logs" + File.separator + "archive"); } @Override @@ -36,9 +43,14 @@ public void registerModule(PluginModule pluginModule, File modulesFolder, File m File dataFolder = new File(modulesDataFolder, pluginModule.getName()); File moduleFolder = new File(modulesFolder, pluginModule.getName()); + File logsFolder = new File(this.globalLogsFolder, pluginModule.getName()); + + ModuleLogger moduleLogger = new ModuleLogger(pluginModule); + ModuleLoggerFileHandler.addToLogger(logsFolder, this.globalArchiveLogsFolder, moduleLogger); try { - pluginModule.initModule(plugin, moduleFolder, dataFolder); + ModuleInitializeDataImpl context = new ModuleInitializeDataImpl(dataFolder, moduleFolder, moduleLogger); + pluginModule.initModule(plugin, context); } catch (Throwable error) { Log.error("An unexpected error occurred while initializing the module ", pluginModule.getName(), "."); Log.error(error, "Contact ", pluginModule.getAuthor(), " regarding this, this has nothing to do with the plugin."); @@ -90,4 +102,32 @@ public ModuleData getModuleData(PluginModule module) { return this.modulesData.get(module); } + private static class ModuleInitializeDataImpl implements ModuleInitializeData { + + private final File dataFolder; + private final File moduleFolder; + private final ModuleLogger logger; + + public ModuleInitializeDataImpl(File dataFolder, File moduleFolder, ModuleLogger logger) { + this.dataFolder = dataFolder; + this.moduleFolder = moduleFolder; + this.logger = logger; + } + + @Override + public File getDataFolder() { + return this.dataFolder; + } + + @Override + public File getModuleFolder() { + return this.moduleFolder; + } + + @Override + public ModuleLogger getLogger() { + return this.logger; + } + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/logging/ModuleLoggerFileHandler.java b/src/main/java/com/bgsoftware/superiorskyblock/module/logging/ModuleLoggerFileHandler.java new file mode 100644 index 0000000000..396ad62332 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/logging/ModuleLoggerFileHandler.java @@ -0,0 +1,212 @@ +package com.bgsoftware.superiorskyblock.module.logging; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.attribute.FileTime; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.ZoneOffset; +import java.util.Date; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.logging.FileHandler; +import java.util.logging.Formatter; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +public class ModuleLoggerFileHandler { + + private static final SimpleDateFormat ARCHIVE_DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy"); + private static final Path BASE_LOGS_FOLDER = new File(SuperiorSkyblockPlugin.getPlugin().getDataFolder(), "logs").toPath(); + + public static Logger addToLogger(File logsFolder, File archiveFolder, Logger logger) { + try { + logsFolder.mkdirs(); + + File logsFile = new File(logsFolder, "latest.log"); + + long startOfDayTime = LocalDate.now().atStartOfDay(ZoneOffset.systemDefault()).toEpochSecond() * 1000; + + if (logsFile.exists() && logsFile.lastModified() < startOfDayTime) { + // Save old file + File dateLogsFileZipped = new File(archiveFolder, ARCHIVE_DATE_FORMAT.format(new Date(logsFile.lastModified())) + ".zip"); + zipLogsFile(logsFile, BASE_LOGS_FOLDER.relativize(logsFile.toPath()).toString(), dateLogsFileZipped); + } + + AsyncFileHandler asyncFileHandler = new AsyncFileHandler(archiveFolder); + asyncFileHandler.setFile(logsFile); + asyncFileHandler.setLevel(Level.ALL); + + logger.addHandler(asyncFileHandler); + } catch (IOException error) { + error.printStackTrace(); + } + + return logger; + } + + private static void zipLogsFile(File file, String name, File zipFile) { + zipFile.getParentFile().mkdirs(); + + try { + File tempFile = new File(zipFile.getAbsolutePath() + ".tmp"); + + byte[] buffer = new byte[1024]; + + try (ZipInputStream zis = zipFile.exists() ? new ZipInputStream(new FileInputStream(zipFile)) : null; + ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tempFile))) { + + ZipEntry entry; + + if (zis != null) { + // Copy existing entries + while ((entry = zis.getNextEntry()) != null) { + ZipEntry newEntry = new ZipEntry(entry.getName()); + zos.putNextEntry(newEntry); + newEntry.setLastModifiedTime(entry.getLastModifiedTime()); + int len; + while ((len = zis.read(buffer)) != -1) { + zos.write(buffer, 0, len); + } + zos.closeEntry(); + } + } + + // Create new zip entry + ZipEntry zipEntry = new ZipEntry(name); + zos.putNextEntry(zipEntry); + zipEntry.setLastModifiedTime(FileTime.fromMillis(file.lastModified())); + zipEntry.setLastAccessTime(FileTime.fromMillis(file.lastModified())); + try (FileInputStream input = new FileInputStream(file)) { + int length; + while ((length = input.read(buffer)) >= 0) { + zos.write(buffer, 0, length); + } + } + zos.closeEntry(); + } finally { + zipFile.delete(); + tempFile.renameTo(zipFile); + } + } catch (Throwable error) { + error.printStackTrace(); + } + + file.delete(); + } + + private static class AsyncFileHandler extends FileHandler { + + private final BlockingQueue queue = new LinkedBlockingQueue<>(10000); + private final Thread worker; + private final File archiveFolder; + + private FileHandler fileHandler; + private File logsFile; + + private volatile boolean running = true; + + private volatile long nextDayTime; + + private AsyncFileHandler(File archiveFolder) throws IOException { + this.archiveFolder = archiveFolder; + + calculateTimeOfNextDay(); + + this.worker = new Thread(() -> { + try { + while (running || !queue.isEmpty()) { + LogRecord record = queue.poll(100, TimeUnit.MILLISECONDS); + if (record != null) { + if (System.currentTimeMillis() > nextDayTime) { + // Upgrade file + nextDayLogsFile(); + } + + fileHandler.publish(record); + } + } + } catch (InterruptedException ignored) { + } finally { + fileHandler.flush(); + fileHandler.close(); + } + }, "AsyncLoggerThread"); + + this.worker.setDaemon(true); + this.worker.start(); + } + + private void calculateTimeOfNextDay() { + this.nextDayTime = LocalDate.now().plusDays(1).atStartOfDay(ZoneOffset.systemDefault()).toEpochSecond() * 1000; + } + + public void setFile(File file) throws IOException { + file.createNewFile(); + this.fileHandler = new FileHandler(file.getAbsolutePath(), true); + this.fileHandler.setFormatter(new DebugFormatter()); + this.logsFile = file; + } + + private void nextDayLogsFile() { + this.fileHandler.close(); + this.fileHandler = null; + + File dateLogsFileZipped = new File(archiveFolder, ARCHIVE_DATE_FORMAT.format(new Date(logsFile.lastModified())) + ".zip"); + zipLogsFile(logsFile, BASE_LOGS_FOLDER.relativize(logsFile.toPath()).toString(), dateLogsFileZipped); + + try { + setFile(this.logsFile); + } catch (Throwable error) { + error.printStackTrace(); + } + + calculateTimeOfNextDay(); + } + + @Override + public void publish(LogRecord record) { + if (!running) return; + this.queue.offer(record); + } + + @Override + public void flush() { + this.fileHandler.flush(); + } + + @Override + public void close() throws SecurityException { + running = false; + try { + this.worker.join(1000); + } catch (InterruptedException ignored) { + } + } + + } + + private static class DebugFormatter extends Formatter { + + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm:ss"); + + @Override + public String format(LogRecord record) { + String time = DATE_FORMAT.format(new Date(record.getMillis())); + String level = record.getLevel().getLocalizedName(); + return String.format("[%s %s]: %s%n", time, level, formatMessage(record)); + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java index 6ca88f9722..75aa45e550 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java @@ -10,7 +10,6 @@ import com.bgsoftware.superiorskyblock.core.io.Resources; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookup; import com.bgsoftware.superiorskyblock.core.io.loader.FilesLookupFactory; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; import com.bgsoftware.superiorskyblock.core.menu.MenuPatternSlots; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuIslandMembers; @@ -170,12 +169,12 @@ private boolean canLoadCategory(String categoryName, List> categoryMi File categoryFolder = new File(getModuleFolder(), "categories/" + categoryName); if (!categoryFolder.exists()) { - Log.warn("The directory of the mission category ", categoryName, " doesn't exist, skipping..."); + getLogger().w("The directory of the mission category " + categoryName + " doesn't exist, skipping..."); return false; } if (!categoryFolder.isDirectory()) { - Log.warn("The directory of the mission category ", categoryName, " is not valid, skipping..."); + getLogger().w("The directory of the mission category " + categoryName + " is not valid, skipping..."); return false; } @@ -183,7 +182,7 @@ private boolean canLoadCategory(String categoryName, List> categoryMi file.isFile() && file.getName().endsWith(".yml")); if (missionFiles == null || missionFiles.length == 0) { - Log.warn("The mission category ", categoryName, " doesn't have missions, skipping..."); + getLogger().w("The mission category " + categoryName + " doesn't have missions, skipping..."); return false; } @@ -201,10 +200,10 @@ private boolean canLoadCategory(String categoryName, List> categoryMi try { missionConfigFile.load(missionFile); } catch (InvalidConfigurationException error) { - Log.error(error, "A format-error occurred while parsing the mission file ", missionFile.getName() + ":"); + getLogger().e("A format-error occurred while parsing the mission file " + missionFile.getName() + ":", error); continue; } catch (IOException error) { - Log.error(error, "An unexpected error occurred while parsing the mission file ", missionFile.getName() + ":"); + getLogger().e("An unexpected error occurred while parsing the mission file " + missionFile.getName() + ":", error); continue; } @@ -220,7 +219,7 @@ private boolean canLoadCategory(String categoryName, List> categoryMi } if (categoryMissions.isEmpty()) { - Log.warn("The mission category ", categoryName, " doesn't have missions, skipping..."); + getLogger().w("The mission category " + categoryName + " doesn't have missions, skipping..."); return false; } @@ -281,7 +280,7 @@ private boolean convertNonCategorizedMissions(SuperiorSkyblockPlugin plugin, Yam try { missionFile.createNewFile(); } catch (IOException error) { - Log.error(error, "An unexpected error occurred while converting non-categorized mission ", missionName, ":"); + getLogger().e("An unexpected error occurred while converting non-categorized mission " + missionName + ":", error); continue; } @@ -291,7 +290,7 @@ private boolean convertNonCategorizedMissions(SuperiorSkyblockPlugin plugin, Yam try { missionConfigFile.save(missionFile); } catch (Exception error) { - Log.error(error, "An unexpected error occurred while saving non-categorized mission ", missionName, ":"); + getLogger().e("An unexpected error occurred while saving non-categorized mission " + missionName + ":", error); } } @@ -340,7 +339,7 @@ private void copyOldMissionsMenuFile(SuperiorSkyblockPlugin plugin) { try { java.nio.file.Files.copy(Paths.get(oldMissionsMenuFile.toURI()), Paths.get(newMissionsCategoryMenuFile.toURI())); } catch (IOException error) { - Log.error(error, "An unexpected error occurred while copying old missions-menu to the new format:"); + getLogger().e("An unexpected error occurred while copying old missions-menu to the new format:", error); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java index 6b55861cdc..760ed7b3d2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java @@ -218,7 +218,7 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade UpgradeCostLoader costLoader = plugin.getUpgrades().getUpgradeCostLoader(priceType); if (costLoader == null) { - Log.warn("Upgrade by name ", upgrade.getName(), " (level ", level, ") has invalid price-type. Skipping..."); + getLogger().w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has invalid price-type. Skipping..."); return; } @@ -227,7 +227,7 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade try { upgradeCost = costLoader.loadCost(levelSection); } catch (UpgradeCostLoadException error) { - Log.error(error, "Upgrade by name ", upgrade.getName(), " (level ", level, ") failed to initialize:"); + getLogger().e("Upgrade by name " + upgrade.getName() + " (level " + level + ") failed to initialize:", error); return; } @@ -248,7 +248,7 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade IntValue borderSize = IntValue.syncedFixed(levelSection.getInt("border-size", -1)); if (borderSize.get() > plugin.getSettings().getMaxIslandSize()) { - Log.warn("Upgrade by name ", upgrade.getName(), " (level ", level, ") has illegal border-size, skipping..."); + getLogger().w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has illegal border-size, skipping..."); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java index 1b33b754e3..abddc9eff8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java @@ -19,10 +19,10 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; +import com.bgsoftware.superiorskyblock.module.BuiltinModules; import org.bukkit.Bukkit; import java.time.Duration; @@ -140,7 +140,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer try { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), parsedCommand); } catch (Throwable error) { - Log.error(error, "An unexpected error occurred while executing command:\n", parsedCommand); + BuiltinModules.UPGRADES.getLogger().e("An unexpected error occurred while executing command:\n" + parsedCommand, error); } } From fcccd0aea7f0b0cc921ed2fd94cffd6ca76a2ad3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 1 Nov 2025 16:44:16 +0200 Subject: [PATCH 408/600] Fixed issues with placing schematics in some versions (#2750) --- .../world/WorldEditSessionImpl.java.template | 2 +- NMS/v1_17/properties | 3 +- NMS/v1_18/properties | 3 +- NMS/v1_19/properties | 3 +- NMS/v1_20_3/properties | 3 +- .../nms/v1_20_3/utils/NMSUtilsVersioned.java | 76 ++++++++++++++++--- NMS/v1_20_4/properties | 3 +- NMS/v1_21/properties | 3 +- NMS/v1_21_3/properties | 3 +- NMS/v1_21_4/properties | 3 +- NMS/v1_21_5/properties | 3 +- NMS/v1_21_7/properties | 3 +- NMS/v1_21_9/properties | 3 +- 13 files changed, 88 insertions(+), 23 deletions(-) diff --git a/NMS/src/main/templates/world/WorldEditSessionImpl.java.template b/NMS/src/main/templates/world/WorldEditSessionImpl.java.template index d460e6a48b..42e2658c34 100644 --- a/NMS/src/main/templates/world/WorldEditSessionImpl.java.template +++ b/NMS/src/main/templates/world/WorldEditSessionImpl.java.template @@ -51,7 +51,7 @@ public class WorldEditSessionImpl implements WorldEditSession { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final boolean isStarLightInterface = ((Supplier) () -> { try { - Class.forName("ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface"); + Class.forName("${STAR_LIGHT_INTERFACE_CLASS}"); return true; } catch (ClassNotFoundException error) { return false; diff --git a/NMS/v1_17/properties b/NMS/v1_17/properties index 0f646ce51e..25c8fbd427 100644 --- a/NMS/v1_17/properties +++ b/NMS/v1_17/properties @@ -4,4 +4,5 @@ COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.Registry CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus -SERVER_LEVEL_RANDOM_TYPE=java.util.Random \ No newline at end of file +SERVER_LEVEL_RANDOM_TYPE=java.util.Random +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.light.StarLightInterface \ No newline at end of file diff --git a/NMS/v1_18/properties b/NMS/v1_18/properties index 73516ca50b..d7b672fdf8 100644 --- a/NMS/v1_18/properties +++ b/NMS/v1_18/properties @@ -4,4 +4,5 @@ COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.Registry CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus -SERVER_LEVEL_RANDOM_TYPE=java.util.Random \ No newline at end of file +SERVER_LEVEL_RANDOM_TYPE=java.util.Random +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface \ No newline at end of file diff --git a/NMS/v1_19/properties b/NMS/v1_19/properties index 955961c644..f685ea3153 100644 --- a/NMS/v1_19/properties +++ b/NMS/v1_19/properties @@ -4,4 +4,5 @@ COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus -SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface \ No newline at end of file diff --git a/NMS/v1_20_3/properties b/NMS/v1_20_3/properties index d57d752166..bd4e388926 100644 --- a/NMS/v1_20_3/properties +++ b/NMS/v1_20_3/properties @@ -4,4 +4,5 @@ COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus -SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface \ No newline at end of file diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java index 40bbf797f9..4cb159d4bb 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_3.utils.TickingBlockList; import com.google.common.base.Suppliers; +import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; @@ -19,6 +20,8 @@ import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; @@ -29,12 +32,14 @@ import net.minecraft.server.level.ThreadedLevelLightEngine; import net.minecraft.server.level.WorldGenRegion; import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelHeightAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; @@ -53,7 +58,6 @@ import org.bukkit.Material; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome; -import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; @@ -62,14 +66,19 @@ import java.io.IOException; import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; public class NMSUtilsVersioned { + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); private static final ReflectField ENTITY_STORAGE_WORKER = new ReflectField<>( @@ -174,16 +183,9 @@ public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set textLines = new ArrayList<>(); + for (net.minecraft.nbt.Tag lineTag : messages) { + try { + textLines.add(CraftChatMessage.fromJSON(lineTag.getAsString())); + } catch (JsonParseException error) { + textLines.add(CraftChatMessage.fromString(lineTag.getAsString())[0]); + } + } + + while (textLines.size() < 4) + textLines.add(Component.empty()); + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put(key, frontTextNBT)); + } + } + + private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_20_4/properties b/NMS/v1_20_4/properties index 151398b620..6770f40102 100644 --- a/NMS/v1_20_4/properties +++ b/NMS/v1_20_4/properties @@ -4,4 +4,5 @@ COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus -SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface \ No newline at end of file diff --git a/NMS/v1_21/properties b/NMS/v1_21/properties index 9e52643419..9bea625c4d 100644 --- a/NMS/v1_21/properties +++ b/NMS/v1_21/properties @@ -4,4 +4,5 @@ COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus -SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface \ No newline at end of file diff --git a/NMS/v1_21_3/properties b/NMS/v1_21_3/properties index c28e94c157..a5f266fb91 100644 --- a/NMS/v1_21_3/properties +++ b/NMS/v1_21_3/properties @@ -4,4 +4,5 @@ COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus -SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface \ No newline at end of file diff --git a/NMS/v1_21_4/properties b/NMS/v1_21_4/properties index 4a9b3b888d..4b5d1da73b 100644 --- a/NMS/v1_21_4/properties +++ b/NMS/v1_21_4/properties @@ -4,4 +4,5 @@ COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus -SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface \ No newline at end of file diff --git a/NMS/v1_21_5/properties b/NMS/v1_21_5/properties index b3e920e518..ed461d72fd 100644 --- a/NMS/v1_21_5/properties +++ b/NMS/v1_21_5/properties @@ -4,4 +4,5 @@ COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus -SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface \ No newline at end of file diff --git a/NMS/v1_21_7/properties b/NMS/v1_21_7/properties index 9c939718b7..12001562cf 100644 --- a/NMS/v1_21_7/properties +++ b/NMS/v1_21_7/properties @@ -4,4 +4,5 @@ COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus -SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface \ No newline at end of file diff --git a/NMS/v1_21_9/properties b/NMS/v1_21_9/properties index 928a628a97..12871ded67 100644 --- a/NMS/v1_21_9/properties +++ b/NMS/v1_21_9/properties @@ -4,4 +4,5 @@ COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus -SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource \ No newline at end of file +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface \ No newline at end of file From f4c0812693bc215db05c3b900673bc08993bd88f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 1 Nov 2025 16:57:43 +0200 Subject: [PATCH 409/600] Fix module commands are not registered again upon reloading the plugin (#2749) --- .../commands/CommandsMap.java | 5 +++++ .../commands/admin/AdminCommandsMap.java | 2 ++ .../commands/player/PlayerCommandsMap.java | 2 ++ .../module/ModulesManagerImpl.java | 20 ++++++++++++------- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java index 4e0c52ad6a..b12e95b02d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsMap.java @@ -101,6 +101,11 @@ public List getSubCommands(boolean includeDisabled) { return listBuilder.build(this.subCommands.values()); } + protected void clearCommands() { + this.subCommands.clear(); + this.aliasesToCommand.clear(); + } + private boolean isCommandEnabled(SuperiorCommand superiorCommand) { return superiorCommand instanceof IAdminIslandCommand || !DISABLED_COMMANDS_CACHE.contains(superiorCommand.getAliases().get(0).toLowerCase(Locale.ENGLISH)); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java index 4e9910d4ea..2f197827b1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java @@ -11,6 +11,8 @@ public AdminCommandsMap(SuperiorSkyblockPlugin plugin) { @Override public void loadDefaultCommands() { + clearCommands(); + registerCommand(new CmdAdminAdd()); registerCommand(new CmdAdminAddBlockLimit()); registerCommand(new CmdAdminAddBonus()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java index d8086dc559..ae5b2651bb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/PlayerCommandsMap.java @@ -11,6 +11,8 @@ public PlayerCommandsMap(SuperiorSkyblockPlugin plugin) { @Override public void loadDefaultCommands() { + clearCommands(); + registerCommand(new CmdAccept()); registerCommand(new CmdAdmin()); registerCommand(new CmdBan()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java index 46a1d74c4d..47c1d15a2a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java @@ -206,14 +206,20 @@ private void reloadModuleInternal(PluginModule pluginModule) { // We register listeners again ModuleData moduleData = this.modulesContainer.getModuleData(pluginModule); - if (moduleData != null) { - Listener[] listeners = moduleData.getListeners(); - if (listeners != null) { - for (Listener listener : listeners) - Bukkit.getPluginManager().registerEvents(listener, plugin); - } - } + if (moduleData == null) + return; + + Listener[] listeners = moduleData.getListeners(); + if (listeners != null) + Arrays.stream(listeners).forEach(listener -> Bukkit.getPluginManager().registerEvents(listener, plugin)); + SuperiorCommand[] commands = moduleData.getCommands(); + if (commands != null) + Arrays.stream(commands).forEach(plugin.getCommands()::registerCommand); + + SuperiorCommand[] adminCommands = moduleData.getAdminCommands(); + if (adminCommands != null) + Arrays.stream(adminCommands).forEach(plugin.getCommands()::registerAdminCommand); } public void loadModulesData(SuperiorSkyblockPlugin plugin) { From d2aad0086aaa4498f2ef179c7e92d729eeb55146 Mon Sep 17 00:00:00 2001 From: nivcoo <36514752+nivcoo@users.noreply.github.com> Date: Sat, 1 Nov 2025 15:59:35 +0100 Subject: [PATCH 410/600] improv. add order by for warps and use SortingTypes instead of string to validate values (#2744) --- .../api/config/SettingsManager.java | 7 ++++ .../commands/player/CmdTop.java | 2 +- .../config/SettingsContainer.java | 21 ++++++++++-- .../config/SettingsManagerImpl.java | 9 ++++- .../config/section/GlobalSection.java | 7 +++- .../events/plugin/PluginEventsDispatcher.java | 2 ++ .../core/menu/impl/MenuGlobalWarps.java | 5 +-- .../superiorskyblock/island/SIsland.java | 13 ++++---- .../island/top/SortingTypes.java | 33 +++++++++++++++++-- src/main/resources/config.yml | 4 +++ 10 files changed, 86 insertions(+), 17 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 6bbad68728..81d01ea29a 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -3,6 +3,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; +import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; @@ -107,6 +108,12 @@ public interface SettingsManager { */ String getIslandTopOrder(); + /** + * The default global-warps sorting type. + * Config path: global-warps-order + */ + String getGlobalWarpsOrder(); + /** * Whether coop members are enabled. * Config path: coop-members diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTop.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTop.java index 59ab15ee95..c48305a602 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTop.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTop.java @@ -51,7 +51,7 @@ public boolean canBeExecutedByConsole() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - plugin.getMenus().openTopIslands(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), SortingTypes.getDefaultSorting()); + plugin.getMenus().openTopIslands(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), SortingTypes.getIslandTopSorting()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 56db039528..7f40612c94 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; +import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.key.KeySet; @@ -106,7 +107,8 @@ public class SettingsContainer { public final boolean roundedIslandLevel; public final RoundingMode islandLevelRoundingMode; public final boolean autoBlocksTracking; - public final String islandTopOrder; + public final SortingType islandTopOrder; + public final SortingType globalWarpsOrder; public boolean coopMembers; public boolean editPlayerPermissions; public final ConfigurationSection islandRolesSection; @@ -310,7 +312,22 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config config.getString("island-level-rounding-mode").toUpperCase(Locale.ENGLISH))) .orElse(RoundingMode.HALF_UP); autoBlocksTracking = config.getBoolean("auto-blocks-tracking", true); - islandTopOrder = config.getString("island-top-order", "WORTH").toUpperCase(Locale.ENGLISH); + + String rawTop = config.getString("island-top-order", "WORTH"); + SortingType parsedTop = SortingType.getByName(rawTop.toUpperCase(Locale.ENGLISH)); + if (parsedTop == null) { + parsedTop = SortingType.getByName("WORTH"); + Log.warnFromFile("config.yml", "Invalid island-top-order '" + rawTop + "', using 'WORTH'."); + } + this.islandTopOrder = parsedTop; + + String rawGlobalWarps = config.getString("global-warps-order", "WORTH").toUpperCase(Locale.ENGLISH); + SortingType foundGlobalWarpsOrder = SortingType.getByName(rawGlobalWarps); + if (foundGlobalWarpsOrder == null) { + foundGlobalWarpsOrder = SortingType.getByName("WORTH"); + Log.warnFromFile("config.yml", "Invalid global-warps-order '" + rawGlobalWarps + "', using 'WORTH'."); + } + this.globalWarpsOrder = foundGlobalWarpsOrder; coopMembers = config.getBoolean("coop-members", true); editPlayerPermissions = config.getBoolean("edit-player-permissions", true); islandRolesSection = config.getConfigurationSection("island-roles"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index 4ee1b7829b..bd9106543b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; +import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; @@ -28,6 +29,7 @@ import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.island.top.SortingComparators; import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import org.bukkit.Location; import org.bukkit.configuration.file.YamlConfiguration; @@ -155,7 +157,12 @@ public boolean isAutoBlocksTracking() { @Override public String getIslandTopOrder() { - return this.global.getIslandTopOrder(); + return this.global.getIslandTopOrder().getName(); + } + + @Override + public String getGlobalWarpsOrder() { + return this.global.getGlobalWarpsOrder().getName(); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index bfed81f321..8db3debabb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; +import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; @@ -54,10 +55,14 @@ public boolean isAutoBlocksTracking() { return getContainer().autoBlocksTracking; } - public String getIslandTopOrder() { + public SortingType getIslandTopOrder() { return getContainer().islandTopOrder; } + public SortingType getGlobalWarpsOrder() { + return getContainer().globalWarpsOrder; + } + public boolean isCoopMembers() { return getContainer().coopMembers; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java index 72d05b411e..2da5602d67 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.SpawnIsland; +import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; import com.bgsoftware.superiorskyblock.world.entity.EntityCategories; @@ -43,6 +44,7 @@ public void registerDefaultListeners() { Message.registerListeners(this); SSuperiorPlayer.registerListeners(this); EntityCategories.registerListeners(this); + SortingTypes.registerListeners(this); } public void registerCallback(PluginEventType type, Runnable callback) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java index 76fdb979fe..158144ba91 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java @@ -3,6 +3,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; @@ -19,7 +20,7 @@ import com.bgsoftware.superiorskyblock.core.menu.layout.AbstractMenuLayout; import com.bgsoftware.superiorskyblock.core.menu.view.AbstractPagedMenuView; import com.bgsoftware.superiorskyblock.core.menu.view.args.EmptyViewArgs; -import com.bgsoftware.superiorskyblock.island.top.SortingComparators; +import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; @@ -86,7 +87,7 @@ public class View extends AbstractPagedMenuView requestObjects() { return new SequentialListBuilder() - .sorted(SortingComparators.WORTH_COMPARATOR) + .sorted(SortingTypes.getGlobalWarpsSorting().getComparator()) .filter(ISLANDS_FILTER) .build(plugin.getGrid().getIslands()); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 7a417c989b..2f755a3647 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -4857,13 +4857,12 @@ public int compareTo(Island other) { if (other == null) return -1; - if (plugin.getSettings().getIslandTopOrder().equals("WORTH")) { - int compare = getWorth().compareTo(other.getWorth()); - if (compare != 0) return compare; - } else { - int compare = getIslandLevel().compareTo(other.getIslandLevel()); - if (compare != 0) return compare; - } + SortingType sortingType = SortingTypes.getIslandTopSorting(); + Comparator comparator = sortingType.getComparator(); + + int result = comparator.compare(this, other); + if (result != 0) + return result; return getOwner().getName().compareTo(other.getOwner().getName()); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingTypes.java b/src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingTypes.java index 52f779699a..c25e5fa17b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingTypes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingTypes.java @@ -3,8 +3,11 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.SortingType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import java.util.Comparator; +import java.util.Objects; public class SortingTypes { @@ -13,8 +16,12 @@ public class SortingTypes { public static final SortingType BY_RATING = register("RATING", SortingComparators.RATING_COMPARATOR, false); public static final SortingType BY_PLAYERS = register("PLAYERS", SortingComparators.PLAYERS_COMPARATOR, false); - private SortingTypes() { + private static volatile SortingType ISLAND_TOP_SORTING = resolveByName( + SuperiorSkyblockPlugin.getPlugin().getSettings().getIslandTopOrder()); + private static volatile SortingType GLOBAL_WARPS_SORTING = resolveByName( + SuperiorSkyblockPlugin.getPlugin().getSettings().getGlobalWarpsOrder()); + private SortingTypes() { } public static void registerSortingTypes() { @@ -26,8 +33,28 @@ private static SortingType register(String name, Comparator comparator, return SortingType.getByName(name); } - public static SortingType getDefaultSorting() { - return SortingType.getByName(SuperiorSkyblockPlugin.getPlugin().getSettings().getIslandTopOrder()); + public static SortingType getIslandTopSorting() { + return ISLAND_TOP_SORTING; + } + + public static SortingType getGlobalWarpsSorting() { + return GLOBAL_WARPS_SORTING; + } + + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SortingTypes::onSettingsUpdate); } + private static void onSettingsUpdate() { + String topOrder = SuperiorSkyblockPlugin.getPlugin().getSettings().getIslandTopOrder(); + String warpsOrder = SuperiorSkyblockPlugin.getPlugin().getSettings().getGlobalWarpsOrder(); + + ISLAND_TOP_SORTING = resolveByName(topOrder); + GLOBAL_WARPS_SORTING = resolveByName(warpsOrder); + } + + private static SortingType resolveByName(String name) { + return SortingType.getByName(name); + } } + diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 24d9aba519..45c55bb243 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -175,6 +175,10 @@ auto-blocks-tracking: true # Use WORTH, LEVEL, RATING or PLAYERS. island-top-order: 'WORTH' +# How should the global warps be ordered by default? +# Use WORTH, LEVEL, RATING or PLAYERS. +global-warps-order: 'WORTH' + # Whether coop members should be enabled or not. coop-members: true From 782792feb84042de62b782d4cbd5635fe3bda8fd Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 1 Nov 2025 17:40:19 +0200 Subject: [PATCH 411/600] Fix cannot startup due to recent changes (#2752) --- .../superiorskyblock/SuperiorSkyblockPlugin.java | 2 +- .../events/plugin/PluginEventsDispatcher.java | 2 -- .../superiorskyblock/island/top/SortingTypes.java | 15 +++++++-------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index 2dcaf09291..6f7a1c9b6a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -179,7 +179,7 @@ public void onLoad() { Runtime.getRuntime().addShutdownHook(new ShutdownTask(this)); IslandPrivileges.registerPrivileges(); - SortingTypes.registerSortingTypes(); + SortingTypes.registerSortingTypes(this); IslandFlags.registerFlags(); ClearActions.registerActions(); RespawnActions.registerActions(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java index 2da5602d67..72d05b411e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java @@ -13,7 +13,6 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.SpawnIsland; -import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; import com.bgsoftware.superiorskyblock.world.entity.EntityCategories; @@ -44,7 +43,6 @@ public void registerDefaultListeners() { Message.registerListeners(this); SSuperiorPlayer.registerListeners(this); EntityCategories.registerListeners(this); - SortingTypes.registerListeners(this); } public void registerCallback(PluginEventType type, Runnable callback) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingTypes.java b/src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingTypes.java index c25e5fa17b..79a2c3ddfa 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingTypes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/top/SortingTypes.java @@ -7,7 +7,6 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import java.util.Comparator; -import java.util.Objects; public class SortingTypes { @@ -16,16 +15,16 @@ public class SortingTypes { public static final SortingType BY_RATING = register("RATING", SortingComparators.RATING_COMPARATOR, false); public static final SortingType BY_PLAYERS = register("PLAYERS", SortingComparators.PLAYERS_COMPARATOR, false); - private static volatile SortingType ISLAND_TOP_SORTING = resolveByName( - SuperiorSkyblockPlugin.getPlugin().getSettings().getIslandTopOrder()); - private static volatile SortingType GLOBAL_WARPS_SORTING = resolveByName( - SuperiorSkyblockPlugin.getPlugin().getSettings().getGlobalWarpsOrder()); + private static volatile SortingType ISLAND_TOP_SORTING; + private static volatile SortingType GLOBAL_WARPS_SORTING; private SortingTypes() { } - public static void registerSortingTypes() { - // Do nothing, only trigger all the register calls + public static void registerSortingTypes(SuperiorSkyblockPlugin plugin) { + // We actually register the settings update listener in here, as otherwise it causes errors + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2752 + registerListeners(plugin.getPluginEventsDispatcher()); } private static SortingType register(String name, Comparator comparator, boolean handleEqualsIslands) { @@ -41,7 +40,7 @@ public static SortingType getGlobalWarpsSorting() { return GLOBAL_WARPS_SORTING; } - public static void registerListeners(PluginEventsDispatcher dispatcher) { + private static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SortingTypes::onSettingsUpdate); } From 6e3b1cedadb025b63d0c7a88b38eec8a7746c24e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 1 Nov 2025 17:43:05 +0200 Subject: [PATCH 412/600] API version 15 --- .../bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java index 12dc0096f5..5c2d152ede 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java @@ -71,7 +71,7 @@ public static void setPluginInstance(SuperiorSkyblock plugin) { * Everytime a change is made to the API, the version of it changes. */ public static int getAPIVersion() { - return 14; + return 15; } /* From 941cbb4f4613fd2da3ef96041ec1bb42a9527df2 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 1 Nov 2025 18:07:03 +0200 Subject: [PATCH 413/600] Version 2025.2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index edce232615..0abb797b95 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'SuperiorSkyblock' -version = "2025.1" +version = "2025.2" project.ext { archiveFolder = file("archive/") From 6ca99c5ca297dc4056294ceeef3d9a9a0f888c21 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 1 Nov 2025 22:31:20 +0100 Subject: [PATCH 414/600] Fixed tab completes of /is admin close and /is admin open commands (#2753) --- .../superiorskyblock/commands/admin/CmdAdminClose.java | 8 ++++++++ .../superiorskyblock/commands/admin/CmdAdminOpen.java | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java index d941b115ec..46094b4749 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminClose.java @@ -4,12 +4,14 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; +import java.util.Collections; import java.util.List; public class CmdAdminClose implements IAdminIslandCommand { @@ -67,4 +69,10 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab } } + @Override + public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + return args.length == 3 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[2], false, + (superiorPlayer, island) -> !island.isLocked()) : Collections.emptyList(); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java index 10859a6d68..5ad59f122d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminOpen.java @@ -4,12 +4,14 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; import java.util.Arrays; +import java.util.Collections; import java.util.List; public class CmdAdminOpen implements IAdminIslandCommand { @@ -66,4 +68,10 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab } } + @Override + public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + return args.length == 3 ? CommandTabCompletes.getOnlinePlayersAndIslands(plugin, args[2], false, + (superiorPlayer, island) -> island.isLocked()) : Collections.emptyList(); + } + } From d0a5e7224ec4e5e18337f0af975e7e2b321c0444 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 12 Nov 2025 21:28:25 +0200 Subject: [PATCH 415/600] Fixed PluginModule#getLogger breaks api backwards-compability --- .../api/modules/PluginModule.java | 3 ++- .../superiorskyblock/module/BuiltinModule.java | 7 +++++-- .../module/missions/MissionsModule.java | 18 +++++++++--------- .../module/upgrades/UpgradesModule.java | 6 +++--- .../module/upgrades/commands/CmdRankup.java | 4 +++- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/PluginModule.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/PluginModule.java index f7787bda79..a5204fa3a2 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/PluginModule.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/PluginModule.java @@ -7,6 +7,7 @@ import java.io.File; import java.io.InputStream; +import java.util.logging.Logger; /** * Plugin modules are similar to plugins. The difference between them and regular plugins is that the modules are @@ -194,7 +195,7 @@ public final ClassLoader getClassLoader() { /** * Get the logger of the module {@link ModuleLogger} */ - public final ModuleLogger getLogger() { + public final Logger getLogger() { return logger; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java index 42e1a7902b..7799a528c8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; +import com.bgsoftware.superiorskyblock.api.modules.ModuleLogger; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import com.bgsoftware.superiorskyblock.core.io.Resources; import org.bukkit.event.Listener; @@ -15,6 +16,8 @@ public abstract class BuiltinModule extends Plug protected T configuration; + protected final ModuleLogger logger = (ModuleLogger) getLogger(); + public BuiltinModule(String moduleName) { super(moduleName, "Ome_R"); } @@ -95,7 +98,7 @@ protected void onPluginInit(SuperiorSkyblockPlugin plugin) { try { config.save(configFile); } catch (Exception error) { - getLogger().e("An error occurred while saving config file for module " + getName() + ":", error); + this.logger.e("An error occurred while saving config file for module " + getName() + ":", error); } } @@ -104,7 +107,7 @@ protected void onPluginInit(SuperiorSkyblockPlugin plugin) { Resources.getResource("modules/" + getName() + "/config.yml"), getIgnoredSections()); } catch (Exception error) { - getLogger().e("An error occurred while loading config file:", error); + this.logger.e("An error occurred while loading config file:", error); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java index 75aa45e550..d0c361edca 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java @@ -169,12 +169,12 @@ private boolean canLoadCategory(String categoryName, List> categoryMi File categoryFolder = new File(getModuleFolder(), "categories/" + categoryName); if (!categoryFolder.exists()) { - getLogger().w("The directory of the mission category " + categoryName + " doesn't exist, skipping..."); + logger.w("The directory of the mission category " + categoryName + " doesn't exist, skipping..."); return false; } if (!categoryFolder.isDirectory()) { - getLogger().w("The directory of the mission category " + categoryName + " is not valid, skipping..."); + logger.w("The directory of the mission category " + categoryName + " is not valid, skipping..."); return false; } @@ -182,7 +182,7 @@ private boolean canLoadCategory(String categoryName, List> categoryMi file.isFile() && file.getName().endsWith(".yml")); if (missionFiles == null || missionFiles.length == 0) { - getLogger().w("The mission category " + categoryName + " doesn't have missions, skipping..."); + logger.w("The mission category " + categoryName + " doesn't have missions, skipping..."); return false; } @@ -200,10 +200,10 @@ private boolean canLoadCategory(String categoryName, List> categoryMi try { missionConfigFile.load(missionFile); } catch (InvalidConfigurationException error) { - getLogger().e("A format-error occurred while parsing the mission file " + missionFile.getName() + ":", error); + logger.e("A format-error occurred while parsing the mission file " + missionFile.getName() + ":", error); continue; } catch (IOException error) { - getLogger().e("An unexpected error occurred while parsing the mission file " + missionFile.getName() + ":", error); + logger.e("An unexpected error occurred while parsing the mission file " + missionFile.getName() + ":", error); continue; } @@ -219,7 +219,7 @@ private boolean canLoadCategory(String categoryName, List> categoryMi } if (categoryMissions.isEmpty()) { - getLogger().w("The mission category " + categoryName + " doesn't have missions, skipping..."); + logger.w("The mission category " + categoryName + " doesn't have missions, skipping..."); return false; } @@ -280,7 +280,7 @@ private boolean convertNonCategorizedMissions(SuperiorSkyblockPlugin plugin, Yam try { missionFile.createNewFile(); } catch (IOException error) { - getLogger().e("An unexpected error occurred while converting non-categorized mission " + missionName + ":", error); + logger.e("An unexpected error occurred while converting non-categorized mission " + missionName + ":", error); continue; } @@ -290,7 +290,7 @@ private boolean convertNonCategorizedMissions(SuperiorSkyblockPlugin plugin, Yam try { missionConfigFile.save(missionFile); } catch (Exception error) { - getLogger().e("An unexpected error occurred while saving non-categorized mission " + missionName + ":", error); + logger.e("An unexpected error occurred while saving non-categorized mission " + missionName + ":", error); } } @@ -339,7 +339,7 @@ private void copyOldMissionsMenuFile(SuperiorSkyblockPlugin plugin) { try { java.nio.file.Files.copy(Paths.get(oldMissionsMenuFile.toURI()), Paths.get(newMissionsCategoryMenuFile.toURI())); } catch (IOException error) { - getLogger().e("An unexpected error occurred while copying old missions-menu to the new format:", error); + logger.e("An unexpected error occurred while copying old missions-menu to the new format:", error); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java index 760ed7b3d2..038a914b83 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java @@ -218,7 +218,7 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade UpgradeCostLoader costLoader = plugin.getUpgrades().getUpgradeCostLoader(priceType); if (costLoader == null) { - getLogger().w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has invalid price-type. Skipping..."); + this.logger.w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has invalid price-type. Skipping..."); return; } @@ -227,7 +227,7 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade try { upgradeCost = costLoader.loadCost(levelSection); } catch (UpgradeCostLoadException error) { - getLogger().e("Upgrade by name " + upgrade.getName() + " (level " + level + ") failed to initialize:", error); + this.logger.e("Upgrade by name " + upgrade.getName() + " (level " + level + ") failed to initialize:", error); return; } @@ -248,7 +248,7 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade IntValue borderSize = IntValue.syncedFixed(levelSection.getInt("border-size", -1)); if (borderSize.get() > plugin.getSettings().getMaxIslandSize()) { - getLogger().w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has illegal border-size, skipping..."); + this.logger.w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has illegal border-size, skipping..."); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java index abddc9eff8..3dfdb46cb8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdRankup.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.events.IslandUpgradeEvent; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.modules.ModuleLogger; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.upgrades.UpgradeLevel; @@ -140,7 +141,8 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer try { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), parsedCommand); } catch (Throwable error) { - BuiltinModules.UPGRADES.getLogger().e("An unexpected error occurred while executing command:\n" + parsedCommand, error); + ModuleLogger logger = (ModuleLogger) BuiltinModules.UPGRADES.getLogger(); + logger.e("An unexpected error occurred while executing command:\n" + parsedCommand, error); } } From 1be202c09efa5a3a2e914204adbdaf8ced7a39a0 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 12 Nov 2025 22:08:52 +0200 Subject: [PATCH 416/600] Fix errors due to recent commit related to loggers --- .../superiorskyblock/module/BuiltinModule.java | 10 ++++++---- .../module/missions/MissionsModule.java | 18 +++++++++--------- .../module/upgrades/UpgradesModule.java | 6 +++--- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java index 7799a528c8..f475b42d29 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/BuiltinModule.java @@ -16,8 +16,6 @@ public abstract class BuiltinModule extends Plug protected T configuration; - protected final ModuleLogger logger = (ModuleLogger) getLogger(); - public BuiltinModule(String moduleName) { super(moduleName, "Ome_R"); } @@ -98,7 +96,7 @@ protected void onPluginInit(SuperiorSkyblockPlugin plugin) { try { config.save(configFile); } catch (Exception error) { - this.logger.e("An error occurred while saving config file for module " + getName() + ":", error); + this.logger().e("An error occurred while saving config file for module " + getName() + ":", error); } } @@ -107,13 +105,17 @@ protected void onPluginInit(SuperiorSkyblockPlugin plugin) { Resources.getResource("modules/" + getName() + "/config.yml"), getIgnoredSections()); } catch (Exception error) { - this.logger.e("An error occurred while loading config file:", error); + this.logger().e("An error occurred while loading config file:", error); } this.configuration = createConfigFile(config); } + protected ModuleLogger logger() { + return (ModuleLogger) super.getLogger(); + } + protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) { return false; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java index d0c361edca..48d4d5fa82 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/MissionsModule.java @@ -169,12 +169,12 @@ private boolean canLoadCategory(String categoryName, List> categoryMi File categoryFolder = new File(getModuleFolder(), "categories/" + categoryName); if (!categoryFolder.exists()) { - logger.w("The directory of the mission category " + categoryName + " doesn't exist, skipping..."); + logger().w("The directory of the mission category " + categoryName + " doesn't exist, skipping..."); return false; } if (!categoryFolder.isDirectory()) { - logger.w("The directory of the mission category " + categoryName + " is not valid, skipping..."); + logger().w("The directory of the mission category " + categoryName + " is not valid, skipping..."); return false; } @@ -182,7 +182,7 @@ private boolean canLoadCategory(String categoryName, List> categoryMi file.isFile() && file.getName().endsWith(".yml")); if (missionFiles == null || missionFiles.length == 0) { - logger.w("The mission category " + categoryName + " doesn't have missions, skipping..."); + logger().w("The mission category " + categoryName + " doesn't have missions, skipping..."); return false; } @@ -200,10 +200,10 @@ private boolean canLoadCategory(String categoryName, List> categoryMi try { missionConfigFile.load(missionFile); } catch (InvalidConfigurationException error) { - logger.e("A format-error occurred while parsing the mission file " + missionFile.getName() + ":", error); + logger().e("A format-error occurred while parsing the mission file " + missionFile.getName() + ":", error); continue; } catch (IOException error) { - logger.e("An unexpected error occurred while parsing the mission file " + missionFile.getName() + ":", error); + logger().e("An unexpected error occurred while parsing the mission file " + missionFile.getName() + ":", error); continue; } @@ -219,7 +219,7 @@ private boolean canLoadCategory(String categoryName, List> categoryMi } if (categoryMissions.isEmpty()) { - logger.w("The mission category " + categoryName + " doesn't have missions, skipping..."); + logger().w("The mission category " + categoryName + " doesn't have missions, skipping..."); return false; } @@ -280,7 +280,7 @@ private boolean convertNonCategorizedMissions(SuperiorSkyblockPlugin plugin, Yam try { missionFile.createNewFile(); } catch (IOException error) { - logger.e("An unexpected error occurred while converting non-categorized mission " + missionName + ":", error); + logger().e("An unexpected error occurred while converting non-categorized mission " + missionName + ":", error); continue; } @@ -290,7 +290,7 @@ private boolean convertNonCategorizedMissions(SuperiorSkyblockPlugin plugin, Yam try { missionConfigFile.save(missionFile); } catch (Exception error) { - logger.e("An unexpected error occurred while saving non-categorized mission " + missionName + ":", error); + logger().e("An unexpected error occurred while saving non-categorized mission " + missionName + ":", error); } } @@ -339,7 +339,7 @@ private void copyOldMissionsMenuFile(SuperiorSkyblockPlugin plugin) { try { java.nio.file.Files.copy(Paths.get(oldMissionsMenuFile.toURI()), Paths.get(newMissionsCategoryMenuFile.toURI())); } catch (IOException error) { - logger.e("An unexpected error occurred while copying old missions-menu to the new format:", error); + logger().e("An unexpected error occurred while copying old missions-menu to the new format:", error); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java index 038a914b83..36835f7be5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java @@ -218,7 +218,7 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade UpgradeCostLoader costLoader = plugin.getUpgrades().getUpgradeCostLoader(priceType); if (costLoader == null) { - this.logger.w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has invalid price-type. Skipping..."); + this.logger().w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has invalid price-type. Skipping..."); return; } @@ -227,7 +227,7 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade try { upgradeCost = costLoader.loadCost(levelSection); } catch (UpgradeCostLoadException error) { - this.logger.e("Upgrade by name " + upgrade.getName() + " (level " + level + ") failed to initialize:", error); + this.logger().e("Upgrade by name " + upgrade.getName() + " (level " + level + ") failed to initialize:", error); return; } @@ -248,7 +248,7 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade IntValue borderSize = IntValue.syncedFixed(levelSection.getInt("border-size", -1)); if (borderSize.get() > plugin.getSettings().getMaxIslandSize()) { - this.logger.w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has illegal border-size, skipping..."); + this.logger().w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has illegal border-size, skipping..."); return; } From 9765403e75c391a2c3eb7c8ab2d6bbe2f5f67cec Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 12 Nov 2025 22:25:41 +0200 Subject: [PATCH 417/600] Version 2025.2.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 0abb797b95..3cb5be383a 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'SuperiorSkyblock' -version = "2025.2" +version = "2025.2.1" project.ext { archiveFolder = file("archive/") From 7980c78fdadfd2f797e89d723cc4f99c5858719e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 14 Nov 2025 20:07:03 +0200 Subject: [PATCH 418/600] Fix spawn location does not respect yaw & pitch (#2772) --- .../superiorskyblock/island/SpawnIsland.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 59045490ca..a8fa22b32d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -38,7 +38,7 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.IslandArea; import com.bgsoftware.superiorskyblock.core.LazyReference; -import com.bgsoftware.superiorskyblock.core.SBlockPosition; +import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.WorldInfoImpl; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; @@ -133,7 +133,7 @@ protected IslandCache create() { } }; - private final BlockPosition center; + private final WorldPosition center; private final World spawnWorld; private final WorldInfo spawnWorldInfo; private final int islandSize; @@ -161,8 +161,8 @@ public SpawnIsland() throws ManagerLoadException { this.islandSize = plugin.getSettings().getSpawn().getSize(); - this.center = SBlockPosition.of(centerLocation); - this.islandArea.update(this.center, this.islandSize); + this.center = SWorldPosition.of(centerLocation); + this.islandArea.update(this.center.toBlockPosition(), this.islandSize); this.spawnWorldInfo = new WorldInfoImpl(this.spawnWorld.getName(), Dimensions.fromEnvironment(this.spawnWorld.getEnvironment())); this.dirtyChunksContainer = new DirtyChunksContainer(this); @@ -346,12 +346,12 @@ public boolean isVisitor(SuperiorPlayer superiorPlayer, boolean includeCoopStatu @Override public Location getCenter(Dimension unused) { - return this.center.toWorldPosition().toLocation(this.spawnWorld); + return this.center.toLocation(this.spawnWorld); } @Override public BlockPosition getCenterPosition() { - return this.center; + return this.center.toBlockPosition(); } @Override From c7cc8a26d18e15ef368ba8e2cf928ea23521a571 Mon Sep 17 00:00:00 2001 From: Djoey Date: Fri, 14 Nov 2025 19:08:29 +0100 Subject: [PATCH 419/600] Fix players can destroy without permissions: Glow item frames + Armor Stands (#2771) --- .../world/entity/EntityCategories.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategories.java b/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategories.java index 3224929ef7..bf6c3503cf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategories.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategories.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; @@ -31,6 +32,8 @@ public class EntityCategories { private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); + @Nullable + private static final EntityType GLOW_ITEM_FRAME = EnumHelper.getEnum(EntityType.class, "GLOW_ITEM_FRAME"); public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, EntityCategories::onSettingsUpdate); @@ -54,9 +57,12 @@ private static void onSettingsUpdate() { new Builder("PAINTING", createEntityTypesSet(EntityType.PAINTING)) .damagePrivilege(IslandPrivileges.PAINTING).spawnPrivilege(IslandPrivileges.BUILD) .naturalSpawnFlag(null).spawnerSpawnFlag(null).build(); - new Builder("ITEM_FRAME", createEntityTypesSet(EntityType.ITEM_FRAME)) + new Builder("ITEM_FRAME", createEntityTypesSet(EntityType.ITEM_FRAME, GLOW_ITEM_FRAME)) .damagePrivilege(IslandPrivileges.ITEM_FRAME).spawnPrivilege(IslandPrivileges.BUILD) .naturalSpawnFlag(null).spawnerSpawnFlag(null).build(); + new Builder("ARMOR_STAND", createEntityTypesSet(EntityType.ARMOR_STAND)) + .damagePrivilege(IslandPrivileges.BREAK).spawnPrivilege(IslandPrivileges.BUILD) + .naturalSpawnFlag(null).spawnerSpawnFlag(null).build(); new Builder("VEHICLE", createEntityTypesSet(EntityCategories::isVehicleType)) .damagePrivilege(IslandPrivileges.MINECART_DAMAGE).spawnPrivilege(IslandPrivileges.MINECART_PLACE) .naturalSpawnFlag(null).spawnerSpawnFlag(null).build(); @@ -110,10 +116,13 @@ private static KeySet createEntityTypesSet(Predicate predicate) { return entityTypes; } - private static KeySet createEntityTypesSet(EntityType entityType) { - KeySet entityTypes = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); - entityTypes.add(Keys.of(entityType)); - return entityTypes; + private static KeySet createEntityTypesSet(EntityType... entityTypes) { + KeySet entities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); + for (EntityType entityType : entityTypes) { + if (entityType != null) + entities.add(Keys.of(entityType)); + } + return entities; } private static Class getEntityTypeClass(String clazz) { From b9c6eb13b5dab4dc38ceaaff2c90a0f03d17ad23 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 14 Nov 2025 23:16:53 +0100 Subject: [PATCH 420/600] Added option to toggle who sees the island name change announcement (#2775) --- .../superiorskyblock/api/config/SettingsManager.java | 6 ++++++ .../superiorskyblock/commands/admin/CmdAdminName.java | 9 ++------- .../superiorskyblock/commands/player/CmdName.java | 7 +------ .../superiorskyblock/config/SettingsContainer.java | 2 ++ .../config/section/IslandNamesSection.java | 5 +++++ .../superiorskyblock/island/IslandNames.java | 11 +++++++++++ src/main/resources/config.yml | 4 ++++ 7 files changed, 31 insertions(+), 13 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 81d01ea29a..60bc7669bb 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -1272,6 +1272,12 @@ interface IslandNames { */ boolean isPreventPlayerNames(); + /** + * Whether the name change announcement should be sent to all players or not. + * Config-path: island-names.announce-change-to-all + */ + boolean isAnnounceChangeToAll(); + } interface AFKIntegrations { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java index 781f17aa6a..1be7f0ce1f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminName.java @@ -8,12 +8,9 @@ import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandNames; -import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; import java.util.Arrays; import java.util.List; @@ -81,12 +78,10 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab String coloredName = island.getName(); if (targetPlayer == null) { - for (Player player : Bukkit.getOnlinePlayers()) - Message.NAME_ANNOUNCEMENT_OTHER_NAME.send(player, sender.getName(), oldName, coloredName); + IslandNames.announceChange(island, Message.NAME_ANNOUNCEMENT_OTHER_NAME, sender.getName(), oldName, coloredName); Message.CHANGED_NAME_OTHER_NAME.send(sender, oldName, coloredName); } else { - for (Player player : Bukkit.getOnlinePlayers()) - Message.NAME_ANNOUNCEMENT_OTHER.send(player, sender.getName(), targetPlayer.getName(), coloredName); + IslandNames.announceChange(island, Message.NAME_ANNOUNCEMENT_OTHER, sender.getName(), targetPlayer.getName(), coloredName); Message.CHANGED_NAME_OTHER.send(sender, targetPlayer.getName(), coloredName); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java index 38bd669ec9..8f15f2cb76 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdName.java @@ -8,12 +8,9 @@ import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; -import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandNames; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; import java.util.Arrays; import java.util.List; @@ -81,9 +78,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer String coloredName = island.getName(); - for (Player player : Bukkit.getOnlinePlayers()) - Message.NAME_ANNOUNCEMENT.send(player, superiorPlayer.getName(), coloredName); - + IslandNames.announceChange(island, Message.NAME_ANNOUNCEMENT, superiorPlayer.getName(), coloredName); Message.CHANGED_NAME.send(superiorPlayer, coloredName); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 7f40612c94..1ea73aefcb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -154,6 +154,7 @@ public class SettingsContainer { public final boolean islandNamesColorSupport; public final boolean islandNamesIslandTop; public final boolean islandNamesPreventPlayerNames; + public final boolean islandNamesAnnounceChangeToAll; public final boolean teleportOnCreate; public final boolean teleportOnJoin; public final boolean teleportOnKick; @@ -423,6 +424,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config islandNamesColorSupport = config.getBoolean("island-names.color-support", true); islandNamesIslandTop = config.getBoolean("island-names.island-top", true); islandNamesPreventPlayerNames = config.getBoolean("island-names.prevent-player-names", true); + islandNamesAnnounceChangeToAll = config.getBoolean("island-names.announce-change-to-all", true); teleportOnCreate = config.getBoolean("teleport-on-create", true); teleportOnJoin = config.getBoolean("teleport-on-join", false); teleportOnKick = config.getBoolean("teleport-on-kick", true); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandNamesSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandNamesSection.java index cfb8a008c1..f89b9f96eb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandNamesSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/IslandNamesSection.java @@ -42,4 +42,9 @@ public boolean isPreventPlayerNames() { return getContainer().islandNamesPreventPlayerNames; } + @Override + public boolean isAnnounceChangeToAll() { + return getContainer().islandNamesAnnounceChangeToAll; + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandNames.java b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandNames.java index ee1aa0ee85..261c55da22 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandNames.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandNames.java @@ -5,10 +5,13 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import javax.annotation.Nullable; +import java.util.Collections; import java.util.Locale; public class IslandNames { @@ -68,6 +71,14 @@ public static boolean isValidName(CommandSender sender, Island currentIsland, St return true; } + public static void announceChange(Island island, Message message, Object... args) { + if (plugin.getSettings().getIslandNames().isAnnounceChangeToAll()) + for (Player player : Bukkit.getOnlinePlayers()) + message.send(player, args); + else + IslandUtils.sendMessage(island, message, Collections.emptyList(), args); + } + public static String getNameForDatabase(Island island) { return island.getFormattedName().replace(ChatColor.COLOR_CHAR, '&'); } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 45c55bb243..2e63af6db5 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -494,6 +494,10 @@ island-names: # Should the plugin prevent players from using player names as island names? prevent-player-names: false + # Should the name change announcement be sent to all players? + # When disabled, only island members will see the announcement. + announce-change-to-all: true + # Should players get teleported to the island when they create it? teleport-on-create: true From 8de949f08c80da4e5f07de98a1b65fd89955a1c2 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 14 Nov 2025 23:17:47 +0100 Subject: [PATCH 421/600] Moved /is admin setbanklimit command to the bank module (#2768) --- .../superiorskyblock/commands/admin/AdminCommandsMap.java | 1 - .../superiorskyblock/commands/admin/CmdAdminShow.java | 3 ++- .../bgsoftware/superiorskyblock/module/bank/BankModule.java | 3 ++- .../admin => module/bank/commands}/CmdAdminSetBankLimit.java | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) rename src/main/java/com/bgsoftware/superiorskyblock/{commands/admin => module/bank/commands}/CmdAdminSetBankLimit.java (98%) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java index 2f197827b1..8f31757195 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java @@ -54,7 +54,6 @@ public void loadDefaultCommands() { registerCommand(new CmdAdminResetSettings()); registerCommand(new CmdAdminResetWorld()); registerCommand(new CmdAdminSchematic()); - registerCommand(new CmdAdminSetBankLimit()); registerCommand(new CmdAdminSetBiome()); registerCommand(new CmdAdminSetBlockAmount()); registerCommand(new CmdAdminSetBlockLimit()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java index 7aa161f3c7..f445853726 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminShow.java @@ -193,7 +193,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ collectIslandData(locale, infoMessage, island::getCoopLimit, island::getCoopLimitRaw, Message.ISLAND_INFO_ADMIN_COOP_LIMIT); // Island bank limit - collectIslandData(locale, infoMessage, island::getBankLimit, island::getBankLimitRaw, Message.ISLAND_INFO_ADMIN_BANK_LIMIT, + if (BuiltinModules.BANK.isEnabled()) + collectIslandData(locale, infoMessage, island::getBankLimit, island::getBankLimitRaw, Message.ISLAND_INFO_ADMIN_BANK_LIMIT, Formatters.NUMBER_FORMATTER::format); if (upgradesModule) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java index 873406ddde..6331db5c4d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.module.BuiltinModule; import com.bgsoftware.superiorskyblock.module.IModuleConfiguration; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminDeposit; +import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminSetBankLimit; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminWithdraw; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdBalance; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdBank; @@ -77,7 +78,7 @@ public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) { @Override public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) { - return new SuperiorCommand[]{new CmdAdminDeposit(), new CmdAdminWithdraw()}; + return new SuperiorCommand[]{new CmdAdminDeposit(), new CmdAdminSetBankLimit(), new CmdAdminWithdraw()}; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBankLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminSetBankLimit.java similarity index 98% rename from src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBankLimit.java rename to src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminSetBankLimit.java index 9a24af2ae9..0ace847be5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBankLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminSetBankLimit.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.commands.admin; +package com.bgsoftware.superiorskyblock.module.bank.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; From eb4afa7b01d421bca3636b1f6a6dac15cf18ec2b Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 14 Nov 2025 23:25:53 +0100 Subject: [PATCH 422/600] Added support for multiple islands to the /is admin setupgrade command (#2764) --- .../core/messages/Message.java | 1 + .../upgrades/commands/CmdAdminSetUpgrade.java | 29 ++++++++++++------- src/main/resources/lang/de-DE.yml | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/tr-TR.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + 14 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index f1a60f761b..e96915bd9c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -718,6 +718,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { SETTINGS_UPDATED_ALL, SETTINGS_UPDATED_NAME, SET_UPGRADE_LEVEL, + SET_UPGRADE_LEVEL_ALL, SET_UPGRADE_LEVEL_NAME, SET_WARP, SET_WARP_OUTSIDE, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetUpgrade.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetUpgrade.java index 9a5be76cea..4e460c05af 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetUpgrade.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetUpgrade.java @@ -35,7 +35,8 @@ public String getPermission() { public String getUsage(java.util.Locale locale) { return "admin setupgrade <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + - Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "> <" + + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_UPGRADE_NAME.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_LEVEL.getMessage(locale) + ">"; } @@ -62,11 +63,11 @@ public boolean canBeExecutedByConsole() { @Override public boolean supportMultipleIslands() { - return false; + return true; } @Override - public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, Island island, String[] args) { + public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { Upgrade upgrade = CommandArguments.getUpgrade(plugin, sender, args[3]); if (upgrade == null) @@ -85,16 +86,24 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab return; } - PluginEvent event = PluginEventsFactory.callIslandUpgradeEvent( - island, sender, upgrade, upgrade.getUpgradeLevel(level), IslandUpgradeEvent.Cause.ADMIN_SET_UPGRADE); + int islandsChangedCount = 0; - if (event.isCancelled()) - return; + for (Island island : islands) { + PluginEvent event = PluginEventsFactory.callIslandUpgradeEvent( + island, sender, upgrade, upgrade.getUpgradeLevel(level), IslandUpgradeEvent.Cause.ADMIN_SET_UPGRADE); + if (!event.isCancelled()) { + island.setUpgradeLevel(upgrade, level); + ++islandsChangedCount; + } + } - island.setUpgradeLevel(upgrade, level); + if (islandsChangedCount <= 0) + return; - if (targetPlayer == null) - Message.SET_UPGRADE_LEVEL_NAME.send(sender, upgrade.getName(), island.getName()); + if (islandsChangedCount > 1) + Message.SET_UPGRADE_LEVEL_ALL.send(sender, upgrade.getName()); + else if (targetPlayer == null) + Message.SET_UPGRADE_LEVEL_NAME.send(sender, upgrade.getName(), islands.get(0).getName()); else Message.SET_UPGRADE_LEVEL.send(sender, upgrade.getName(), targetPlayer.getName()); } diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 45c1371b33..ce8ec166f5 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -880,6 +880,7 @@ SCHEMATIC_SAVED: '&e&lSchematics | &7Schaltplan erfolgreich gespeichert!' SELF_ROLE_CHANGE: '&c&lError | &7Du kannst deine Rolle nicht ändern.' SET_UPGRADE_LEVEL: '&e&lUpgrades | &7Die Ebene von {0} für die Insel von {1} wurde erfolgreich aktualisiert.' +SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lUpgrades | &7Die Ebene von {0} für {1} wurde erfolgreich aktualisiert.' SET_WARP: '&e&lInsel | &7Erzeugt erfolgreich einen neuen Warp am {0}.' diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index f30bc98bc5..f408be93b4 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -700,6 +700,7 @@ SCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Selected position #1 ({0})' SCHEMATIC_SAVED: '&e&lSchematics | &7Successfully saved schematic!' SELF_ROLE_CHANGE: '&c&lError | &7You cannot change the role of yourself.' SET_UPGRADE_LEVEL: '&e&lUpgrades | &7Successfully updated the level of {0} for {1}''s island.' +SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lUpgrades | &7Successfully updated the level of {0} for {1}.' SET_WARP: '&e&lIsland | &7Successfully created a new warp at {0}.' SET_WARP_OUTSIDE: '&c&lError | &7You cannot set warps outside your island.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 03cdbef83c..1e9c739ca2 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -697,6 +697,7 @@ SCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Posición seleccionada #1 ({0})' SCHEMATIC_SAVED: '&e&lSchematics | &7Schematic/Esquematica guardada correctamente!' SELF_ROLE_CHANGE: '&c&lError | &7No puedes cambiar tu rol.' SET_UPGRADE_LEVEL: '&e&lMejoras| &7Se actualizó correctamente el nivel de {0} para la isla de {1}.' +SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lMejoras| &7Se actualizó correctamente el nivel de {0} para {1}.' SET_WARP: '&e&lIsla | &7Se creó con éxito una nuevo warp en {0}.' SET_WARP_OUTSIDE: '&c&lError | &7No puedes establecer warps fuera de tu isla.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 39d064ee43..77f06c827e 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -699,6 +699,7 @@ SCHEMATIC_RIGHT_SELECT: '&e&lSchémas | &7Position #1 séléctionnée ({0})' SCHEMATIC_SAVED: '&e&lSchémas | &7Schematic sauvegardé !' SELF_ROLE_CHANGE: '&c&lErreur | &7Vous ne pouvez pas changer votre propre rôle.' SET_UPGRADE_LEVEL: '&e&lAméliorations | &7Niveau de {0} augmenté sur l''île de {1}.' +SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lAméliorations | &7Niveau de {0} augmenté sur {1}.' SET_WARP: '&e&lIle | &7Nouveau warp crée au coordonnées {0}.' SET_WARP_OUTSIDE: '&c&lErreur | &7Vous ne pouvez pas définir de warps hors de votre île.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index b6463be04b..4addd6ef6b 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -705,6 +705,7 @@ SCHEMATIC_RIGHT_SELECT: '&e&lSchematics | &7Posizione selezionata #1 ({0})' SCHEMATIC_SAVED: '&e&lSchematics | &7Schematica salvata con successo!' SELF_ROLE_CHANGE: '&c&lErrore | &7Non puoi cambiare il tuo ruolo.' SET_UPGRADE_LEVEL: '&e&lAggiornamenti | &7Aggiornato con successo il livello di {0} per l''isola di {1}.' +SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lAggiornamenti | &7Aggiornato con successo il livello di {0} per {1}.' SET_WARP: '&e&lIsola | &7Creato con successo un nuovo warp a {0}.' SET_WARP_OUTSIDE: '&c&lErrore | &7Non puoi impostare warp fuori dalla tua isola.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 9795cd8d40..ba57d13ea1 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -719,6 +719,7 @@ SCHEMATIC_RIGHT_SELECT: '&e&lםינבמ רצוי | &7הנושאר הדוקנ ת SCHEMATIC_SAVED: '&e&lםינבמ רצוי | &7החלצהב רמשנ הנבמה!' SELF_ROLE_CHANGE: '&c&lהאיגש | &7ךמצע לש הגרדה תא תונשל לוכי אל התא.' SET_UPGRADE_LEVEL: '&e&lםיגורדש | &7החלצהב התנוש {1} לש יאב {0} גורדשה לש המרה.' +SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lםיגורדש | &7החלצהב התנוש {1} יאב {0} גורדשה לש המרה.' SET_WARP: '&e&lיא | &7{0} ב החלצהב שדח םוקימ תרצי.' SET_WARP_OUTSIDE: '&c&lהאיגש | &7ךלש יאל ץוחמ םימוקימ רוציל לוכי אל התא.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 9c886c1945..fa937e0cbd 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -697,6 +697,7 @@ SCHEMATIC_RIGHT_SELECT: '&e&lSchematy | &7Wybrana pozycja nr 1 ({0})' SCHEMATIC_SAVED: '&e&lSchematy | &7Schemat zapisany pomyslnie!' SELF_ROLE_CHANGE: '&c&lBlad | &7Nie mozesz zmienic swojej roli.' SET_UPGRADE_LEVEL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla wyspy {1}.' +SET_UPGRADE_LEVEL_ALL: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla wszystkich wysp.' SET_UPGRADE_LEVEL_NAME: '&e&lAktualizacje | &7Pomyslnie zaktualizowano poziom {0} dla {1}.' SET_WARP: '&e&lWyspa | &7Pomyslnie utworzono nowe wypaczenie w {0}.' SET_WARP_OUTSIDE: '&c&lBlad | &7Nie mozesz ustawic warp poza swoja wyspa.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 742285f7e9..83eac78656 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -697,6 +697,7 @@ SCHEMATIC_RIGHT_SELECT: '&e&lschematic | &7Posição selecionada nº 1 ({0})' SCHEMATIC_SAVED: '&e&lschematic | &7Esquema salvo com sucesso!' SELF_ROLE_CHANGE: '&c&lErro | &7Você não pode alterar sua função.' SET_UPGRADE_LEVEL: '&e&lAtualizações | &7Atualizou com sucesso o nível de {0} para a ilha de {1}.' +SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lAtualizações | &7Atualizou com sucesso o nível de {0} para {1}.' SET_WARP: '&e&lIlha | &7Criou com sucesso um novo warp em {0}.' SET_WARP_OUTSIDE: '&c&lErro | &7Você não pode definir warps fora da sua ilha.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index be4b97b972..d0d52ee799 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -697,6 +697,7 @@ SCHEMATIC_RIGHT_SELECT: '&e&lСхемы | &7Выбрана позиция #1 ({0 SCHEMATIC_SAVED: '&e&lСхемы | &7Схема успешно сохранена!' SELF_ROLE_CHANGE: '&c&lОшибка | &7Вы не можете изменить свою роль.' SET_UPGRADE_LEVEL: '&e&lУлучшения | &7Успешно обновлен уровень {0} для острова {1}.' +SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lУлучшения | &7Успешно обновлен уровень {0} для {1}.' SET_WARP: '&e&lОстров | &7Успешно создан новый варп на {0}.' SET_WARP_OUTSIDE: '&c&lОшибка | &7Вы не можете устанавливать варпы за пределами вашего острова.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index e3a009f3f9..0f73f0a7f3 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -826,6 +826,7 @@ SCHEMATIC_SAVED: '&e&lŞematikler | &7Şematik başarıyla kaydedildi!' SELF_ROLE_CHANGE: '&c&lHata | &7Kendi rolünü değiştiremezsin.' SET_UPGRADE_LEVEL: '&e&lYükseltmeler | &7{1}''in adası için {0} seviyesi başarıyla güncellendi.' +SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lYükseltmeler | &7{1} adası için {0} seviyesi başarıyla güncellendi.' SET_WARP: '&e&lAda | &7{0} konumunda yeni bir ışınlanma noktası başarıyla oluşturuldu.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 108e7573ae..a6c58b0e47 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -782,6 +782,7 @@ SCHEMATIC_SAVED: '&e&lSchematics | &7Lưu thành công schematic!' SELF_ROLE_CHANGE: '&c&lLỗi | &7Bạn không thể thay đổi vai trò của chính mình.' SET_UPGRADE_LEVEL: '&e&lNâng Cấp | &7Nâng cấp thành công cấp độ của {0} cho đảo của {1}.' +SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&lNâng Cấp | &7Thay đổi thành công cấp độ {0} cho đảo {1}.' SET_WARP: '&e&lĐảo | &7Tạo thành công một khu vực mới tại {0}.' SET_WARP_OUTSIDE: '&c&lLỗi | &7Bạn không thể đặt khu vực bên ngoài hòn đảo của bạn.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 02ee975c13..7c3f306c95 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -697,6 +697,7 @@ SCHEMATIC_RIGHT_SELECT: '&e&l结构 | &7已选中 #1 位点 ({0})' SCHEMATIC_SAVED: '&e&l结构 | &7结构文件成功保存!' SELF_ROLE_CHANGE: '&c&l错误 | &7你不能修改自己的职位.' SET_UPGRADE_LEVEL: '&e&l升级 | &7成功更新了玩家 {1} 的岛屿等级 {0}.' +SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' SET_UPGRADE_LEVEL_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的等级 {0}.' SET_WARP: '&e&l岛屿 | &7成功在 {0} 处设置了传送点.' SET_WARP_OUTSIDE: '&c&l错误 | &7你不能在岛屿外设置传送点.' From 99c0449bc4ab4d29747a656f7375c86ed02811b5 Mon Sep 17 00:00:00 2001 From: nivcoo <36514752+nivcoo@users.noreply.github.com> Date: Fri, 14 Nov 2025 23:29:48 +0100 Subject: [PATCH 423/600] improv. fix issue stacked block (#2756) --- .../StackedBlocksInteractionServiceImpl.java | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java index b351fce3bd..c52461a8b4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/stackedblocks/StackedBlocksInteractionServiceImpl.java @@ -238,8 +238,11 @@ private InteractionResult handleBlockStackInternal(SuperiorPlayer superiorPlayer if (blockAmount + amountToDeposit > blockLimit) amountToDeposit = blockLimit - blockAmount; - if (amountToDeposit <= 0) + if (amountToDeposit <= 0) { + // Inform GUI/caller that nothing was deposited so it can refund its previewed removal + removalData.ifRight(cb -> cb.accept(0)); return InteractionResult.NOT_ENOUGH_BLOCKS; + } Island island = plugin.getGrid().getIslandAt(stackedBlockLocation); if (island != null) { @@ -264,22 +267,32 @@ private InteractionResult handleBlockStackInternal(SuperiorPlayer superiorPlayer } } - if (amountToDeposit > 0) { - int newStackedBlockAmount = blockAmount + amountToDeposit; - - if (onlinePlayer != null && !PluginEventsFactory.callBlockStackEvent(stackedBlock, onlinePlayer, blockAmount, newStackedBlockAmount)) - return InteractionResult.EVENT_CANCELLED; + if (amountToDeposit <= 0) { + // Island/global limit reached ⇒ notify caller so it can refund + removalData.ifRight(cb -> cb.accept(0)); + return InteractionResult.NOT_ENOUGH_BLOCKS; + } - if (!plugin.getStackedBlocks().setStackedBlock(stackedBlockLocation, blockKey, newStackedBlockAmount)) - return InteractionResult.GLITCHED_STACKED_BLOCK; + int newStackedBlockAmount = blockAmount + amountToDeposit; - if (island != null) - island.handleBlockPlace(blockKey, amountToDeposit); + if (onlinePlayer != null && !PluginEventsFactory.callBlockStackEvent(stackedBlock, onlinePlayer, blockAmount, newStackedBlockAmount)) { + // Event cancelled ⇒ nothing deposited, request refund + removalData.ifRight(cb -> cb.accept(0)); + return InteractionResult.EVENT_CANCELLED; + } - plugin.getProviders().notifyStackedBlocksListeners(onlinePlayer == null ? superiorPlayer.asOfflinePlayer() : onlinePlayer, - stackedBlock, IStackedBlocksListener.Action.BLOCK_PLACE); + if (!plugin.getStackedBlocks().setStackedBlock(stackedBlockLocation, blockKey, newStackedBlockAmount)) { + // Failed to persist/update ⇒ request refund + removalData.ifRight(cb -> cb.accept(0)); + return InteractionResult.GLITCHED_STACKED_BLOCK; } + if (island != null) + island.handleBlockPlace(blockKey, amountToDeposit); + + plugin.getProviders().notifyStackedBlocksListeners(onlinePlayer == null ? superiorPlayer.asOfflinePlayer() : onlinePlayer, + stackedBlock, IStackedBlocksListener.Action.BLOCK_PLACE); + final int finalAmountToDeposit = amountToDeposit; removalData.ifRight(itemRemovalCallback -> itemRemovalCallback.accept(finalAmountToDeposit)).ifLeft(usedHand -> { From 34914a6deb40de7ce68c8392843f8bd037aefc31 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 14 Nov 2025 23:31:19 +0100 Subject: [PATCH 424/600] Renamed level formula option (#2754) --- .../superiorskyblock/api/config/SettingsManager.java | 7 +++---- .../superiorskyblock/config/SettingsContainer.java | 4 ++-- .../superiorskyblock/config/SettingsManagerImpl.java | 8 +++++--- .../superiorskyblock/config/section/GlobalSection.java | 4 ++-- src/main/resources/config.yml | 6 ++---- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 60bc7669bb..7329cd36c2 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -3,7 +3,6 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; -import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; @@ -78,9 +77,9 @@ public interface SettingsManager { StackedBlocks getStackedBlocks(); /** - * The island worth to island level conversion formula. - * The formula contains a placeholder: `{}`, which is replaced with the island worth. - * Config path: island-level-formula + * The formula used to calculate a block's level when it has a worth defined but no level specified. + * The formula can contain a placeholder: `{}`, which is replaced with the block worth. + * Config path: block-level-formula */ String getIslandLevelFormula(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 1ea73aefcb..780ef0adb4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -103,7 +103,7 @@ public class SettingsContainer { public final boolean stackedBlocksAutoPickup; public final boolean stackedBlocksMenuEnabled; public final String stackedBlocksMenuTitle; - public final String islandLevelFormula; + public final String blockLevelFormula; public final boolean roundedIslandLevel; public final RoundingMode islandLevelRoundingMode; public final boolean autoBlocksTracking; @@ -307,7 +307,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config stackedBlocksAutoPickup = config.getBoolean("stacked-blocks.auto-collect", false); stackedBlocksMenuEnabled = config.getBoolean("stacked-blocks.deposit-menu.enabled", true); stackedBlocksMenuTitle = Formatters.COLOR_FORMATTER.format(config.getString("stacked-blocks.deposit-menu.title", "&lDeposit Blocks")); - islandLevelFormula = config.getString("island-level-formula", "{} / 2"); + blockLevelFormula = config.getString("block-level-formula", "{} / 2"); roundedIslandLevel = config.getBoolean("rounded-island-level", false); islandLevelRoundingMode = Optional.ofNullable(EnumHelper.getEnum(RoundingMode.class, config.getString("island-level-rounding-mode").toUpperCase(Locale.ENGLISH))) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index bd9106543b..5daaf7a9f3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -5,7 +5,6 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; -import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; @@ -29,7 +28,6 @@ import com.bgsoftware.superiorskyblock.core.errors.ManagerLoadException; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.island.top.SortingComparators; import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import org.bukkit.Location; import org.bukkit.configuration.file.YamlConfiguration; @@ -137,7 +135,7 @@ public StackedBlocks getStackedBlocks() { @Override public String getIslandLevelFormula() { - return this.global.getIslandLevelFormula(); + return this.global.getBlockLevelFormula(); } @Override @@ -724,6 +722,10 @@ private void loadContainerFromConfig(YamlConfiguration cfg) throws ManagerLoadEx } private void convertData(YamlConfiguration cfg) { + if (cfg.get("island-level-formula") != null) { + cfg.set("block-level-formula", cfg.getString("island-level-formula")); + cfg.set("island-level-formula", null); + } if (!cfg.isConfigurationSection("entity-categories")) { cfg.createSection("entity-categories"); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index 8db3debabb..887f1bc928 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -39,8 +39,8 @@ public boolean isWorldBorders() { return getContainer().worldBordersEnabled; } - public String getIslandLevelFormula() { - return getContainer().islandLevelFormula; + public String getBlockLevelFormula() { + return getContainer().blockLevelFormula; } public boolean isRoundedIslandLevels() { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 2e63af6db5..5c159db2f7 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -151,11 +151,9 @@ stacked-blocks: # The title of the menu. title: '&lDeposit Blocks' -# Set a formula to calculate the island level by it's worth. +# The formula used to calculate a block's level when it has a worth defined but no level specified. # Use {} as a placeholder for worth. Make sure you only use digits and mathematical operations! -# If you use Java 15 or above (Minecraft 1.16+), check out this page: -# https://wiki.bg-software.com/superiorskyblock/new-java-engine -island-level-formula: '{} / 2' +block-level-formula: '{} / 2' # Should the island levels be a rounded integer? rounded-island-level: false From 476c361b95dc8c0182c8ff56384117f0f1f462f7 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 15 Nov 2025 12:13:18 +0100 Subject: [PATCH 425/600] Improved disabling the upgrades module (#2767) --- .../commands/admin/AdminCommandsMap.java | 6 --- .../module/upgrades/UpgradesModule.java | 38 ++++++++++++++----- .../commands}/CmdAdminAddBlockLimit.java | 2 +- .../commands}/CmdAdminAddEntityLimit.java | 2 +- .../commands}/CmdAdminRemoveBlockLimit.java | 2 +- .../commands}/CmdAdminRemoveEntityLimit.java | 2 +- .../commands}/CmdAdminSetBlockLimit.java | 2 +- .../commands}/CmdAdminSetEntityLimit.java | 2 +- .../upgrades/type/UpgradeTypeBlockLimits.java | 6 ++- .../upgrades/type/UpgradeTypeCropGrowth.java | 5 +-- .../type/UpgradeTypeEntityLimits.java | 7 +++- .../type/UpgradeTypeIslandEffects.java | 5 +-- .../upgrades/type/UpgradeTypeMobDrops.java | 5 +-- .../type/UpgradeTypeSpawnerRates.java | 5 +-- src/main/resources/modules/bank/config.yml | 2 + .../resources/modules/generators/config.yml | 2 + .../resources/modules/missions/config.yml | 3 +- .../resources/modules/upgrades/config.yml | 4 ++ 18 files changed, 58 insertions(+), 42 deletions(-) rename src/main/java/com/bgsoftware/superiorskyblock/{commands/admin => module/upgrades/commands}/CmdAdminAddBlockLimit.java (98%) rename src/main/java/com/bgsoftware/superiorskyblock/{commands/admin => module/upgrades/commands}/CmdAdminAddEntityLimit.java (98%) rename src/main/java/com/bgsoftware/superiorskyblock/{commands/admin => module/upgrades/commands}/CmdAdminRemoveBlockLimit.java (98%) rename src/main/java/com/bgsoftware/superiorskyblock/{commands/admin => module/upgrades/commands}/CmdAdminRemoveEntityLimit.java (98%) rename src/main/java/com/bgsoftware/superiorskyblock/{commands/admin => module/upgrades/commands}/CmdAdminSetBlockLimit.java (98%) rename src/main/java/com/bgsoftware/superiorskyblock/{commands/admin => module/upgrades/commands}/CmdAdminSetEntityLimit.java (98%) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java index 8f31757195..5e230c2c76 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/AdminCommandsMap.java @@ -14,12 +14,10 @@ public void loadDefaultCommands() { clearCommands(); registerCommand(new CmdAdminAdd()); - registerCommand(new CmdAdminAddBlockLimit()); registerCommand(new CmdAdminAddBonus()); if (plugin.getSettings().isCoopMembers()) registerCommand(new CmdAdminAddCoopLimit()); registerCommand(new CmdAdminAddDisbands()); - registerCommand(new CmdAdminAddEntityLimit()); registerCommand(new CmdAdminAddSize()); registerCommand(new CmdAdminAddTeamLimit()); registerCommand(new CmdAdminAddWarpsLimit()); @@ -47,8 +45,6 @@ public void loadDefaultCommands() { registerCommand(new CmdAdminPurge()); registerCommand(new CmdAdminRecalc()); registerCommand(new CmdAdminReload()); - registerCommand(new CmdAdminRemoveBlockLimit()); - registerCommand(new CmdAdminRemoveEntityLimit()); registerCommand(new CmdAdminRemoveRatings()); registerCommand(new CmdAdminResetPermissions()); registerCommand(new CmdAdminResetSettings()); @@ -56,13 +52,11 @@ public void loadDefaultCommands() { registerCommand(new CmdAdminSchematic()); registerCommand(new CmdAdminSetBiome()); registerCommand(new CmdAdminSetBlockAmount()); - registerCommand(new CmdAdminSetBlockLimit()); registerCommand(new CmdAdminSetBonus()); registerCommand(new CmdAdminSetChestRow()); if (plugin.getSettings().isCoopMembers()) registerCommand(new CmdAdminSetCoopLimit()); registerCommand(new CmdAdminSetDisbands()); - registerCommand(new CmdAdminSetEntityLimit()); registerCommand(new CmdAdminSetIslandPreview()); registerCommand(new CmdAdminSetLeader()); registerCommand(new CmdAdminSetPermission()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java index 36835f7be5..927f754cd2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java @@ -18,7 +18,6 @@ import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; -import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.value.DoubleValue; import com.bgsoftware.superiorskyblock.core.value.IntValue; import com.bgsoftware.superiorskyblock.core.value.Value; @@ -72,17 +71,36 @@ public UpgradesModule() { @Override protected boolean onConfigCreate(SuperiorSkyblockPlugin plugin, CommentedConfiguration config, boolean firstTime) { File oldUpgradesFile = new File(plugin.getDataFolder(), "upgrades.yml"); - if (!oldUpgradesFile.exists()) - return false; - - CommentedConfiguration oldConfig = CommentedConfiguration.loadConfiguration(oldUpgradesFile); boolean updatedConfig = false; - if (oldConfig.isConfigurationSection("upgrades")) { - config.set("upgrades", oldConfig.getConfigurationSection("upgrades")); + if (oldUpgradesFile.exists()) { + CommentedConfiguration oldConfig = CommentedConfiguration.loadConfiguration(oldUpgradesFile); + + if (oldConfig.isConfigurationSection("upgrades")) + config.set("upgrades", oldConfig.getConfigurationSection("upgrades")); + + oldUpgradesFile.delete(); } - oldUpgradesFile.delete(); + if (!config.isBoolean("enabled")) { + boolean status = false; + + if (config.getBoolean("crop-growth", true)) + status = true; + else if (config.getBoolean("mob-drops", true)) + status = true; + else if (config.getBoolean("island-effects", true)) + status = true; + else if (config.getBoolean("spawner-rates", true)) + status = true; + else if (config.getBoolean("block-limits", true)) + status = true; + else if (config.getBoolean("entity-limits", true)) + status = true; + + config.set("enabled", status); + updatedConfig = true; + } return updatedConfig; } @@ -115,7 +133,7 @@ public Listener[] getModuleListeners(SuperiorSkyblockPlugin plugin) { @Override public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) { - return !isEnabled() ? null : new SuperiorCommand[]{new CmdRankup(), new CmdUpgrade()}; + return new SuperiorCommand[]{new CmdRankup(), new CmdUpgrade()}; } @Override @@ -163,8 +181,8 @@ public class Configuration implements IModuleConfiguration { private final List enabledUpgrades = new LinkedList<>(); Configuration(CommentedConfiguration config) { + this.enabled = config.getBoolean("enabled", true); loadUpgrades(config); - this.enabled = !this.enabledUpgrades.isEmpty(); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBlockLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddBlockLimit.java similarity index 98% rename from src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBlockLimit.java rename to src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddBlockLimit.java index dd9788e701..9c8d6f6c13 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddBlockLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddBlockLimit.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.commands.admin; +package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddEntityLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddEntityLimit.java similarity index 98% rename from src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddEntityLimit.java rename to src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddEntityLimit.java index 58de1a1382..44e80d5b23 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAddEntityLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminAddEntityLimit.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.commands.admin; +package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveBlockLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRemoveBlockLimit.java similarity index 98% rename from src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveBlockLimit.java rename to src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRemoveBlockLimit.java index 3904625227..0af9f77f3c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveBlockLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRemoveBlockLimit.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.commands.admin; +package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveEntityLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRemoveEntityLimit.java similarity index 98% rename from src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveEntityLimit.java rename to src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRemoveEntityLimit.java index c81b7d02ae..6fcce57bbd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminRemoveEntityLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminRemoveEntityLimit.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.commands.admin; +package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetBlockLimit.java similarity index 98% rename from src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockLimit.java rename to src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetBlockLimit.java index 0ea67b62b0..f48751f0b4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBlockLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetBlockLimit.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.commands.admin; +package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetEntityLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetEntityLimit.java similarity index 98% rename from src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetEntityLimit.java rename to src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetEntityLimit.java index e541bddd25..87551131d9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetEntityLimit.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/commands/CmdAdminSetEntityLimit.java @@ -1,4 +1,4 @@ -package com.bgsoftware.superiorskyblock.commands.admin; +package com.bgsoftware.superiorskyblock.module.upgrades.commands; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java index db170c41c6..093e4f748d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java @@ -14,6 +14,9 @@ import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; +import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddBlockLimit; +import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminRemoveBlockLimit; +import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetBlockLimit; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Location; import org.bukkit.Material; @@ -33,6 +36,7 @@ import org.bukkit.material.Directional; import org.bukkit.material.MaterialData; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -51,7 +55,7 @@ public List getListeners() { @Override public List getCommands() { - return Collections.emptyList(); + return Arrays.asList(new CmdAdminAddBlockLimit(), new CmdAdminRemoveBlockLimit(), new CmdAdminSetBlockLimit()); } private class BlockLimitsListener implements Listener { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java index f6660649db..93045784af 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java @@ -18,9 +18,6 @@ public class UpgradeTypeCropGrowth implements IUpgradeType { - private static final List commands = Arrays.asList(new CmdAdminAddCropGrowth(), - new CmdAdminSetCropGrowth()); - private final SuperiorSkyblockPlugin plugin; public UpgradeTypeCropGrowth(SuperiorSkyblockPlugin plugin) { @@ -34,7 +31,7 @@ public List getListeners() { @Override public List getCommands() { - return commands; + return Arrays.asList(new CmdAdminAddCropGrowth(), new CmdAdminSetCropGrowth()); } private class CropGrowthListener implements Listener { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java index 3dbb1bd0a3..61d42798c2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java @@ -15,6 +15,9 @@ import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminAddEntityLimit; +import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminRemoveEntityLimit; +import com.bgsoftware.superiorskyblock.module.upgrades.commands.CmdAdminSetEntityLimit; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.BukkitItems; import org.bukkit.Location; @@ -37,7 +40,7 @@ import org.bukkit.inventory.PlayerInventory; import java.lang.ref.WeakReference; -import java.util.Collections; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -69,7 +72,7 @@ public List getListeners() { @Override public List getCommands() { - return Collections.emptyList(); + return Arrays.asList(new CmdAdminAddEntityLimit(), new CmdAdminRemoveEntityLimit(), new CmdAdminSetEntityLimit()); } private Optional checkEntityBreedListener() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeIslandEffects.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeIslandEffects.java index 5181b6dcb7..79b60a278b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeIslandEffects.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeIslandEffects.java @@ -19,9 +19,6 @@ public class UpgradeTypeIslandEffects implements IUpgradeType { - private static final List commands = Arrays.asList(new CmdAdminAddEffect(), - new CmdAdminSetEffect()); - private final SuperiorSkyblockPlugin plugin; public UpgradeTypeIslandEffects(SuperiorSkyblockPlugin plugin) { @@ -37,7 +34,7 @@ public List getListeners() { @Override public List getCommands() { - return commands; + return Arrays.asList(new CmdAdminAddEffect(), new CmdAdminSetEffect()); } private class IslandEffectsListener implements Listener { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java index c9aeaf640d..c1b479c538 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeMobDrops.java @@ -28,9 +28,6 @@ public class UpgradeTypeMobDrops implements IUpgradeType { - private static final List commands = Arrays.asList(new CmdAdminAddMobDrops(), - new CmdAdminSetMobDrops()); - private final SuperiorSkyblockPlugin plugin; private final boolean isWildStackerInstalled; @@ -46,7 +43,7 @@ public List getListeners() { @Override public List getCommands() { - return commands; + return Arrays.asList(new CmdAdminAddMobDrops(), new CmdAdminSetMobDrops()); } private static boolean canDupeDropsForEntity(Entity entity) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeSpawnerRates.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeSpawnerRates.java index c52403caae..1d0abdba3e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeSpawnerRates.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeSpawnerRates.java @@ -22,9 +22,6 @@ public class UpgradeTypeSpawnerRates implements IUpgradeType { - private static final List commands = Arrays.asList(new CmdAdminAddSpawnerRates(), - new CmdAdminSetSpawnerRates()); - private final SuperiorSkyblockPlugin plugin; public UpgradeTypeSpawnerRates(SuperiorSkyblockPlugin plugin) { @@ -38,7 +35,7 @@ public List getListeners() { @Override public List getCommands() { - return commands; + return Arrays.asList(new CmdAdminAddSpawnerRates(), new CmdAdminSetSpawnerRates()); } public void handleSpawnerPlace(Block block) { diff --git a/src/main/resources/modules/bank/config.yml b/src/main/resources/modules/bank/config.yml index 7f535c9542..e542f52df6 100644 --- a/src/main/resources/modules/bank/config.yml +++ b/src/main/resources/modules/bank/config.yml @@ -5,6 +5,8 @@ ## ## ###################################################### +# Whether the module should be enabled. +# When disabled, all module commands and features will also be disabled. enabled: true # Set the divider for the island bank money in the total island worth. diff --git a/src/main/resources/modules/generators/config.yml b/src/main/resources/modules/generators/config.yml index 33a377b333..b7daeac0e3 100644 --- a/src/main/resources/modules/generators/config.yml +++ b/src/main/resources/modules/generators/config.yml @@ -5,6 +5,8 @@ ## ## ###################################################### +# Whether the module should be enabled. +# When disabled, all module commands and features will also be disabled. enabled: true # Whether generators should match their intended world instead of the world they actually generate in. diff --git a/src/main/resources/modules/missions/config.yml b/src/main/resources/modules/missions/config.yml index a33cf11f58..27c6fc62aa 100644 --- a/src/main/resources/modules/missions/config.yml +++ b/src/main/resources/modules/missions/config.yml @@ -5,7 +5,8 @@ ## ## ###################################################### -# Should missions be enabled on your server? +# Whether the module should be enabled. +# When disabled, all module commands and features will also be disabled. enabled: true # Should mission rewards be automatically claimed outside island worlds? diff --git a/src/main/resources/modules/upgrades/config.yml b/src/main/resources/modules/upgrades/config.yml index 3617b5f0fd..03f3ec677a 100644 --- a/src/main/resources/modules/upgrades/config.yml +++ b/src/main/resources/modules/upgrades/config.yml @@ -5,6 +5,10 @@ ## ## ###################################################### +# Whether the module should be enabled. +# When disabled, all module commands and features will also be disabled. +enabled: true + # Whether crop-growth should be enabled. # When disabled, the plugin will not alter crop growth. crop-growth: true From 70fe996c4c6648f3e7e455aabe036096a2841ec4 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 15 Nov 2025 13:02:17 +0100 Subject: [PATCH 426/600] Fixed dimension usage in commands (#2766) --- .../commands/CommandTabCompletes.java | 10 ++++++---- .../commands/admin/CmdAdminResetWorld.java | 16 +++------------- .../commands/admin/CmdAdminTeleport.java | 5 +++-- .../commands/admin/CmdAdminUnlockWorld.java | 12 ++++-------- .../superiorskyblock/core/messages/Message.java | 1 + .../commands/CmdAdminAddGenerator.java | 4 ++-- .../commands/CmdAdminClearGenerator.java | 4 ++-- .../commands/CmdAdminSetGenerator.java | 4 ++-- src/main/resources/lang/de-DE.yml | 3 ++- src/main/resources/lang/en-US.yml | 3 ++- src/main/resources/lang/es-ES.yml | 3 ++- src/main/resources/lang/fr-FR.yml | 3 ++- src/main/resources/lang/it-IT.yml | 3 ++- src/main/resources/lang/iw-IL.yml | 3 ++- src/main/resources/lang/pl-PL.yml | 3 ++- src/main/resources/lang/pt-BR.yml | 3 ++- src/main/resources/lang/ru-RU.yml | 3 ++- src/main/resources/lang/tr-TR.yml | 3 ++- src/main/resources/lang/vi-VN.yml | 3 ++- src/main/resources/lang/zh-CN.yml | 3 ++- 20 files changed, 47 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index 8c25c4f3b1..47e3662c63 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -259,10 +259,12 @@ public static List getIslandFlags(String argument) { .build(IslandFlag.values(), islandFlag -> islandFlag.getName().toLowerCase(Locale.ENGLISH)); } - public static List getDimensions(String argument) { - return filterByArgument(Dimension.values(), - dimension -> dimension.getName().toLowerCase(Locale.ENGLISH), - argument.toLowerCase(Locale.ENGLISH)); + public static List getDimensions(SuperiorSkyblockPlugin plugin, String argument) { + String lowerArgument = argument.toLowerCase(Locale.ENGLISH); + return new SequentialListBuilder().build(Dimension.values().stream() + .filter(dimension -> plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension) && + dimension.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) + .map(dimension -> dimension.getName().toLowerCase(Locale.ENGLISH))); } public static List getBorderColors(String argument) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java index b204e00556..3bbe5bac81 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java @@ -53,7 +53,8 @@ public String getUsage(java.util.Locale locale) { return "admin resetworld <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + - Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> "; + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + + Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + ">"; } @Override @@ -164,18 +165,7 @@ private static void regenerateSchematicInternal(Island island, Dimension dimensi @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { - if (args.length != 4) - return Collections.emptyList(); - - List environments = new ArrayList<>(); - - for (Dimension dimension : Dimension.values()) { - if (plugin.getProviders().getWorldsProvider().isDimensionEnabled(dimension)) { - environments.add(dimension.getName().toLowerCase(Locale.ENGLISH)); - } - } - - return CommandTabCompletes.getCustomComplete(args[3], environments.toArray(new String[0])); + return args.length == 4 ? CommandTabCompletes.getDimensions(plugin, args[3]) : Collections.emptyList(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java index 7cf9a48dce..63f4741127 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java @@ -47,7 +47,8 @@ public String getPermission() { public String getUsage(java.util.Locale locale) { return "admin teleport <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + - Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "> [normal/nether/the_end]"; + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "> [" + + Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + "]"; } @Override @@ -118,7 +119,7 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { - return args.length == 4 ? CommandTabCompletes.getDimensions(args[3]) : Collections.emptyList(); + return args.length == 4 ? CommandTabCompletes.getDimensions(plugin, args[3]) : Collections.emptyList(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java index 2ee5e2ab30..00408fb7b1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminUnlockWorld.java @@ -34,7 +34,8 @@ public String getUsage(java.util.Locale locale) { return "admin unlockworld <" + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + - Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> "; + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + + Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + "> "; } @Override @@ -85,13 +86,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { - if (args.length == 5) - return CommandTabCompletes.getCustomComplete(args[4], "true", "false"); - - if (args.length != 4) - return Collections.emptyList(); - - return CommandTabCompletes.getDimensions(args[3]); + return args.length == 4 ? CommandTabCompletes.getDimensions(plugin, args[3]) : args.length == 5 ? + CommandTabCompletes.getCustomComplete(args[4], "true", "false") : Collections.emptyList(); } private void handleWorldUnlock(CommandSender sender, List islands, Dimension dimension, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index e96915bd9c..9c2cdcf382 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -142,6 +142,7 @@ public enum Message { COMMAND_ARGUMENT_BIOME("biome"), COMMAND_ARGUMENT_BORDER_COLOR("border-color"), COMMAND_ARGUMENT_COMMAND("command..."), + COMMAND_ARGUMENT_DIMENSION("dimension"), COMMAND_ARGUMENT_DISCORD("discord..."), COMMAND_ARGUMENT_EFFECT("effect"), COMMAND_ARGUMENT_EMAIL("email"), diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminAddGenerator.java b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminAddGenerator.java index 31c557249d..34ceb32f3b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminAddGenerator.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminAddGenerator.java @@ -42,7 +42,7 @@ public String getUsage(java.util.Locale locale) { Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_VALUE.getMessage(locale) + "> [" + - Message.COMMAND_ARGUMENT_WORLD.getMessage(locale) + "]"; + Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + "]"; } @Override @@ -140,7 +140,7 @@ else if (targetPlayer == null) @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getMaterialsForGenerators(args[3]) : - args.length == 6 ? CommandTabCompletes.getDimensions(args[5]) : Collections.emptyList(); + args.length == 6 ? CommandTabCompletes.getDimensions(plugin, args[5]) : Collections.emptyList(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java index 2005e923b5..0d3e4386e4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminClearGenerator.java @@ -34,7 +34,7 @@ public String getUsage(java.util.Locale locale) { Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> [" + - Message.COMMAND_ARGUMENT_WORLD.getMessage(locale) + "]"; + Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + "]"; } @Override @@ -94,6 +94,6 @@ else if (targetPlayer == null) @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { - return args.length == 4 ? CommandTabCompletes.getDimensions(args[3]) : Collections.emptyList(); + return args.length == 4 ? CommandTabCompletes.getDimensions(plugin, args[3]) : Collections.emptyList(); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminSetGenerator.java b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminSetGenerator.java index 570c7d86b4..cabd915567 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminSetGenerator.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/commands/CmdAdminSetGenerator.java @@ -42,7 +42,7 @@ public String getUsage(java.util.Locale locale) { Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_MATERIAL.getMessage(locale) + "> <" + Message.COMMAND_ARGUMENT_VALUE.getMessage(locale) + "> [" + - Message.COMMAND_ARGUMENT_WORLD.getMessage(locale) + "]"; + Message.COMMAND_ARGUMENT_DIMENSION.getMessage(locale) + "]"; } @Override @@ -137,7 +137,7 @@ else if (targetPlayer == null) @Override public List adminTabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, Island island, String[] args) { return args.length == 4 ? CommandTabCompletes.getMaterialsForGenerators(args[3]) : - args.length == 6 ? CommandTabCompletes.getDimensions(args[5]) : Collections.emptyList(); + args.length == 6 ? CommandTabCompletes.getDimensions(plugin, args[5]) : Collections.emptyList(); } } diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index ce8ec166f5..fe4a9208e1 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -167,6 +167,7 @@ COMMAND_ARGUMENT_AMOUNT: Betrag COMMAND_ARGUMENT_BIOME: biom COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: Befehl... +COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: Discord... COMMAND_ARGUMENT_EFFECT: Trank-Effekt COMMAND_ARGUMENT_EMAIL: E-Mail @@ -488,7 +489,7 @@ INVALID_BLOCK: '&c&lError | &7Ungültige Blockposition {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_EFFECT: '&c&lError | &7Ungültige Wirkung {0}.' INVALID_ENTITY: '&c&lError | &7Ungültige Entität {0}.' -INVALID_ENVIRONMENT: '&c&lError | &7Ungültige Welt {0}.' +INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.' INVALID_ISLAND: '&c&lError | &7Du hast keine Insel.' INVALID_ISLAND_LOCATION: '&c&lError | &7An deinem Standort gibt es keine Insel.' diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index f408be93b4..4494d67695 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -115,6 +115,7 @@ COMMAND_ARGUMENT_AMOUNT: 'amount' COMMAND_ARGUMENT_BIOME: 'biome' COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: 'command...' +COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: 'discord...' COMMAND_ARGUMENT_EFFECT: 'potion-effect' COMMAND_ARGUMENT_EMAIL: 'email' @@ -378,7 +379,7 @@ INVALID_BLOCK: '&c&lError | &7Invalid block location {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_EFFECT: '&c&lError | &7Invalid effect {0}.' INVALID_ENTITY: '&c&lError | &7Invalid entity {0}.' -INVALID_ENVIRONMENT: '&c&lError | &7Invalid world {0}.' +INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.' INVALID_ISLAND: '&c&lError | &7You don''t have an island.' INVALID_ISLAND_LOCATION: '&c&lError | &7There is no island in your location.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 1e9c739ca2..314a48b66a 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -115,6 +115,7 @@ COMMAND_ARGUMENT_AMOUNT: 'cantidad' COMMAND_ARGUMENT_BIOME: 'bioma' COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: 'command...' +COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: 'discord...' COMMAND_ARGUMENT_EFFECT: 'pefecto-de-poción' COMMAND_ARGUMENT_EMAIL: 'email' @@ -378,7 +379,7 @@ INVALID_BLOCK: '&c&lError | &7Ubicación de bloque no válida {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_EFFECT: '&c&lError | &7Efecto no válido {0}.' INVALID_ENTITY: '&c&lError | &7Entidad no válida {0}.' -INVALID_ENVIRONMENT: '&c&lError | &7Mundo no válido {0}.' +INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.' INVALID_ISLAND: '&c&lError | &7No tienes una isla.' INVALID_ISLAND_LOCATION: '&c&lError | &7No hay ninguna isla en tu ubicación.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 77f06c827e..688eacbf75 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -115,6 +115,7 @@ COMMAND_ARGUMENT_AMOUNT: quantité COMMAND_ARGUMENT_BIOME: biome COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: 'commande...' +COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: discord COMMAND_ARGUMENT_EFFECT: effet-de-potion COMMAND_ARGUMENT_EMAIL: email @@ -378,8 +379,8 @@ INVALID_BLOCK: '&c&lErreur | &7Emplacement {0} du bloc invalide.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_EFFECT: '&c&lErreur | &7Effet invalide {0}.' INVALID_ENTITY: '&c&lErreur | &7Entité invalide {0}.' +INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_SCHEMATIC: '&c&lErreur | &7Il n''existe aucun schematic portant le nom {0}.' -INVALID_ENVIRONMENT: '&c&lErreur | &7Monde invalide {0}.' INVALID_INTERVAL: '&c&lErreur | &7Interval invalide {0}.' INVALID_ISLAND: '&c&lErreur | &7Vous n''avez pas d''île.' INVALID_ISLAND_LOCATION: '&c&lErreur | &7Il n''y a pas d''île sur votre position.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 4addd6ef6b..5c82ff2ac5 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -118,6 +118,7 @@ COMMAND_ARGUMENT_AMOUNT: quantità COMMAND_ARGUMENT_BIOME: bioma COMMAND_ARGUMENT_BORDER_COLOR: 'colore-bordo' COMMAND_ARGUMENT_COMMAND: 'comando...' +COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: discord... COMMAND_ARGUMENT_EFFECT: effetto-pozione COMMAND_ARGUMENT_EMAIL: email @@ -382,7 +383,7 @@ INVALID_BLOCK: '&c&lErrore| &7Posizione del blocco invalida {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Colore del bordo non valido: {0}' INVALID_EFFECT: '&c&lErrore| &7Effetto invalido {0}.' INVALID_ENTITY: '&c&lErrore | &7Entità invalida {0}.' -INVALID_ENVIRONMENT: '&c&lErrore | &7Mondo invalido {0}.' +INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lError | &7Intervallo non valido: {0}' INVALID_ISLAND: '&c&lErrore | &7Non hai un''isola.' INVALID_ISLAND_LOCATION: '&c&lErrore | &7Non c''è un isola nella tua posizione.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index ba57d13ea1..45af3f586a 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -123,6 +123,7 @@ COMMAND_ARGUMENT_AMOUNT: תומכ COMMAND_ARGUMENT_BIOME: 'biome' COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: 'command...' +COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: '...דרוקסיד' COMMAND_ARGUMENT_EFFECT: 'potion-effect' COMMAND_ARGUMENT_EMAIL: ליימיא @@ -394,7 +395,7 @@ INVALID_BLOCK: '&c&lError | &7Invalid block location {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_EFFECT: '&c&lError | &7Invalid effect {0}.' INVALID_ENTITY: '&c&lError | &7Invalid entity {0}.' -INVALID_ENVIRONMENT: '&c&lהאיגש | &7םייק אל {0} םלועה.' +INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.' INVALID_ISLAND: '&c&lהאיגש | &7יא ךל ןיא.' INVALID_ISLAND_LOCATION: '&c&lהאיגש | &7ךלש םוקימב יא ןיא.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index fa937e0cbd..3649a44728 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -115,6 +115,7 @@ COMMAND_ARGUMENT_AMOUNT: 'kwota' COMMAND_ARGUMENT_BIOME: 'biom' COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: 'polecenie...' +COMMAND_ARGUMENT_DIMENSION: 'wymiar' COMMAND_ARGUMENT_DISCORD: 'niezgoda...' COMMAND_ARGUMENT_EFFECT: 'efekt mikstury' COMMAND_ARGUMENT_EMAIL: 'e-mail' @@ -378,7 +379,7 @@ INVALID_BLOCK: '&c&lBlad | &7Nieprawidlowa lokalizacja bloku {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_EFFECT: '&c&lBlad | &7Nieprawidlowy efekt {0}.' INVALID_ENTITY: '&c&lBlad | &7Nieprawidlowa jednostka {0}.' -INVALID_ENVIRONMENT: '&c&lBlad | &7Nieprawidlowy swiat {0}.' +INVALID_ENVIRONMENT: '&c&lBlad | &7Nieprawidlowy wymiar {0}.' INVALID_INTERVAL: '&c&lError | &7Invalid interval {0}.' INVALID_ISLAND: '&c&lBlad | &7Nie masz wyspy.' INVALID_ISLAND_LOCATION: '&c&lBlad | &7W Twojej lokalizacji nie ma wyspy.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 83eac78656..08f1ddf926 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -115,6 +115,7 @@ COMMAND_ARGUMENT_AMOUNT: 'quantidade' COMMAND_ARGUMENT_BIOME: 'bioma' COMMAND_ARGUMENT_BORDER_COLOR: 'cor-da-borda' COMMAND_ARGUMENT_COMMAND: 'comando...' +COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: 'discord...' COMMAND_ARGUMENT_EFFECT: 'efeito-de-poção' COMMAND_ARGUMENT_EMAIL: 'email' @@ -378,7 +379,7 @@ INVALID_BLOCK: '&c&lErro | &7Localização de bloco inválida {0}.' INVALID_BORDER_COLOR: '&c&lErro | &7Cor da borda inválida {0}.' INVALID_EFFECT: '&c&lErro | &7Efeito inválido {0}.' INVALID_ENTITY: '&c&lErro | &7Entidade inválida {0}.' -INVALID_ENVIRONMENT: '&c&lErro | &7Mundo inválido {0}.' +INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lErro | &7Intervalo inválido {0}.' INVALID_ISLAND: '&c&lErro | &7Você não tem uma ilha.' INVALID_ISLAND_LOCATION: '&c&lErro | &7Não há ilha na sua localização.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index d0d52ee799..92cc1e0932 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -115,6 +115,7 @@ COMMAND_ARGUMENT_AMOUNT: 'количество' COMMAND_ARGUMENT_BIOME: 'биом' COMMAND_ARGUMENT_BORDER_COLOR: 'цвет-границы' COMMAND_ARGUMENT_COMMAND: 'команда...' +COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: 'дискорд...' COMMAND_ARGUMENT_EFFECT: 'эффект-зелья' COMMAND_ARGUMENT_EMAIL: 'email' @@ -378,7 +379,7 @@ INVALID_BLOCK: '&c&lОшибка | &7Недопустимое местополо INVALID_BORDER_COLOR: '&c&lОшибка | &7Недопустимый цвет границы {0}.' INVALID_EFFECT: '&c&lОшибка | &7Недопустимый эффект {0}.' INVALID_ENTITY: '&c&lОшибка | &7Недопустимое существо {0}.' -INVALID_ENVIRONMENT: '&c&lОшибка | &7Недопустимый мир {0}.' +INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lОшибка | &7Недопустимый интервал {0}.' INVALID_ISLAND: '&c&lОшибка | &7У вас нет острова.' INVALID_ISLAND_LOCATION: '&c&lОшибка | &7В вашем местоположении нет острова.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 0f73f0a7f3..5d10035b75 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -159,6 +159,7 @@ COMMAND_ARGUMENT_AMOUNT: miktar COMMAND_ARGUMENT_BIOME: biyom COMMAND_ARGUMENT_BORDER_COLOR: sınır-rengi COMMAND_ARGUMENT_COMMAND: komut... +COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: discord... COMMAND_ARGUMENT_EFFECT: iksir-efekti COMMAND_ARGUMENT_EMAIL: e-posta @@ -462,7 +463,7 @@ INVALID_BLOCK: '&c&lHata | &7Geçersiz blok konumu {0}.' INVALID_BORDER_COLOR: '&c&lHata | &7Geçersiz sınır rengi {0}.' INVALID_EFFECT: '&c&lHata | &7Geçersiz efekt {0}.' INVALID_ENTITY: '&c&lHata | &7Geçersiz varlık {0}.' -INVALID_ENVIRONMENT: '&c&lHata | &7Geçersiz dünya {0}.' +INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lHata | &7Geçersiz aralık {0}.' INVALID_ISLAND: '&c&lHata | &7Bir adan yok.' INVALID_ISLAND_LOCATION: '&c&lHata | &7Konumunda bir ada bulunmuyor.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index a6c58b0e47..b41f2276f2 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -140,6 +140,7 @@ COMMAND_ARGUMENT_AMOUNT: so-luong COMMAND_ARGUMENT_BIOME: quan-xa COMMAND_ARGUMENT_BORDER_COLOR: 'border-color' COMMAND_ARGUMENT_COMMAND: lenh... +COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: discord... COMMAND_ARGUMENT_EFFECT: hieu-ung-thuoc COMMAND_ARGUMENT_EMAIL: email @@ -430,7 +431,7 @@ INVALID_BLOCK: '&c&lLỗi | &7Vị trí khối không hợp lệ {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' INVALID_EFFECT: '&c&lLỗi | &7Hiệu ứng không hợp lệ {0}.' INVALID_ENTITY: '&c&lLỗi | &7Vật thể không chính xác {0}.' -INVALID_ENVIRONMENT: '&c&lLỗi | &7Thế giới {0} không hợp lệ.' +INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&lLỗi | &7Thời gian nghỉ không hợp lệ {0}.' INVALID_ISLAND: '&c&lLỗi | &7Bạn không có một hòn đảo.' INVALID_ISLAND_LOCATION: '&c&lLỗi | &7Không có đảo nào ở vị trí của bạn.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 7c3f306c95..34384db464 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -115,6 +115,7 @@ COMMAND_ARGUMENT_AMOUNT: '数量' COMMAND_ARGUMENT_BIOME: '群系' COMMAND_ARGUMENT_BORDER_COLOR: '边界颜色' COMMAND_ARGUMENT_COMMAND: '命令...' +COMMAND_ARGUMENT_DIMENSION: 'dimension' COMMAND_ARGUMENT_DISCORD: 'discord...' COMMAND_ARGUMENT_EFFECT: '药水效果' COMMAND_ARGUMENT_EMAIL: '邮箱' @@ -378,7 +379,7 @@ INVALID_BLOCK: '&c&l错误 | &7无效方块位置 {0}.' INVALID_BORDER_COLOR: '&c&l错误 | &7无效边界颜色 {0}.' INVALID_EFFECT: '&c&l错误 | &7无效效果 {0}.' INVALID_ENTITY: '&c&l错误 | &7无效实体 {0}.' -INVALID_ENVIRONMENT: '&c&l错误 | &7无效世界 {0}.' +INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' INVALID_INTERVAL: '&c&l错误 | &7无效间隔 {0}.' INVALID_ISLAND: '&c&l错误 | &7你没有岛屿.' INVALID_ISLAND_LOCATION: '&c&l错误 | &7你当前位置没有岛屿.' From 3c3679b2b7e6d56c7dca0aa725a75340c1ce3268 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 15 Nov 2025 15:07:46 +0200 Subject: [PATCH 427/600] Fix bank interest is not given to players correctly (#2770) --- .../core/threads/BukkitExecutor.java | 16 +++-- .../superiorskyblock/island/SIsland.java | 63 +++++++++++-------- .../notifications/IslandNotifications.java | 11 ++++ 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java index 36ace404b3..74fc16f1f8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.core.threads; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -29,14 +30,16 @@ public static void init(SuperiorSkyblockPlugin plugin) { BukkitExecutor.plugin = plugin; } - public static void ensureMain(Runnable runnable) { + @Nullable + public static BukkitTask ensureMain(Runnable runnable) { if (ensureNotShudown()) - return; + return null; if (state != State.PREPARE_SHUTDOWN && !Bukkit.isPrimaryThread()) { - sync(runnable); + return sync(runnable); } else { runnable.run(); + return null; } } @@ -67,14 +70,15 @@ public static void async(Runnable runnable) { } } - public static void async(Runnable runnable, long delay) { + public static BukkitTask async(Runnable runnable, long delay) { if (ensureNotShudown()) - return; + return null; if (state == State.PREPARE_SHUTDOWN) { runnable.run(); + return null; } else { - Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay); + return Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, runnable, delay); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 2f755a3647..b0cfd27107 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -148,6 +148,7 @@ import java.util.SortedSet; import java.util.TreeSet; import java.util.UUID; +import java.util.WeakHashMap; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadLocalRandom; @@ -180,6 +181,7 @@ protected PlaceholdersService create() { private final IslandBlocksTrackerAlgorithm blocksTracker; private final IslandEntitiesTrackerAlgorithm entitiesTracker; private final Synchronized bankInterestTask = Synchronized.of(null); + private final Synchronized> activeTasks = Synchronized.of(Collections.newSetFromMap(new WeakHashMap<>())); private final DirtyChunksContainer dirtyChunksContainer; private final LazyReference islandCache = new LazyReference() { @Override @@ -521,7 +523,7 @@ public void inviteMember(SuperiorPlayer superiorPlayer) { superiorPlayer.addInvite(this); //Revoke the invite after 5 minutes - BukkitExecutor.sync(() -> revokeInvite(superiorPlayer), 6000L); + registerTask(BukkitExecutor.sync(() -> revokeInvite(superiorPlayer), 6000L)); } @Override @@ -1743,6 +1745,11 @@ public void disbandIsland() { } }); + this.activeTasks.write(activeTasks -> { + activeTasks.forEach(BukkitTask::cancel); + }); + this.bankInterestTask.set((BukkitTask) null); + invitedPlayers.forEach(invitedPlayer -> invitedPlayer.removeInvite(this)); coopPlayers.forEach(coopPlayer -> coopPlayer.removeCoop(this)); @@ -1843,11 +1850,9 @@ public void calcIslandWorth(@Nullable SuperiorPlayer asker, @Nullable Runnable c return; } - if (Bukkit.isPrimaryThread()) { + registerTask(BukkitExecutor.ensureMain(() -> { calcIslandWorthInternal(asker, callback); - } else { - BukkitExecutor.sync(() -> calcIslandWorthInternal(asker, callback)); - } + })); } @Override @@ -1909,12 +1914,12 @@ private void setIslandSizeInternal(IntValue islandSize) { // We now collect the new chunks after the size was changed List newChunks = getLoadedChunks(IslandChunkFlags.ONLY_PROTECTED); - BukkitExecutor.ensureMain(() -> { + registerTask(BukkitExecutor.ensureMain(() -> { // We stop all old chunks from being ticked. oldChunks.getValue().forEach(chunk -> plugin.getNMSChunks().startTickingChunk(this, chunk, true)); // We start ticking all the new chunks newChunks.forEach(chunk -> plugin.getNMSChunks().startTickingChunk(this, chunk, false)); - }); + })); } this.protectedArea.update(this.center, getIslandSize()); @@ -2180,7 +2185,7 @@ public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ig Log.debug(Debug.EXECUTE_ISLAND_COMMANDS, owner.getName(), command, onlyOnlineMembers, Arrays.toString(ignoredMembers)); - BukkitExecutor.ensureMain(() -> { + registerTask(BukkitExecutor.ensureMain(() -> { forEachIslandMember(ignoredMembers, onlyOnlineMembers, islandMember -> { String playerCommand = command; @@ -2191,7 +2196,7 @@ public void executeCommand(String command, boolean onlyOnlineMembers, UUID... ig Bukkit.dispatchCommand(Bukkit.getConsoleSender(), playerCommand); }); - }); + })); } @Override @@ -2296,7 +2301,7 @@ public boolean giveInterest(boolean checkOnlineOwner) { long currentTime = System.currentTimeMillis() / 1000; int bankInterestRecentActive = BuiltinModules.BANK.getConfiguration().getBankInterestRecentActive(); - if (checkOnlineOwner && bankInterestRecentActive > 0 && + if (checkOnlineOwner && bankInterestRecentActive > 0 && !owner.isOnline() && currentTime - owner.getLastTimeStatus() > bankInterestRecentActive) { Log.debugResult(Debug.GIVE_BANK_INTEREST, "Return Cooldown", owner.getName()); return false; @@ -2337,11 +2342,7 @@ public void setLastInterestTime(long lastInterest) { if (BuiltinModules.BANK.getConfiguration().isBankInterestEnabled()) { long ticksToNextInterest = BuiltinModules.BANK.getConfiguration().getBankInterestInterval() * 20L; - this.bankInterestTask.set(bankInterestTask -> { - if (bankInterestTask != null) - bankInterestTask.cancel(); - return BukkitExecutor.sync(() -> giveInterest(true), ticksToNextInterest); - }); + resetBankInterestTask(ticksToNextInterest); } this.lastInterest = lastInterest; @@ -2355,6 +2356,14 @@ public long getNextInterest() { return bankInterestInterval - (currentTime - lastInterest); } + private void resetBankInterestTask(long ticksToNextInterest) { + this.bankInterestTask.set(bankInterestTask -> { + if (bankInterestTask != null) + bankInterestTask.cancel(); + return registerTask(BukkitExecutor.sync(() -> giveInterest(true), ticksToNextInterest)); + }); + } + /* * Worth related methods */ @@ -3371,7 +3380,7 @@ public void setPotionEffect(PotionEffectType type, int level) { if (level == IntValue.getNonSynced(oldPotionLevel, -1)) return; - BukkitExecutor.ensureMain(() -> getAllPlayersInside().forEach(superiorPlayer -> { + registerTask(BukkitExecutor.ensureMain(() -> getAllPlayersInside().forEach(superiorPlayer -> { Player player = superiorPlayer.asPlayer(); assert player != null; if (oldPotionLevel != null && oldPotionLevel.get() > level) @@ -3379,7 +3388,7 @@ public void setPotionEffect(PotionEffectType type, int level) { PotionEffect potionEffect = new PotionEffect(type, Integer.MAX_VALUE, level - 1); player.addPotionEffect(potionEffect, true); - })); + }))); IslandsDatabaseBridge.saveIslandEffect(this, type, level); } @@ -3395,11 +3404,11 @@ public void removePotionEffect(PotionEffectType type) { if (oldEffectLevel == null) return; - BukkitExecutor.ensureMain(() -> getAllPlayersInside().forEach(superiorPlayer -> { + registerTask(BukkitExecutor.ensureMain(() -> getAllPlayersInside().forEach(superiorPlayer -> { Player player = superiorPlayer.asPlayer(); if (player != null) player.removePotionEffect(type); - })); + }))); IslandsDatabaseBridge.removeIslandEffect(this, type); } @@ -4649,7 +4658,8 @@ private void saveBlockCounts(BigInteger currentTotalBlocksCount, BigDecimal oldW BigDecimal newLevel = getIslandLevel(); if (oldLevel.compareTo(newLevel) != 0 || oldWorth.compareTo(newWorth) != 0) { - BukkitExecutor.async(() -> PluginEventsFactory.callIslandWorthUpdateEvent(this, oldWorth, oldLevel, newWorth, newLevel), 0L); + registerTask(BukkitExecutor.async(() -> + PluginEventsFactory.callIslandWorthUpdateEvent(this, oldWorth, oldLevel, newWorth, newLevel), 0L)); } BigInteger deltaBlockCounts = this.lastSavedBlockCounts.subtract(currentTotalBlocksCount); @@ -4888,11 +4898,7 @@ private void startBankInterest() { if (ticksToNextInterest <= 0) { giveInterest(true); } else { - this.bankInterestTask.set(bankInterestTask -> { - if (bankInterestTask != null) - bankInterestTask.cancel(); - return BukkitExecutor.sync(() -> giveInterest(true), ticksToNextInterest); - }); + resetBankInterestTask(ticksToNextInterest); } } @@ -5255,6 +5261,13 @@ private R accessBlocksTracker(boolean rawBlocks, Function activeTasks.add(bukkitTask)); + } + return bukkitTask; + } + public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, SIsland::onSettingsUpdate); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/notifications/IslandNotifications.java b/src/main/java/com/bgsoftware/superiorskyblock/island/notifications/IslandNotifications.java index 88c7a5c045..0ff1814545 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/notifications/IslandNotifications.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/notifications/IslandNotifications.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.module.BuiltinModules; import java.util.Collections; @@ -42,6 +43,16 @@ public static void notifyPlayerJoin(SuperiorPlayer superiorPlayer) { IslandUtils.sendMessage(island, Message.PLAYER_JOIN_ANNOUNCEMENT, Collections.singletonList(superiorPlayer.getUniqueId()), superiorPlayer.getName()); island.updateLastTime(); island.setCurrentlyActive(true); + + // Give interest as soon as the owner joins the server + if (BuiltinModules.BANK.getConfiguration().isBankInterestEnabled() && superiorPlayer == island.getOwner()) { + int bankInterestInterval = BuiltinModules.BANK.getConfiguration().getBankInterestInterval(); + long currentTime = System.currentTimeMillis() / 1000; + long ticksToNextInterest = (bankInterestInterval - (currentTime - island.getLastInterestTime())) * 20; + if (ticksToNextInterest <= 0) { + island.giveInterest(false); + } + } } } From 2a10930432903cda99d6b5f7bac923fc601b6130 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Mon, 24 Nov 2025 10:59:33 +0100 Subject: [PATCH 428/600] Fixed some things related to new features in 1.21.9+ (#2782) --- .../superiorskyblock/core/Materials.java | 5 ++--- .../button/impl/CountsPagedObjectButton.java | 1 + src/main/resources/heads.yml | 2 ++ src/main/resources/interactables.yml | 20 +++++++++++++++++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java index ccd284a2e4..212d8c1c8e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java @@ -158,9 +158,8 @@ private static EnumMap> setupMaterialTags() { materialTags.add(Tag.RAIL); if (materialName.contains("MINECART")) materialTags.add(Tag.MINECART); - if (material == Material.CHEST || material == Material.ENDER_CHEST || - material == Material.TRAPPED_CHEST || materialName.contains("SHULKER_BOX") || - materialName.equals("BARREL")) + if (material == Material.CHEST || materialName.endsWith("_CHEST") || + materialName.contains("SHULKER_BOX") || materialName.equals("BARREL")) materialTags.add(Tag.CHEST); if (materialName.contains("BOAT")) materialTags.add(Tag.BOAT); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java index 01c0a21402..db993a43de 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java @@ -66,6 +66,7 @@ public class CountsPagedObjectButton extends AbstractPagedMenuButton Date: Mon, 24 Nov 2025 11:05:24 +0100 Subject: [PATCH 429/600] Added /is admin addbanklimit command (#2776) --- .../core/messages/Message.java | 1 + .../module/bank/BankModule.java | 4 +- .../bank/commands/CmdAdminAddBankLimit.java | 94 +++++++++++++++++++ src/main/resources/lang/de-DE.yml | 3 +- src/main/resources/lang/en-US.yml | 3 +- src/main/resources/lang/es-ES.yml | 3 +- src/main/resources/lang/fr-FR.yml | 3 +- src/main/resources/lang/it-IT.yml | 3 +- src/main/resources/lang/iw-IL.yml | 3 +- src/main/resources/lang/pl-PL.yml | 3 +- src/main/resources/lang/pt-BR.yml | 3 +- src/main/resources/lang/ru-RU.yml | 3 +- src/main/resources/lang/tr-TR.yml | 3 +- src/main/resources/lang/vi-VN.yml | 3 +- src/main/resources/lang/zh-CN.yml | 3 +- src/main/resources/plugin.yml | 4 +- 16 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminAddBankLimit.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 9c2cdcf382..d8d2a0eee5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -183,6 +183,7 @@ public enum Message { COMMAND_DESCRIPTION_ACCEPT, COMMAND_DESCRIPTION_ADMIN, COMMAND_DESCRIPTION_ADMIN_ADD, + COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT, COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT, COMMAND_DESCRIPTION_ADMIN_ADD_BONUS, COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java index 6331db5c4d..d832dfd86b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/BankModule.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.module.BuiltinModule; import com.bgsoftware.superiorskyblock.module.IModuleConfiguration; +import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminAddBankLimit; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminDeposit; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminSetBankLimit; import com.bgsoftware.superiorskyblock.module.bank.commands.CmdAdminWithdraw; @@ -78,7 +79,8 @@ public SuperiorCommand[] getSuperiorCommands(SuperiorSkyblockPlugin plugin) { @Override public SuperiorCommand[] getSuperiorAdminCommands(SuperiorSkyblockPlugin plugin) { - return new SuperiorCommand[]{new CmdAdminDeposit(), new CmdAdminSetBankLimit(), new CmdAdminWithdraw()}; + return new SuperiorCommand[]{new CmdAdminAddBankLimit(), new CmdAdminDeposit(), + new CmdAdminSetBankLimit(), new CmdAdminWithdraw()}; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminAddBankLimit.java b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminAddBankLimit.java new file mode 100644 index 0000000000..38b76b7e94 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdAdminAddBankLimit.java @@ -0,0 +1,94 @@ +package com.bgsoftware.superiorskyblock.module.bank.commands; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; +import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; +import com.bgsoftware.superiorskyblock.core.messages.Message; +import org.bukkit.command.CommandSender; + +import java.math.BigDecimal; +import java.util.Collections; +import java.util.List; + +public class CmdAdminAddBankLimit implements IAdminIslandCommand { + + @Override + public List getAliases() { + return Collections.singletonList("addbanklimit"); + } + + @Override + public String getPermission() { + return "superior.admin.addbanklimit"; + } + + @Override + public String getUsage(java.util.Locale locale) { + return "admin addbanklimit <" + + Message.COMMAND_ARGUMENT_PLAYER_NAME.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ISLAND_NAME.getMessage(locale) + "/" + + Message.COMMAND_ARGUMENT_ALL_ISLANDS.getMessage(locale) + "> <" + + Message.COMMAND_ARGUMENT_LIMIT.getMessage(locale) + ">"; + } + + @Override + public String getDescription(java.util.Locale locale) { + return Message.COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT.getMessage(locale); + } + + @Override + public int getMinArgs() { + return 4; + } + + @Override + public int getMaxArgs() { + return 4; + } + + @Override + public boolean canBeExecutedByConsole() { + return true; + } + + @Override + public boolean supportMultipleIslands() { + return true; + } + + @Override + public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { + BigDecimal limit = CommandArguments.getBigDecimalAmount(sender, args[3]); + + if (limit == null) + return; + + int islandsChangedCount = 0; + + for (Island island : islands) { + PluginEvent event = PluginEventsFactory.callIslandChangeBankLimitEvent( + island, sender, island.getBankLimit().add(limit)); + if (!event.isCancelled()) { + island.setBankLimit(event.getArgs().bankLimit); + ++islandsChangedCount; + } + } + + if (islandsChangedCount <= 0) + return; + + if (islandsChangedCount > 1) + Message.CHANGED_BANK_LIMIT_ALL.send(sender); + else if (targetPlayer == null) + Message.CHANGED_BANK_LIMIT_NAME.send(sender, islands.get(0).getName()); + else + Message.CHANGED_BANK_LIMIT.send(sender, targetPlayer.getName()); + } + +} diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index fe4a9208e1..76754c58a6 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -209,6 +209,7 @@ COMMAND_COOLDOWN_FORMAT: '&c&lError | &7Du darfst den Befehl nur in {0} verwende COMMAND_DESCRIPTION_ACCEPT: Eine Einladung von einem Spieler annehmen. COMMAND_DESCRIPTION_ADMIN: Verwende die Admin-Befehle. COMMAND_DESCRIPTION_ADMIN_ADD: Einen Benutzer zu einer Insel hinzufügen. +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Blocklimit für die Insel eines anderen Spielers erhöhen. COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Einem Spieler einen Bonus hinzufügen. @@ -274,7 +275,7 @@ COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Setze eine Welt für eine Insel zurück. COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Schaltpläne für das Plugin erstellen. -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: Banklimit für eine Insel festlegen. +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: Lege das Biom einer Insel fest. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Blockierungsbetrag an einem bestimmten Ort festlegen. diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 4494d67695..4114b57693 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -157,6 +157,7 @@ COMMAND_COOLDOWN_FORMAT: '&c&lError | &7You may only use the command in {0}.' COMMAND_DESCRIPTION_ACCEPT: 'Accept an invitation from a player.' COMMAND_DESCRIPTION_ADMIN: 'Use the admin commands.' COMMAND_DESCRIPTION_ADMIN_ADD: 'Add a user to an island.' +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Increase block limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Add a bonus to a player.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Increase coop players limit for another player''s island.' @@ -206,7 +207,7 @@ COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Create schematics for the plugin.' -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set a bank limit to an island.' +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Set the biome of an island.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Set the block amount in a specific location.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Set block limit for another player''s island.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 314a48b66a..7710cbb7da 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -157,6 +157,7 @@ COMMAND_COOLDOWN_FORMAT: '&c&lError | &7Solo puede usar el comando en {0}.' COMMAND_DESCRIPTION_ACCEPT: 'Aceptar una invitación de un jugador.' COMMAND_DESCRIPTION_ADMIN: 'Utilice los comandos de administrador.' COMMAND_DESCRIPTION_ADMIN_ADD: 'Añadir un usuario a una isla.' +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Aumenta el límite de bloques para la isla de otro jugador.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Añadir un bono a un jugador.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Aumentar el límite de jugadores cooperativos para la isla de otro jugador.' @@ -206,7 +207,7 @@ COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Cree schematics para el plugin.' -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Establezca un límite bancario para una isla.' +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Establecer el bioma de una isla.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Establece una cantidad de bloques en una ubicación específica.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Establecer límite de bloques para la isla de otro jugador.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 688eacbf75..c1acaa3a5c 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -159,6 +159,7 @@ COMMAND_DESCRIPTION_ADMIN_DEL_WARP: Delete a warp for an island. COMMAND_DESCRIPTION_ACCEPT: Accepter l'invitation d'un joueur. COMMAND_DESCRIPTION_ADMIN: Utiliser les commandes admin. COMMAND_DESCRIPTION_ADMIN_ADD: Ajouter un joueur comme membre d'une île. +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Augmenter la limite de blocs pour l'île du joueur spécifié. COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Attribuer un bonus au joueur spécifié. COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: Augmenter la limite de coopérateurs pour l'île du joueur spécifié. @@ -209,7 +210,7 @@ COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Réinitialiser l'île d'un monde précis pour l'île spécifiée. COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Créer des schematics pour le plugin. -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: Définir la limite bancaire d'une île. +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: Définir le biome de l'île spécifiée. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Définir la quantité de blocs sur une position spécifique. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Définir une limite de blocs pour l'île d'un joueur. diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 5c82ff2ac5..25e73f3341 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -160,6 +160,7 @@ COMMAND_COOLDOWN_FORMAT: '&c&lErrore | &7È possibile utilizzare questo comando COMMAND_DESCRIPTION_ACCEPT: Accetta un invito da un giocatore. COMMAND_DESCRIPTION_ADMIN: Utilizzare i comandi di amministrazione. COMMAND_DESCRIPTION_ADMIN_ADD: Aggiungi un utente a un'isola. +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Aumenta il limite di blocchi per l'isola di un altro giocatore. COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Aggiungi un bonus a un giocatore. COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: Aumenta il limite dei giocatori coop per l'isola di un altro giocatore. @@ -209,7 +210,7 @@ COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: Rimuovi tutte le valutazioni fornite d COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Ripristina il mondo su un''isole.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Crea una schematica per il plugin. -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: Imposta un limite di banca per un'isola. +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: Imposta il bioma di un'isola. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Imposta la quantità di un blocco in una posizione specifica. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Imposta il limite di un blocco per l'isola di un giocatore. diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 45af3f586a..b219b4d8dc 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -166,6 +166,7 @@ COMMAND_DESCRIPTION_ACCEPT: םינקחשמ יאל הנמזה רשאל. COMMAND_DESCRIPTION_ADMIN: .ןימדאה תודוקפב שמתשהל. COMMAND_DESCRIPTION_ADMIN_BONUS: יאל סונוב תתל. COMMAND_DESCRIPTION_ADMIN_ADD: 'Add a user to an island.' +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Increase block limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Add a bonus to a player.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Increase coop players limit for another player''s island.' @@ -214,7 +215,7 @@ COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Reset a world for an island.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: ןיגאלפל שדח הנבמ רוציל. -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set a bank limit to an island.' +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Set the biome of an island.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Set the block amount in a specific location.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: רחא ןקחש לש יאל םיקולב לש הלבגה תונשל. diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 3649a44728..e2f057fa3a 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -157,6 +157,7 @@ COMMAND_COOLDOWN_FORMAT: '&c&lBlad | &7Mozesz uzywac tylko polecenia w {0}.' COMMAND_DESCRIPTION_ACCEPT: 'Zaakceptuj zaproszenie od gracza.' COMMAND_DESCRIPTION_ADMIN: 'Uzyj poleceń administratora.' COMMAND_DESCRIPTION_ADMIN_ADD: 'Dodaj uzytkownika do wyspy.' +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Zwieksz limit banku dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Zwieksz limit bloków dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Dodaj bonus do gracza.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Zwieksz limit graczy w trybie wspólpracy na wyspie innego gracza.' @@ -206,7 +207,7 @@ COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Zresetuj wszystkie uprawnienia wys COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Zresetuj wszystkie ustawienia wyspy dla konkretnej wyspy.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Zresetuj swiat dla wyspy.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Utwórz schematy dla wtyczki.' -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Ustaw limit banku dla wyspy.' +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Ustaw limit banku dla wyspy innego gracza.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Ustaw biom wyspy.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Ustaw kwote bloku w okreslonej lokalizacji.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Ustaw limit bloków dla wyspy innego gracza.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 08f1ddf926..4d512edca7 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -157,6 +157,7 @@ COMMAND_COOLDOWN_FORMAT: '&c&lErro | &7Você só pode usar o comando novamente e COMMAND_DESCRIPTION_ACCEPT: 'Aceite um convite de um jogador.' COMMAND_DESCRIPTION_ADMIN: 'Use os comandos de administrador.' COMMAND_DESCRIPTION_ADMIN_ADD: 'Adicione um usuário a uma ilha.' +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Aumente o limite de blocos para a ilha de outro jogador.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Adicione um bônus a um jogador.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Aumente o limite de jogadores na cooperação da ilha de outro jogador.' @@ -206,7 +207,7 @@ COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Redefinir um mundo para uma ilha.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Criar esquemas para o plugin.' -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Definir o limite do banco para uma ilha.' +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Definir o bioma de uma ilha.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Definir a quantidade de blocos em um local específico.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Definir o limite de blocos para a ilha de outro jogador.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 92cc1e0932..9f7164054e 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -157,6 +157,7 @@ COMMAND_COOLDOWN_FORMAT: '&c&lОшибка | &7Вы можете использ COMMAND_DESCRIPTION_ACCEPT: 'Принять приглашение от игрока.' COMMAND_DESCRIPTION_ADMIN: 'Использовать команды администратора.' COMMAND_DESCRIPTION_ADMIN_ADD: 'Добавить пользователя на остров.' +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Увеличить лимит блоков для острова другого игрока.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Добавить бонус игроку.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Увеличить лимит игроков-кооператоров для острова другого игрока.' @@ -206,7 +207,7 @@ COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Сбросить мир для острова.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: 'Создать схемы для плагина.' -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Установить лимит банка для острова.' +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: 'Установить биом для острова.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Установить количество блоков в конкретном месте.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: 'Установить лимит блоков для острова другого игрока.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 5d10035b75..7717498eb0 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -201,6 +201,7 @@ COMMAND_COOLDOWN_FORMAT: '&c&lHata | &7Komutu sadece {0} içinde kullanabilirsin COMMAND_DESCRIPTION_ACCEPT: Bir oyuncudan gelen daveti kabul et. COMMAND_DESCRIPTION_ADMIN: Yönetici komutlarını kullan. COMMAND_DESCRIPTION_ADMIN_ADD: Bir adaya kullanıcı ekle. +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: Başka bir oyuncunun adası için blok limitini artır. COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: Bir oyuncuya bonus ekle. @@ -264,7 +265,7 @@ COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: Bir ada için bir dünyayı sıfırla. COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Eklenti için şematikler oluştur. -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: Bir adaya banka limiti belirle. +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: Bir adanın biyomunu ayarla. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: Belirli bir konumdaki blok miktarını ayarla. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Başka bir oyuncunun adası için blok limiti diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index b41f2276f2..df66b1f47c 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -183,6 +183,7 @@ COMMAND_DESCRIPTION_ACCEPT: Chấp nhận lời mời từ người chơi. COMMAND_DESCRIPTION_ADMIN: Sử dụng các lệnh của admin. COMMAND_DESCRIPTION_ADMIN_BONUS: Cấp tiền thưởng cho người chơi. COMMAND_DESCRIPTION_ADMIN_ADD: Thêm người vào đảo. +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: 'Tăng giới hạn khối cho đảo của người chơi khác.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: 'Thêm thưởng cho người chơi.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: 'Tăng giới hạn thành viên đảo co-op của người chơi khác.' @@ -235,7 +236,7 @@ COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: 'Tái tạo lại thế giới cho một hòn đảo.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: Tạo các schematic cho plugin. -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Đặt mức giới hạn ngân hàng cho một hòn đảo.' +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: Đặt quần xã cho đảo. COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: 'Đặt số lượng khối ở một vị trí cụ thể.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: Đặt giới hạn khối cho đảo của người chơi diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 34384db464..ac9c2bb265 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -157,6 +157,7 @@ COMMAND_COOLDOWN_FORMAT: '&c&l错误 | &7你只能在 {0} 中使用该命令.' COMMAND_DESCRIPTION_ACCEPT: '接受玩家的邀请.' COMMAND_DESCRIPTION_ADMIN: '使用管理员命令.' COMMAND_DESCRIPTION_ADMIN_ADD: '将玩家添加至岛屿.' +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: '为指定玩家的岛屿增加方块数量上限.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: '向指定玩家添加奖励.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: '为指定玩家的岛屿增加合作玩家数量上限.' @@ -206,7 +207,7 @@ COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: '重置指定岛屿所在的世界.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: '从插件创建结构文件.' -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: '设置指定岛屿的银行存量上限.' +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: '设置指定岛屿的生物群系.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: '设置指定位置的方块数量.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: '设置指定岛屿的方块数量限制.' diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 81f33894c5..3a93f262b2 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -187,6 +187,8 @@ permissions: description: Use the admin commands. superior.admin.add: description: Add a user to an island. + superior.admin.addbanklimit: + description: Increase the bank limit for another player's island. superior.admin.addblocklimit: description: Increase block limit for another player's island. superior.admin.addbonus: @@ -282,7 +284,7 @@ permissions: superior.admin.schematic: description: Create schematics for the plugin. superior.admin.setbanklimit: - description: Set a bank limit to an island. + description: Set the bank limit for another player's island. superior.admin.setbiome: description: Set the biome of an island. superior.admin.setblockamount: From d04147e4f03c0374a8fc4165d5250ae1bbcb1844 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 24 Nov 2025 12:07:43 +0200 Subject: [PATCH 430/600] Fix admin setspawn not centering location to a block (#2772) --- .../superiorskyblock/commands/admin/CmdAdminSetSpawn.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSpawn.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSpawn.java index de1163790d..d1b8bbfdbc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSpawn.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetSpawn.java @@ -60,6 +60,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ location.setX(location.getBlockX()); location.setY(location.getBlockY()); location.setZ(location.getBlockZ()); + // Fix to corner of a block + location.add(0.5, 0, 0.5); newSpawnLocation = Serializers.LOCATION_SPACED_SERIALIZER.serialize(location); } From 4c58e9fa02dc009514faba10539e5064a4a6cc98 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Mon, 24 Nov 2025 11:09:42 +0100 Subject: [PATCH 431/600] Added the ability to open mission categories via command (#2762) --- .../commands/CommandTabCompletes.java | 12 +++++- .../commands/arguments/CommandArguments.java | 10 +++++ .../impl/OpenMissionCategoryButton.java | 3 +- .../core/messages/Message.java | 2 + .../mission/MissionsManagerImpl.java | 8 ++++ .../container/DefaultMissionsContainer.java | 18 +++++++++ .../mission/container/MissionsContainer.java | 4 ++ .../module/missions/commands/CmdMissions.java | 38 +++++++++++++++---- src/main/resources/lang/de-DE.yml | 2 + src/main/resources/lang/en-US.yml | 2 + src/main/resources/lang/es-ES.yml | 2 + src/main/resources/lang/fr-FR.yml | 2 + src/main/resources/lang/it-IT.yml | 2 + src/main/resources/lang/iw-IL.yml | 2 + src/main/resources/lang/pl-PL.yml | 2 + src/main/resources/lang/pt-BR.yml | 2 + src/main/resources/lang/ru-RU.yml | 2 + src/main/resources/lang/tr-TR.yml | 2 + src/main/resources/lang/vi-VN.yml | 2 + src/main/resources/lang/zh-CN.yml | 2 + 20 files changed, 108 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java index 47e3662c63..7185387276 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandTabCompletes.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.missions.Mission; +import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; @@ -216,10 +217,19 @@ public static List getMaterialsForGenerators(String argument) { public static List getMissions(SuperiorSkyblockPlugin plugin, String argument, Predicate> predicate) { String lowerArgument = argument.toLowerCase(Locale.ENGLISH); return new SequentialListBuilder().build(plugin.getMissions().getAllMissions().stream() - .filter(mission -> predicate.test(mission) && mission.getName().contains(lowerArgument)) + .filter(mission -> predicate.test(mission) && + mission.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) .map(mission -> mission.getName().toLowerCase(Locale.ENGLISH))); } + public static List getMissionCategories(SuperiorSkyblockPlugin plugin, String argument, Predicate predicate) { + String lowerArgument = argument.toLowerCase(Locale.ENGLISH); + return new SequentialListBuilder().build(plugin.getMissions().getMissionCategories().stream() + .filter(category -> predicate.test(category) && + category.getName().toLowerCase(Locale.ENGLISH).contains(lowerArgument)) + .map(category -> category.getName().toLowerCase(Locale.ENGLISH))); + } + public static List getCustomMenus(SuperiorSkyblockPlugin plugin, String argument) { return filterByArgument(plugin.getMenus().getCustomMenus().values(), menu -> menu.getIdentifier().substring(MenuIdentifiers.MENU_CUSTOM_PREFIX.length()), diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java index 3d15ba3806..6ce5d83c9c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.island.PlayerRole; import com.bgsoftware.superiorskyblock.api.island.warps.IslandWarp; import com.bgsoftware.superiorskyblock.api.missions.Mission; +import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.upgrades.Upgrade; import com.bgsoftware.superiorskyblock.api.world.Dimension; @@ -160,6 +161,15 @@ public static List> getMultipleMissions(SuperiorSkyblockPlugin plugin return Collections.unmodifiableList(missions); } + public static MissionCategory getMissionCategory(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { + MissionCategory missionCategory = plugin.getMissions().getMissionCategory(argument); + + if (missionCategory == null) + Message.INVALID_MISSION_CATEGORY.send(sender, argument); + + return missionCategory; + } + public static Upgrade getUpgrade(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, String argument) { return getUpgrade(plugin, superiorPlayer.asPlayer(), argument); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenMissionCategoryButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenMissionCategoryButton.java index 53c4ecc1e4..a7db1e9a5e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenMissionCategoryButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/OpenMissionCategoryButton.java @@ -2,7 +2,6 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; -import com.bgsoftware.superiorskyblock.api.missions.Mission; import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; @@ -65,7 +64,7 @@ public static class Template extends MenuTemplateButtonImpl { super(buttonItem, clickSound, commands, requiredPermission, lackPermissionSound, OpenMissionCategoryButton.class, OpenMissionCategoryButton::new); this.missionCategory = Objects.requireNonNull(missionCategory, "missionCategory cannot be null"); - this.requireIsland = missionCategory.getMissions().stream().allMatch(Mission::getIslandMission); + this.requireIsland = !plugin.getMissions().isPlayerMissionCategory(missionCategory); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index d8d2a0eee5..6712f6d261 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -155,6 +155,7 @@ public enum Message { COMMAND_ARGUMENT_MATERIAL("material"), COMMAND_ARGUMENT_MENU("menu-name"), COMMAND_ARGUMENT_MESSAGE("message..."), + COMMAND_ARGUMENT_MISSION_CATEGORY("mission-category"), COMMAND_ARGUMENT_MISSION_NAME("mission-name"), COMMAND_ARGUMENT_MODULE_NAME("module-name"), COMMAND_ARGUMENT_MULTIPLIER("multiplier"), @@ -447,6 +448,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { INVALID_MATERIAL_DATA, INVALID_MENU, INVALID_MISSION, + INVALID_MISSION_CATEGORY, INVALID_MODULE, INVALID_MULTIPLIER, INVALID_PAGE, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java index 1557ae7959..54570113a5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java @@ -496,6 +496,14 @@ public boolean canDisplayMission(Mission mission, SuperiorPlayer superiorPlay return true; } + public boolean isPlayerMissionCategory(MissionCategory missionCategory) { + return this.missionsContainer.isPlayerMissionCategory(missionCategory); + } + + public boolean hasAnyPlayerMissionCategories() { + return this.missionsContainer.hasAnyPlayerMissionCategories(); + } + @SuppressWarnings("deprecation") public Mission loadMission(String missionName, String missionCategoryName, FilesLookup filesLookup, ConfigurationSection missionSection) { Mission newMission = null; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/container/DefaultMissionsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/container/DefaultMissionsContainer.java index b91ec8ceaf..4bb41199d0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/container/DefaultMissionsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/container/DefaultMissionsContainer.java @@ -8,13 +8,17 @@ import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.function.Predicate; public class DefaultMissionsContainer implements MissionsContainer { + private final Set playerMissionCategoriesCache = new HashSet<>(); + private final Map> missionMap = new HashMap<>(); private final Map missionDataMap = new HashMap<>(); private final Map missionCategoryMap = new HashMap<>(); @@ -59,6 +63,9 @@ public MissionData getMissionData(Mission mission) { @Override public void addMissionCategory(MissionCategory missionCategory) { this.missionCategoryMap.put(missionCategory.getName().toLowerCase(Locale.ENGLISH), missionCategory); + + if (missionCategory.getMissions().stream().anyMatch(mission -> !mission.getIslandMission())) + playerMissionCategoriesCache.add(missionCategory); } @Nullable @@ -72,8 +79,19 @@ public List getMissionCategories() { return new SequentialListBuilder().build(missionCategoryMap.values()); } + @Override + public boolean isPlayerMissionCategory(MissionCategory missionCategory) { + return playerMissionCategoriesCache.contains(missionCategory); + } + + @Override + public boolean hasAnyPlayerMissionCategories() { + return !playerMissionCategoriesCache.isEmpty(); + } + @Override public void clearMissionsData() { + this.playerMissionCategoriesCache.clear(); this.missionMap.clear(); this.missionDataMap.clear(); this.missionCategoryMap.clear(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/container/MissionsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/container/MissionsContainer.java index 84a5390253..3eb4fae475 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/container/MissionsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/container/MissionsContainer.java @@ -32,6 +32,10 @@ public interface MissionsContainer { List getMissionCategories(); + boolean isPlayerMissionCategory(MissionCategory missionCategory); + + boolean hasAnyPlayerMissionCategories(); + void clearMissionsData(); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMissions.java b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMissions.java index bcd339e5fb..441930698e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMissions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/missions/commands/CmdMissions.java @@ -1,9 +1,11 @@ package com.bgsoftware.superiorskyblock.module.missions.commands; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.missions.Mission; +import com.bgsoftware.superiorskyblock.api.missions.MissionCategory; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.command.CommandSender; @@ -26,7 +28,7 @@ public String getPermission() { @Override public String getUsage(java.util.Locale locale) { - return "missions"; + return "missions [" + Message.COMMAND_ARGUMENT_MISSION_CATEGORY.getMessage(locale) + "]"; } @Override @@ -52,18 +54,38 @@ public boolean canBeExecutedByConsole() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - boolean requireIsland = plugin.getMissions().getAllMissions().stream().allMatch(Mission::getIslandMission); - if (requireIsland && !superiorPlayer.hasIsland()) { - Message.INVALID_ISLAND.send(superiorPlayer); - return; - } + if (args.length == 1) { + if (!superiorPlayer.hasIsland() && !plugin.getMissions().hasAnyPlayerMissionCategories()) { + Message.INVALID_ISLAND.send(superiorPlayer); + return; + } + + plugin.getMenus().openMissions(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView())); + } else { + MissionCategory missionCategory = CommandArguments.getMissionCategory(plugin, sender, args[1]); + + if (missionCategory == null) + return; + + if (!superiorPlayer.hasIsland() && !plugin.getMissions().isPlayerMissionCategory(missionCategory)) { + Message.INVALID_ISLAND.send(superiorPlayer); + return; + } - plugin.getMenus().openMissions(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView())); + plugin.getMenus().openMissionsCategory(superiorPlayer, + MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), missionCategory); + } } @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + if (args.length == 2) { + boolean hasIsland = plugin.getPlayers().getSuperiorPlayer(sender).hasIsland(); + return CommandTabCompletes.getMissionCategories(plugin, args[1], category -> + hasIsland || plugin.getMissions().isPlayerMissionCategory(category)); + } + return Collections.emptyList(); } diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 76754c58a6..559019da7b 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -180,6 +180,7 @@ COMMAND_ARGUMENT_LIMIT: limit COMMAND_ARGUMENT_MATERIAL: Material COMMAND_ARGUMENT_MENU: Menüname COMMAND_ARGUMENT_MESSAGE: Nachricht... +COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: mission-name COMMAND_ARGUMENT_MODULE_NAME: Modulname COMMAND_ARGUMENT_MULTIPLIER: Multiplikator @@ -505,6 +506,7 @@ INVALID_MATERIAL: '&c&lError | &7Ungültiges Material {0}.' INVALID_MATERIAL_DATA: '&c&lError | &7Ungültige Materialdaten {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lError | &7Ungültige Mission {0}.' +INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lError | &7Ungültiges Modul {0}.' INVALID_MULTIPLIER: '&c&lError | &7Ungültiger Multiplikator {0}.' INVALID_PAGE: '&c&lError | &7Ungültige Seite {0}.' diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 4114b57693..57b0526291 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -128,6 +128,7 @@ COMMAND_ARGUMENT_LIMIT: 'limit' COMMAND_ARGUMENT_MATERIAL: 'material' COMMAND_ARGUMENT_MENU: 'menu-name' COMMAND_ARGUMENT_MESSAGE: 'message...' +COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: 'mission-name' COMMAND_ARGUMENT_MODULE_NAME: 'module-name' COMMAND_ARGUMENT_MULTIPLIER: 'multiplier' @@ -395,6 +396,7 @@ INVALID_MATERIAL: '&c&lError | &7Invalid material {0}.' INVALID_MATERIAL_DATA: '&c&lError | &7Invalid material-data {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lError | &7Invalid mission {0}.' +INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lError | &7Invalid module {0}.' INVALID_MULTIPLIER: '&c&lError | &7Invalid multiplier {0}.' INVALID_PAGE: '&c&lError | &7Invalid page {0}.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index 7710cbb7da..fb27623dac 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -128,6 +128,7 @@ COMMAND_ARGUMENT_LIMIT: 'límite' COMMAND_ARGUMENT_MATERIAL: 'material' COMMAND_ARGUMENT_MENU: 'nombre-del-menu' COMMAND_ARGUMENT_MESSAGE: 'mensaje...' +COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: 'nombre-de-misión' COMMAND_ARGUMENT_MODULE_NAME: 'module-name' COMMAND_ARGUMENT_MULTIPLIER: 'multiplicador' @@ -395,6 +396,7 @@ INVALID_MATERIAL: '&c&lError | &7Material no válido {0}.' INVALID_MATERIAL_DATA: '&c&lError | &7Invalid material-data {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lError | &7Misión no válida {0}.' +INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lError | &7Invalid module {0}.' INVALID_MULTIPLIER: '&c&lError | &7Multiplicador no válido {0}.' INVALID_PAGE: '&c&lError | &7Página no válida {0}.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index c1acaa3a5c..7b58677f7a 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -132,6 +132,7 @@ COMMAND_ARGUMENT_LIMIT: limite COMMAND_ARGUMENT_MATERIAL: matériau COMMAND_ARGUMENT_MENU: nom-du-menu COMMAND_ARGUMENT_MESSAGE: message +COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: nom-de-la-mission COMMAND_ARGUMENT_MODULE_NAME: 'nom-du-module' COMMAND_ARGUMENT_MULTIPLIER: multiplicateur @@ -396,6 +397,7 @@ INVALID_MATERIAL: '&c&lErreur | &7Matériau invalide: {0}.' INVALID_MATERIAL_DATA: '&c&lErreur | &7Donnée de matériau {0} invalide.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lErreur | &7Mission {0} invalide.' +INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lErreur | &7Module {0} invalide.' INVALID_MULTIPLIER: '&c&lErreur | &7Multiplicateur invalide: {0}.' INVALID_PAGE: '&c&lErreur | &7Page {0} invalide.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 25e73f3341..3299eb2dc0 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -131,6 +131,7 @@ COMMAND_ARGUMENT_LIMIT: limite COMMAND_ARGUMENT_MATERIAL: materiale COMMAND_ARGUMENT_MENU: nome-menu COMMAND_ARGUMENT_MESSAGE: messagio... +COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: nome-missione COMMAND_ARGUMENT_MODULE_NAME: 'nome-modulo' COMMAND_ARGUMENT_MULTIPLIER: moltiplicatore @@ -399,6 +400,7 @@ INVALID_MATERIAL: '&c&lErrore | &7Materiale non valido {0}.' INVALID_MATERIAL_DATA: '&c&lErrore | &7Il material-data non è corretto {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lErrore | &7La missione {0} non è corretta.' +INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lError | &7Modulo non valido: {0}' INVALID_MULTIPLIER: '&c&lErrore | &7Il moltiplicatore {0} non è corretto.' INVALID_PAGE: '&c&lErrore | &7La pagina {0} non è corretta.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index b219b4d8dc..39e28c3207 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -136,6 +136,7 @@ COMMAND_ARGUMENT_LIMIT: הלבגמ COMMAND_ARGUMENT_MATERIAL: רמוח COMMAND_ARGUMENT_MENU: 'menu-name' COMMAND_ARGUMENT_MESSAGE: '...העדוה' +COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: המישמה םש COMMAND_ARGUMENT_MODULE_NAME: 'module-name' COMMAND_ARGUMENT_MULTIPLIER: סונוב @@ -411,6 +412,7 @@ INVALID_MATERIAL: '&c&lהאיגש | &7{0} תיקוח אל רמוח.' INVALID_MATERIAL_DATA: '&c&lError | &7Invalid material-data {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lהאיגש | &7{0} תיקוח אל המישמ.' +INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lError | &7Invalid module {0}.' INVALID_MULTIPLIER: '&c&lהאיגש | &7{0} יקוח אל סונוב.' INVALID_PAGE: '&c&lError | &7Invalid page {0}.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index e2f057fa3a..09444deefa 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -128,6 +128,7 @@ COMMAND_ARGUMENT_LIMIT: 'limit' COMMAND_ARGUMENT_MATERIAL: 'material' COMMAND_ARGUMENT_MENU: 'nazwa-menu' COMMAND_ARGUMENT_MESSAGE: 'wiadomosc...' +COMMAND_ARGUMENT_MISSION_CATEGORY: 'kategoria misji' COMMAND_ARGUMENT_MISSION_NAME: 'nazwa misji' COMMAND_ARGUMENT_MODULE_NAME: 'nazwa-modulu' COMMAND_ARGUMENT_MULTIPLIER: 'mnoznik' @@ -395,6 +396,7 @@ INVALID_MATERIAL: '&c&lBlad | &7Nieprawidlowy material {0}.' INVALID_MATERIAL_DATA: '&c&lBlad | &7Nieprawidlowe dane materialu {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lBlad | &7Nieprawidlowa misja {0}.' +INVALID_MISSION_CATEGORY: '&c&lBlad | &7Nieprawidlowa kategoria misji {0}.' INVALID_MODULE: '&c&lBlad | &7Nieprawidlowy modul {0}.' INVALID_MULTIPLIER: '&c&lBlad | &7Nieprawidlowy mnoznik {0}.' INVALID_PAGE: '&c&lBlad | &7Nieprawidlowa strona {0}.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 4d512edca7..c9ba89f723 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -128,6 +128,7 @@ COMMAND_ARGUMENT_LIMIT: 'limite' COMMAND_ARGUMENT_MATERIAL: 'material' COMMAND_ARGUMENT_MENU: 'nome-do-menu' COMMAND_ARGUMENT_MESSAGE: 'mensagem...' +COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: 'nome-da-missão' COMMAND_ARGUMENT_MODULE_NAME: 'nome-do-módulo' COMMAND_ARGUMENT_MULTIPLIER: 'multiplicador' @@ -395,6 +396,7 @@ INVALID_MATERIAL: '&c&lErro | &7Material inválido {0}.' INVALID_MATERIAL_DATA: '&c&lErro | &7Material-dados inválido {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lErro | &7Missão inválida {0}.' +INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lErro | &7Módulo inválido {0}.' INVALID_MULTIPLIER: '&c&lErro | &7Multiplicador inválido {0}.' INVALID_PAGE: '&c&lErro | &7Página inválida {0}.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index 9f7164054e..e6522c795a 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -128,6 +128,7 @@ COMMAND_ARGUMENT_LIMIT: 'лимит' COMMAND_ARGUMENT_MATERIAL: 'материал' COMMAND_ARGUMENT_MENU: 'название-меню' COMMAND_ARGUMENT_MESSAGE: 'сообщение...' +COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: 'название-миссии' COMMAND_ARGUMENT_MODULE_NAME: 'название-модуля' COMMAND_ARGUMENT_MULTIPLIER: 'множитель' @@ -395,6 +396,7 @@ INVALID_MATERIAL: '&c&lОшибка | &7Недопустимый материа INVALID_MATERIAL_DATA: '&c&lОшибка | &7Недопустимые данные материала {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lОшибка | &7Недопустимая миссия {0}.' +INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lОшибка | &7Недопустимый модуль {0}.' INVALID_MULTIPLIER: '&c&lОшибка | &7Недопустимый множитель {0}.' INVALID_PAGE: '&c&lОшибка | &7Недопустимая страница {0}.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 7717498eb0..e945c02009 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -172,6 +172,7 @@ COMMAND_ARGUMENT_LIMIT: limit COMMAND_ARGUMENT_MATERIAL: materyal COMMAND_ARGUMENT_MENU: menü-adı COMMAND_ARGUMENT_MESSAGE: mesaj... +COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: görev-adı COMMAND_ARGUMENT_MODULE_NAME: modül-adı COMMAND_ARGUMENT_MULTIPLIER: çarpan @@ -479,6 +480,7 @@ INVALID_MATERIAL: '&c&lHata | &7Geçersiz materyal {0}.' INVALID_MATERIAL_DATA: '&c&lHata | &7Geçersiz materyal-veri {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&lHata | &7Geçersiz görev {0}.' +INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lHata | &7Geçersiz modül {0}.' INVALID_MULTIPLIER: '&c&lHata | &7Geçersiz çarpan {0}.' INVALID_PAGE: '&c&lHata | &7Geçersiz sayfa {0}.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index df66b1f47c..7d2c7a9f26 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -153,6 +153,7 @@ COMMAND_ARGUMENT_LIMIT: gioi-han COMMAND_ARGUMENT_MATERIAL: vat-lieu COMMAND_ARGUMENT_MENU: ten-giao-dien COMMAND_ARGUMENT_MESSAGE: tin-nhan... +COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: ten-nhiem-vu COMMAND_ARGUMENT_MODULE_NAME: ten-module COMMAND_ARGUMENT_MULTIPLIER: he-so @@ -447,6 +448,7 @@ INVALID_MATERIAL: '&c&lLỗi | &7Vật liệu không hợp lệ {0}.' INVALID_MATERIAL_DATA: '&c&lLỗi | &7Dữ liệu-vật liệu không hợp lệ {0}.' INVALID_MENU: '&c&lLỗi | &7Menu không hợp lệ {0}.' INVALID_MISSION: '&c&lLỗi | &7Nhiệm vụ không hợp lệ {0}.' +INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&lLỗi | &7Module không hợp lệ {0}.' INVALID_MULTIPLIER: '&c&lLỗi | &7Hệ số không hợp lệ {0}.' INVALID_PAGE: '&c&lLỗi | &7Trang không hợp lệ {0}.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index ac9c2bb265..58161461fc 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -128,6 +128,7 @@ COMMAND_ARGUMENT_LIMIT: '限制' COMMAND_ARGUMENT_MATERIAL: '材料' COMMAND_ARGUMENT_MENU: '菜单名称' COMMAND_ARGUMENT_MESSAGE: '消息...' +COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' COMMAND_ARGUMENT_MISSION_NAME: '任务名称' COMMAND_ARGUMENT_MODULE_NAME: '模块名称' COMMAND_ARGUMENT_MULTIPLIER: '翻倍卡' @@ -395,6 +396,7 @@ INVALID_MATERIAL: '&c&l错误 | &7无效材料名 {0}.' INVALID_MATERIAL_DATA: '&c&l错误 | &7无效材料数据 {0}.' INVALID_MENU: '&c&lError | &7Invalid menu {0}.' INVALID_MISSION: '&c&l错误 | &7无效任务 {0}.' +INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' INVALID_MODULE: '&c&l错误 | &7无效模块 {0}.' INVALID_MULTIPLIER: '&c&l错误 | &7无效翻倍 {0}.' INVALID_PAGE: '&c&l错误 | &7无效页码 {0}.' From 28a5e8b8fcaaff5af984137c83a8d76454ad1f98 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 6 Dec 2025 14:27:05 +0200 Subject: [PATCH 432/600] Adds the ability to configure sea level for island worlds (#2789) --- .../api/config/SettingsManager.java | 6 +++ .../templates/AbstractNMSWorld.java.template | 36 +++++++++++++++++ .../nms/v1_12_R1/NMSWorldImpl.java | 5 +++ .../nms/v1_16_R3/NMSWorldImpl.java | 5 +++ .../nms/v1_17/NMSWorldImpl.java | 25 ++++++++++++ .../nms/v1_18/NMSWorldImpl.java | 25 ++++++++++++ .../nms/v1_19/NMSWorldImpl.java | 25 ++++++++++++ .../nms/v1_20_3/NMSWorldImpl.java | 25 ++++++++++++ .../nms/v1_20_4/NMSWorldImpl.java | 25 ++++++++++++ .../nms/v1_21/NMSWorldImpl.java | 25 ++++++++++++ .../nms/v1_21_3/NMSWorldImpl.java | 25 ++++++++++++ .../nms/v1_21_4/NMSWorldImpl.java | 25 ++++++++++++ .../nms/v1_21_5/NMSWorldImpl.java | 25 ++++++++++++ .../nms/v1_21_7/NMSWorldImpl.java | 35 ++++++++++++++--- .../nms/v1_21_9/NMSWorldImpl.java | 39 ++++++++++++++++--- .../nms/v1_8_R3/NMSWorldImpl.java | 5 +++ .../config/SettingsContainer.java | 2 + .../config/section/GlobalSection.java | 4 ++ .../config/section/WorldsSection.java | 5 +++ .../events/plugin/PluginEventsDispatcher.java | 2 + .../worlds/WorldsProvider_Default.java | 17 ++++++++ .../superiorskyblock/nms/NMSWorld.java | 2 + src/main/resources/config.yml | 3 ++ 23 files changed, 381 insertions(+), 10 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 7329cd36c2..197f67b420 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -1106,6 +1106,12 @@ interface Worlds { */ String getDifficulty(); + /** + * The sea level of island worlds. + * Config path: worlds.sea-level-height + */ + int getSeaLevelHeight(); + interface DimensionConfig { /** diff --git a/NMS/src/main/templates/AbstractNMSWorld.java.template b/NMS/src/main/templates/AbstractNMSWorld.java.template index 2b358d08d7..de4cd0cb6b 100644 --- a/NMS/src/main/templates/AbstractNMSWorld.java.template +++ b/NMS/src/main/templates/AbstractNMSWorld.java.template @@ -38,6 +38,10 @@ import net.minecraft.world.level.block.entity.SpawnerBlockEntity; import net.minecraft.world.level.block.entity.TickingBlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.ChunkSnapshot; @@ -54,6 +58,7 @@ import ${CRAFTBUKKIT_PACKAGE}.block.CraftBlockState; import ${CRAFTBUKKIT_PACKAGE}.block.CraftSign; import ${CRAFTBUKKIT_PACKAGE}.block.data.CraftBlockData; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer; +import ${CRAFTBUKKIT_PACKAGE}.generator.CustomChunkGenerator; import org.bukkit.entity.Player; import java.lang.reflect.Modifier; @@ -68,6 +73,10 @@ public abstract class AbstractNMSWorld implements NMSWorld { private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(Level.class, Object.class, "chunkPacketBlockController") .removeFinal(); + private static final ReflectField CUSTOM_CHUNK_GENERATOR_DELEGATE = new ReflectField( + CustomChunkGenerator.class, ChunkGenerator.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField NOISE_GENERATOR_SETTINGS_SEA_LEVEL = new ReflectField( + NoiseGeneratorSettings.class, Integer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); protected final SuperiorSkyblockPlugin plugin; @@ -342,6 +351,33 @@ public abstract class AbstractNMSWorld implements NMSWorld { CHUNK_PACKET_BLOCK_CONTROLLER.set(serverLevel, ${PAPER_CHUNK_BLOCK_CONTROLLER_CLASS}.NO_OPERATION_INSTANCE); } + @Override + public void setOceanLevel(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + + if (!(serverLevel.getChunkSource().getGenerator() instanceof CustomChunkGenerator chunkGenerator)) + return; + + ChunkGenerator delegateChunkGenerator = getChunkGeneratorDelegate(chunkGenerator); + + if (delegateChunkGenerator instanceof FlatLevelSource flatLevelSource) { + FlatLevelSource newLevelSource = createFlatLevelSource(flatLevelSource, plugin.getSettings().getWorlds().getSeaLevelHeight()); + CUSTOM_CHUNK_GENERATOR_DELEGATE.set(chunkGenerator, newLevelSource); + } else if(delegateChunkGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + NoiseGeneratorSettings settings = getNoiseGeneratorSettings(noiseBasedChunkGenerator); + NOISE_GENERATOR_SETTINGS_SEA_LEVEL.set(settings, plugin.getSettings().getWorlds().getSeaLevelHeight()); + + } else { + throw new IllegalStateException("Cannot set ocean level for chunk generator of type " + delegateChunkGenerator); + } + } + + protected abstract ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator); + + protected abstract FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel); + + protected abstract NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator); + @Override public IslandsGenerator createGenerator(Dimension dimension) { return new IslandsGeneratorImpl(dimension); diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java index 1ae7a488dc..eb382ceac7 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java @@ -318,6 +318,11 @@ public void removeAntiXray(World world) { // Doesn't exist in this version. } + @Override + public void setOceanLevel(World world) { + ((CraftWorld) world).getHandle().b(plugin.getSettings().getWorlds().getSeaLevelHeight()); + } + @Override public IslandsGenerator createGenerator(Dimension dimension) { return new IslandsGeneratorImpl(dimension); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java index c3243d2a2b..2b36cbee07 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java @@ -318,6 +318,11 @@ public void removeAntiXray(org.bukkit.World bukkitWorld) { CHUNK_PACKET_BLOCK_CONTROLLER.set(world, ChunkPacketBlockController.NO_OPERATION_INSTANCE); } + @Override + public void setOceanLevel(org.bukkit.World world) { + // Not possible in this version, it is hardcoded 63 + } + @Override public IslandsGenerator createGenerator(Dimension dimension) { return new IslandsGeneratorImpl(dimension); diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index fda5296fd3..bace8d2ed5 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -8,8 +8,13 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSWorld { @@ -22,6 +27,26 @@ protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.messages; } + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.delegate; + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.get(); + } + @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index efd986740b..e957a63ac8 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -8,8 +8,13 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSWorld { @@ -22,6 +27,26 @@ protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.messages; } + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.delegate; + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.structureSets, original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.value(); + } + @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index ee377ac070..d95e3a7a0a 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -9,10 +9,15 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSWorld { @@ -25,6 +30,26 @@ protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.messages; } + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.getDelegate(); + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.value(); + } + @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index a4d4416b0f..b643e62c73 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -9,10 +9,15 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -30,6 +35,26 @@ protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.getDelegate(); + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.value(); + } + @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index a796c96512..8692288b35 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -9,10 +9,15 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -30,6 +35,26 @@ protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.getDelegate(); + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.value(); + } + @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index 615e9550af..1a1c0ade3a 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -16,10 +16,15 @@ import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -37,6 +42,26 @@ protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.getDelegate(); + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.value(); + } + @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index 481da694b9..3c5c55526c 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -16,10 +16,15 @@ import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -37,6 +42,26 @@ protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.getDelegate(); + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.value(); + } + @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index 996cd0738e..6090c4c417 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -16,10 +16,15 @@ import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -37,6 +42,26 @@ protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.getDelegate(); + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.value(); + } + @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java index 2a9cd9f852..e7282183d5 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java @@ -16,10 +16,15 @@ import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -37,6 +42,26 @@ protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); } + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.getDelegate(); + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.value(); + } + @Override public void replaceSculkSensorListener(Island island, Location location) { SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java index c494b6d483..9a717f0567 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java @@ -16,10 +16,15 @@ import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -32,6 +37,31 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + @Override + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); + } + + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.getDelegate(); + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.value(); + } + @Override public void replaceTrialBlockPlayerDetector(Island island, Location location) { BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); @@ -86,9 +116,4 @@ else if (sign instanceof WallHangingSign) return super.getSignType(sign); } - @Override - protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { - return signBlockEntity.getFrontText().getMessages(false); - } - } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java index dd072e9c03..b0b75a65ca 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_9.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -16,10 +17,18 @@ import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -28,9 +37,34 @@ public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.Ab private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + @Override + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); + } + + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.getDelegate(); + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.value(); + } @Override public void replaceTrialBlockPlayerDetector(Island island, Location location) { @@ -86,9 +120,4 @@ else if (sign instanceof WallHangingSign) return super.getSignType(sign); } - @Override - protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { - return signBlockEntity.getFrontText().getMessages(false); - } - } diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java index 97d3653cab..4e5c6261ff 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java @@ -320,6 +320,11 @@ public void removeAntiXray(World bukkitWorld) { // Doesn't exist in this version. } + @Override + public void setOceanLevel(World world) { + ((CraftWorld) world).getHandle().b(plugin.getSettings().getWorlds().getSeaLevelHeight()); + } + @Override public IslandsGenerator createGenerator(Dimension dimension) { return new IslandsGeneratorImpl(dimension); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 780ef0adb4..50918f6405 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -94,6 +94,7 @@ public class SettingsContainer { public final Int2IntMapView defaultRoleLimits; public final Map defaultIslandEffects; public final int islandsHeight; + public final int seaLevelHeight; public final boolean worldBordersEnabled; public final boolean stackedBlocksEnabled; public final KeySet whitelistedStackedBlocks; @@ -293,6 +294,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config } }); islandsHeight = config.getInt("islands-height", 100); + seaLevelHeight = config.getInt("sea-level-height", 100); worldBordersEnabled = config.getBoolean("world-borders", true); stackedBlocksEnabled = config.getBoolean("stacked-blocks.enabled", true); stackedBlocksDisabledWorlds = Collections.unmodifiableList(config.getStringList("stacked-blocks.disabled-worlds")); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index 887f1bc928..c25c4c6ce5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -35,6 +35,10 @@ public int getIslandHeight() { return getContainer().islandsHeight; } + public int getSeaLevelHeight() { + return getContainer().seaLevelHeight; + } + public boolean isWorldBorders() { return getContainer().worldBordersEnabled; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java index b5f27af95f..21f6c3fbfa 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java @@ -58,6 +58,11 @@ public String getDifficulty() { return getContainer().worldsDifficulty; } + @Override + public int getSeaLevelHeight() { + return getContainer().seaLevelHeight; + } + @Override public DimensionConfig getDimensionConfig(Dimension dimension) { return getContainer().dimensionConfigs.get(dimension); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java index 72d05b411e..a25f7802b9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.external.worlds.WorldsProvider_Default; import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.SpawnIsland; import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; @@ -43,6 +44,7 @@ public void registerDefaultListeners() { Message.registerListeners(this); SSuperiorPlayer.registerListeners(this); EntityCategories.registerListeners(this); + WorldsProvider_Default.registerListeners(this); } public void registerCallback(PluginEventType type, Runnable callback) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java index 7cfd7124d6..cbd223e080 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java @@ -10,6 +10,8 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.WorldGenerator; import com.google.common.base.Preconditions; @@ -189,6 +191,7 @@ private World loadWorld(String worldName, Difficulty difficulty, Dimension dimen islandWorldsToDimensions.put(world.getUID(), dimension); plugin.getNMSWorld().removeAntiXray(world); + plugin.getNMSWorld().setOceanLevel(world); if (Bukkit.getPluginManager().isPluginEnabled("Multiverse-Core")) { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "mv import " + worldName + " normal -g " + plugin.getName()); @@ -202,4 +205,18 @@ private static BlockPosition nextPosition(BlockPosition previousPosition, int is return SBlockPosition.of(previousPosition.getX() + offsetX, islandsHeight, previousPosition.getZ() + offsetZ); } + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, WorldsProvider_Default::onSettingsUpdate); + } + + private static void onSettingsUpdate() { + WorldsProvider worldsProvider = SuperiorSkyblockPlugin.getPlugin().getProviders().getWorldsProvider(); + + if (!(worldsProvider instanceof WorldsProvider_Default)) + return; + + WorldsProvider_Default worldsProviderDefault = (WorldsProvider_Default) worldsProvider; + worldsProviderDefault.islandWorlds.values().forEach(SuperiorSkyblockPlugin.getPlugin().getNMSWorld()::setOceanLevel); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java index a9b6b6d471..cfb24b88d9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java @@ -68,6 +68,8 @@ default SignType getSignType(Block block) { void removeAntiXray(World world); + void setOceanLevel(World world); + IslandsGenerator createGenerator(Dimension dimension); WorldEditSession createEditSession(World world); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 5c159db2f7..04d74df33d 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -382,6 +382,9 @@ worlds: # The difficulty of the island worlds. difficulty: EASY + # Set the sea level height for island worlds. + sea-level-height: 100 + # All settings related to the spawn island. spawn: # The location of the island. Players will be teleported to this From 4f3cc4bb8e4e7642157e620bccbd8c5df9dfe778 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 6 Dec 2025 14:43:14 +0200 Subject: [PATCH 433/600] Fix interactions with copper golem & statues on other islands (#2788) --- .../island/privilege/IslandPrivileges.java | 3 ++ .../region/RegionManagerServiceImpl.java | 4 +++ src/main/resources/config.yml | 1 + src/main/resources/interactables.yml | 8 +++++ src/main/resources/menus/permissions1_21.yml | 33 +++++++++++++++++++ 5 files changed, 49 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index b5be0f8e25..d51d8bbc40 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -3,8 +3,10 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import org.bukkit.entity.EntityType; import java.util.Comparator; import java.util.Locale; @@ -27,6 +29,7 @@ public class IslandPrivileges { public static final IslandPrivilege CLOSE_BYPASS = register("CLOSE_BYPASS"); public static final IslandPrivilege CLOSE_ISLAND = register("CLOSE_ISLAND", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege COOP_MEMBER = register("COOP_MEMBER", IslandPrivilege.Type.COMMAND); + public static final IslandPrivilege COPPER_GOLEM_INTERACT = register("COPPER_GOLEM_INTERACT", EnumHelper.getEnum(EntityType.class, "COPPER_GOLEM") != null); public static final IslandPrivilege DELETE_WARP = register("DELETE_WARP", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege DEMOTE_MEMBERS = register("DEMOTE_MEMBERS", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege DEPOSIT_MONEY = register("DEPOSIT_MONEY", IslandPrivilege.Type.COMMAND); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index f623300fe9..06f4f21a7d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -89,6 +89,8 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService private static final EntityType HAPPY_GHAST_TYPE = EnumHelper.getEnum(EntityType.class, "HAPPY_GHAST"); @Nullable private static final EntityType PARROT_TYPE = EnumHelper.getEnum(EntityType.class, "PARROT"); + @Nullable + private static final EntityType COPPER_GOLEM_TYPE = EnumHelper.getEnum(EntityType.class, "COPPER_GOLEM"); private static final int MAX_PICKUP_DISTANCE = 1; private static EnumerateSet WORLD_PERMISSIONS_CACHE; @@ -298,6 +300,8 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent } else if (BukkitEntities.isHorse(entity)) { islandPrivilege = IslandPrivileges.HORSE_INTERACT; closeInventory = true; + } else if (entityType == COPPER_GOLEM_TYPE) { + islandPrivilege = IslandPrivileges.COPPER_GOLEM_INTERACT; } else if (usedItemType == Material.FLINT_AND_STEEL && entity instanceof Creeper) { islandPrivilege = IslandPrivileges.IGNITE_CREEPER; } else if (usedItemType == Material.WATER_BUCKET && entityType == AXOLOTL_TYPE && ServerVersion.isAtLeast(ServerVersion.v1_17)) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 04d74df33d..2dbea93b27 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -206,6 +206,7 @@ island-roles: - BUILD - CLOSE_BYPASS - CHORUS_FRUIT + - COPPER_GOLEM_INTERACT - CROPS_GROWTH - DROP_ITEMS - DYE_SHEEP diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index 11cef9c200..59db7bf72d 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -88,6 +88,7 @@ interactables: - 'COMPOSTER' - 'COPPER_CHEST' - 'COPPER_DOOR' + - 'COPPER_GOLEM_STATUE' - 'COPPER_TRAPDOOR' - 'CRAFTER' - 'CRAFTING_TABLE' @@ -130,6 +131,7 @@ interactables: - 'ENDER_PORTAL_FRAME' - 'EXPOSED_COPPER_CHEST' - 'EXPOSED_COPPER_DOOR' + - 'EXPOSED_COPPER_GOLEM_STATUE' - 'EXPOSED_COPPER_TRAPDOOR' - 'FARMLAND' - 'FENCE' @@ -206,6 +208,7 @@ interactables: - 'ORANGE_SHULKER_BOX' - 'OXIDIZED_COPPER_CHEST' - 'OXIDIZED_COPPER_DOOR' + - 'OXIDIZED_COPPER_GOLEM_STATUE' - 'OXIDIZED_COPPER_TRAPDOOR' - 'PALE_OAK_BUTTON' - 'PALE_OAK_DOOR' @@ -312,18 +315,23 @@ interactables: - 'WARPED_WALL_SIGN' - 'WAXED_COPPER_CHEST' - 'WAXED_COPPER_DOOR' + - 'WAXED_COPPER_GOLEM_STATUE' - 'WAXED_COPPER_TRAPDOOR' - 'WAXED_EXPOSED_COPPER_CHEST' - 'WAXED_EXPOSED_COPPER_DOOR' + - 'WAXED_EXPOSED_COPPER_GOLEM_STATUE' - 'WAXED_EXPOSED_COPPER_TRAPDOOR' - 'WAXED_OXIDIZED_COPPER_CHEST' - 'WAXED_OXIDIZED_COPPER_DOOR' + - 'WAXED_OXIDIZED_COPPER_GOLEM_STATUE' - 'WAXED_OXIDIZED_COPPER_TRAPDOOR' - 'WAXED_WEATHERED_COPPER_CHEST' - 'WAXED_WEATHERED_COPPER_DOOR' + - 'WAXED_WEATHERED_COPPER_GOLEM_STATUE' - 'WAXED_WEATHERED_COPPER_TRAPDOOR' - 'WEATHERED_COPPER_CHEST' - 'WEATHERED_COPPER_DOOR' + - 'WEATHERED_COPPER_GOLEM_STATUE' - 'WEATHERED_COPPER_TRAPDOOR' - 'WHITE_BED' - 'WHITE_CANDLE' diff --git a/src/main/resources/menus/permissions1_21.yml b/src/main/resources/menus/permissions1_21.yml index 0a930cba8e..6f71f6e80d 100644 --- a/src/main/resources/menus/permissions1_21.yml +++ b/src/main/resources/menus/permissions1_21.yml @@ -549,6 +549,39 @@ permissions: volume: 0.2 pitch: 0.2 + copper_golem_interact: + display-menu: true + permission-enabled: + type: COPPER_GOLEM_STATUE + name: '&6Copper Golem Interact' + lore: + - '&7Access to take items from copper golems.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: COPPER_GOLEM_STATUE + name: '&6Copper Golem Interact' + lore: + - '&7Access to take items from copper golems.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: COPPER_GOLEM_STATUE + name: '&6Copper Golem Interact' + lore: + - '&7Access to take items from copper golems.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + delete_warp: display-menu: true permission-enabled: From 297b2a3df1659caf6c9989de9a2c736622ff2564 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 6 Dec 2025 15:12:29 +0200 Subject: [PATCH 434/600] Fix lock files from logger created in home dir (#2774) --- .../superiorskyblock/api/modules/ModuleLogger.java | 9 ++++++++- .../module/logging/ModuleLoggerFileHandler.java | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleLogger.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleLogger.java index 7a12ae93a2..152af4450c 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleLogger.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/modules/ModuleLogger.java @@ -55,7 +55,7 @@ public void d(String message) { } else { LogRecord logRecord = new LogRecord(Level.INFO, message); for (Handler handler : getHandlers()) { - if (handler instanceof FileHandler) { + if (handler instanceof ModuleFileHandler) { handler.publish(logRecord); } } @@ -69,4 +69,11 @@ private void logError(Throwable error) { super.severe(buffer.toString()); } + /** + * Custom interface to distinguish between logger handlers and the module's custom file handler. + */ + public interface ModuleFileHandler { + + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/logging/ModuleLoggerFileHandler.java b/src/main/java/com/bgsoftware/superiorskyblock/module/logging/ModuleLoggerFileHandler.java index 396ad62332..845ef232a6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/logging/ModuleLoggerFileHandler.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/logging/ModuleLoggerFileHandler.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.module.logging; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.modules.ModuleLogger; import java.io.File; import java.io.FileInputStream; @@ -17,6 +18,7 @@ import java.util.concurrent.TimeUnit; import java.util.logging.FileHandler; import java.util.logging.Formatter; +import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; @@ -105,7 +107,7 @@ private static void zipLogsFile(File file, String name, File zipFile) { file.delete(); } - private static class AsyncFileHandler extends FileHandler { + private static class AsyncFileHandler extends Handler implements ModuleLogger.ModuleFileHandler { private final BlockingQueue queue = new LinkedBlockingQueue<>(10000); private final Thread worker; From 101be406e527e064e268501fe566ba7a562797f2 Mon Sep 17 00:00:00 2001 From: nivcoo <36514752+nivcoo@users.noreply.github.com> Date: Sun, 7 Dec 2025 07:05:18 +0100 Subject: [PATCH 435/600] improv. fix config path (#2795) --- .../bgsoftware/superiorskyblock/config/SettingsContainer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 50918f6405..8581357d28 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -294,7 +294,6 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config } }); islandsHeight = config.getInt("islands-height", 100); - seaLevelHeight = config.getInt("sea-level-height", 100); worldBordersEnabled = config.getBoolean("world-borders", true); stackedBlocksEnabled = config.getBoolean("stacked-blocks.enabled", true); stackedBlocksDisabledWorlds = Collections.unmodifiableList(config.getStringList("stacked-blocks.disabled-worlds")); @@ -388,6 +387,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config } worldsDifficulty = config.getString("worlds.difficulty", "EASY").toUpperCase(Locale.ENGLISH); + seaLevelHeight = config.getInt("worlds.sea-level-height", 100); spawnLocation = config.getString("spawn.location", "SuperiorWorld, 0, 100, 0, 0, 0"); spawnProtection = config.getBoolean("spawn.protection", true); spawnSettings = Collections.unmodifiableList(new LinkedList<>(config.getStringList("spawn.settings") From e87b6feb98509fbe2c8c30513932ad31d8947129 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sun, 7 Dec 2025 07:05:59 +0100 Subject: [PATCH 436/600] Fixed placing Bamboo Rafts without permissions (#2794) --- .../java/com/bgsoftware/superiorskyblock/core/Materials.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java index 212d8c1c8e..c5b8c756b0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java @@ -161,7 +161,7 @@ private static EnumMap> setupMaterialTags() { if (material == Material.CHEST || materialName.endsWith("_CHEST") || materialName.contains("SHULKER_BOX") || materialName.equals("BARREL")) materialTags.add(Tag.CHEST); - if (materialName.contains("BOAT")) + if (materialName.contains("BOAT") || materialName.contains("_RAFT")) materialTags.add(Tag.BOAT); if (materialName.contains("LAVA")) materialTags.add(Tag.LAVA); From 70a0cf6b956860ac5aa83017a71b08a3e0a19806 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sun, 7 Dec 2025 07:06:37 +0100 Subject: [PATCH 437/600] Fixed Pickup Lectern Book permission (#2793) --- .../service/region/RegionManagerServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 06f4f21a7d..76c596d48e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -217,6 +217,8 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc islandPrivilege = IslandPrivileges.MINECART_PLACE; } else if (Materials.isChest(blockType)) { islandPrivilege = IslandPrivileges.CHEST_ACCESS; + } else if (blockType == LECTERN) { + islandPrivilege = IslandPrivileges.PICKUP_LECTERN_BOOK; } else if (blockState instanceof InventoryHolder) { islandPrivilege = IslandPrivileges.USE; } else if (usedItem != null && blockType == VAULT && (usedItem.getType() == TRIAL_KEY || usedItem.getType() == OMINOUS_TRIAL_KEY)) { @@ -235,8 +237,6 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc islandPrivilege = IslandPrivileges.BREAK; } else if (blockType == Material.PUMPKIN) { islandPrivilege = IslandPrivileges.BREAK; - } else if (blockType == LECTERN) { - islandPrivilege = IslandPrivileges.PICKUP_LECTERN_BOOK; } else { islandPrivilege = IslandPrivileges.INTERACT; } From 88c0c3af7f45a37c2fb8751c571988aef93b1523 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sun, 14 Dec 2025 22:05:02 +0100 Subject: [PATCH 438/600] Fix Decorated Pot breaking without permission (#2799) --- .../superiorskyblock/listener/ProtectionListener.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 27cdc5cfcb..9bba372f6b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -61,6 +61,8 @@ public class ProtectionListener extends AbstractGameEventListener { private static final Material POINTED_DRIPSTONE = EnumHelper.getEnum(Material.class, "POINTED_DRIPSTONE"); @Nullable private static final EntityType TRIDENT = EnumHelper.getEnum(EntityType.class, "TRIDENT"); + @Nullable + private static final Material DECORATED_POT = EnumHelper.getEnum(Material.class, "DECORATED_POT"); private final LazyReference protectionManager = new LazyReference() { @Override @@ -510,7 +512,7 @@ private void onProjectileHit(GameEvent e) { hitBlock = null; } else { hitBlock = e.getArgs().hitBlock; - if (hitBlock == null || hitBlock.getType() != CHORUS_FLOWER) + if (hitBlock == null || (hitBlock.getType() != CHORUS_FLOWER && hitBlock.getType() != DECORATED_POT)) return; location = hitBlock.getLocation(wrapper.getHandle()); From c05af620785c66ca137bd4fe2b4977a565ba52f5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 15 Dec 2025 00:28:59 +0200 Subject: [PATCH 439/600] Adds support to 1.21.11 (Paper only) --- .../AbstractNMSAlgorithms.java.template | 2 +- .../templates/AbstractNMSWorld.java.template | 6 +- .../crops/CropsBlockEntity.java.template | 3 +- .../world/BlockEntityCache.java.template | 3 +- NMS/v1_17/properties | 4 +- .../nms/v1_17/NMSWorldImpl.java | 6 + NMS/v1_18/properties | 4 +- .../nms/v1_18/NMSWorldImpl.java | 6 + NMS/v1_19/properties | 4 +- .../nms/v1_19/NMSWorldImpl.java | 6 + NMS/v1_20_3/properties | 4 +- .../nms/v1_20_3/NMSWorldImpl.java | 6 + NMS/v1_20_4/properties | 4 +- .../nms/v1_20_4/NMSWorldImpl.java | 6 + NMS/v1_21/properties | 4 +- .../nms/v1_21/NMSWorldImpl.java | 6 + NMS/v1_21_10/build.gradle | 23 + NMS/v1_21_10/properties | 10 + .../nms/v1_21_10/NMSAlgorithmsImpl.java | 87 ++++ .../nms/v1_21_10/NMSChunksImpl.java | 362 ++++++++++++++++ .../nms/v1_21_10/NMSEntitiesImpl.java | 24 + .../nms/v1_21_10/NMSTagsImpl.java | 146 +++++++ .../nms/v1_21_10/NMSWorldImpl.java | 126 ++++++ .../dragon/IslandEntityEnderDragon.java | 40 ++ .../nms/v1_21_10/hologram/EntityHologram.java | 55 +++ .../v1_21_10/trial/IslandPlayerDetector.java | 53 +++ .../nms/v1_21_10/utils/NMSUtilsVersioned.java | 410 ++++++++++++++++++ .../vibration/IslandVibrationUser.java | 90 ++++ .../world/PropertiesMapperVersioned.java | 18 + NMS/v1_21_3/properties | 4 +- .../nms/v1_21_3/NMSWorldImpl.java | 6 + NMS/v1_21_4/properties | 4 +- .../nms/v1_21_4/NMSWorldImpl.java | 6 + NMS/v1_21_5/properties | 4 +- .../nms/v1_21_5/NMSWorldImpl.java | 6 + NMS/v1_21_7/properties | 4 +- .../nms/v1_21_7/NMSWorldImpl.java | 6 + NMS/v1_21_9/properties | 4 +- .../nms/v1_21_9/NMSWorldImpl.java | 8 +- build.gradle | 2 +- settings.gradle | 3 +- 41 files changed, 1554 insertions(+), 21 deletions(-) create mode 100644 NMS/v1_21_10/build.gradle create mode 100644 NMS/v1_21_10/properties create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSChunksImpl.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSEntitiesImpl.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSTagsImpl.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSWorldImpl.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/IslandEntityEnderDragon.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/hologram/EntityHologram.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/vibration/IslandVibrationUser.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/PropertiesMapperVersioned.java diff --git a/NMS/src/main/templates/AbstractNMSAlgorithms.java.template b/NMS/src/main/templates/AbstractNMSAlgorithms.java.template index ba10d0b4ef..245debbc66 100644 --- a/NMS/src/main/templates/AbstractNMSAlgorithms.java.template +++ b/NMS/src/main/templates/AbstractNMSAlgorithms.java.template @@ -28,7 +28,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.Container; import net.minecraft.world.entity.item.FallingBlockEntity; -import net.minecraft.world.entity.vehicle.AbstractMinecart; +import net.minecraft.world.entity.${ABSTRACT_MINECART_SUBPACKAGE}.AbstractMinecart; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import org.bukkit.Bukkit; diff --git a/NMS/src/main/templates/AbstractNMSWorld.java.template b/NMS/src/main/templates/AbstractNMSWorld.java.template index de4cd0cb6b..3df41b15f4 100644 --- a/NMS/src/main/templates/AbstractNMSWorld.java.template +++ b/NMS/src/main/templates/AbstractNMSWorld.java.template @@ -164,11 +164,11 @@ public abstract class AbstractNMSWorld implements NMSWorld { break; case GREEN: worldBorder.setSize((islandSize * 2) + 1.001D); - worldBorder.lerpSizeBetween(worldBorder.getSize() - 0.001D, worldBorder.getSize(), Long.MAX_VALUE); + lerpSizeBetween(worldBorder, worldBorder.getSize() - 0.001D, worldBorder.getSize()); break; case RED: worldBorder.setSize((islandSize * 2) + 1D); - worldBorder.lerpSizeBetween(worldBorder.getSize(), worldBorder.getSize() - 0.001D, Long.MAX_VALUE); + lerpSizeBetween(worldBorder, worldBorder.getSize(), worldBorder.getSize() - 0.001D); break; } } @@ -177,6 +177,8 @@ public abstract class AbstractNMSWorld implements NMSWorld { ((CraftPlayer) player).getHandle().connection.send(initializeBorderPacket); } + protected abstract void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize); + @Override public Object getBlockData(org.bukkit.block.Block block) { return block.getBlockData(); diff --git a/NMS/src/main/templates/crops/CropsBlockEntity.java.template b/NMS/src/main/templates/crops/CropsBlockEntity.java.template index cbe4fb3831..ddf7f54db3 100644 --- a/NMS/src/main/templates/crops/CropsBlockEntity.java.template +++ b/NMS/src/main/templates/crops/CropsBlockEntity.java.template @@ -10,7 +10,6 @@ import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsTickingMeth import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; -import net.minecraft.world.level.GameRules; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; @@ -90,7 +89,7 @@ public class CropsBlockEntity extends BlockEntity { currentTick = 0; - int worldRandomTick = serverLevel.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); + int worldRandomTick = serverLevel.getGameRules().${GET_RANDOM_TICK_SPEED_METHOD}; int chunkRandomTickSpeed = (int) (worldRandomTick * this.cachedCropGrowthMultiplier * plugin.getSettings().getCropsInterval()); if (chunkRandomTickSpeed > 0) CropsTickingMethod.tick(levelChunk, chunkRandomTickSpeed); diff --git a/NMS/src/main/templates/world/BlockEntityCache.java.template b/NMS/src/main/templates/world/BlockEntityCache.java.template index 7cf37ad66a..2223fad16e 100644 --- a/NMS/src/main/templates/world/BlockEntityCache.java.template +++ b/NMS/src/main/templates/world/BlockEntityCache.java.template @@ -1,6 +1,5 @@ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; @@ -20,7 +19,7 @@ public class BlockEntityCache { return BLOCK_TO_ID.computeIfAbsent(blockState.getBlock(), block -> { for (BlockEntityType blockEntityType : ${REGISTRY_CLASS}.BLOCK_ENTITY_TYPE) { if (blockEntityType.isValid(blockState)) { - ResourceLocation resourceLocation = BlockEntityType.getKey(blockEntityType); + Object resourceLocation = BlockEntityType.getKey(blockEntityType); if (resourceLocation != null) return resourceLocation.toString(); } diff --git a/NMS/v1_17/properties b/NMS/v1_17/properties index 25c8fbd427..cb208334a4 100644 --- a/NMS/v1_17/properties +++ b/NMS/v1_17/properties @@ -5,4 +5,6 @@ PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketB REGISTRY_CLASS=net.minecraft.core.Registry CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=java.util.Random -STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.light.StarLightInterface \ No newline at end of file +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index bace8d2ed5..0257ff3f92 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -8,6 +8,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; @@ -22,6 +23,11 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); + } + @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.messages; diff --git a/NMS/v1_18/properties b/NMS/v1_18/properties index d7b672fdf8..47b4067ae2 100644 --- a/NMS/v1_18/properties +++ b/NMS/v1_18/properties @@ -5,4 +5,6 @@ PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketB REGISTRY_CLASS=net.minecraft.core.Registry CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=java.util.Random -STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface \ No newline at end of file +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index e957a63ac8..26a4a9fc8e 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -8,6 +8,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; @@ -22,6 +23,11 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); + } + @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.messages; diff --git a/NMS/v1_19/properties b/NMS/v1_19/properties index f685ea3153..4e09ae1316 100644 --- a/NMS/v1_19/properties +++ b/NMS/v1_19/properties @@ -5,4 +5,6 @@ PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketB REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource -STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface \ No newline at end of file +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index d95e3a7a0a..5bf801071a 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -9,6 +9,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; @@ -25,6 +26,11 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); + } + @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.messages; diff --git a/NMS/v1_20_3/properties b/NMS/v1_20_3/properties index bd4e388926..3a073245fb 100644 --- a/NMS/v1_20_3/properties +++ b/NMS/v1_20_3/properties @@ -5,4 +5,6 @@ PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketB REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource -STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface \ No newline at end of file +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index b643e62c73..e06a38c883 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -9,6 +9,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; @@ -30,6 +31,11 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); + } + @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); diff --git a/NMS/v1_20_4/properties b/NMS/v1_20_4/properties index 6770f40102..ecc89fb050 100644 --- a/NMS/v1_20_4/properties +++ b/NMS/v1_20_4/properties @@ -5,4 +5,6 @@ PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketB REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource -STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface \ No newline at end of file +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index 8692288b35..94c5f6f200 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -9,6 +9,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; @@ -30,6 +31,11 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); + } + @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); diff --git a/NMS/v1_21/properties b/NMS/v1_21/properties index 9bea625c4d..ba78f8cb8d 100644 --- a/NMS/v1_21/properties +++ b/NMS/v1_21/properties @@ -5,4 +5,6 @@ PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketB REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource -STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface \ No newline at end of file +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index 1a1c0ade3a..82b37892c5 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -16,6 +16,7 @@ import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; @@ -37,6 +38,11 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); + } + @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); diff --git a/NMS/v1_21_10/build.gradle b/NMS/v1_21_10/build.gradle new file mode 100644 index 0000000000..6f27afb632 --- /dev/null +++ b/NMS/v1_21_10/build.gradle @@ -0,0 +1,23 @@ +plugins { + id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } +} + +group 'NMS:v1_21_10' + +dependencies { + paperweight.paperDevBundle("1.21.11-R0.1-SNAPSHOT") + compileOnly project(":NMS:Spigot-1_20_3") + compileOnly project(":NMS:Paper-1_20_3") + compileOnly project(":API") + compileOnly rootProject +} + +if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/NMS/v1_21_10/properties b/NMS/v1_21_10/properties new file mode 100644 index 0000000000..dfc0b992a7 --- /dev/null +++ b/NMS/v1_21_10/properties @@ -0,0 +1,10 @@ +NMS_VERSION=v1_21_10 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle.minecart +GET_RANDOM_TICK_SPEED_METHOD=get(net.minecraft.world.level.gamerules.GameRules.RANDOM_TICK_SPEED) \ No newline at end of file diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java new file mode 100644 index 0000000000..bcfff72f40 --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java @@ -0,0 +1,87 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10; + +import com.bgsoftware.common.reflection.ReflectField; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.mojang.serialization.JsonOps; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.ComponentSerialization; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.inventory.ItemRarity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; + +import java.lang.reflect.Modifier; +import java.util.Locale; +import java.util.Objects; + +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms { + + public static final ReflectField SERVER_RECENT_TPS = new ReflectField<>(MinecraftServer.class, + double[].class, Modifier.PUBLIC | Modifier.FINAL, 1); + + private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create(); + + @Override + public String parseSignLine(String original) { + RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE); + JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0]) + .getOrThrow(JsonParseException::new); + return COMPONENT_GSON.toJson(jsonElement); + } + + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + itemMeta.setRarity(ItemRarity.valueOf(rarity)); + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + + @Override + public String getMinecraftKey(ItemStack itemStack) { + return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); + } + + @Override + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.setEnchantmentGlintOverride(true); + } + + @Override + public double getCurrentTps() { + return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0]; + } + +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSChunksImpl.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSChunksImpl.java new file mode 100644 index 0000000000..836913a9ad --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSChunksImpl.java @@ -0,0 +1,362 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10; + +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.core.CalculatedChunk; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.bgsoftware.superiorskyblock.nms.v1_21_10.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_10.utils.NMSUtilsVersioned; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.mojang.logging.LogUtils; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; +import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.ProblemReporter; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerFactory; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.ValueInput; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.generator.ChunkGenerator; +import org.slf4j.Logger; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import static com.bgsoftware.superiorskyblock.nms.v1_21_10.utils.NMSUtilsVersioned.DEFAULT_PALETTED_CONTAINER_FACTORY; + +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSChunks { + + private static final ReflectMethod>>> CONTAINER_FACTORY_BIOME_RW_CODEC = + new ReflectMethod<>(PalettedContainerFactory.class, "biomeContainerCodecRW"); + + private static final Logger LOGGER = LogUtils.getLogger(); + + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { + super(plugin); + } + + @Override + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); + + ChunkPos chunkPos = levelChunk.getPos(); + + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + LevelChunkSection currentSection = chunkSections[i]; + if (currentSection != null) { + PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); + chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); + } + } + + levelChunk.markUnsaved(); + + ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); + ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( + levelChunk, levelChunk.level.getLightEngine(), null, null); + + playersToUpdate.forEach(player -> { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + serverPlayer.connection.send(forgetLevelChunkPacket); + serverPlayer.connection.send(mapChunkPacket); + }); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); + + PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); + DataResult dataResult = getBiomeContainerRWCodec() + .encodeStart(NbtOps.INSTANCE, biomesContainer); + Tag biomesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); + + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); + } + + @Override + public void onFinish() { + // Do nothing. + } + }; + } + + @Override + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + chunkSections[i] = new LevelChunkSection(DEFAULT_PALETTED_CONTAINER_FACTORY); + } + + removeEntities(levelChunk); + removeBlockEntities(levelChunk); + removeBlocks(levelChunk); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + ListTag tileEntities = new ListTag(); + + chunkCompound.put("Entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); + + if (serverLevel.generator instanceof IslandsGenerator) { + PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() + .encodeStart(NbtOps.INSTANCE, statesContainer); + Tag blockStatesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); + } else { + ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); + + try { + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); + } catch (Exception ignored) { + } + + LevelLightEngine lightEngine = serverLevel.getLightEngine(); + LevelChunkSection[] chunkSections = protoChunk.getSections(); + + ListTag sectionsList = new ListTag(); + + // Save blocks + for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { + int chunkSectionIndex = serverLevel.getSectionIndex(i); + + CompoundTag sectionCompound = new CompoundTag(); + + if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { + LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; + + { + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() + .encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); + sectionCompound.put("block_states", dataResult.getOrThrow()); + } + + { + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerCodec() + .encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); + sectionCompound.put("biomes", dataResult.getOrThrow()); + } + } + + if (!sectionCompound.isEmpty()) { + sectionCompound.putByte("Y", (byte) i); + sectionsList.add(sectionCompound); + } + } + + for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { + CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, + MinecraftServer.getServer().registryAccess()); + if (blockEntityCompound != null) + tileEntities.add(blockEntityCompound); + } + + chunkCompound.put("sections", sectionsList); + } + } + + @Override + public void onFinish() { + if (onFinish != null) + onFinish.run(); + } + }; + } + + @Override + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + + latchCountDown(); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + + LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; + + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); + for (int i = 0; i < sectionsList.size(); ++i) { + CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); + byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); + int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); + + if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { + PalettedContainer blocksPalettedContainer; + Optional blockStatesCompound = sectionCompound.getCompound("block_states"); + if (blockStatesCompound.isPresent()) { + DataResult> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY + .blockStatesContainerCodec().parse(NbtOps.INSTANCE, blockStatesCompound.get()) + .promotePartial((sx) -> { + }); + blocksPalettedContainer = dataResult.getOrThrow(); + } else { + blocksPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + } + + PalettedContainer> biomesPalettedContainer; + Optional biomesCompound = sectionCompound.getCompound("biomes"); + if (biomesCompound.isPresent()) { + DataResult>> dataResult = getBiomeContainerRWCodec() + .parse(NbtOps.INSTANCE, biomesCompound.get()) + .promotePartial((sx) -> { + }); + biomesPalettedContainer = dataResult.getOrThrow(); + } else { + biomesPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBiomes(); + } + + chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); + } + + } + + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + allCalculatedChunks.add(calculatedChunk); + unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + latchCountDown(); + } + + @Override + public void onFinish() { + completableFuture.complete(allCalculatedChunks); + } + }; + } + + @Override + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + ChunkPos chunkPos = levelChunk.getPos(); + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), chunkPos.x, chunkPos.z, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); + + latchCountDown(); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + unloadedChunkCompounds.add(unloadedChunkCompound); + + latchCountDown(); + } + + @Override + public void onFinish() { + BukkitExecutor.ensureMain(() -> { + for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("Entities"); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); + } + + completableFuture.complete(allCalculatedChunks); + }); + } + }; + } + + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getIntOr("DataVersion", 0); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag); + return EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL); + } + } + + private static void removeBlocks(ChunkAccess chunk) { + ServerLevel serverLevel = ((LevelChunk) chunk).level; + ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); + + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; + + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); + } + + private static Codec>> getBiomeContainerRWCodec() { + if (CONTAINER_FACTORY_BIOME_RW_CODEC.isValid()) { + return CONTAINER_FACTORY_BIOME_RW_CODEC.invoke(DEFAULT_PALETTED_CONTAINER_FACTORY); + } else { + return DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerRWCodec(); + } + } + +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSEntitiesImpl.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSEntitiesImpl.java new file mode 100644 index 0000000000..e770d1ce1d --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSEntitiesImpl.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10; + +import net.minecraft.tags.ItemTags; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PortalProcessor; +import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.minecart.PoweredMinecart; + +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSEntities { + + @Override + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); + } + + @Override + protected int getPortalTicks(Entity entity) { + PortalProcessor portalProcessor = entity.portalProcess; + return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); + } + +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSTagsImpl.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSTagsImpl.java new file mode 100644 index 0000000000..fe07bbb87e --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSTagsImpl.java @@ -0,0 +1,146 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10; + +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.logging.LogUtils; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.ByteArrayTag; +import net.minecraft.nbt.IntArrayTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.NumericTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Util; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ResolvableProfile; +import org.bukkit.Location; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.slf4j.Logger; + +import java.util.Set; + +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSTags { + + private static final Logger LOGGER = LogUtils.getLogger(); + + @Override + public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + Multimap properties = HashMultimap.create(); + properties.put("textures", new Property("textures", texture)); + + GameProfile gameProfile = new GameProfile(Util.NIL_UUID, "", new PropertyMap(properties)); + + ResolvableProfile resolvableProfile = ResolvableProfile.createResolved(gameProfile); + + itemStack.set(DataComponents.PROFILE, resolvableProfile); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { + RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); + + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) + ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow(); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms.DATA_VERSION); + + return CompoundTag.fromNBT(tagCompound); + } + + @Override + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.getIntOr(key, def); + } + + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + RegistryOps context = + MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); + + return ItemStack.CODEC.parse(context, compoundTag) + .resultOrPartial((itemId) -> LOGGER.error("Tried to load invalid item: '{}'", itemId)) + .orElseThrow(); + } + + @Override + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); + } + + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { + EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { + entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); + return !serverLevel.addWithUUID(entity) ? null : entity; + }); + } + + @Override + public byte[] getNBTByteArrayValue(Object object) { + return ((ByteArrayTag) object).getAsByteArray(); + } + + @Override + public byte getNBTByteValue(Object object) { + return ((NumericTag) object).byteValue(); + } + + @Override + public Set getNBTCompoundValue(Object object) { + return ((net.minecraft.nbt.CompoundTag) object).keySet(); + } + + @Override + public double getNBTDoubleValue(Object object) { + return ((NumericTag) object).doubleValue(); + } + + @Override + public float getNBTFloatValue(Object object) { + return ((NumericTag) object).floatValue(); + } + + @Override + public int[] getNBTIntArrayValue(Object object) { + return ((IntArrayTag) object).getAsIntArray(); + } + + @Override + public int getNBTIntValue(Object object) { + return ((NumericTag) object).intValue(); + } + + @Override + public Object getNBTListIndexValue(Object object, int index) { + return ((net.minecraft.nbt.ListTag) object).get(index); + } + + @Override + public long getNBTLongValue(Object object) { + return ((NumericTag) object).longValue(); + } + + @Override + public short getNBTShortValue(Object object) { + return ((NumericTag) object).shortValue(); + } + + @Override + public String getNBTStringValue(Object object) { + return ((StringTag) object).value(); + } + +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSWorldImpl.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSWorldImpl.java new file mode 100644 index 0000000000..b5f2b9de49 --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSWorldImpl.java @@ -0,0 +1,126 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.nms.v1_21_10.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_10.trial.IslandPlayerDetector; +import com.bgsoftware.superiorskyblock.nms.v1_21_10.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.world.SignType; +import net.minecraft.network.chat.Component; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; +import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; +import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import org.bukkit.Location; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; + +import java.lang.reflect.Modifier; + +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSWorld { + + private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( + SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + + + public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { + super(plugin); + } + + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE, worldBorder.world.getGameTime()); + } + + @Override + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); + } + + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.getDelegate(); + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.value(); + } + + @Override + public void replaceTrialBlockPlayerDetector(Island island, Location location) { + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); + if (blockEntity == null) + return; + + if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { + VaultConfig vaultConfig = vaultBlockEntity.getConfig(); + + PlayerDetector playerDetector = vaultConfig.playerDetector(); + if (playerDetector instanceof IslandPlayerDetector) + return; + + VaultConfig newConfig = new VaultConfig( + vaultConfig.lootTable(), + vaultConfig.activationRange(), + vaultConfig.deactivationRange(), + vaultConfig.keyItem(), + vaultConfig.overrideLootTableToDisplay(), + IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), + vaultConfig.entitySelector() + ); + + vaultBlockEntity.setConfig(newConfig); + } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { + TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); + PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); + + if (playerDetector instanceof IslandPlayerDetector) + return; + + trialSpawnerBlockEntity.trialSpawner.setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector)); + } + } + + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) + return; + + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } + + @Override + public SignType getSignType(Object sign) { + if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return super.getSignType(sign); + } + +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/IslandEntityEnderDragon.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/IslandEntityEnderDragon.java new file mode 100644 index 0000000000..6353eb7adf --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/IslandEntityEnderDragon.java @@ -0,0 +1,40 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10.dragon; + +import com.bgsoftware.common.annotations.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.SpawnGroupData; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; +import net.minecraft.world.level.storage.ValueInput; + +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v1_21_10.dragon.AbstractIslandEntityEnderDragon { + + public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { + super(level, islandBlockPos); + } + + public IslandEntityEnderDragon(Level level) { + super(level); + } + + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, + DifficultyInstance difficulty, + EntitySpawnReason spawnReason, + @Nullable SpawnGroupData entityData) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(world, difficulty, spawnReason, entityData); + } + + @Override + protected void readAdditionalSaveData(ValueInput input) { + super.readAdditionalSaveData(input); + finalizeIslandEnderDragon(); + } + +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/hologram/EntityHologram.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/hologram/EntityHologram.java new file mode 100644 index 0000000000..9c18f54de0 --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/hologram/EntityHologram.java @@ -0,0 +1,55 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10.hologram; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.level.storage.ValueOutput; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_10.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + protected void addAdditionalSaveData(ValueOutput output) { + // Do not save NBT. + } + + @Override + protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) { + // Do not save NBT. + } + + @Override + protected void readAdditionalSaveData(ValueInput input) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { + // Do not save NBT. + return false; + } + + @Override + public boolean saveAsPassenger(ValueOutput output) { + // Do not save NBT. + return false; + } + + @Override + public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { + // Do not save NBT. + } + + @Override + public void saveWithoutId(ValueOutput output) { + // Do not save NBT. + } + + @Override + public void load(ValueInput input) { + // Do not load NBT. + } + +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java new file mode 100644 index 0000000000..d11bc37f28 --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java @@ -0,0 +1,53 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10.trial; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +public class IslandPlayerDetector implements PlayerDetector { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final PlayerDetector original; + private final IslandPrivilege requiredPrivilege; + + public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + } + + public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + } + + private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + this.island = island; + this.original = original; + this.requiredPrivilege = requiredPrivilege; + } + + @Override + public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { + List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); + if (!players.isEmpty()) { + players = new LinkedList<>(players); + players.removeIf(uuid -> { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); + return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + }); + players = Collections.unmodifiableList(players); + } + return players; + } + +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..f17adceab1 --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java @@ -0,0 +1,410 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10.utils; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_10.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v1_21_10.utils.TickingBlockList; +import com.google.common.base.Suppliers; +import com.google.gson.JsonParseException; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.logging.LogUtils; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.util.ProblemReporter; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerFactory; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.Strategy; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.TagValueOutput; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; +import org.slf4j.Logger; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; + +public class NMSUtilsVersioned { + + private static final Logger LOGGER = LogUtils.getLogger(); + + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( + EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + public static final PalettedContainerFactory DEFAULT_PALETTED_CONTAINER_FACTORY = PalettedContainerFactory.create( + MinecraftServer.getServer().registryAccess()); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { + return chunkMap.read(chunkPos).join().orElse(null); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { + return chunkMap.upgradeChunkTag(chunkCompoundTag); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { + chunkMap.write(chunkPos, () -> chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } else { + return BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + MoonriseRegionFileIO.RegionDataController regionDataController = + serverLevel.moonrise$getEntityChunkDataController(); + int chunkX = chunkPosition.getX(); + int chunkZ = chunkPosition.getZ(); + MoonriseRegionFileIO.RegionDataController.ReadData readData = + regionDataController.readData(chunkX, chunkZ); + if(readData != null) { + CompoundTag entityData = switch (readData.result()) { + case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); + case SYNC_READ -> readData.syncRead(); + default -> null; + }; + if (entityData != null) { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + return; + } + } + + chunkCallback.onChunkNotExist(chunkPosition); + } catch (IOException error) { + countDownLatch.countDown(); + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + DEFAULT_PALETTED_CONTAINER_FACTORY, + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), + new ProtoChunkTicks<>(), levelHeightAccessor, DEFAULT_PALETTED_CONTAINER_FACTORY, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.liquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "block_entity@" + blockEntity.getBlockPos(), LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag); + blockEntity.loadWithComponents(valueInput); + } + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + applySignTextLines(compoundTag, "front_text"); + applySignTextLines(compoundTag, "back_text"); + convertLegacySignTextLines(compoundTag); + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + PalettedContainer> biomesContainer = createBiomesContainer(biome); + PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); + + // Unsafe: we do not provide chunks cache, even tho it is required. + // Should be fine in normal flow, as the only method that access the chunks cache + // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 + WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); + + customChunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + } + + public static CompoundTag saveEntity(Entity entity) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "cached_entity@" + entity.getUUID(), LOGGER)) { + TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess()); + entity.save(valueOutput); + return valueOutput.buildResult(); + } + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.moonrise$getTickingBlockList().size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.properties(); + } + + public static String getPropertyValue(Property property) { + return property.value(); + } + + public static EndDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.getDragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absSnapTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSectionY(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinY(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxY(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.markUnsaved(); + } + + public static PalettedContainer> createBiomesContainer(Holder biome) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + Strategy> biomesStrategy = Strategy.createForBiomes(biomesRegistry.asHolderIdMap()); + return new PalettedContainerFactory( + null, + null, + null, + biomesStrategy, + biome, + null, + null + ).createForBiomes(); + } + + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { + blockEntityCompound.getCompound(key).ifPresent(textCompound -> { + ListTag messages = textCompound.getListOrEmpty("messages"); + List textLines = new ArrayList<>(); + for (net.minecraft.nbt.Tag lineTag : messages) { + try { + textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); + } catch (JsonParseException error) { + textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); + } + } + + for (int i = 0; i < 4; i++) { + if (textLines.get(i) == null) + textLines.set(i, Component.empty()); + } + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); + }); + } + + private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/vibration/IslandVibrationUser.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/vibration/IslandVibrationUser.java new file mode 100644 index 0000000000..dedc1d1bbc --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/vibration/IslandVibrationUser.java @@ -0,0 +1,90 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.PositionSource; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; + +import javax.annotation.Nullable; + +public class IslandVibrationUser implements VibrationSystem.User { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final VibrationSystem.User original; + + public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + this.island = island; + this.original = sculkSensorBlockEntity.getVibrationUser(); + } + + @Override + public int getListenerRadius() { + return this.original.getListenerRadius(); + } + + @Override + public PositionSource getPositionSource() { + return this.original.getPositionSource(); + } + + @Override + public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { + if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) + return false; + + if (context.sourceEntity() instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + + @Override + public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { + this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); + } + + @Override + public TagKey getListenableEvents() { + return this.original.getListenableEvents(); + } + + @Override + public boolean canTriggerAvoidVibration() { + return this.original.canTriggerAvoidVibration(); + } + + @Override + public boolean requiresAdjacentChunksToBeTicking() { + return this.original.requiresAdjacentChunksToBeTicking(); + } + + @Override + public int calculateTravelTimeInTicks(float distance) { + return this.original.calculateTravelTimeInTicks(distance); + } + + @Override + public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { + return this.original.isValidVibration(gameEvent, context); + } + + @Override + public void onDataChanged() { + this.original.onDataChanged(); + } + +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/PropertiesMapperVersioned.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..5f12f03f86 --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/PropertiesMapperVersioned.java @@ -0,0 +1,18 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10.world; + +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/NMS/v1_21_3/properties b/NMS/v1_21_3/properties index a5f266fb91..5fc11e7a2a 100644 --- a/NMS/v1_21_3/properties +++ b/NMS/v1_21_3/properties @@ -5,4 +5,6 @@ PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=com.destroystokyo.paper.antixray.ChunkPacketB REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource -STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface \ No newline at end of file +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index 3c5c55526c..bdde657f5e 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -16,6 +16,7 @@ import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; @@ -37,6 +38,11 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); + } + @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); diff --git a/NMS/v1_21_4/properties b/NMS/v1_21_4/properties index 4b5d1da73b..15bec624c2 100644 --- a/NMS/v1_21_4/properties +++ b/NMS/v1_21_4/properties @@ -5,4 +5,6 @@ PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockCon REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource -STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface \ No newline at end of file +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index 6090c4c417..8c4bc8b1c5 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -16,6 +16,7 @@ import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; @@ -37,6 +38,11 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); + } + @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); diff --git a/NMS/v1_21_5/properties b/NMS/v1_21_5/properties index ed461d72fd..c2c62d87f0 100644 --- a/NMS/v1_21_5/properties +++ b/NMS/v1_21_5/properties @@ -5,4 +5,6 @@ PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockCon REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource -STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface \ No newline at end of file +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java index e7282183d5..eea8117d71 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java @@ -16,6 +16,7 @@ import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; @@ -37,6 +38,11 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); + } + @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); diff --git a/NMS/v1_21_7/properties b/NMS/v1_21_7/properties index 12001562cf..db87c5e455 100644 --- a/NMS/v1_21_7/properties +++ b/NMS/v1_21_7/properties @@ -5,4 +5,6 @@ PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockCon REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource -STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface \ No newline at end of file +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java index 9a717f0567..e74ede3bd5 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java @@ -16,6 +16,7 @@ import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; @@ -37,6 +38,11 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); + } + @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); diff --git a/NMS/v1_21_9/properties b/NMS/v1_21_9/properties index 12871ded67..9f4a5728ed 100644 --- a/NMS/v1_21_9/properties +++ b/NMS/v1_21_9/properties @@ -5,4 +5,6 @@ PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockCon REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource -STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface \ No newline at end of file +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java index b0b75a65ca..52043b8eec 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java @@ -17,6 +17,7 @@ import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; import net.minecraft.world.level.levelgen.FlatLevelSource; @@ -37,10 +38,15 @@ public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.Ab private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); - public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } + + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE); + } + @Override protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { return signBlockEntity.getFrontText().getMessages(false); diff --git a/build.gradle b/build.gradle index 3cb5be383a..907134d8e3 100644 --- a/build.gradle +++ b/build.gradle @@ -72,7 +72,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b16' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b17' implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b2' implementation 'org.bstats:bstats-bukkit:3.0.0' diff --git a/settings.gradle b/settings.gradle index c8ada85806..7bf55744bd 100644 --- a/settings.gradle +++ b/settings.gradle @@ -70,4 +70,5 @@ include 'NMS:v1_21_3' include 'NMS:v1_21_4' include 'NMS:v1_21_5' include 'NMS:v1_21_7' -include 'NMS:v1_21_9' \ No newline at end of file +include 'NMS:v1_21_9' +include 'NMS:v1_21_10' \ No newline at end of file From 5fd92573eadc3ad2d10fe610b6ccca066f9f3580 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Tue, 16 Dec 2025 11:54:12 +0100 Subject: [PATCH 440/600] Fixed loading upgrades when all upgrade types are disabled (#2777) --- .../module/upgrades/UpgradesModule.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java index 927f754cd2..d8e94536e8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java @@ -191,6 +191,10 @@ public boolean isEnabled() { } private void loadUpgrades(CommentedConfiguration config) { + plugin.getUpgrades().clearUpgrades(); + + if (!enabled) return; + if (config.getBoolean("crop-growth", true)) enabledUpgrades.add(new UpgradeTypeCropGrowth(plugin)); if (config.getBoolean("mob-drops", true)) @@ -204,22 +208,18 @@ private void loadUpgrades(CommentedConfiguration config) { if (config.getBoolean("entity-limits", true)) enabledUpgrades.add(new UpgradeTypeEntityLimits(plugin)); - plugin.getUpgrades().clearUpgrades(); + ConfigurationSection upgrades = config.getConfigurationSection("upgrades"); + if (upgrades != null) { + for (String upgradeName : upgrades.getKeys(false)) { + if (upgradeName.length() > MAX_UPGRADES_NAME_LENGTH) + upgradeName = upgradeName.substring(0, MAX_UPGRADES_NAME_LENGTH); - if (!enabledUpgrades.isEmpty()) { - ConfigurationSection upgrades = config.getConfigurationSection("upgrades"); - if (upgrades != null) { - for (String upgradeName : upgrades.getKeys(false)) { - if (upgradeName.length() > MAX_UPGRADES_NAME_LENGTH) - upgradeName = upgradeName.substring(0, MAX_UPGRADES_NAME_LENGTH); - - SUpgrade upgrade = new SUpgrade(upgradeName); - for (String _level : upgrades.getConfigurationSection(upgradeName).getKeys(false)) { - loadUpgradeLevelFromSection(plugin, upgrade, _level, upgrades.getConfigurationSection(upgradeName + "." + _level)); - } - - plugin.getUpgrades().addUpgrade(upgrade); + SUpgrade upgrade = new SUpgrade(upgradeName); + for (String _level : upgrades.getConfigurationSection(upgradeName).getKeys(false)) { + loadUpgradeLevelFromSection(plugin, upgrade, _level, upgrades.getConfigurationSection(upgradeName + "." + _level)); } + + plugin.getUpgrades().addUpgrade(upgrade); } } From 6ded5ae00a29e725c6703e7ebdbf938e994f0792 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 16 Dec 2025 13:27:52 +0200 Subject: [PATCH 441/600] Add missing head textures of new mobs (#2803) --- src/main/resources/heads.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/resources/heads.yml b/src/main/resources/heads.yml index 32bd9c52de..c5b39eb081 100644 --- a/src/main/resources/heads.yml +++ b/src/main/resources/heads.yml @@ -17,6 +17,7 @@ BLAZE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQu BOGGED: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTNiOTAwM2JhMmQwNTU2MmM3NTExOWI4YTYyMTg1YzY3MTMwZTkyODJmN2FjYmFjNGJjMjgyNGMyMWViOTVkOSJ9fX0=' BREEZE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTI3NTcyOGFmN2U2YTI5Yzg4MTI1YjY3NWEzOWQ4OGFlOTkxOWJiNjFmZGMyMDAzMzdmZWQ2YWIwYzQ5ZDY1YyJ9fX0=' CAMEL: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvN2ViNmFkOTA4YjhkNTE1NWJjNGQyNDkyNzFlZjYwODRkNDU1ZGQwZTcwYTQwMDJlYjE0OGY5ZTIwYjlkZWIyYyJ9fX0=' +CAMEL_HUSK: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzUwYmZjOWIyY2M0MGY0ZDhkMDIyNGNjYmFiYWMyNmIzMzhhYTk0N2Q5OWRjZGU3NjlmODU5YjU5YjhkMGIwZSJ9fX0=' CAT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMmYxODA2NDE3YzE2Y2NkYzMzOWQ0NGQzMjgyNTFhOGQxYmJlYWI5NDVmODdhODViNDhlNGIxMTRmZGVmYiJ9fX0=' CAVE_SPIDER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDE2NDVkZmQ3N2QwOTkyMzEwN2IzNDk2ZTk0ZWViNWMzMDMyOWY5N2VmYzk2ZWQ3NmUyMjZlOTgyMjQifX19' CHICKEN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTYzODQ2OWE1OTljZWVmNzIwNzUzNzYwMzI0OGE5YWIxMWZmNTkxZmQzNzhiZWE0NzM1YjM0NmE3ZmFlODkzIn19fQ==' @@ -51,8 +52,10 @@ MAGMA_CUBE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3J MOOSHROOM: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDBiYzYxYjk3NTdhN2I4M2UwM2NkMjUwN2EyMTU3OTEzYzJjZjAxNmU3YzA5NmE0ZDZjZjFmZTFiOGRiIn19fQ==' MULE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTA0ODZhNzQyZTdkZGEwYmFlNjFjZTJmNTVmYTEzNTI3ZjFjM2IzMzRjNTdjMDM0YmI0Y2YxMzJmYjVmNWYifX19' MUSHROOM_COW: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZDBiYzYxYjk3NTdhN2I4M2UwM2NkMjUwN2EyMTU3OTEzYzJjZjAxNmU3YzA5NmE0ZDZjZjFmZTFiOGRiIn19fQ==' +NAUTILUS: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYjUzZDYzZWIxNzViMDBmYjM1Mjg1ZjQzMzBkMGJlNjhhMDcxM2RiOTRlMDBlNmZkZDg1ODMyZDQxZTNhMDhiIn19fQ==' OCELOT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTY1N2NkNWMyOTg5ZmY5NzU3MGZlYzRkZGNkYzY5MjZhNjhhMzM5MzI1MGMxYmUxZjBiMTE0YTFkYjEifX19' PANDA: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZGYwMDg1ODkyNmNkOGNkZjNmMWNmNzFlMjEwY2RlNWRhZjg3MDgzMjA1NDdiZDZkZjU3OTU4NTljNjhkOWIzZiJ9fX0=' +PARCHED: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMjRhZWNlZmY1ZjI2ZGQ4NDEzYzVjMDM1NDdjMjM0YWMwMzEwOGQxODdhZjBiOWNkODM0YThjZTEyNTk4NTkxYyJ9fX0=' PARROT: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTRiYThkNjZmZWNiMTk5MmU5NGI4Njg3ZDZhYjRhNTMyMGFiNzU5NGFjMTk0YTI2MTVlZDRkZjgxOGVkYmMzIn19fQ==' PHANTOM: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNzQ2ODMwZGE1ZjgzYTNhYWVkODM4YTk5MTU2YWQ3ODFhNzg5Y2ZjZjEzZTI1YmVlZjdmNTRhODZlNGZhNCJ9fX0=' PIG: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNjIxNjY4ZWY3Y2I3OWRkOWMyMmNlM2QxZjNmNGNiNmUyNTU5ODkzYjZkZjRhNDY5NTE0ZTY2N2MxNmFhNCJ9fX0=' @@ -94,5 +97,6 @@ WOLF: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQub ZOGLIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZTY3ZTE4NjAyZTAzMDM1YWQ2ODk2N2NlMDkwMjM1ZDg5OTY2NjNmYjllYTQ3NTc4ZDNhN2ViYmM0MmE1Y2NmOSJ9fX0=' ZOMBIE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNTZmYzg1NGJiODRjZjRiNzY5NzI5Nzk3M2UwMmI3OWJjMTA2OTg0NjBiNTFhNjM5YzYwZTVlNDE3NzM0ZTExIn19fQ==' ZOMBIE_HORSE: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTcxY2U0NjljYmE0NDI2YzgxMWY2OWJlNWQ5NThhMDliZmI5YjFiMmJiNjQ5ZDM1NzdhMGMyMTYxYWQyZjUyNCJ9fX0=' +ZOMBIE_NAUTILUS: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvZmQ5YTkzMzM3NmRhNDRjMzM5MTMwN2NiOWY0Y2YwM2YxNmYzYTU0ZjQ5NWZkNWExMWJhZDhhMzczZjlkNTcyMCJ9fX0=' ZOMBIE_VILLAGER: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYTYyMjQ5NDEzMTRiY2EyZWJiYjY2YjEwZmZkOTQ2ODBjYzk4YzM0MzVlZWI3MWEyMjhhMDhmZDQyYzI0ZGIifX19' ZOMBIFIED_PIGLIN: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvODk1NGQwZDFjMjg2YzFiMzRmYjA5MTg0MWMwNmFlZDc0MWExYmY5YjY1YjlhNDMwZTRlNWNhMWQxYzRiOWY2ZiJ9fX0=' \ No newline at end of file From e5a575dc91fa39de280c65303067a89af9c83861 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 16 Dec 2025 13:45:37 +0200 Subject: [PATCH 442/600] Fixed the ability to interact with nautiluses on other islands (#2803) --- .../island/privilege/IslandPrivileges.java | 1 + .../listener/ProtectionListener.java | 3 +- .../region/RegionManagerServiceImpl.java | 6 +++- .../world/BukkitEntities.java | 11 ++++++- src/main/resources/menus/permissions1_21.yml | 33 +++++++++++++++++++ 5 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index d51d8bbc40..3ccf05f227 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -59,6 +59,7 @@ public class IslandPrivileges { public static final IslandPrivilege MINECART_PLACE = register("MINECART_PLACE"); public static final IslandPrivilege MONSTER_DAMAGE = register("MONSTER_DAMAGE"); public static final IslandPrivilege MONSTER_SPAWN = register("MONSTER_SPAWN"); + public static final IslandPrivilege NAUTILUS_INTERACT = register("NAUTILUS_INTERACT", EnumHelper.getEnum(EntityType.class, "NAUTILUS") != null); public static final IslandPrivilege NAME_ENTITY = register("NAME_ENTITY"); public static final IslandPrivilege OPEN_ISLAND = register("OPEN_ISLAND", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege PAINTING = register("PAINTING"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 9bba372f6b..eb8f7a4811 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -404,7 +404,8 @@ private void onVehicleOpen(GameEvent e) { return; IslandPrivilege islandPrivilege = BukkitEntities.isHorse((Vehicle) inventoryHolder) ? IslandPrivileges.HORSE_INTERACT : - inventoryHolder instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_OPEN; + BukkitEntities.isNautilus(((Vehicle) inventoryHolder).getType()) ? IslandPrivileges.NAUTILUS_INTERACT : + inventoryHolder instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_OPEN; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().bukkitEvent.getPlayer()); InteractionResult interactionResult; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 76c596d48e..b3b41ae6d7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -300,6 +300,9 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent } else if (BukkitEntities.isHorse(entity)) { islandPrivilege = IslandPrivileges.HORSE_INTERACT; closeInventory = true; + } else if (BukkitEntities.isNautilus(entityType)) { + islandPrivilege = IslandPrivileges.NAUTILUS_INTERACT; + closeInventory = true; } else if (entityType == COPPER_GOLEM_TYPE) { islandPrivilege = IslandPrivileges.COPPER_GOLEM_INTERACT; } else if (usedItemType == Material.FLINT_AND_STEEL && entity instanceof Creeper) { @@ -395,7 +398,8 @@ public InteractionResult handleEntityRide(SuperiorPlayer superiorPlayer, Entity return InteractionResult.SUCCESS; IslandPrivilege islandPrivilege = BukkitEntities.isHorse(vehicle) ? IslandPrivileges.HORSE_INTERACT : - vehicle instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_ENTER; + BukkitEntities.isNautilus(vehicle.getType()) ? IslandPrivileges.NAUTILUS_INTERACT : + vehicle instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_ENTER; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = vehicle.getLocation(wrapper.getHandle()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java index bf019c58c1..71167cb77c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java @@ -42,6 +42,10 @@ public class BukkitEntities { private static final Synchronized>> entityContent = Synchronized.of(CollectionsFactory.createInt2ObjectArrayMap()); @Nullable private static final EntityType CAMEL_TYPE = EnumHelper.getEnum(EntityType.class, "CAMEL"); + @Nullable + private static final EntityType CAMEL_HUSK_TYPE = EnumHelper.getEnum(EntityType.class, "CAMEL_HUSK"); + @Nullable + private static final EntityType NAUTILUS_TYPE = EnumHelper.getEnum(EntityType.class, "NAUTILUS"); private BukkitEntities() { @@ -153,8 +157,13 @@ public static boolean isTameable(Entity entity) { } public static boolean isHorse(Entity entity) { - return entity instanceof Horse || entity.getType() == CAMEL_TYPE || + EntityType entityType = entity.getType(); + return entity instanceof Horse || entityType == CAMEL_TYPE || entityType == CAMEL_HUSK_TYPE || (ServerVersion.isAtLeast(ServerVersion.v1_11) && (entity instanceof Mule || entity instanceof Donkey)); } + public static boolean isNautilus(EntityType entityType) { + return entityType == NAUTILUS_TYPE; + } + } diff --git a/src/main/resources/menus/permissions1_21.yml b/src/main/resources/menus/permissions1_21.yml index 6f71f6e80d..c63b14b1ec 100644 --- a/src/main/resources/menus/permissions1_21.yml +++ b/src/main/resources/menus/permissions1_21.yml @@ -1540,6 +1540,39 @@ permissions: volume: 0.2 pitch: 0.2 + nautilus_interact: + display-menu: true + permission-enabled: + type: NAUTILUS_SHELL + name: '&6Nautilus Interact' + lore: + - '&7Access to interact with nautiluses inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: NAUTILUS_SHELL + name: '&6Nautilus Interact' + lore: + - '&7Access to interact with nautiluses inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: NAUTILUS_SHELL + name: '&6Nautilus Interact' + lore: + - '&7Access to interact with nautiluses inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + name_entity: display-menu: true permission-enabled: From d5b39ed6b10d857f8edb263ad9d7f76449d8d052 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 18 Dec 2025 15:20:43 +0200 Subject: [PATCH 443/600] Fix zombie nautilus can be accessed on other islands & fix zombie and skeleton horses not considered horse types (#2803) --- .../superiorskyblock/world/BukkitEntities.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java index 71167cb77c..cc3e49fd33 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java @@ -13,13 +13,11 @@ import org.bukkit.Material; import org.bukkit.entity.AbstractHorse; import org.bukkit.entity.ArmorStand; -import org.bukkit.entity.Donkey; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Hanging; import org.bukkit.entity.Horse; import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Mule; import org.bukkit.entity.Pig; import org.bukkit.entity.Player; import org.bukkit.entity.Projectile; @@ -41,11 +39,9 @@ public class BukkitEntities { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final Synchronized>> entityContent = Synchronized.of(CollectionsFactory.createInt2ObjectArrayMap()); @Nullable - private static final EntityType CAMEL_TYPE = EnumHelper.getEnum(EntityType.class, "CAMEL"); - @Nullable - private static final EntityType CAMEL_HUSK_TYPE = EnumHelper.getEnum(EntityType.class, "CAMEL_HUSK"); - @Nullable private static final EntityType NAUTILUS_TYPE = EnumHelper.getEnum(EntityType.class, "NAUTILUS"); + @Nullable + private static final EntityType ZOMBIE_NAUTILUS_TYPE = EnumHelper.getEnum(EntityType.class, "ZOMBIE_NAUTILUS"); private BukkitEntities() { @@ -157,13 +153,11 @@ public static boolean isTameable(Entity entity) { } public static boolean isHorse(Entity entity) { - EntityType entityType = entity.getType(); - return entity instanceof Horse || entityType == CAMEL_TYPE || entityType == CAMEL_HUSK_TYPE || - (ServerVersion.isAtLeast(ServerVersion.v1_11) && (entity instanceof Mule || entity instanceof Donkey)); + return entity instanceof Horse || (ServerVersion.isAtLeast(ServerVersion.v1_11) && entity instanceof org.bukkit.entity.AbstractHorse); } public static boolean isNautilus(EntityType entityType) { - return entityType == NAUTILUS_TYPE; + return entityType == NAUTILUS_TYPE || entityType == ZOMBIE_NAUTILUS_TYPE; } } From 61e15701825abd3617d7f39d96cd5895d722c71d Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 19 Dec 2025 20:29:10 +0100 Subject: [PATCH 444/600] Prevent pistons from pushing blocks outside island (#2809) --- .../listener/WorldDestructionListener.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java index cff7000802..69541867c1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/WorldDestructionListener.java @@ -56,15 +56,16 @@ private void onBlockSpread(GameEvent e) { } public void onPistonExtend(GameEvent e) { - Block block = e.getArgs().block; + Block pistonBlock = e.getArgs().block; // We care about destruction of island worlds only - if (!plugin.getGrid().isIslandsWorld(block.getWorld())) { + if (!plugin.getGrid().isIslandsWorld(pistonBlock.getWorld())) { return; } try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - if (preventMultiDestruction(block.getLocation(wrapper.getHandle()), e.getArgs().blocks, null)) + if (preventMultiDestruction(pistonBlock.getLocation(wrapper.getHandle()), e.getArgs().blocks, + block -> block.getRelative(e.getArgs().direction))) e.setCancelled(); } } From 837b3e1301d7ebf50e61b291a4473a94d66f06b7 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 22 Dec 2025 20:33:22 +0200 Subject: [PATCH 445/600] Fix detection of players inside islands when are banned (#2806) --- .../island/GridManagerImpl.java | 2 +- .../superiorskyblock/island/SIsland.java | 22 +++++++++------ .../container/DefaultIslandsContainer.java | 28 +++++++++++++------ 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index 6b2279e7db..dcb5aa1f18 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -565,7 +565,7 @@ public Island getIslandAt(@Nullable Location location) { if (spawnIsland != null && spawnIsland.isInside(location)) return spawnIsland; - return isIslandsWorld(world) ? this.islandsContainer.getIslandAt(location) : null; + return this.islandsContainer.getIslandAt(location); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index b0cfd27107..98b5ad3af4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -1224,8 +1224,7 @@ public boolean isInside(Location location, int extraRadius) { @Override public boolean isInside(Location location, double extraRadius) { Preconditions.checkNotNull(location, "location parameter cannot be null."); - Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); - return isIslandWorld(location.getWorld()) && this.entireArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); + return isIslandWorld(location) && this.entireArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); } @Override @@ -1326,8 +1325,7 @@ public boolean isInsideRange(Location location, int extraRadius) { @Override public boolean isInsideRange(Location location, double extraRadius) { Preconditions.checkNotNull(location, "location parameter cannot be null."); - Preconditions.checkNotNull(location.getWorld(), "location's world parameter cannot be null."); - return isIslandWorld(location.getWorld()) && this.protectedArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); + return isIslandWorld(location) && this.protectedArea.expandAndIntercepts(location.getBlockX(), location.getBlockZ(), extraRadius); } @Override @@ -1414,15 +1412,23 @@ public boolean isInsideRange(int chunkX, int chunkZ, double extraRadius) { return this.protectedArea.expandRshiftAndIntercepts(chunkX, chunkZ, extraRadius, 4); } - private static boolean isIslandWorld(@Nullable World world) { - return world != null && plugin.getProviders().getWorldsProvider().isIslandsWorld(world); + private boolean isIslandWorld(Location location) { + return isIslandWorld(LazyWorldLocation.getWorldName(location)); + } + + private boolean isIslandWorld(@Nullable World world) { + return world != null && isIslandWorld(world.getName()); } private boolean isIslandWorld(@Nullable WorldInfo worldInfo) { - if (worldInfo == null) + return worldInfo != null && isIslandWorld(worldInfo.getName()); + } + + private boolean isIslandWorld(@Nullable String worldName) { + if (worldName == null) return false; - return plugin.getGrid().getIslandsWorldInfo(this, worldInfo.getName()) != null; + return plugin.getGrid().getIslandsWorldInfo(this, worldName) != null; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index 5b4a7cbbf4..328b6c6181 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; import com.bgsoftware.superiorskyblock.core.IslandPosition; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; +import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; @@ -29,6 +30,7 @@ import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.World; import java.util.LinkedList; import java.util.List; @@ -154,17 +156,27 @@ public int getIslandsAmount() { @Nullable @Override public Island getIslandAt(Location location) { + return plugin.getProviders().hasCustomWorldsSupport() ? + customWorldsSupportIslandLookup(location) : nativeIslandLookup(location); + } + + private Island customWorldsSupportIslandLookup(Location location) { long packedPos = IslandPosition.calculatePackedPosFromLocation(location.getBlockX(), location.getBlockZ()); + String worldName = LazyWorldLocation.getWorldName(location); + Island island = this.islandsGrid.getIslandAt(worldName, packedPos); + // We already checked for the world by calling `IslandsGrid#getIslandAt` with the world name parameter. + // We will only check that the location's position is inside the island. + return island == null || !island.isInside(SWorldPosition.of(location)) ? null : island; + } - Island island; - if (plugin.getProviders().hasCustomWorldsSupport()) { - String worldName = LazyWorldLocation.getWorldName(location); - island = this.islandsGrid.getIslandAt(worldName, packedPos); - } else { - island = this.islandsGrid.getIslandAt(null, packedPos); - } + private Island nativeIslandLookup(Location location) { + // We first check that the world is an islands world. + World world = location.getWorld(); + if(world == null || !plugin.getGrid().isIslandsWorld(world)) + return null; - return island == null || !island.isInside(location) ? null : island; + long packedPos = IslandPosition.calculatePackedPosFromLocation(location.getBlockX(), location.getBlockZ()); + return this.islandsGrid.getIslandAt(null, packedPos); } @Override From 417e91a2a615051aa78a1f9242a882ed357419db Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Mon, 22 Dec 2025 20:59:51 +0100 Subject: [PATCH 446/600] Fix IslandPreviewListener (#2813) --- .../superiorskyblock/listener/IslandPreviewListener.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java index c0d5abb8cc..e8485bb2b4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandPreviewListener.java @@ -31,10 +31,11 @@ private void onPlayerQuit(GameEvent e) { // Cancelling island preview mode if (plugin.getGrid().getIslandPreview(superiorPlayer) != null) { + GameMode gameMode = plugin.getGrid().getIslandPreview(superiorPlayer).getPreviousGameMode(); plugin.getGrid().cancelIslandPreview(superiorPlayer); /* cancelIslandPreview changes the GameMode and teleports the player later. In this case tho, we want the things to be instant - no async, no nothing. */ - player.setGameMode(GameMode.SURVIVAL); + player.setGameMode(gameMode); player.teleport(plugin.getGrid().getSpawnIsland().getCenter( plugin.getSettings().getWorlds().getDefaultWorldDimension())); } @@ -52,7 +53,7 @@ private void onPlayerTeleport(GameEvent e) { return; } - if (((Player) entity).getGameMode() == GameMode.SPECTATOR && + if (((Player) entity).getGameMode() == plugin.getSettings().getIslandPreviews().getGameMode() && plugin.getGrid().getIslandPreview(superiorPlayer) != null) e.setCancelled(); } From 0f527589210a8e93ce619194068e5be0e0e63836 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 24 Dec 2025 13:00:33 +0200 Subject: [PATCH 447/600] Optimize permissions lookups by caching values (#2814) --- .../api/player/DelegateSuperiorPlayer.java | 5 + .../api/wrappers/SuperiorPlayer.java | 25 +++- .../PermissionsProvider_LuckPerms.java | 49 ++++++- .../superiorskyblock/island/SIsland.java | 4 +- .../superiorskyblock/island/SpawnIsland.java | 6 +- .../listener/PlayersListener.java | 6 + .../player/SSuperiorPlayer.java | 36 +++-- .../player/SuperiorNPCPlayer.java | 5 + .../permissions/PlayerPermissionsStore.java | 135 ++++++++++++++++++ 9 files changed, 250 insertions(+), 21 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/player/permissions/PlayerPermissionsStore.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java index f50cbc54f4..5b8a5e73a3 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java @@ -148,6 +148,11 @@ public boolean hasPermission(IslandPrivilege permission) { return this.handle.hasPermission(permission); } + @Override + public boolean hasBypassPermission(IslandPrivilege permission) { + return this.handle.hasBypassPermission(permission); + } + @Override public HitActionResult canHit(SuperiorPlayer otherPlayer) { return this.handle.canHit(otherPlayer); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java index 48343f0301..0e812002c0 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java @@ -146,23 +146,38 @@ public interface SuperiorPlayer extends IMissionsHolder, IPersistentDataHolder, boolean isShownAsOnline(); /** - * Check whether or not the player has a permission. - * When the player is offline, false will be returned. + * Check whether the player has a permission. + * + * @param permission The permission to check. + * @return When the player is offline, false will be returned. */ boolean hasPermission(String permission); /** - * Check whether or not the player has a permission without having op. - * When the player is offline, false will be returned. + * Check whether the player has a permission without having op. + * + * @param permission The permission to check. + * @return When the player is offline, false may be returned. */ boolean hasPermissionWithoutOP(String permission); /** - * Check whether or not the player has a permission on his island. + * Check whether the player has a permission on his island. + * + * @param permission The {@link IslandPrivilege} to check. + * @return Whether the player has the permission on his island. * When the player doesn't have an island, false will be returned. */ boolean hasPermission(IslandPrivilege permission); + /** + * Check whether the player has the bypass permission for the provided {@link IslandPrivilege}. + * + * @param permission The {@link IslandPrivilege} to check. + * @return Whether the player has the bypass permission. If the player is offline, false may be returned. + */ + boolean hasBypassPermission(IslandPrivilege permission); + /** * Check whether or not this player can hit another player. *

    diff --git a/Hooks/LuckPerms/src/main/java/com/bgsoftware/superiorskyblock/external/permissions/PermissionsProvider_LuckPerms.java b/Hooks/LuckPerms/src/main/java/com/bgsoftware/superiorskyblock/external/permissions/PermissionsProvider_LuckPerms.java index 5f7dad8681..02763ab34d 100644 --- a/Hooks/LuckPerms/src/main/java/com/bgsoftware/superiorskyblock/external/permissions/PermissionsProvider_LuckPerms.java +++ b/Hooks/LuckPerms/src/main/java/com/bgsoftware/superiorskyblock/external/permissions/PermissionsProvider_LuckPerms.java @@ -1,25 +1,32 @@ package com.bgsoftware.superiorskyblock.external.permissions; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.hooks.PermissionsProvider; import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.player.permissions.PlayerPermissionsStore; import net.luckperms.api.LuckPerms; import net.luckperms.api.cacheddata.CachedDataManager; +import net.luckperms.api.event.node.NodeAddEvent; +import net.luckperms.api.event.node.NodeRemoveEvent; import net.luckperms.api.model.user.User; +import net.luckperms.api.node.Node; +import net.luckperms.api.node.types.InheritanceNode; +import net.luckperms.api.node.types.PermissionNode; +import net.luckperms.api.node.types.RegexPermissionNode; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import java.util.Locale; +import java.util.UUID; @SuppressWarnings("unused") public class PermissionsProvider_LuckPerms implements PermissionsProvider { - private static LuckPerms luckPerms = null; + private final LuckPerms luckPerms; public static boolean isCompatible() { try { CachedDataManager.class.getMethod("getPermissionData"); - luckPerms = Bukkit.getServicesManager().getRegistration(LuckPerms.class).getProvider(); - Log.info("Using LuckPerms as a permissions provider."); return true; } catch (Throwable ex) { Log.warn("You are using an outdated version of LuckPerms. It's recommended to update for a more optimized experience (v5.1+)."); @@ -27,11 +34,45 @@ public static boolean isCompatible() { } } + public PermissionsProvider_LuckPerms(SuperiorSkyblockPlugin plugin) { + this.luckPerms = Bukkit.getServicesManager().getRegistration(LuckPerms.class).getProvider(); + this.luckPerms.getEventBus().subscribe(plugin, NodeAddEvent.class, this::onPermissionsAdd); + this.luckPerms.getEventBus().subscribe(plugin, NodeRemoveEvent.class, this::onPermissionsRemove); + Log.info("Using LuckPerms as a permissions provider."); + } + @Override public boolean hasPermission(Player player, String permission) { - User user = luckPerms.getUserManager().getUser(player.getUniqueId()); + User user = this.luckPerms.getUserManager().getUser(player.getUniqueId()); return user != null && user.getCachedData().getPermissionData().getPermissionMap() .getOrDefault(permission.toLowerCase(Locale.ENGLISH), false); } + private void onPermissionsAdd(NodeAddEvent e) { + if (e.getTarget() instanceof User && isTrackableNode(e.getNode())) + notifyPermissionsUpdate(((User) e.getTarget()).getUniqueId()); + } + + private void onPermissionsRemove(NodeRemoveEvent e) { + if (e.getTarget() instanceof User && isTrackableNode(e.getNode())) + notifyPermissionsUpdate(((User) e.getTarget()).getUniqueId()); + } + + private void notifyPermissionsUpdate(UUID playerUUID) { + PlayerPermissionsStore permissionsStore = PlayerPermissionsStore.getPermissionsStore(playerUUID); + if (permissionsStore != null) + permissionsStore.markDirty(); + } + + private static boolean isTrackableNode(Node node) { + if (node instanceof PermissionNode) { + return ((PermissionNode) node).getPermission().contains("superior"); + } + + // In the case of RegexPermissionNode - we are not going to try and parse the regex. + // In the case of InheritanceNode - we are not going to go through the inherited group and check for permissions. + // We will always mark cache as dirty for both of these events. + return node instanceof RegexPermissionNode || node instanceof InheritanceNode; + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 98b5ad3af4..5055f51ae1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -1509,8 +1509,8 @@ public boolean hasPermission(SuperiorPlayer superiorPlayer, IslandPrivilege isla Preconditions.checkNotNull(islandPrivilege, "islandPrivilege parameter cannot be null."); PermissionNode playerNode = getPermissionNode(superiorPlayer); - return superiorPlayer.hasBypassModeEnabled() || superiorPlayer.hasPermissionWithoutOP("superior.admin.bypass.*") || - superiorPlayer.hasPermissionWithoutOP("superior.admin.bypass." + islandPrivilege.getName()) || + return superiorPlayer.hasBypassModeEnabled() || superiorPlayer.hasBypassPermission(islandPrivilege) || + superiorPlayer.hasPermissionWithoutOP("superior.admin.bypass.*") || (playerNode != null && playerNode.hasPermission(islandPrivilege)); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index a8fa22b32d..3d1106bf27 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -866,8 +866,10 @@ public boolean hasPermission(CommandSender sender, IslandPrivilege islandPrivile @Override public boolean hasPermission(SuperiorPlayer superiorPlayer, IslandPrivilege islandPrivilege) { boolean checkForProtection = islandPrivilege != IslandPrivileges.FLY; - return (checkForProtection && !plugin.getSettings().getSpawn().isProtected()) || superiorPlayer.hasBypassModeEnabled() || - superiorPlayer.hasPermissionWithoutOP("superior.admin.bypass." + islandPrivilege.getName()) || + return (checkForProtection && !plugin.getSettings().getSpawn().isProtected()) || + superiorPlayer.hasBypassModeEnabled() || + superiorPlayer.hasBypassPermission(islandPrivilege) || + superiorPlayer.hasPermissionWithoutOP("superior.admin.bypass.*") || hasPermission(SPlayerRole.guestRole(), islandPrivilege); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java index 823a6ad68b..93ef6aa78f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java @@ -32,6 +32,7 @@ import com.bgsoftware.superiorskyblock.player.PlayerLocales; import com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; +import com.bgsoftware.superiorskyblock.player.permissions.PlayerPermissionsStore; import com.bgsoftware.superiorskyblock.player.respawn.RespawnActions; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import org.bukkit.Bukkit; @@ -127,6 +128,11 @@ private void onPlayerJoin(GameEvent e) { if (superiorPlayer.isShownAsOnline()) IslandNotifications.notifyPlayerJoin(superiorPlayer); + // Refresh PermissionsStore + PlayerPermissionsStore permissionsStore = PlayerPermissionsStore.getPermissionsStore(player.getUniqueId()); + if (permissionsStore != null) + permissionsStore.refreshCache(player); + MoveResult moveResult; Island island; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index 959a162f94..e132fb9fe7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -36,6 +36,7 @@ import com.bgsoftware.superiorskyblock.mission.MissionReference; import com.bgsoftware.superiorskyblock.player.builder.SuperiorPlayerBuilderImpl; import com.bgsoftware.superiorskyblock.player.cache.PlayerCacheImpl; +import com.bgsoftware.superiorskyblock.player.permissions.PlayerPermissionsStore; import com.bgsoftware.superiorskyblock.world.Dimensions; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; @@ -73,12 +74,13 @@ public class SSuperiorPlayer implements SuperiorPlayer { private final PlayerTeleportAlgorithm playerTeleportAlgorithm; @Nullable private PersistentDataContainer persistentDataContainer; // Lazy loading - private LazyReference playerCache = new LazyReference() { + private final LazyReference playerCache = new LazyReference() { @Override protected PlayerCache create() { return new PlayerCacheImpl(SSuperiorPlayer.this); } }; + private final PlayerPermissionsStore permissionsStore; private final Map completedMissions = new ConcurrentHashMap<>(); private final List pendingInvites = new LinkedList<>(); @@ -129,6 +131,7 @@ public SSuperiorPlayer(SuperiorPlayerBuilderImpl builder) { this.databaseBridge = plugin.getFactory().createDatabaseBridge(this); this.playerTeleportAlgorithm = plugin.getFactory().createPlayerTeleportAlgorithm(this); + this.permissionsStore = new PlayerPermissionsStore(this); databaseBridge.setDatabaseBridgeMode(DatabaseBridgeMode.SAVE_DATA); } @@ -325,6 +328,8 @@ public boolean isShownAsOnline() { public boolean hasPermission(String permission) { Preconditions.checkNotNull(permission, "permission parameter cannot be null."); + Log.debugResult(Debug.PERMISSION_LOOKUP, "Checking for permission", permission); + if (permission.isEmpty()) return true; @@ -347,22 +352,21 @@ public boolean hasPermission(String permission) { public boolean hasPermissionWithoutOP(String permission) { Preconditions.checkNotNull(permission, "permission parameter cannot be null."); + Log.debugResult(Debug.PERMISSION_LOOKUP, "Checking for permission", permission); + if (permission.isEmpty()) return true; Log.debug(Debug.PERMISSION_LOOKUP, getName(), permission, "No-Op Check"); Player player = asPlayer(); - if (player == null) { - Log.debugResult(Debug.PERMISSION_LOOKUP, "Result", "Player is not online"); - return false; - } - boolean res = plugin.getProviders().getPermissionsProvider().hasPermission(player, permission); + PlayerPermissionsStore.PermissionResult permissionResult = + this.permissionsStore.hasCustomPermission(player, permission); - Log.debugResult(Debug.PERMISSION_LOOKUP, "Result", res); + Log.debugResult(Debug.PERMISSION_LOOKUP, "Result", permissionResult); - return res; + return permissionResult == PlayerPermissionsStore.PermissionResult.PRIVILEGED; } @Override @@ -372,6 +376,22 @@ public boolean hasPermission(IslandPrivilege permission) { return island != null && island.hasPermission(this, permission); } + @Override + public boolean hasBypassPermission(IslandPrivilege permission) { + Preconditions.checkNotNull(permission, "permission parameter cannot be null."); + + Log.debugResult(Debug.PERMISSION_LOOKUP, "Checking for IslandPrivilege bypass permission", permission); + + Player player = asPlayer(); + + PlayerPermissionsStore.PermissionResult permissionResult = + this.permissionsStore.hasBypassPermission(player, permission); + + Log.debugResult(Debug.PERMISSION_LOOKUP, "Result", permissionResult); + + return permissionResult == PlayerPermissionsStore.PermissionResult.PRIVILEGED; + } + /* * Location Methods */ diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java index 9883dc6a32..888d9c58f2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java @@ -169,6 +169,11 @@ public boolean hasPermission(IslandPrivilege permission) { return false; } + @Override + public boolean hasBypassPermission(IslandPrivilege islandPrivilege) { + return false; + } + @Override public HitActionResult canHit(SuperiorPlayer other) { return HitActionResult.NOT_ONLINE; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/permissions/PlayerPermissionsStore.java b/src/main/java/com/bgsoftware/superiorskyblock/player/permissions/PlayerPermissionsStore.java new file mode 100644 index 0000000000..5e408429f3 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/permissions/PlayerPermissionsStore.java @@ -0,0 +1,135 @@ +package com.bgsoftware.superiorskyblock.player.permissions; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import org.bukkit.entity.Player; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.StampedLock; + +public class PlayerPermissionsStore { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + private static final Map PERMISSIONS_STORE_MAP = new ConcurrentHashMap<>(); + + private final EnumerateMap bypassPermissionsStore = new EnumerateMap<>(IslandPrivilege.values()); + private final Map customPermissionsStore = new ConcurrentHashMap<>(); + private final StampedLock lock = new StampedLock(); + + private final AtomicBoolean dirty = new AtomicBoolean(true); + + @Nullable + public static PlayerPermissionsStore getPermissionsStore(UUID uuid) { + return PERMISSIONS_STORE_MAP.get(uuid); + } + + public PlayerPermissionsStore(SuperiorPlayer superiorPlayer) { + PERMISSIONS_STORE_MAP.put(superiorPlayer.getUniqueId(), this); + } + + public void markDirty() { + this.dirty.set(true); + } + + public void refreshCache(Player player) { + // We want to refresh cache for common permissions + hasBypassPermission(player, IslandPrivileges.BUILD); + hasBypassPermission(player, IslandPrivileges.BREAK); + hasCustomPermission(player, "superior.admin.bypass.*"); + } + + public PermissionResult hasBypassPermission(@Nullable Player player, IslandPrivilege islandPrivilege) { + if (this.dirty.get()) { + checkDirty(); + } + + long stamp = this.lock.readLock(); + Boolean value; + try { + value = this.bypassPermissionsStore.get(islandPrivilege); + } finally { + this.lock.unlockRead(stamp); + } + + if (value == null) { + if (player == null) return PermissionResult.NOT_ONLINE; + + value = checkPermission(player, "superior.admin.bypass." + islandPrivilege.getName()); + + stamp = this.lock.writeLock(); + try { + this.bypassPermissionsStore.put(islandPrivilege, value); + } finally { + this.lock.unlockWrite(stamp); + } + } + + return value ? PermissionResult.PRIVILEGED : PermissionResult.RESTRICTED; + } + + public PermissionResult hasCustomPermission(@Nullable Player player, String permission) { + long stamp = this.lock.tryOptimisticRead(); + Boolean value = this.customPermissionsStore.get(permission); + boolean isDirty = this.dirty.get(); + + if (!this.lock.validate(stamp) || isDirty) { + if (isDirty) { + checkDirty(); + } + + stamp = this.lock.readLock(); + try { + value = this.customPermissionsStore.get(permission); + } finally { + this.lock.unlockRead(stamp); + } + } + + if (value == null) { + if (player == null) return PermissionResult.NOT_ONLINE; + + value = checkPermission(player, permission); + + stamp = this.lock.writeLock(); + try { + this.customPermissionsStore.put(permission, value); + } finally { + this.lock.unlockWrite(stamp); + } + } + + return value ? PermissionResult.PRIVILEGED : PermissionResult.RESTRICTED; + } + + private void checkDirty() { + if (dirty.compareAndSet(true, false)) { + long stamp = this.lock.writeLock(); + try { + this.bypassPermissionsStore.clear(); + this.customPermissionsStore.clear(); + } finally { + this.lock.unlockWrite(stamp); + } + } + } + + private static boolean checkPermission(Player player, String permission) { + return plugin.getProviders().getPermissionsProvider().hasPermission(player, permission); + } + + public enum PermissionResult { + + PRIVILEGED, + RESTRICTED, + NOT_ONLINE + + } + +} From e3d4fc85ef50cd1443914b6d73e2f24ce61675e0 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 24 Dec 2025 20:42:05 +0200 Subject: [PATCH 448/600] Add MANGROVE_TRAPDOOR to interactables file (#2817) --- src/main/resources/interactables.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index 59db7bf72d..9401adfa9e 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -186,6 +186,7 @@ interactables: - 'MANGROVE_HANGING_SIGN' - 'MANGROVE_SHELF' - 'MANGROVE_SIGN' + - 'MANGROVE_TRAPDOOR' - 'MANGROVE_WALL_HANGING_SIGN' - 'MANGROVE_WALL_SIGN' - 'MOB_SPAWNER' From 229104a76ad02e848e9682c24a060e151078ca9b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 24 Dec 2025 21:41:29 +0200 Subject: [PATCH 449/600] Fixed detection of counts of changing spawner types using a spawn egg (#2796) --- .../spawners/SpawnersProvider_WildStacker.java | 12 ++++++++++++ .../listener/BlockChangesListener.java | 6 ++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java index 6658f26774..20c327df87 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java @@ -17,10 +17,12 @@ import com.bgsoftware.superiorskyblock.external.WildStackerSnapshotsContainer; import com.bgsoftware.superiorskyblock.module.upgrades.listeners.WildStackerListener; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; +import com.bgsoftware.wildstacker.api.WildStackerAPI; import com.bgsoftware.wildstacker.api.events.SpawnerPlaceEvent; import com.bgsoftware.wildstacker.api.events.SpawnerPlaceInventoryEvent; import com.bgsoftware.wildstacker.api.events.SpawnerStackEvent; import com.bgsoftware.wildstacker.api.events.SpawnerUnstackEvent; +import com.bgsoftware.wildstacker.api.objects.StackedSpawner; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; @@ -61,6 +63,16 @@ public Pair getSpawner(Location location) { entry = WildStackerSnapshotsContainer.accessStackedSnapshot(chunkPosition, stackedSnapshot -> stackedSnapshot.getStackedSpawner(location)); } + + if (entry == null) { + StackedSpawner stackedSpawner = WildStackerAPI.getWildStacker().getSystemManager().getStackedSpawner(location); + if (stackedSpawner == null) { + return new Pair<>(1, null); + } else { + return new Pair<>(stackedSpawner.getStackAmount(), stackedSpawner.getSpawnedType().name()); + } + } + return new Pair<>(entry.getKey(), entry.getValue() + ""); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index 15abccdbcc..3f05e4bba5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -235,8 +235,10 @@ private void onSpawnerChange(GameEvent e) { Key newSpawnerKey = Keys.of(clickedBlock); if (!oldSpawnerKey.equals(newSpawnerKey)) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockPlace(newSpawnerKey, clickedBlock.getLocation(wrapper.getHandle()), - 1, oldBlockState, REGULAR_RECORD_FLAGS); + Location location = clickedBlock.getLocation(wrapper.getHandle()); + int spawnerCount = plugin.getProviders().getSpawnersProvider().getSpawner(location).getKey(); + this.worldRecordService.get().recordBlockBreak(oldSpawnerKey, location, spawnerCount, REGULAR_RECORD_FLAGS); + this.worldRecordService.get().recordBlockPlace(newSpawnerKey, location, spawnerCount, null, REGULAR_RECORD_FLAGS); } } }, 1L); From 3fe71a9ac513d45274303517140811149fd8b1b0 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 24 Dec 2025 21:51:08 +0200 Subject: [PATCH 450/600] Fixed the ability to bypass interaction permissions when holding certain items (#2812) --- .../service/region/RegionManagerServiceImpl.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index b3b41ae6d7..23eeb18952 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -206,14 +206,7 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc IslandPrivilege islandPrivilege; - if (spawnType != EntityType.UNKNOWN) { - EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(spawnType)); - if (entityCategory == null) - return InteractionResult.SUCCESS; - islandPrivilege = entityCategory.getSpawnPrivilege(); - if (islandPrivilege == null) - return InteractionResult.SUCCESS; - } else if (usedItem != null && Materials.isMinecart(usedItem.getType()) ? Materials.isRail(blockType) : Materials.isBoat(blockType)) { + if (usedItem != null && Materials.isMinecart(usedItem.getType()) ? Materials.isRail(blockType) : Materials.isBoat(blockType)) { islandPrivilege = IslandPrivileges.MINECART_PLACE; } else if (Materials.isChest(blockType)) { islandPrivilege = IslandPrivileges.CHEST_ACCESS; @@ -237,6 +230,13 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc islandPrivilege = IslandPrivileges.BREAK; } else if (blockType == Material.PUMPKIN) { islandPrivilege = IslandPrivileges.BREAK; + } else if (spawnType != EntityType.UNKNOWN) { + EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(spawnType)); + if (entityCategory == null) { + islandPrivilege = IslandPrivileges.INTERACT; + } else { + islandPrivilege = Optional.ofNullable(entityCategory.getSpawnPrivilege()).orElse(IslandPrivileges.INTERACT); + } } else { islandPrivilege = IslandPrivileges.INTERACT; } From f3d086e02bd55f92a1b731243f5f24a0230778cf Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Mon, 29 Dec 2025 21:51:39 +0100 Subject: [PATCH 451/600] Prevent non-island members from editing warps (#2824) --- .../superiorskyblock/core/menu/impl/MenuWarpCategories.java | 3 ++- .../bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java index c36cb2babc..49c92b40fb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarpCategories.java @@ -79,7 +79,8 @@ protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previous Menu menu, IslandViewArgs args) { super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); - this.hasManagePerms = island.hasPermission(inventoryViewer, IslandPrivileges.SET_WARP); + this.hasManagePerms = island.isMember(inventoryViewer) && + island.hasPermission(inventoryViewer, IslandPrivileges.SET_WARP); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java index d60d49fd1c..6092e12ea6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuWarps.java @@ -103,7 +103,8 @@ protected View(SuperiorPlayer inventoryViewer, @Nullable MenuView previous super(inventoryViewer, previousMenuView, menu); this.island = args.getIsland(); this.warpCategory = args.warpCategory; - this.hasManagePerms = warpCategory.getIsland().hasPermission(inventoryViewer, IslandPrivileges.SET_WARP); + this.hasManagePerms = warpCategory.getIsland().isMember(inventoryViewer) && + warpCategory.getIsland().hasPermission(inventoryViewer, IslandPrivileges.SET_WARP); } @Override From 8cc0640ae08d52cf823257d81df5117a9b79a06f Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Tue, 30 Dec 2025 19:54:55 +0100 Subject: [PATCH 452/600] Adds Allay Interact privilege (#2822) --- .../island/privilege/IslandPrivileges.java | 1 + .../region/RegionManagerServiceImpl.java | 4 + src/main/resources/config.yml | 1 + src/main/resources/menus/permissions1_19.yml | 2546 +++++++++++++++++ src/main/resources/menus/permissions1_20.yml | 33 + src/main/resources/menus/permissions1_21.yml | 33 + 6 files changed, 2618 insertions(+) create mode 100644 src/main/resources/menus/permissions1_19.yml diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index 3ccf05f227..11c578321a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -15,6 +15,7 @@ public class IslandPrivileges { public static final IslandPrivilege ALL = register("ALL"); + public static final IslandPrivilege ALLAY_INTERACT = register("ALLAY_INTERACT", ServerVersion.isAtLeast(ServerVersion.v1_19)); public static final IslandPrivilege ANIMAL_BREED = register("ANIMAL_BREED"); public static final IslandPrivilege ANIMAL_DAMAGE = register("ANIMAL_DAMAGE"); public static final IslandPrivilege ANIMAL_SHEAR = register("ANIMAL_SHEAR"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 23eeb18952..feccbafaac 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -82,6 +82,8 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService @Nullable private static final Material OMINOUS_TRIAL_KEY = EnumHelper.getEnum(Material.class, "OMINOUS_TRIAL_KEY"); @Nullable + private static final EntityType ALLAY_TYPE = EnumHelper.getEnum(EntityType.class, "ALLAY"); + @Nullable private static final EntityType AXOLOTL_TYPE = EnumHelper.getEnum(EntityType.class, "AXOLOTL"); @Nullable private static final EntityType LLAMA_TYPE = EnumHelper.getEnum(EntityType.class, "LLAMA"); @@ -305,6 +307,8 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent closeInventory = true; } else if (entityType == COPPER_GOLEM_TYPE) { islandPrivilege = IslandPrivileges.COPPER_GOLEM_INTERACT; + } else if (entityType == ALLAY_TYPE) { + islandPrivilege = IslandPrivileges.ALLAY_INTERACT; } else if (usedItemType == Material.FLINT_AND_STEEL && entity instanceof Creeper) { islandPrivilege = IslandPrivileges.IGNITE_CREEPER; } else if (usedItemType == Material.WATER_BUCKET && entityType == AXOLOTL_TYPE && ServerVersion.isAtLeast(ServerVersion.v1_17)) { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 2dbea93b27..5b562b8e55 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -198,6 +198,7 @@ island-roles: coop: name: 'Coop' permissions: + - ALLAY_INTERACT - ANIMAL_BREED - ANIMAL_DAMAGE - ANIMAL_SHEAR diff --git a/src/main/resources/menus/permissions1_19.yml b/src/main/resources/menus/permissions1_19.yml new file mode 100644 index 0000000000..61f86ab524 --- /dev/null +++ b/src/main/resources/menus/permissions1_19.yml @@ -0,0 +1,2546 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +title: '&lPermissions Controller' +previous-menu: true + +pattern: + - '$ $ $ $ $ $ $ $ $' + - '$ @ @ @ @ @ @ @ $' + - '$ @ @ @ @ @ @ @ $' + - '$ @ @ @ @ @ @ @ $' + - '$ $ % $ * $ ^ $ $' + +slots: '@' +previous-page: '%' +current-page: '*' +next-page: '^' + +messages: + no-role-permission: '&8 - &c{}' + exact-role-permission: '&8 - &2{}' + higher-role-permission: '&8 - &a{}' + +items: + '$': + type: CYAN_STAINED_GLASS_PANE + name: '&f' + '%': + type: PAPER + name: '{0}Previous Page' + '*': + type: SUNFLOWER + name: '&aCurrent Page' + lore: + - '&7Page {0}' + '^': + type: PAPER + name: '{0}Next Page' + +permissions: + all: + display-menu: true + permission-enabled: + type: BEDROCK + name: '&6All' + lore: + - '&7Access to all the abilities of the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BEDROCK + name: '&6All' + lore: + - '&7Access to all the abilities of the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BEDROCK + name: '&6All' + lore: + - '&7Access to all the abilities of the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + allay_interact: + display-menu: true + permission-enabled: + type: ALLAY_SPAWN_EGG + name: '&6Allay Interact' + lore: + - '&7Access to interact with allays inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ALLAY_SPAWN_EGG + name: '&6Allay Interact' + lore: + - '&7Access to interact with allays inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ALLAY_SPAWN_EGG + name: '&6Allay Interact' + lore: + - '&7Access to interact with allays inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + animal_breed: + display-menu: true + permission-enabled: + type: WHEAT + name: '&6Animal Breed' + lore: + - '&7Access to breed animals inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + name: '&6Animal Breed' + type: WHEAT + lore: + - '&7Access to breed animals inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + name: '&6Animal Breed' + type: WHEAT + lore: + - '&7Access to breed animals inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + animal_damage: + display-menu: true + permission-enabled: + type: DIAMOND_SWORD + name: '&6Animal Damage' + lore: + - '&7Access to damage animals inside the island.' + - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES + permission-disabled: + type: DIAMOND_SWORD + name: '&6Animal Damage' + lore: + - '&7Access to damage animals inside the island.' + - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES + role-permission: + type: DIAMOND_SWORD + name: '&6Animal Damage' + lore: + - '&7Access to damage animals inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + flags: + - HIDE_ATTRIBUTES + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + animal_shear: + display-menu: true + permission-enabled: + type: SHEARS + name: '&6Animal Shear' + lore: + - '&7Access to shear animals inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SHEARS + name: '&6Animal Shear' + lore: + - '&7Access to shear animals inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SHEARS + name: '&6Animal Shear' + lore: + - '&7Access to shear animals inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + animal_spawn: + display-menu: true + permission-enabled: + type: CHICKEN_SPAWN_EGG + name: '&6Animal Spawn' + lore: + - '&7Access to spawn animals inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: CHICKEN_SPAWN_EGG + name: '&6Animal Spawn' + lore: + - '&7Access to spawn animals inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: CHICKEN_SPAWN_EGG + name: '&6Animal Spawn' + lore: + - '&7Access to spawn animals inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + ban_member: + display-menu: true + permission-enabled: + type: SKELETON_SKULL + name: '&6Ban Member' + lore: + - '&7Access to ban members from the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SKELETON_SKULL + name: '&6Ban Member' + lore: + - '&7Access to ban members from the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SKELETON_SKULL + name: '&6Ban Member' + lore: + - '&7Access to ban members from the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + break: + display-menu: true + permission-enabled: + type: DIAMOND_PICKAXE + name: '&6Break' + lore: + - '&7Access to break blocks inside the island.' + - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES + permission-disabled: + type: DIAMOND_PICKAXE + name: '&6Break' + lore: + - '&7Access to break blocks inside the island.' + - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES + role-permission: + type: DIAMOND_PICKAXE + name: '&6Break' + lore: + - '&7Access to break blocks inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + flags: + - HIDE_ATTRIBUTES + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + brush: + display-menu: true + permission-enabled: + type: BRUSH + name: '&6Brush' + lore: + - '&7Access to brush suspicious blocks inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BRUSH + name: '&6Brush' + lore: + - '&7Access to brush suspicious blocks inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BRUSH + name: '&6Brush' + lore: + - '&7Access to brush suspicious blocks inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + build: + display-menu: true + permission-enabled: + type: COBBLESTONE + name: '&6Build' + lore: + - '&7Access to place blocks inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: COBBLESTONE + name: '&6Build' + lore: + - '&7Access to place blocks inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: COBBLESTONE + name: '&6Build' + lore: + - '&7Access to place blocks inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + change_name: + display-menu: true + permission-enabled: + type: NAME_TAG + name: '&6Change Name' + lore: + - '&7Access to change the island''s name.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: NAME_TAG + name: '&6Change Name' + lore: + - '&7Access to change the island''s name.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: NAME_TAG + name: '&6Change Name' + lore: + - '&7Access to change the island''s name.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + chest_access: + display-menu: true + permission-enabled: + type: CHEST + name: '&6Chest Access' + lore: + - '&7Access to open chests inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: CHEST + name: '&6Chest Access' + lore: + - '&7Access to open chests inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: CHEST + name: '&6Chest Access' + lore: + - '&7Access to open chests inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + chorus_fruit: + display-menu: true + permission-enabled: + type: CHORUS_FRUIT + name: '&6Chorus Fruit' + lore: + - '&7Access to consume chorus fruits inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: CHORUS_FRUIT + name: '&6Chorus Fruit' + lore: + - '&7Access to consume chorus fruits inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: CHORUS_FRUIT + name: '&6Chorus Fruit' + lore: + - '&7Access to consume chorus fruits inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + close_bypass: + display-menu: true + permission-enabled: + type: TRIPWIRE_HOOK + name: '&6Locked Bypass' + lore: + - '&7Access to bypass the island''s lock.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: TRIPWIRE_HOOK + name: '&6Locked Bypass' + lore: + - '&7Access to bypass the island''s lock.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: TRIPWIRE_HOOK + name: '&6Locked Bypass' + lore: + - '&7Access to bypass the island''s lock.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + close_island: + display-menu: true + permission-enabled: + type: BARRIER + name: '&6Lock Island' + lore: + - '&7Access to lock the island from public.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BARRIER + name: '&6Lock Island' + lore: + - '&7Access to lock the island from public.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BARRIER + name: '&6Lock Island' + lore: + - '&7Access to lock the island from public.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + coop_member: + display-menu: true + permission-enabled: + type: GOLDEN_APPLE + name: '&6Coop Member' + lore: + - '&7Access to add a player as a co-op member.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: GOLDEN_APPLE + name: '&6Coop Member' + lore: + - '&7Access to add a player as a co-op member.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: GOLDEN_APPLE + name: '&6Coop Member' + lore: + - '&7Access to add a player as a co-op member.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + delete_warp: + display-menu: true + permission-enabled: + type: ENDER_PEARL + name: '&6Delete Warp' + lore: + - '&7Access to delete island warps.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ENDER_PEARL + name: '&6Delete Warp' + lore: + - '&7Access to delete island warps.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ENDER_PEARL + name: '&6Delete Warp' + lore: + - '&7Access to delete island warps.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + demote_members: + display-menu: true + permission-enabled: + type: IRON_INGOT + name: '&6Demote Members' + lore: + - '&7Access to demote members inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: IRON_INGOT + name: '&6Demote Members' + lore: + - '&7Access to demote members inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: IRON_INGOT + name: '&6Demote Members' + lore: + - '&7Access to demote members inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + deposit_money: + display-menu: true + permission-enabled: + type: MAP + name: '&6Deposit Money' + lore: + - '&7Access to deposit money into the island''s bank.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: MAP + name: '&6Deposit Money' + lore: + - '&7Access to deposit money into the island''s bank.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: MAP + name: '&6Deposit Money' + lore: + - '&7Access to deposit money into the island''s bank.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + disband_island: + display-menu: true + permission-enabled: + type: TNT + name: '&6Disband Island' + lore: + - '&7Access to disband the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: TNT + name: '&6Disband Island' + lore: + - '&7Access to disband the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: TNT + name: '&6Disband Island' + lore: + - '&7Access to disband the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + discord_show: + display-menu: true + permission-enabled: + type: LIGHT_BLUE_TERRACOTTA + name: '&6Discord Show' + lore: + - '&7Access to check the island''s linked discord.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: LIGHT_BLUE_TERRACOTTA + name: '&6Discord Show' + lore: + - '&7Access to check the island''s linked discord.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: LIGHT_BLUE_TERRACOTTA + name: '&6Discord Show' + lore: + - '&7Access to check the island''s linked discord.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + drop_items: + display-menu: true + permission-enabled: + type: ARROW + name: '&6Drop Items' + lore: + - '&7Access to drop items inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ARROW + name: '&6Drop Items' + lore: + - '&7Access to drop items inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ARROW + name: '&6Drop Items' + lore: + - '&7Access to drop items inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + dye_sheep: + display-menu: true + permission-enabled: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SHEEP_SPAWN_EGG + name: '&6Dye Sheep' + lore: + - '&7Access to dye sheep inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + ender_pearl: + display-menu: true + permission-enabled: + type: ENDER_PEARL + name: '&6Ender Pearl' + lore: + - '&7Access to use ender pearls inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ENDER_PEARL + name: '&6Ender Pearl' + lore: + - '&7Access to use ender pearls inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ENDER_PEARL + name: '&6Ender Pearl' + lore: + - '&7Access to use ender pearls inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + entity_ride: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Entity Ride' + lore: + - '&7Access to ride entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + expel_bypass: + display-menu: true + permission-enabled: + type: FEATHER + name: '&6Expel Bypass' + lore: + - '&7Access to bypass from being expelled.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: FEATHER + name: '&6Expel Bypass' + lore: + - '&7Access to bypass from being expelled.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: FEATHER + name: '&6Expel Bypass' + lore: + - '&7Access to bypass from being expelled.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + expel_players: + display-menu: true + permission-enabled: + type: DISPENSER + name: '&6Expel Players' + lore: + - '&7Access to expel players from the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: DISPENSER + name: '&6Expel Players' + lore: + - '&7Access to expel players from the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: DISPENSER + name: '&6Expel Players' + lore: + - '&7Access to expel players from the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + farm_tramping: + display-menu: true + permission-enabled: + type: FARMLAND + name: '&6Farm Tramping' + lore: + - '&7Access to tramp farmlands inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: FARMLAND + name: '&6Farm Tramping' + lore: + - '&7Access to tramp farmlands inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: FARMLAND + name: '&6Farm Tramping' + lore: + - '&7Access to tramp farmlands inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + fertilize: + display-menu: true + permission-enabled: + type: BONE_MEAL + name: '&6Fertilize' + lore: + - '&7Access to fertilize blocks around the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BONE_MEAL + name: '&6Fertilize' + lore: + - '&7Access to fertilize blocks around the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BONE_MEAL + name: '&6Fertilize' + lore: + - '&7Access to fertilize blocks around the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + fish: + display-menu: true + permission-enabled: + type: FISHING_ROD + name: '&6Fish' + lore: + - '&7Access fishing around the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: FISHING_ROD + name: '&6Fish' + lore: + - '&7Access fishing around the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: FISHING_ROD + name: '&6Fish' + lore: + - '&7Access fishing around the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + fly: + display-menu: true + permission-enabled: + type: FEATHER + name: '&6Fly' + lore: + - '&7Access fly around the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: FEATHER + name: '&6Fly' + lore: + - '&7Access fly around the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: FEATHER + name: '&6Fly' + lore: + - '&7Access fly around the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + horse_interact: + display-menu: true + permission-enabled: + type: HORSE_SPAWN_EGG + name: '&6Horse Interact' + lore: + - '&7Access to interact with horses inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: HORSE_SPAWN_EGG + name: '&6Horse Interact' + lore: + - '&7Access to interact with horses inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: HORSE_SPAWN_EGG + name: '&6Horse Interact' + lore: + - '&7Access to interact with horses inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + ignite_creeper: + display-menu: true + permission-enabled: + type: CREEPER_SPAWN_EGG + name: '&6Ignite Creepers' + lore: + - '&7Access to ignite creepers with flint and steel inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: CREEPER_SPAWN_EGG + name: '&6Ignite Creepers' + lore: + - '&7Access to ignite creepers with flint and steel inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: CREEPER_SPAWN_EGG + name: '&6Ignite Creepers' + lore: + - '&7Access to ignite creepers with flint and steel inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + interact: + display-menu: true + permission-enabled: + type: PISTON + name: '&6Interact' + lore: + - '&7Access to interact with blocks inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: PISTON + name: '&6Interact' + lore: + - '&7Access to interact with blocks inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: PISTON + name: '&6Interact' + lore: + - '&7Access to interact with blocks inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + invite_member: + display-menu: true + permission-enabled: + type: PLAYER_HEAD + data: 3 + name: '&6Invite Member' + lore: + - '&7Access to invite new members to the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: PLAYER_HEAD + name: '&6Invite Member' + lore: + - '&7Access to invite new members to the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: PLAYER_HEAD + name: '&6Invite Member' + lore: + - '&7Access to invite new members to the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + island_chest: + display-menu: true + permission-enabled: + type: ENDER_CHEST + name: '&6Community Chest' + lore: + - '&7Access to the community chest of the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ENDER_CHEST + name: '&6Community Chest' + lore: + - '&7Access to the community chest of the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ENDER_CHEST + name: '&6Community Chest' + lore: + - '&7Access to the community chest of the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + item_frame: + display-menu: true + permission-enabled: + type: ITEM_FRAME + name: '&6Item Frame' + lore: + - '&7Access to interact with item frames inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ITEM_FRAME + name: '&6Item Frame' + lore: + - '&7Access to interact with item frames inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ITEM_FRAME + name: '&6Item Frame' + lore: + - '&7Access to interact with item frames inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + kick_member: + display-menu: true + permission-enabled: + type: SKELETON_SKULL + name: '&6Kick Member' + lore: + - '&7Access to kick members from the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SKELETON_SKULL + name: '&6Kick Member' + lore: + - '&7Access to kick members from the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SKELETON_SKULL + name: '&6Kick Member' + lore: + - '&7Access to kick members from the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + leash: + display-menu: true + permission-enabled: + type: LEAD + name: '&6Leash Mobs' + lore: + - '&7Access to leash mobs inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: LEAD + name: '&6Leash Mobs' + lore: + - '&7Access to leash mobs inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: LEAD + name: '&6Leash Mobs' + lore: + - '&7Access to leash mobs inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + minecart_damage: + display-menu: true + permission-enabled: + type: TNT_MINECART + name: '&6Minecart Damage' + lore: + - '&7Access to damage minecarts inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: TNT_MINECART + name: '&6Minecart Damage' + lore: + - '&7Access to damage minecarts inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: TNT_MINECART + name: '&6Minecart Damage' + lore: + - '&7Access to damage minecarts inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + minecart_enter: + display-menu: true + permission-enabled: + type: HOPPER_MINECART + name: '&6Minecart Enter' + lore: + - '&7Access to enter minecarts inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: HOPPER_MINECART + name: '&6Minecart Enter' + lore: + - '&7Access to enter minecarts inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: HOPPER_MINECART + name: '&6Minecart Enter' + lore: + - '&7Access to enter minecarts inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + minecart_open: + display-menu: true + permission-enabled: + type: CHEST_MINECART + name: '&6Minecart Open' + lore: + - '&7Access to open minecarts inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: CHEST_MINECART + name: '&6Minecart Open' + lore: + - '&7Access to open minecarts inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: CHEST_MINECART + name: '&6Minecart Open' + lore: + - '&7Access to open minecarts inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + minecart_place: + display-menu: true + permission-enabled: + type: MINECART + name: '&6Minecart Place' + lore: + - '&7Access to place minecarts inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: MINECART + name: '&6Minecart Place' + lore: + - '&7Access to place minecarts inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: MINECART + name: '&6Minecart Place' + lore: + - '&7Access to place minecarts inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + monster_damage: + display-menu: true + permission-enabled: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ZOMBIE_HEAD + name: '&6Monster Damage' + lore: + - '&7Access to damage monsters inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + monster_spawn: + display-menu: true + permission-enabled: + type: CAVE_SPIDER_SPAWN_EGG + name: '&6Monster Spawn' + lore: + - '&7Access to spawn monsters inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: CAVE_SPIDER_SPAWN_EGG + name: '&6Monster Spawn' + lore: + - '&7Access to spawn monsters inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: CAVE_SPIDER_SPAWN_EGG + name: '&6Monster Spawn' + lore: + - '&7Access to spawn monsters inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + name_entity: + display-menu: true + permission-enabled: + type: NAME_TAG + name: '&6Name Entity' + lore: + - '&7Access to name-tag entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: NAME_TAG + name: '&6Name Entity' + lore: + - '&7Access to name-tag entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: NAME_TAG + name: '&6Name Entity' + lore: + - '&7Access to name-tag entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + open_island: + display-menu: true + permission-enabled: + type: REDSTONE_TORCH + name: '&6Open Island' + lore: + - '&7Access to open the island to the public.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: REDSTONE_TORCH + name: '&6Open Island' + lore: + - '&7Access to open the island to the public.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: REDSTONE_TORCH + name: '&6Open Island' + lore: + - '&7Access to open the island to the public.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + painting: + display-menu: true + permission-enabled: + type: PAINTING + name: '&6Painting' + lore: + - '&7Access to interact with paintings inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: PAINTING + name: '&6Painting' + lore: + - '&7Access to interact with paintings inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: PAINTING + name: '&6Painting' + lore: + - '&7Access to interact with paintings inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + paypal_show: + display-menu: true + permission-enabled: + type: BLUE_WOOL + name: '&6Paypal Show' + lore: + - '&7Access to check the island''s linked paypal.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BLUE_WOOL + name: '&6Paypal Show' + lore: + - '&7Access to check the island''s linked paypal.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BLUE_WOOL + name: '&6Paypal Show' + lore: + - '&7Access to check the island''s linked paypal.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + pickup_axolotl: + display-menu: true + permission-enabled: + type: AXOLOTL_SPAWN_EGG + name: '&6Pickup Axolotls' + lore: + - '&7Access to pickup axolotls using a water bucket inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: AXOLOTL_SPAWN_EGG + name: '&6Pickup Axolotls' + lore: + - '&7Access to pickup axolotls using a water bucket inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: AXOLOTL_SPAWN_EGG + name: '&6Pickup Axolotls' + lore: + - '&7Access to pickup axolotls using a water bucket inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + pickup_drops: + display-menu: true + permission-enabled: + type: HOPPER + name: '&6Pickup Drops' + lore: + - '&7Access to pickup items inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: HOPPER + name: '&6Pickup Drops' + lore: + - '&7Access to pickup items inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: HOPPER + name: '&6Pickup Drops' + lore: + - '&7Access to pickup items inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + pickup_fish: + display-menu: true + permission-enabled: + type: COD + name: '&6Pickup Fish' + lore: + - '&7Access to pickup fish using buckets inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: COD + name: '&6Pickup Fish' + lore: + - '&7Access to pickup fish using buckets inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: COD + name: '&6Pickup Fish' + lore: + - '&7Access to pickup fish using buckets inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + pickup_lectern_book: + display-menu: true + permission-enabled: + type: LECTERN + name: '&6Pickup Lectern Book' + lore: + - '&7Access to pickup books out of lecterns inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: LECTERN + name: '&6Pickup Lectern Book' + lore: + - '&7Access to pickup books out of lecterns inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: LECTERN + name: '&6Pickup Lectern Book' + lore: + - '&7Access to pickup books out of lecterns inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + promote_members: + display-menu: true + permission-enabled: + type: DIAMOND + name: '&6Promote Members' + lore: + - '&7Access to promote members inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: DIAMOND + name: '&6Promote Members' + lore: + - '&7Access to promote members inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: DIAMOND + name: '&6Promote Members' + lore: + - '&7Access to promote members inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + rankup: + display-menu: true + permission-enabled: + type: GOLD_INGOT + name: '&6Upgrades Rankup' + lore: + - '&7Access to rankup island''s upgrades.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: GOLD_INGOT + name: '&6Upgrades Rankup' + lore: + - '&7Access to rankup island''s upgrades.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: GOLD_INGOT + name: '&6Upgrades Rankup' + lore: + - '&7Access to rankup island''s upgrades.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + ratings_show: + display-menu: true + permission-enabled: + type: NETHER_STAR + name: '&6Ratings Show' + lore: + - '&7Access to see all island''s ratings.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: NETHER_STAR + name: '&6Ratings Show' + lore: + - '&7Access to see all island''s ratings.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: NETHER_STAR + name: '&6Ratings Show' + lore: + - '&7Access to see all island''s ratings.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + saddle_entity: + display-menu: true + permission-enabled: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SADDLE + name: '&6Saddle Entity' + lore: + - '&7Access to add saddle to entities inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + sculk_sensor: + display-menu: true + permission-enabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: SCULK_SENSOR + name: '&6Sculk Sensor' + lore: + - '&7Access to trigger sculk sensors inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + set_biome: + display-menu: true + permission-enabled: + type: GRASS_BLOCK + name: '&6Set Biome' + lore: + - '&7Access to change the island''s biome.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: GRASS_BLOCK + name: '&6Set Biome' + lore: + - '&7Access to change the island''s biome.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: GRASS_BLOCK + name: '&6Set Biome' + lore: + - '&7Access to change the island''s biome.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + set_discord: + display-menu: true + permission-enabled: + type: LIGHT_BLUE_TERRACOTTA + name: '&6Set Discord' + lore: + - '&7Access to change the discord linked to the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: LIGHT_BLUE_TERRACOTTA + name: '&6Set Discord' + lore: + - '&7Access to change the discord linked to the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: LIGHT_BLUE_TERRACOTTA + name: '&6Set Discord' + lore: + - '&7Access to change the discord linked to the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + set_home: + display-menu: true + permission-enabled: + type: RED_BED + name: '&6Set Home' + lore: + - '&7Access to change the home location of the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: RED_BED + name: '&6Set Home' + lore: + - '&7Access to change the home location of the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: RED_BED + name: '&6Set Home' + lore: + - '&7Access to change the home location of the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + set_paypal: + display-menu: true + permission-enabled: + type: BLUE_WOOL + name: '&6Set Paypal' + lore: + - '&7Access to change the paypal linked to the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BLUE_WOOL + name: '&6Set Paypal' + lore: + - '&7Access to change the paypal linked to the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BLUE_WOOL + name: '&6Set Paypal' + lore: + - '&7Access to change the paypal linked to the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + set_permission: + display-menu: true + permission-enabled: + type: REPEATER + name: '&6Set Permission' + lore: + - '&7Access to change permissions for island members.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: REPEATER + name: '&6Set Permission' + lore: + - '&7Access to change permissions for island members.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: REPEATER + name: '&6Set Permission' + lore: + - '&7Access to change permissions for island members.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + set_role: + display-menu: true + permission-enabled: + type: DIAMOND_CHESTPLATE + name: '&6Set Role' + lore: + - '&7Access to change roles for island members.' + - '&7Currently &aENABLED&7.' + flags: + - HIDE_ATTRIBUTES + permission-disabled: + type: DIAMOND_CHESTPLATE + name: '&6Set Role' + lore: + - '&7Access to change roles for island members.' + - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ATTRIBUTES + role-permission: + type: DIAMOND_CHESTPLATE + name: '&6Set Role' + lore: + - '&7Access to change roles for island members.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + flags: + - HIDE_ATTRIBUTES + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + set_settings: + display-menu: true + permission-enabled: + type: LEVER + name: '&6Set Settings' + lore: + - '&7Access to change settings for islands.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: LEVER + name: '&6Set Settings' + lore: + - '&7Access to change settings for islands.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: LEVER + name: '&6Set Settings' + lore: + - '&7Access to change settings for islands.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + set_warp: + display-menu: true + permission-enabled: + type: ENDER_EYE + name: '&6Set Warp' + lore: + - '&7Access to set new warps for the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ENDER_EYE + name: '&6Set Warp' + lore: + - '&7Access to set new warps for the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ENDER_EYE + name: '&6Set Warp' + lore: + - '&7Access to set new warps for the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + sign_interact: + display-menu: true + permission-enabled: + type: OAK_SIGN + name: '&6Sign Interact' + lore: + - '&7Access to interact with signs inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: OAK_SIGN + name: '&6Sign Interact' + lore: + - '&7Access to interact with signs inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: OAK_SIGN + name: '&6Sign Interact' + lore: + - '&7Access to interact with signs inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + spawner_break: + display-menu: true + permission-enabled: + type: SPAWNER + name: '&6Spawner Break' + lore: + - '&7Access to break spawners inside the island.' + - '&7Currently &aENABLED&7.' + flags: + - HIDE_ADDITIONAL_TOOLTIP + permission-disabled: + type: SPAWNER + name: '&6Spawner Break' + lore: + - '&7Access to break spawners inside the island.' + - '&7Currently &cDISABLED&7.' + flags: + - HIDE_ADDITIONAL_TOOLTIP + role-permission: + type: SPAWNER + name: '&6Spawner Break' + lore: + - '&7Access to break spawners inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + flags: + - HIDE_ADDITIONAL_TOOLTIP + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + turtle_egg_tramping: + display-menu: true + permission-enabled: + type: TURTLE_EGG + name: '&6Turtle Eggs Tramping' + lore: + - '&7Access to tramp turtle eggs inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: TURTLE_EGG + name: '&6Turtle Eggs Tramping' + lore: + - '&7Access to tramp turtle eggs inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: TURTLE_EGG + name: '&6Turtle Eggs Tramping' + lore: + - '&7Access to tramp turtle eggs inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + tamed_animal_damage: + display-menu: true + permission-enabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: BONE + name: '&6Tamed Animal Damage' + lore: + - '&7Access to damage tamed animals inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 + + uncoop_member: + display-menu: true + permission-enabled: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: GOLDEN_APPLE + name: '&6Uncoop Member' + lore: + - '&7Access to remove co-op members from the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + use: + display-menu: true + permission-enabled: + type: STONE_BUTTON + name: '&6Use' + lore: + - '&7Access to use different blocks inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: STONE_BUTTON + name: '&6Use' + lore: + - '&7Access to use different blocks inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: STONE_BUTTON + name: '&6Use' + lore: + - '&7Access to use different blocks inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + valuable_break: + display-menu: true + permission-enabled: + type: GOLD_INGOT + name: '&6Valuable Blocks Break' + lore: + - '&7Access to break valuable blocks inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: GOLD_INGOT + name: '&6Valuable Blocks Break' + lore: + - '&7Access to break valuable blocks inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: GOLD_INGOT + name: '&6Valuable Blocks Break' + lore: + - '&7Access to break valuable blocks inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + villager_trading: + display-menu: true + permission-enabled: + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' + name: '&6Villagers Trading' + lore: + - '&7Access to trade with villagers inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' + name: '&6Villagers Trading' + lore: + - '&7Access to trade with villagers inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: PLAYER_HEAD + skull: 'eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDFiODMwZWI0MDgyYWNlYzgzNmJjODM1ZTQwYTExMjgyYmI1MTE5MzMxNWY5MTE4NDMzN2U4ZDM1NTU1ODMifX19' + name: '&6Villagers Trading' + lore: + - '&7Access to trade with villagers inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + + withdraw_money: + display-menu: true + permission-enabled: + type: EMERALD + name: '&6Withdraw Money' + lore: + - '&7Access to withdraw money from the island''s bank.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: EMERALD + name: '&6Withdraw Money' + lore: + - '&7Access to withdraw money from the island''s bank.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: EMERALD + name: '&6Withdraw Money' + lore: + - '&7Access to withdraw money from the island''s bank.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 \ No newline at end of file diff --git a/src/main/resources/menus/permissions1_20.yml b/src/main/resources/menus/permissions1_20.yml index fd5c3dc3b1..61f86ab524 100644 --- a/src/main/resources/menus/permissions1_20.yml +++ b/src/main/resources/menus/permissions1_20.yml @@ -75,6 +75,39 @@ permissions: volume: 0.2 pitch: 0.2 + allay_interact: + display-menu: true + permission-enabled: + type: ALLAY_SPAWN_EGG + name: '&6Allay Interact' + lore: + - '&7Access to interact with allays inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ALLAY_SPAWN_EGG + name: '&6Allay Interact' + lore: + - '&7Access to interact with allays inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ALLAY_SPAWN_EGG + name: '&6Allay Interact' + lore: + - '&7Access to interact with allays inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + animal_breed: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_21.yml b/src/main/resources/menus/permissions1_21.yml index c63b14b1ec..bdcd57fb7e 100644 --- a/src/main/resources/menus/permissions1_21.yml +++ b/src/main/resources/menus/permissions1_21.yml @@ -75,6 +75,39 @@ permissions: volume: 0.2 pitch: 0.2 + allay_interact: + display-menu: true + permission-enabled: + type: ALLAY_SPAWN_EGG + name: '&6Allay Interact' + lore: + - '&7Access to interact with allays inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: ALLAY_SPAWN_EGG + name: '&6Allay Interact' + lore: + - '&7Access to interact with allays inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: ALLAY_SPAWN_EGG + name: '&6Allay Interact' + lore: + - '&7Access to interact with allays inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + animal_breed: display-menu: true permission-enabled: From e223afd4acf320f40c55b580f783764124b65551 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Tue, 30 Dec 2025 19:55:48 +0100 Subject: [PATCH 453/600] Added missing interactable blocks (#2821) --- src/main/resources/interactables.yml | 41 ++++++++++++++++++---------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index 9401adfa9e..00734a99a9 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -35,6 +35,8 @@ interactables: - 'BEACON' - 'BED_BLOCK' - 'BEE_NEST' + - 'BEEHIVE' + - 'BELL' - 'BIRCH_BUTTON' - 'BIRCH_DOOR' - 'BIRCH_FENCE' @@ -60,8 +62,9 @@ interactables: - 'BURNING_FURNACE' - 'CAKE' - 'CAKE_BLOCK' + - 'CAMPFIRE' - 'CANDLE' - - 'CARTOGRAPHER_TABLE' + - 'CARTOGRAPHY_TABLE' - 'CAULDRON' - 'CAVE_VINES' - 'CAVE_VINES_PLANT' @@ -94,6 +97,7 @@ interactables: - 'CRAFTING_TABLE' - 'CRIMSON_BUTTON' - 'CRIMSON_DOOR' + - 'CRIMSON_FENCE' - 'CRIMSON_FENCE_GATE' - 'CRIMSON_HANGING_SIGN' - 'CRIMSON_PRESSURE_PLATE' @@ -120,13 +124,12 @@ interactables: - 'DAYLIGHT_DETECTOR' - 'DAYLIGHT_DETECTOR_INVERTED' - 'DECORATED_POT' - - 'DIODE_BLOCK_OFF' - - 'DIODE_BLOCK_ON' - 'DISPENSER' - 'DRAGON_EGG' - 'DROPPER' - 'ENCHANTING_TABLE' - 'ENCHANTMENT_TABLE' + - 'END_PORTAL_FRAME' - 'ENDER_CHEST' - 'ENDER_PORTAL_FRAME' - 'EXPOSED_COPPER_CHEST' @@ -149,11 +152,8 @@ interactables: - 'GRINDSTONE' - 'HEAVY_WEIGHTED_PRESSURE_PLATE' - 'HOPPER' - - 'IRON_DOOR' - - 'IRON_DOOR_BLOCK' - - 'IRON_FENCE' - 'IRON_PLATE' - - 'IRON_TRAPDOOR' + - 'JIGSAW' - 'JUKEBOX' - 'JUNGLE_BUTTON' - 'JUNGLE_DOOR' @@ -183,7 +183,12 @@ interactables: - 'MAGENTA_BED' - 'MAGENTA_CANDLE' - 'MAGENTA_SHULKER_BOX' + - 'MANGROVE_BUTTON' + - 'MANGROVE_DOOR' + - 'MANGROVE_FENCE' + - 'MANGROVE_FENCE_GATE' - 'MANGROVE_HANGING_SIGN' + - 'MANGROVE_PRESSURE_PLATE' - 'MANGROVE_SHELF' - 'MANGROVE_SIGN' - 'MANGROVE_TRAPDOOR' @@ -236,6 +241,8 @@ interactables: - 'POTTED_BLUE_ORCHID' - 'POTTED_BROWN_MUSHROOM' - 'POTTED_CACTUS' + - 'POTTED_CHERRY_SAPLING' + - 'POTTED_CLOSED_EYEBLOSSOM' - 'POTTED_CORNFLOWER' - 'POTTED_CRIMSON_FUNGUS' - 'POTTED_CRIMSON_ROOTS' @@ -248,6 +255,7 @@ interactables: - 'POTTED_LILY_OF_THE_VALLEY' - 'POTTED_MANGROVE_PROPAGULE' - 'POTTED_OAK_SAPLING' + - 'POTTED_OPEN_EYEBLOSSOM' - 'POTTED_ORANGE_TULIP' - 'POTTED_OXEYE_DAISY' - 'POTTED_PALE_OAK_SAPLING' @@ -256,6 +264,7 @@ interactables: - 'POTTED_RED_MUSHROOM' - 'POTTED_RED_TULIP' - 'POTTED_SPRUCE_SAPLING' + - 'POTTED_TORCHFLOWER' - 'POTTED_WARPED_FUNGUS' - 'POTTED_WARPED_ROOTS' - 'POTTED_WHITE_TULIP' @@ -264,17 +273,16 @@ interactables: - 'PURPLE_BED' - 'PURPLE_CANDLE' - 'PURPLE_SHULKER_BOX' - - 'REDSTONE_COMPARATOR_OFF' - - 'REDSTONE_COMPARATOR_ON' - - 'REDSTONE_ORE' - 'RED_BED' - 'RED_CANDLE' - 'RED_SHULKER_BOX' + - 'REDSTONE_COMPARATOR_OFF' + - 'REDSTONE_COMPARATOR_ON' + - 'REDSTONE_ORE' - 'REPEATER' - 'REPEATING_COMMAND_BLOCK' - 'RESPAWN_ANCHOR' - 'SHULKER_BOX' - - 'SIGN' - 'SIGN_POST' - 'SMITHING_TABLE' - 'SMOKER' @@ -292,20 +300,23 @@ interactables: - 'SPRUCE_TRAPDOOR' - 'SPRUCE_WALL_HANGING_SIGN' - 'SPRUCE_WALL_SIGN' - - 'STONECUTTER' - 'STONE_BUTTON' - 'STONE_PRESSURE_PLATE' + - 'STONECUTTER' - 'STRUCTURE_BLOCK' - - 'STRUCTURE_VOID' - 'SWEET_BERRY_BUSH' - 'TARGET' + - 'TEST_BLOCK' + - 'TEST_INSTANCE_BLOCK' - 'TNT' - - 'TRAPPED_CHEST' - 'TRAP_DOOR' + - 'TRAPPED_CHEST' - 'TURTLE_EGG' + - 'VAULT' - 'WALL_SIGN' - 'WARPED_BUTTON' - 'WARPED_DOOR' + - 'WARPED_FENCE' - 'WARPED_FENCE_GATE' - 'WARPED_HANGING_SIGN' - 'WARPED_PRESSURE_PLATE' @@ -337,8 +348,8 @@ interactables: - 'WHITE_BED' - 'WHITE_CANDLE' - 'WHITE_SHULKER_BOX' - - 'WOODEN_DOOR' - 'WOOD_BUTTON' + - 'WOODEN_DOOR' - 'WORKBENCH' - 'YELLOW_BED' - 'YELLOW_CANDLE' From 7ca85fb091b04c43be4c239356c2d272d1c95ee7 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Tue, 30 Dec 2025 19:57:26 +0100 Subject: [PATCH 454/600] Fix loading locations from config (#2820) --- .../commands/admin/CmdAdminSetIslandPreview.java | 5 +++++ .../superiorskyblock/config/SettingsContainer.java | 2 +- .../core/serialization/Serializers.java | 1 + .../serialization/impl/LocationSerializer.java | 14 +++++++++++++- .../superiorskyblock/island/SpawnIsland.java | 2 +- 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java index c8ec1af86f..a547ec3e3b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetIslandPreview.java @@ -66,6 +66,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ String schematicPreviewLocation; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = player.getLocation(wrapper.getHandle()); + location.setX(location.getBlockX()); + location.setY(location.getBlockY()); + location.setZ(location.getBlockZ()); + // Fix to corner of a block + location.add(0.5, 0, 0.5); schematicPreviewLocation = Serializers.LOCATION_SPACED_SERIALIZER.serialize(location); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 8581357d28..18a0ee837f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -573,7 +573,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config if (config.isConfigurationSection("island-previews.locations")) { for (String schematic : config.getConfigurationSection("island-previews.locations").getKeys(false)) { try { - islandPreviewsLocations.put(schematic.toLowerCase(Locale.ENGLISH), Serializers.LOCATION_SERIALIZER + islandPreviewsLocations.put(schematic.toLowerCase(Locale.ENGLISH), Serializers.LOCATION_SPACED_CENTERED_SERIALIZER .deserialize(config.getString("island-previews.locations." + schematic))); } catch (Exception error) { Log.warnFromFile("config.yml", "Cannot deserialize island preview for ", schematic, ", skipping..."); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/Serializers.java b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/Serializers.java index 75bc3f8317..4e9b011cf4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/Serializers.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/Serializers.java @@ -19,6 +19,7 @@ public class Serializers { public static final ISerializer INVENTORY_SERIALIZER = InventorySerializer.getInstance(); public static final ISerializer ITEM_STACK_SERIALIZER = ItemStackSerializer.getInstance(); public static final ISerializer ITEM_STACK_TO_TAG_SERIALIZER = ItemStack2TagSerializer.getInstance(); + public static final ISerializer LOCATION_SPACED_CENTERED_SERIALIZER = new LocationSerializer(", ", true); public static final ISerializer LOCATION_SPACED_SERIALIZER = new LocationSerializer(", "); public static final ISerializer LOCATION_SERIALIZER = new LocationSerializer(","); public static final ISerializer BLOCK_POSITION_SERIALIZER = BlockPositionSerializer.getInstance(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/LocationSerializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/LocationSerializer.java index 4dcde284cd..0162b4411a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/LocationSerializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/serialization/impl/LocationSerializer.java @@ -11,9 +11,16 @@ public class LocationSerializer implements ISerializer { private final String separator; + private final boolean center; public LocationSerializer(String separator) { this.separator = separator; + this.center = false; + } + + public LocationSerializer(String separator, boolean center) { + this.separator = separator; + this.center = center; } @NotNull @@ -37,10 +44,15 @@ public Location deserialize(@Nullable String element) { String[] sections = element.split(separator); double x = Double.parseDouble(sections[1]); + if (center && !sections[1].contains(".")) x += 0.5; + double y = Double.parseDouble(sections[2]); + double z = Double.parseDouble(sections[3]); + if (center && !sections[3].contains(".")) z += 0.5; + float yaw = sections.length > 5 ? Float.parseFloat(sections[4]) : 0; - float pitch = sections.length > 4 ? Float.parseFloat(sections[5]) : 0; + float pitch = sections.length > 6 ? Float.parseFloat(sections[5]) : 0; return new LazyWorldLocation(sections[0], x, y, z, yaw, pitch); } catch (Exception error) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 3d1106bf27..6409113faf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -144,7 +144,7 @@ protected IslandCache create() { public SpawnIsland() throws ManagerLoadException { String spawnLocation = plugin.getSettings().getSpawn().getLocation(); - Location centerLocation = Serializers.LOCATION_SPACED_SERIALIZER.deserialize(spawnLocation); + Location centerLocation = Serializers.LOCATION_SPACED_CENTERED_SERIALIZER.deserialize(spawnLocation); if (centerLocation == null) { throw new ManagerLoadException("The spawn location could not be parsed", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } From 27add4c40b29d2528d8a5f6f95d84dd7c72d2021 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 30 Dec 2025 21:22:14 +0200 Subject: [PATCH 455/600] Adds support to Spigot 1.21.11 --- NMS/v1_21_10/build.gradle | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/NMS/v1_21_10/build.gradle b/NMS/v1_21_10/build.gradle index 6f27afb632..404cd93a9a 100644 --- a/NMS/v1_21_10/build.gradle +++ b/NMS/v1_21_10/build.gradle @@ -18,6 +18,21 @@ dependencies { compileOnly rootProject } +shadowJar { + archiveFileName = "${project.name}-exclude.jar" +} + +assemble { + dependsOn(reobfJar) +} + +tasks { + reobfJar { + File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") + outputJar.set(layout.buildDirectory.file(outputFile.getPath())) + } +} + if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file From 1cdcc781ae247e3d74b604364cf57b3ffe35f3c4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 30 Dec 2025 21:56:02 +0200 Subject: [PATCH 456/600] Fix loading OfflinePlayerData makes player teleport to default world (#2823) --- .../OfflinePlayerDataImpl.java.template | 31 ++++++++++++++++++- .../nms/v1_17/utils/NMSUtilsVersioned.java | 9 ++++++ .../nms/v1_18/utils/NMSUtilsVersioned.java | 8 +++++ .../nms/v1_19/utils/NMSUtilsVersioned.java | 8 +++++ .../nms/v1_20_3/utils/NMSUtilsVersioned.java | 8 +++++ .../nms/v1_20_4/utils/NMSUtilsVersioned.java | 8 +++++ .../nms/v1_21/utils/NMSUtilsVersioned.java | 8 +++++ .../nms/v1_21_10/utils/NMSUtilsVersioned.java | 8 +++++ .../nms/v1_21_3/utils/NMSUtilsVersioned.java | 8 +++++ .../nms/v1_21_4/utils/NMSUtilsVersioned.java | 8 +++++ .../nms/v1_21_5/utils/NMSUtilsVersioned.java | 11 +++++-- .../nms/v1_21_7/utils/NMSUtilsVersioned.java | 16 ++++++++++ .../nms/v1_21_9/utils/NMSUtilsVersioned.java | 8 +++++ 13 files changed, 136 insertions(+), 3 deletions(-) diff --git a/NMS/src/main/templates/player/OfflinePlayerDataImpl.java.template b/NMS/src/main/templates/player/OfflinePlayerDataImpl.java.template index 6d4ff52332..25406ac274 100644 --- a/NMS/src/main/templates/player/OfflinePlayerDataImpl.java.template +++ b/NMS/src/main/templates/player/OfflinePlayerDataImpl.java.template @@ -2,9 +2,13 @@ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.player; import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.core.ObjectsPool; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.mojang.authlib.GameProfile; +import com.mojang.serialization.Dynamic; +import net.minecraft.nbt.NbtOps; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -13,12 +17,14 @@ import net.minecraft.world.level.Level; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; +import org.bukkit.World; import ${CRAFTBUKKIT_PACKAGE}.CraftServer; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; import ${CRAFTBUKKIT_PACKAGE}.entity.CraftPlayer; import org.bukkit.entity.Player; import java.util.Optional; +import java.util.UUID; public class OfflinePlayerDataImpl implements OfflinePlayerData { @@ -46,8 +52,31 @@ public class OfflinePlayerDataImpl implements OfflinePlayerData { return null; ServerPlayer serverPlayer = NMSUtilsVersioned.createServerPlayer(serverLevel, profile); + NMSUtilsVersioned.loadPlayerData(serverPlayer).ifPresent(playerData -> { + ResourceKey resourceKey; + if (playerData.contains("WorldUUIDMost") && playerData.contains("WorldUUIDLeast")) { + long worldUUIDMost = NMSUtilsVersioned.getCompoundTagLong(playerData, "WorldUUIDMost", 0L); + long worldUUIDLeast = NMSUtilsVersioned.getCompoundTagLong(playerData, "WorldUUIDLeast", 0L); + UUID uid = new UUID(worldUUIDMost, worldUUIDLeast); + World bukkitWorld = Bukkit.getServer().getWorld(uid); + if (bukkitWorld != null) { + resourceKey = ((CraftWorld) bukkitWorld).getHandle().dimension(); + } else { + resourceKey = Level.OVERWORLD; + } + } else { + resourceKey = Level.OVERWORLD; + } + + ServerLevel worldServer = server.getLevel(resourceKey); + if (worldServer == null) { + worldServer = server.overworld(); + } + + serverPlayer.setLevel(worldServer); + }); + this.fakePlayer = serverPlayer.getBukkitEntity(); - this.fakePlayer.loadData(); return this; } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java index 33a62e6a2d..111d3fbbfe 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java @@ -59,6 +59,7 @@ import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Collections; +import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; @@ -286,6 +287,14 @@ public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } + public static Optional loadPlayerData(ServerPlayer serverPlayer) { + return Optional.ofNullable(MinecraftServer.getServer().getPlayerList().load(serverPlayer)); + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLong(key); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java index ad7afbd43b..6caef06a74 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java @@ -277,6 +277,14 @@ public static void markUnsaved(LevelChunk levelChunk) { levelChunk.setUnsaved(true); } + public static Optional loadPlayerData(ServerPlayer serverPlayer) { + return Optional.ofNullable(MinecraftServer.getServer().getPlayerList().load(serverPlayer)); + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLong(key); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java index b41b9707ba..b429123007 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java @@ -308,6 +308,14 @@ public static void markUnsaved(LevelChunk levelChunk) { levelChunk.setUnsaved(true); } + public static Optional loadPlayerData(ServerPlayer serverPlayer) { + return Optional.ofNullable(MinecraftServer.getServer().getPlayerList().load(serverPlayer)); + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLong(key); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java index 4cb159d4bb..0e8da41819 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java @@ -307,6 +307,14 @@ public static void markUnsaved(LevelChunk levelChunk) { levelChunk.setUnsaved(true); } + public static Optional loadPlayerData(ServerPlayer serverPlayer) { + return Optional.ofNullable(MinecraftServer.getServer().getPlayerList().load(serverPlayer)); + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLong(key); + } + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { CompoundTag frontText = blockEntityCompound.getCompound(key); diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java index bd90957f3c..b05151d123 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java @@ -359,6 +359,14 @@ public static void markUnsaved(LevelChunk levelChunk) { levelChunk.setUnsaved(true); } + public static Optional loadPlayerData(ServerPlayer serverPlayer) { + return MinecraftServer.getServer().getPlayerList().load(serverPlayer); + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLong(key); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java index 3dea5f1635..5b474a2d93 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java @@ -316,6 +316,14 @@ public static void markUnsaved(LevelChunk levelChunk) { levelChunk.setUnsaved(true); } + public static Optional loadPlayerData(ServerPlayer serverPlayer) { + return MinecraftServer.getServer().getPlayerList().load(serverPlayer); + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLong(key); + } + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { CompoundTag frontText = blockEntityCompound.getCompound(key); diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java index f17adceab1..f1e11adcfd 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java @@ -350,6 +350,14 @@ public static PalettedContainer> createBiomesContainer(Holder loadPlayerData(ServerPlayer serverPlayer) { + return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId()); + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLongOr(key, def); + } + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { blockEntityCompound.getCompound(key).ifPresent(textCompound -> { ListTag messages = textCompound.getListOrEmpty("messages"); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java index f385cf7e1a..334bae5862 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java @@ -325,6 +325,14 @@ public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } + public static Optional loadPlayerData(ServerPlayer serverPlayer) { + return MinecraftServer.getServer().getPlayerList().load(serverPlayer); + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLong(key); + } + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { CompoundTag frontText = blockEntityCompound.getCompound(key); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java index 7d5522975f..0e0a16c29c 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java @@ -325,6 +325,14 @@ public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } + public static Optional loadPlayerData(ServerPlayer serverPlayer) { + return MinecraftServer.getServer().getPlayerList().load(serverPlayer); + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLong(key); + } + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { if (blockEntityCompound.contains(key)) { CompoundTag frontText = blockEntityCompound.getCompound(key); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java index 5902adb139..e43c0078d9 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java @@ -10,7 +10,6 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.v1_21_5.utils.TickingBlockList; import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; @@ -139,7 +138,7 @@ public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); - if(readData != null) { + if (readData != null) { CompoundTag entityData = switch (readData.result()) { case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); case SYNC_READ -> readData.syncRead(); @@ -325,6 +324,14 @@ public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } + public static Optional loadPlayerData(ServerPlayer serverPlayer) { + return MinecraftServer.getServer().getPlayerList().load(serverPlayer); + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLongOr(key, def); + } + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { blockEntityCompound.getCompound(key).ifPresent(textCompound -> { ListTag messages = textCompound.getListOrEmpty("messages"); diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java index dc4ded1e59..82f51b65ba 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java @@ -340,6 +340,22 @@ public static void markUnsaved(LevelChunk levelChunk) { levelChunk.markUnsaved(); } + public static Optional loadPlayerData(ServerPlayer serverPlayer) { + try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) { + return MinecraftServer.getServer().getPlayerList().playerIo.load( + serverPlayer.getName().getString(), serverPlayer.getStringUUID(), scopedCollector) + .map(playerData -> { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData); + serverPlayer.load(valueInput); + return playerData; + }); + } + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLongOr(key, def); + } + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { blockEntityCompound.getCompound(key).ifPresent(textCompound -> { ListTag messages = textCompound.getListOrEmpty("messages"); diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java index cb081c95ca..9aa7b43404 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java @@ -352,6 +352,14 @@ public static PalettedContainer> createBiomesContainer(Holder loadPlayerData(ServerPlayer serverPlayer) { + return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId()); + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLongOr(key, def); + } + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { blockEntityCompound.getCompound(key).ifPresent(textCompound -> { ListTag messages = textCompound.getListOrEmpty("messages"); From aa3706335d3b1e41583d275c8ef1a03ee81827ea Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 30 Dec 2025 22:33:36 +0200 Subject: [PATCH 457/600] Fixed many issues related to reloading of the plugin and other built-in plugin hooks (#2796) --- .../spawners/SpawnersProvider_AdvancedSpawners.java | 9 ++------- .../external/vanish/VanishProvider_CMI.java | 9 +-------- .../spawners/SpawnersProvider_CandcSilkSpawners.java | 9 ++------- .../superiorskyblock/external/CraftEngineHook.java | 7 ++++++- .../spawners/SpawnersProvider_EpicSpawners6.java | 10 ++-------- .../spawners/SpawnersProvider_EpicSpawners7.java | 9 ++------- .../spawners/SpawnersProvider_EpicSpawners8.java | 9 ++------- .../spawners/SpawnersProvider_EpicSpawners9.java | 9 ++------- .../external/vanish/VanishProvider_Essentials.java | 9 +-------- .../superiorskyblock/external/ItemsAdderHook.java | 7 ++++++- .../spawners/SpawnersProvider_MergedSpawner.java | 9 ++------- .../superiorskyblock/external/NexoHook.java | 11 ++++++++--- .../superiorskyblock/external/OraxenHook.java | 9 +++++++-- .../spawners/SpawnersProvider_PvpingSpawners.java | 9 ++------- .../spawners/SpawnersProvider_RoseStacker.java | 8 ++------ .../StackedBlocksProvider_RoseStacker.java | 10 ++-------- .../external/vanish/VanishProvider_SuperVanish.java | 9 +-------- .../spawners/SpawnersProvider_TimbruSilkSpawners.java | 8 +------- .../spawners/SpawnersProvider_UltimateStacker.java | 9 ++------- .../spawners/SpawnersProvider_UltimateStacker3.java | 9 ++------- .../spawners/SpawnersProvider_UltimateStacker4.java | 9 ++------- .../vanish/VanishProvider_VanishNoPacket.java | 9 +-------- .../spawners/SpawnersProvider_WildStacker.java | 11 +++-------- .../StackedBlocksProvider_WildStacker.java | 7 ++++--- 24 files changed, 65 insertions(+), 149 deletions(-) diff --git a/Hooks/AdvancedSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_AdvancedSpawners.java b/Hooks/AdvancedSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_AdvancedSpawners.java index 3de241667f..1282e45cec 100644 --- a/Hooks/AdvancedSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_AdvancedSpawners.java +++ b/Hooks/AdvancedSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_AdvancedSpawners.java @@ -21,17 +21,12 @@ public class SpawnersProvider_AdvancedSpawners implements SpawnersProvider_AutoDetect { - private static boolean registered = false; - private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_AdvancedSpawners(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registered) { - Bukkit.getPluginManager().registerEvents(new SpawnersProvider_AdvancedSpawners.StackerListener(), plugin); - registered = true; - Log.info("Using AdvancedSpawners as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new SpawnersProvider_AdvancedSpawners.StackerListener(), plugin); + Log.info("Using AdvancedSpawners as a spawners provider."); } @Override diff --git a/Hooks/CMI/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_CMI.java b/Hooks/CMI/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_CMI.java index 7d4037f9e8..ef1998e39d 100644 --- a/Hooks/CMI/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_CMI.java +++ b/Hooks/CMI/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_CMI.java @@ -15,18 +15,11 @@ public class VanishProvider_CMI implements VanishProvider, Listener { - private static boolean alreadyEnabled = false; - private final SuperiorSkyblockPlugin plugin; public VanishProvider_CMI(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - - if (!alreadyEnabled) { - alreadyEnabled = true; - Bukkit.getPluginManager().registerEvents(this, plugin); - } - + Bukkit.getPluginManager().registerEvents(this, plugin); Log.info("Hooked into CMI for support of vanish status of players."); } diff --git a/Hooks/CandcSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_CandcSilkSpawners.java b/Hooks/CandcSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_CandcSilkSpawners.java index 1885d6e1e0..292d226b96 100644 --- a/Hooks/CandcSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_CandcSilkSpawners.java +++ b/Hooks/CandcSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_CandcSilkSpawners.java @@ -18,17 +18,12 @@ public class SpawnersProvider_CandcSilkSpawners implements SpawnersProvider_AutoDetect { - private static boolean registered = false; - private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_CandcSilkSpawners(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registered) { - Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); - registered = true; - Log.info("Using SilkSpawners as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + Log.info("Using SilkSpawners as a spawners provider."); } @Override diff --git a/Hooks/CraftEngine/src/main/java/com/bgsoftware/superiorskyblock/external/CraftEngineHook.java b/Hooks/CraftEngine/src/main/java/com/bgsoftware/superiorskyblock/external/CraftEngineHook.java index 64ff12df03..932b08c014 100644 --- a/Hooks/CraftEngine/src/main/java/com/bgsoftware/superiorskyblock/external/CraftEngineHook.java +++ b/Hooks/CraftEngine/src/main/java/com/bgsoftware/superiorskyblock/external/CraftEngineHook.java @@ -35,9 +35,14 @@ public class CraftEngineHook { private static final KeyMap CUSTOM_ITEM_CACHE = collectCustomItemsCache(); private static final KeyMap CUSTOM_ITEM_TO_BLOCK_CACHE = collectCustomItemToBlocksCache(); + private static boolean registered = false; + public static void register(SuperiorSkyblockPlugin plugin) { - plugin.getBlockValues().registerKeyParser(new CraftEngineKeyParser(), collectCustomKeys()); plugin.getServer().getPluginManager().registerEvents(new ListenerImpl(), plugin); + if (!registered) { + registered = true; + plugin.getBlockValues().registerKeyParser(new CraftEngineKeyParser(), collectCustomKeys()); + } } private static KeySet collectCustomItemKeys() { diff --git a/Hooks/EpicSpawners6/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners6.java b/Hooks/EpicSpawners6/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners6.java index 280bf0a4a4..536323b773 100644 --- a/Hooks/EpicSpawners6/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners6.java +++ b/Hooks/EpicSpawners6/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners6.java @@ -4,7 +4,6 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; -import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -26,18 +25,13 @@ public class SpawnersProvider_EpicSpawners6 implements SpawnersProvider_AutoDetect { - private static boolean registered = false; - private final EpicSpawners instance = EpicSpawners.getInstance(); private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_EpicSpawners6(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registered) { - Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); - registered = true; - Log.info("Using EpicSpawners as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + Log.info("Using EpicSpawners as a spawners provider."); } @Override diff --git a/Hooks/EpicSpawners7/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners7.java b/Hooks/EpicSpawners7/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners7.java index d00caf8a99..0cc8d4619a 100644 --- a/Hooks/EpicSpawners7/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners7.java +++ b/Hooks/EpicSpawners7/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners7.java @@ -27,18 +27,13 @@ @SuppressWarnings("unused") public class SpawnersProvider_EpicSpawners7 implements SpawnersProvider { - private static boolean registered = false; - private final EpicSpawners instance = EpicSpawners.getInstance(); private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_EpicSpawners7(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registered) { - Bukkit.getPluginManager().registerEvents(new SpawnersProvider_EpicSpawners7.StackerListener(), plugin); - registered = true; - Log.info("Using EpicSpawners as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new SpawnersProvider_EpicSpawners7.StackerListener(), plugin); + Log.info("Using EpicSpawners as a spawners provider."); } @Override diff --git a/Hooks/EpicSpawners8/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners8.java b/Hooks/EpicSpawners8/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners8.java index 73d2a7727c..e5f3cd607d 100644 --- a/Hooks/EpicSpawners8/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners8.java +++ b/Hooks/EpicSpawners8/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners8.java @@ -27,17 +27,12 @@ @SuppressWarnings("unused") public class SpawnersProvider_EpicSpawners8 implements SpawnersProvider { - private static boolean registered = false; - private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_EpicSpawners8(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registered) { - Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); - registered = true; - Log.info("Using EpicSpawners as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + Log.info("Using EpicSpawners as a spawners provider."); } @Override diff --git a/Hooks/EpicSpawners9/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners9.java b/Hooks/EpicSpawners9/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners9.java index 937dc75ab7..0929bd5cbd 100644 --- a/Hooks/EpicSpawners9/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners9.java +++ b/Hooks/EpicSpawners9/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_EpicSpawners9.java @@ -27,17 +27,12 @@ @SuppressWarnings("unused") public class SpawnersProvider_EpicSpawners9 implements SpawnersProvider { - private static boolean registered = false; - private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_EpicSpawners9(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registered) { - Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); - registered = true; - Log.info("Using EpicSpawners as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + Log.info("Using EpicSpawners as a spawners provider."); } @Override diff --git a/Hooks/Essentials/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Essentials.java b/Hooks/Essentials/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Essentials.java index cd50cd99e3..203d31ed03 100644 --- a/Hooks/Essentials/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Essentials.java +++ b/Hooks/Essentials/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_Essentials.java @@ -15,20 +15,13 @@ public class VanishProvider_Essentials implements VanishProvider, Listener { - private static boolean alreadyEnabled = false; - private final SuperiorSkyblockPlugin plugin; private final Essentials instance; public VanishProvider_Essentials(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; this.instance = JavaPlugin.getPlugin(Essentials.class); - - if (!alreadyEnabled) { - alreadyEnabled = true; - Bukkit.getPluginManager().registerEvents(this, plugin); - } - + Bukkit.getPluginManager().registerEvents(this, plugin); Log.info("Hooked into Essentials for support of vanish status of players."); } diff --git a/Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java b/Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java index e80f45b65d..93716f1d74 100644 --- a/Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java +++ b/Hooks/ItemsAdder/src/main/java/com/bgsoftware/superiorskyblock/external/ItemsAdderHook.java @@ -38,12 +38,17 @@ protected WorldRecordService create() { } }; + private static boolean registered = false; + private static SuperiorSkyblockPlugin plugin; public static void register(SuperiorSkyblockPlugin plugin) { ItemsAdderHook.plugin = plugin; - plugin.getBlockValues().registerKeyParser(new ItemsAdderKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY); plugin.getServer().getPluginManager().registerEvents(new ListenerImpl(), plugin); + if (!registered) { + registered = true; + plugin.getBlockValues().registerKeyParser(new ItemsAdderKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY); + } } private static class ListenerImpl implements Listener { diff --git a/Hooks/MergedSpawner/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_MergedSpawner.java b/Hooks/MergedSpawner/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_MergedSpawner.java index 057880246d..03744d5866 100644 --- a/Hooks/MergedSpawner/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_MergedSpawner.java +++ b/Hooks/MergedSpawner/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_MergedSpawner.java @@ -19,17 +19,12 @@ public class SpawnersProvider_MergedSpawner implements SpawnersProvider_AutoDetect { - private static boolean registered = false; - private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_MergedSpawner(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registered) { - Bukkit.getPluginManager().registerEvents(new SpawnersProvider_MergedSpawner.StackerListener(), plugin); - registered = true; - Log.info("Using MergedSpawner as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new SpawnersProvider_MergedSpawner.StackerListener(), plugin); + Log.info("Using MergedSpawner as a spawners provider."); } @Override diff --git a/Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java b/Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java index 7b174d8b44..11af44caf5 100644 --- a/Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java +++ b/Hooks/Nexo/src/main/java/com/bgsoftware/superiorskyblock/external/NexoHook.java @@ -60,14 +60,19 @@ protected WorldRecordService create() { } }; + private static boolean registered = false; + private static SuperiorSkyblockPlugin plugin; public static void register(SuperiorSkyblockPlugin plugin) { NexoHook.plugin = plugin; - plugin.getBlockValues().registerKeyParser(new NexoKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY); - plugin.getProviders().registerCustomBlocksProvider(new NexuCustomBlocksProvider()); plugin.getServer().getPluginManager().registerEvents(new NexoListener(), plugin); - BukkitExecutor.sync(NexoHook::initializeMechanics, 1L); + if (!registered) { + registered = true; + plugin.getProviders().registerCustomBlocksProvider(new NexuCustomBlocksProvider()); + BukkitExecutor.sync(NexoHook::initializeMechanics, 1L); + plugin.getBlockValues().registerKeyParser(new NexoKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY); + } } private static void initializeMechanics() { diff --git a/Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java b/Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java index 6f690257c8..cc7c7bd97b 100644 --- a/Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java +++ b/Hooks/Oraxen/src/main/java/com/bgsoftware/superiorskyblock/external/OraxenHook.java @@ -98,13 +98,18 @@ protected WorldRecordService create() { } }; + private static boolean registered = false; + private static SuperiorSkyblockPlugin plugin; public static void register(SuperiorSkyblockPlugin plugin) { OraxenHook.plugin = plugin; - plugin.getBlockValues().registerKeyParser(new OraxenKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY); - plugin.getProviders().registerCustomBlocksProvider(new OraxenCustomBlocksProvider()); plugin.getServer().getPluginManager().registerEvents(new OraxenListener(), plugin); + if (!registered) { + registered = true; + plugin.getProviders().registerCustomBlocksProvider(new OraxenCustomBlocksProvider()); + plugin.getBlockValues().registerKeyParser(new OraxenKeyParser(), BLOCK_ITEM_KEY, BLOCK_KEY); + } } private static class OraxenCustomBlocksProvider implements ICustomBlocksProvider { diff --git a/Hooks/PvpingSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_PvpingSpawners.java b/Hooks/PvpingSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_PvpingSpawners.java index 850b361952..2c68a334e1 100644 --- a/Hooks/PvpingSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_PvpingSpawners.java +++ b/Hooks/PvpingSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_PvpingSpawners.java @@ -19,19 +19,14 @@ public class SpawnersProvider_PvpingSpawners implements SpawnersProviderItemMetaSpawnerType { - private static boolean registered = false; - private final SuperiorSkyblockPlugin plugin; private final Main main; public SpawnersProvider_PvpingSpawners(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; main = (Main) Bukkit.getPluginManager().getPlugin("PvpingSpawners"); - if (!registered) { - Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); - registered = true; - Log.info("Using PvpingSpawners as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + Log.info("Using PvpingSpawners as a spawners provider."); } @Override diff --git a/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker.java b/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker.java index 03cce73fa0..fda745777b 100644 --- a/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker.java +++ b/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker.java @@ -25,17 +25,13 @@ public class SpawnersProvider_RoseStacker implements SpawnersProvider_AutoDetect private static final ReflectMethod GET_STACKED_ITEM_ENTITY_TYPE = new ReflectMethod<>(StackerUtils.class, "getStackedItemEntityType", ItemStack.class); - private static boolean registered = false; private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_RoseStacker(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registered) { - Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); - registered = true; - Log.info("Using RoseStacker as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + Log.info("Using RoseStacker as a spawners provider."); } @Override diff --git a/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java b/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java index 126b52219d..ea08d1340b 100644 --- a/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java +++ b/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_RoseStacker.java @@ -35,8 +35,6 @@ public class StackedBlocksProvider_RoseStacker implements StackedBlocksProvider_AutoDetect { - private static boolean registered = false; - private final SuperiorSkyblockPlugin plugin; private final LazyReference protectionManager = new LazyReference() { @Override @@ -47,12 +45,8 @@ protected RegionManagerService create() { public StackedBlocksProvider_RoseStacker(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - - if (!registered) { - Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); - registered = true; - Log.info("Using RoseStacker as a stacked-blocks provider."); - } + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + Log.info("Using RoseStacker as a stacked-blocks provider."); } @Override diff --git a/Hooks/SuperVanish/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_SuperVanish.java b/Hooks/SuperVanish/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_SuperVanish.java index 252adc4e1f..0f88082ad8 100644 --- a/Hooks/SuperVanish/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_SuperVanish.java +++ b/Hooks/SuperVanish/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_SuperVanish.java @@ -14,18 +14,11 @@ public class VanishProvider_SuperVanish implements VanishProvider, Listener { - private static boolean alreadyEnabled = false; - private final SuperiorSkyblockPlugin plugin; public VanishProvider_SuperVanish(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - - if (!alreadyEnabled) { - alreadyEnabled = true; - Bukkit.getPluginManager().registerEvents(this, plugin); - } - + Bukkit.getPluginManager().registerEvents(this, plugin); Log.info("Hooked into SuperVanish for support of vanish status of players."); } diff --git a/Hooks/TimbruSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_TimbruSilkSpawners.java b/Hooks/TimbruSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_TimbruSilkSpawners.java index be51ef9ff9..07d208118a 100644 --- a/Hooks/TimbruSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_TimbruSilkSpawners.java +++ b/Hooks/TimbruSilkSpawners/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_TimbruSilkSpawners.java @@ -13,17 +13,11 @@ public class SpawnersProvider_TimbruSilkSpawners implements SpawnersProvider_AutoDetect { - private static boolean registered = false; - private final SilkUtil silkUtil; public SpawnersProvider_TimbruSilkSpawners() { this.silkUtil = SilkUtil.hookIntoSilkSpanwers(); - - if (!registered) { - registered = true; - Log.info("Using SilkSpawners as a spawners provider."); - } + Log.info("Using SilkSpawners as a spawners provider."); } @Override diff --git a/Hooks/UltimateStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker.java b/Hooks/UltimateStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker.java index bf855f720a..8f05b32f5f 100644 --- a/Hooks/UltimateStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker.java +++ b/Hooks/UltimateStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker.java @@ -20,19 +20,14 @@ public class SpawnersProvider_UltimateStacker implements SpawnersProviderItemMetaSpawnerType { - private static boolean registered = false; - private final UltimateStacker instance = UltimateStacker.getInstance(); private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_UltimateStacker(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registered) { - Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); - registered = true; - Log.info("Using UltimateStacker as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + Log.info("Using UltimateStacker as a spawners provider."); } @Override diff --git a/Hooks/UltimateStacker3/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker3.java b/Hooks/UltimateStacker3/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker3.java index 3224be49ff..ebf8c608e9 100644 --- a/Hooks/UltimateStacker3/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker3.java +++ b/Hooks/UltimateStacker3/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker3.java @@ -20,17 +20,12 @@ public class SpawnersProvider_UltimateStacker3 implements SpawnersProviderItemMetaSpawnerType { - private static boolean registered = false; - private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_UltimateStacker3(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registered) { - Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); - registered = true; - Log.info("Using UltimateStacker as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + Log.info("Using UltimateStacker as a spawners provider."); } @Override diff --git a/Hooks/UltimateStacker4/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker4.java b/Hooks/UltimateStacker4/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker4.java index 0a279898ee..8a99240235 100644 --- a/Hooks/UltimateStacker4/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker4.java +++ b/Hooks/UltimateStacker4/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_UltimateStacker4.java @@ -20,17 +20,12 @@ public class SpawnersProvider_UltimateStacker4 implements SpawnersProviderItemMetaSpawnerType { - private static boolean registered = false; - private final SuperiorSkyblockPlugin plugin; public SpawnersProvider_UltimateStacker4(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registered) { - Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); - registered = true; - Log.info("Using UltimateStacker as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + Log.info("Using UltimateStacker as a spawners provider."); } @Override diff --git a/Hooks/VanishNoPacket/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_VanishNoPacket.java b/Hooks/VanishNoPacket/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_VanishNoPacket.java index 42767f9bbd..81d45b4b6d 100644 --- a/Hooks/VanishNoPacket/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_VanishNoPacket.java +++ b/Hooks/VanishNoPacket/src/main/java/com/bgsoftware/superiorskyblock/external/vanish/VanishProvider_VanishNoPacket.java @@ -15,20 +15,13 @@ public class VanishProvider_VanishNoPacket implements VanishProvider, Listener { - private static boolean alreadyEnabled = false; - private final SuperiorSkyblockPlugin plugin; private final VanishPlugin instance; public VanishProvider_VanishNoPacket(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; this.instance = JavaPlugin.getPlugin(VanishPlugin.class); - - if (!alreadyEnabled) { - alreadyEnabled = true; - Bukkit.getPluginManager().registerEvents(this, plugin); - } - + Bukkit.getPluginManager().registerEvents(this, plugin); Log.info("Hooked into VanishNoPacket for support of vanish status of players."); } diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java index 20c327df87..5c7fc37fff 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_WildStacker.java @@ -36,8 +36,6 @@ public class SpawnersProvider_WildStacker implements SpawnersProviderItemMetaSpawnerType, SpawnersSnapshotProvider { - private static boolean registered = false; - private final SuperiorSkyblockPlugin plugin; private final LazyReference protectionManager = new LazyReference() { @Override @@ -48,12 +46,9 @@ protected RegionManagerService create() { public SpawnersProvider_WildStacker(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - if (!registered) { - Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); - Bukkit.getPluginManager().registerEvents(new WildStackerListener(), plugin); - registered = true; - Log.info("Using WildStacker as a spawners provider."); - } + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + Bukkit.getPluginManager().registerEvents(new WildStackerListener(), plugin); + Log.info("Using WildStacker as a spawners provider."); } @Override diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java index 4d0201cffc..b0b24fc77e 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java @@ -45,10 +45,10 @@ public class StackedBlocksProvider_WildStacker implements StackedBlocksProvider_ public StackedBlocksProvider_WildStacker(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + if (!registered) { - Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); registered = true; - SuperiorSkyblockAPI.getBlockValues().registerKeyParser(new CustomKeyParser() { private final SystemManager systemManager = WildStackerAPI.getWildStacker().getSystemManager(); @@ -67,8 +67,9 @@ public boolean isCustomKey(Key key) { }, ConstantKeys.CAULDRON); - Log.info("Using WildStacker as a stacked-blocks provider."); } + + Log.info("Using WildStacker as a stacked-blocks provider."); } @Override From d6bd7e53d5b4de080637f02a6822979a235fd054 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 30 Dec 2025 22:45:36 +0200 Subject: [PATCH 458/600] Fix disabling modules and then reloading plugin does not remove their commands (#2810) --- .../module/ModulesManagerImpl.java | 56 +++++++++---------- .../container/DefaultModulesContainer.java | 5 +- .../module/container/ModulesContainer.java | 3 +- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java index 47c1d15a2a..6fd737f894 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/ModulesManagerImpl.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.lang.reflect.Constructor; import java.net.URLClassLoader; -import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.stream.Stream; @@ -155,21 +154,7 @@ public void enableModule(PluginModule pluginModule) { return; } - Listener[] listeners = pluginModule.getModuleListeners(plugin); - SuperiorCommand[] commands = pluginModule.getSuperiorCommands(plugin); - SuperiorCommand[] adminCommands = pluginModule.getSuperiorAdminCommands(plugin); - - if (listeners != null || commands != null || adminCommands != null) - this.modulesContainer.addModuleData(pluginModule, new ModuleData(listeners, commands, adminCommands)); - - if (listeners != null) - Arrays.stream(listeners).forEach(listener -> Bukkit.getPluginManager().registerEvents(listener, plugin)); - - if (commands != null) - Arrays.stream(commands).forEach(plugin.getCommands()::registerCommand); - - if (adminCommands != null) - Arrays.stream(adminCommands).forEach(plugin.getCommands()::registerAdminCommand); + startupModuleInternal(pluginModule); Log.info("Finished enabling the module ", pluginModule.getName(), " (Took ", System.currentTimeMillis() - startTime, "ms)"); @@ -204,22 +189,35 @@ private void reloadModuleInternal(PluginModule pluginModule) { Log.error(error, "Contact ", pluginModule.getAuthor(), " regarding this, this has nothing to do with the plugin."); } - // We register listeners again - ModuleData moduleData = this.modulesContainer.getModuleData(pluginModule); - if (moduleData == null) - return; + // We remove the old module data, as all listeners and commands were cleared due to the reload + this.modulesContainer.removeModuleData(pluginModule); + + // Register module data again + startupModuleInternal(pluginModule); + } - Listener[] listeners = moduleData.getListeners(); - if (listeners != null) - Arrays.stream(listeners).forEach(listener -> Bukkit.getPluginManager().registerEvents(listener, plugin)); + private void startupModuleInternal(PluginModule pluginModule) { + Listener[] listeners = pluginModule.getModuleListeners(plugin); + SuperiorCommand[] commands = pluginModule.getSuperiorCommands(plugin); + SuperiorCommand[] adminCommands = pluginModule.getSuperiorAdminCommands(plugin); - SuperiorCommand[] commands = moduleData.getCommands(); - if (commands != null) - Arrays.stream(commands).forEach(plugin.getCommands()::registerCommand); + if (listeners != null || commands != null || adminCommands != null) + this.modulesContainer.addModuleData(pluginModule, new ModuleData(listeners, commands, adminCommands)); - SuperiorCommand[] adminCommands = moduleData.getAdminCommands(); - if (adminCommands != null) - Arrays.stream(adminCommands).forEach(plugin.getCommands()::registerAdminCommand); + if (listeners != null) { + for (Listener listener : listeners) + Bukkit.getPluginManager().registerEvents(listener, plugin); + } + + if (commands != null) { + for (SuperiorCommand superiorCommand : commands) + plugin.getCommands().registerCommand(superiorCommand); + } + + if (adminCommands != null) { + for (SuperiorCommand superiorCommand : adminCommands) + plugin.getCommands().registerAdminCommand(superiorCommand); + } } public void loadModulesData(SuperiorSkyblockPlugin plugin) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java index 1d08ae740b..90e3426156 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java @@ -97,9 +97,8 @@ public void addModuleData(PluginModule pluginModule, ModuleData moduleData) { } @Override - @Nullable - public ModuleData getModuleData(PluginModule module) { - return this.modulesData.get(module); + public void removeModuleData(PluginModule module) { + this.modulesData.remove(module); } private static class ModuleInitializeDataImpl implements ModuleInitializeData { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/container/ModulesContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/module/container/ModulesContainer.java index dc1ea01254..e707d20aa6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/container/ModulesContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/container/ModulesContainer.java @@ -20,7 +20,6 @@ public interface ModulesContainer { void addModuleData(PluginModule pluginModule, ModuleData moduleData); - @Nullable - ModuleData getModuleData(PluginModule module); + void removeModuleData(PluginModule module); } From 418a667170e413bf6dde4196e70b236fa3dcc06b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 30 Dec 2025 22:59:10 +0200 Subject: [PATCH 459/600] Do not use Arrays#stream when not necessary --- .../container/DefaultModulesContainer.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java index 90e3426156..59b2d462e3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/container/DefaultModulesContainer.java @@ -2,6 +2,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.api.modules.ModuleInitializeData; import com.bgsoftware.superiorskyblock.api.modules.ModuleLogger; import com.bgsoftware.superiorskyblock.api.modules.PluginModule; @@ -12,9 +13,9 @@ import com.bgsoftware.superiorskyblock.module.logging.ModuleLoggerFileHandler; import com.google.common.base.Preconditions; import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; import java.io.File; -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Locale; @@ -65,14 +66,20 @@ public void unregisterModule(PluginModule pluginModule) { ModuleData moduleData = modulesData.remove(pluginModule); if (moduleData != null) { - if (moduleData.getListeners() != null) - Arrays.stream(moduleData.getListeners()).forEach(HandlerList::unregisterAll); - - if (moduleData.getCommands() != null) - Arrays.stream(moduleData.getCommands()).forEach(plugin.getCommands()::unregisterCommand); - - if (moduleData.getAdminCommands() != null) - Arrays.stream(moduleData.getAdminCommands()).forEach(plugin.getCommands()::unregisterAdminCommand); + if (moduleData.getListeners() != null) { + for (Listener listener : moduleData.getListeners()) + HandlerList.unregisterAll(listener); + } + + if (moduleData.getCommands() != null) { + for (SuperiorCommand superiorCommand : moduleData.getCommands()) + plugin.getCommands().unregisterCommand(superiorCommand); + } + + if (moduleData.getAdminCommands() != null) { + for (SuperiorCommand superiorCommand : moduleData.getAdminCommands()) + plugin.getCommands().unregisterAdminCommand(superiorCommand); + } } pluginModule.disableModule(); From 6802ad2e91d040c8a8e9181e6455d3671bde250d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 30 Dec 2025 23:40:34 +0200 Subject: [PATCH 460/600] Fixed detection of grown chorus flowers and plants (#2816) --- .../core/key/ConstantKeys.java | 3 +++ .../listener/BlockChangesListener.java | 24 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java index f7b9509f4b..4e8d7fe7d8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java @@ -18,6 +18,9 @@ public class ConstantKeys { public static final Key CARVED_PUMPKIN = Keys.of(EnumHelper.getEnum(Material.class, "CARVED_PUMPKIN", "PUMPKIN")); public static final Key CAULDRON = Keys.of(Material.CAULDRON); public static final Key CHEST = Keys.of(Material.CHEST); + @Nullable + public static final Key CHORUS_PLANT = Optional.ofNullable(EnumHelper.getEnum(Material.class, "CHORUS_PLANT")) + .map(Keys::of).orElse(null); public static final Key COBBLESTONE = Keys.of(Material.COBBLESTONE); public static final Key COMMAND_BLOCK = Keys.of(EnumHelper.getEnum(Material.class, "COMMAND_BLOCK", "COMMAND")); public static final Key EGG_MOB_SPAWNER = Keys.ofSpawner("EGG"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index 3f05e4bba5..a159336e1e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -69,6 +69,7 @@ public class BlockChangesListener extends AbstractGameEventListener { } private final Collection alreadySpongeAbosrbCalled = AutoRemovalCollection.newArrayList(5L * 50, TimeUnit.MILLISECONDS); + private final Collection alreadyChorusFlowerTracked = AutoRemovalCollection.newArrayList(1L * 50, TimeUnit.MILLISECONDS); private final LazyReference worldRecordService = new LazyReference() { @Override @@ -179,12 +180,33 @@ private void onBlockSpread(GameEvent e) { if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; + Block source = e.getArgs().source; BlockState newState = e.getArgs().newState; + + Key spreadBlock = null; + + if (newState.getType() == CHORUS_FLOWER && source.getType() == CHORUS_FLOWER) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location spreadBlockLocation = source.getLocation(wrapper.getHandle()); + // When a chorus flower grows, it is replaced with a flower plant and multiple new flowers can grow. + // Therefore, we want to track a plant one time instead of a new flower. + if (!alreadyChorusFlowerTracked.contains(spreadBlockLocation)) { + spreadBlock = ConstantKeys.CHORUS_PLANT; + alreadyChorusFlowerTracked.add(spreadBlockLocation.clone()); + } + } + } + + if (spreadBlock == null) { + spreadBlock = Keys.of(newState); + } + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockPlace(Keys.of(newState), + this.worldRecordService.get().recordBlockPlace(spreadBlock, block.getLocation(wrapper.getHandle()), 1, block.getState(), REGULAR_RECORD_FLAGS); + } } From 3a2438db6b65ea27f2b60aeff7852f5a4ccac5d3 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 2 Jan 2026 08:33:34 +0100 Subject: [PATCH 461/600] Fix ratings formatting in the ratings menu title (#2825) --- .../superiorskyblock/core/menu/impl/MenuIslandRatings.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java index 88a6a12d5c..78ecbdafcf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandRatings.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; @@ -71,7 +72,7 @@ public Island getIsland() { @Override public String replaceTitle(String title) { - return title.replace("{0}", String.valueOf(island.getTotalRating())); + return title.replace("{0}", Formatters.NUMBER_FORMATTER.format(island.getTotalRating())); } @Override From ea0671a2696d8b12bfa176cc072c96907f7e1a40 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 2 Jan 2026 15:06:17 +0200 Subject: [PATCH 462/600] Fixed bamboo sapling are not replaced with a regular sapling after they grow (#2816) --- .../superiorskyblock/core/key/ConstantKeys.java | 3 +++ .../listener/BlockChangesListener.java | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java index 4e8d7fe7d8..2283010663 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java @@ -13,6 +13,9 @@ public class ConstantKeys { public static final Key AIR = Keys.of(Material.AIR); @Nullable + public static final Key BAMBOO = Optional.ofNullable(EnumHelper.getEnum(Material.class, "BAMBOO")) + .map(Keys::of).orElse(null); + @Nullable public static final Key BASALT = Optional.ofNullable(EnumHelper.getEnum(Material.class, "BASALT")) .map(Keys::of).orElse(null); public static final Key CARVED_PUMPKIN = Keys.of(EnumHelper.getEnum(Material.class, "CARVED_PUMPKIN", "PUMPKIN")); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index a159336e1e..ff47c29edd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -53,6 +53,10 @@ public class BlockChangesListener extends AbstractGameEventListener { @Nullable private static final Material POINTED_DRIPSTONE = EnumHelper.getEnum(Material.class, "POINTED_DRIPSTONE"); @Nullable + private static final Material BAMBOO = EnumHelper.getEnum(Material.class, "BAMBOO"); + @Nullable + private static final Material BAMBOO_SAPLING = EnumHelper.getEnum(Material.class, "BAMBOO_SAPLING"); + @Nullable private static final CreatureSpawnEvent.SpawnReason BUILD_COPPERGOLEM = EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "BUILD_COPPERGOLEM"); @WorldRecordFlags @@ -183,10 +187,12 @@ private void onBlockSpread(GameEvent e) { Block source = e.getArgs().source; BlockState newState = e.getArgs().newState; + Material newStateType = newState.getType(); + Material sourceType = source.getType(); Key spreadBlock = null; - if (newState.getType() == CHORUS_FLOWER && source.getType() == CHORUS_FLOWER) { + if (newStateType == CHORUS_FLOWER && sourceType == CHORUS_FLOWER) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location spreadBlockLocation = source.getLocation(wrapper.getHandle()); // When a chorus flower grows, it is replaced with a flower plant and multiple new flowers can grow. @@ -196,6 +202,15 @@ private void onBlockSpread(GameEvent e) { alreadyChorusFlowerTracked.add(spreadBlockLocation.clone()); } } + } else if (newStateType == BAMBOO && sourceType == BAMBOO_SAPLING) { + // Bamboo saplings are turned into a bamboo. + // We want to record an additional block place for that sapling. + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + this.worldRecordService.get().recordBlockPlace(ConstantKeys.BAMBOO, + block.getLocation(wrapper.getHandle()), + 1, source.getState(), REGULAR_RECORD_FLAGS); + + } } if (spreadBlock == null) { From 910bd207b3224b82d55c9258594022c90b1eb952 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 2 Jan 2026 15:18:06 +0200 Subject: [PATCH 463/600] Do not record block break for dripstone when hit by wind charge (#2816) --- .../superiorskyblock/listener/BlockChangesListener.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index ff47c29edd..a199ce27c1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -51,8 +51,6 @@ public class BlockChangesListener extends AbstractGameEventListener { @Nullable private static final Material CHORUS_FLOWER = EnumHelper.getEnum(Material.class, "CHORUS_FLOWER"); @Nullable - private static final Material POINTED_DRIPSTONE = EnumHelper.getEnum(Material.class, "POINTED_DRIPSTONE"); - @Nullable private static final Material BAMBOO = EnumHelper.getEnum(Material.class, "BAMBOO"); @Nullable private static final Material BAMBOO_SAPLING = EnumHelper.getEnum(Material.class, "BAMBOO_SAPLING"); @@ -499,7 +497,7 @@ private void onEntityExplode(GameEvent e) { e.getArgs().blocks.forEach(block -> { Material blockType = block.getType(); // Soft explosions only break chorus flowers and pointed drip-stones - if (e.getArgs().isSoftExplosion && blockType != CHORUS_FLOWER && blockType != POINTED_DRIPSTONE) + if (e.getArgs().isSoftExplosion && blockType != CHORUS_FLOWER) return; Key blockKey = Keys.of(block); From fccd108dee79692303daaa0b8c16da9116b4bc4b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 2 Jan 2026 15:33:56 +0200 Subject: [PATCH 464/600] Do not listen to BlockDestroyEvent as it causes multiple block breaks on Paper (#2816) --- .../listener/BlockChangesListener.java | 12 ---- .../listener/BukkitEventsListener.java | 19 ------ .../platform/event/GameEventType.java | 62 ++++++++++++++++++- .../platform/event/args/GameEventArgs.java | 4 -- 4 files changed, 60 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index a199ce27c1..68c9d996f7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -22,7 +22,6 @@ import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.Material; @@ -323,16 +322,6 @@ private void onBlockBreak(GameEvent e) { this.worldRecordService.get().recordBlockBreak(block, ALL_RECORD_FLAGS); } - private void onBlockDestroy(GameEvent e) { - Block block = e.getArgs().block; - - // We do not care about spawn island, and therefore only island worlds are relevant. - if (!plugin.getGrid().isIslandsWorld(block.getWorld())) - return; - - this.worldRecordService.get().recordBlockBreak(block, WorldRecordFlags.DIRTY_CHUNKS); - } - private void onBucketFill(GameEvent e) { Block clickedBlock = e.getArgs().clickedBlock; @@ -560,7 +549,6 @@ private void registerListeners() { registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.MONITOR, this::onSpawnerChange); registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.MONITOR, this::onEntityChangeBlock); registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.MONITOR, this::onBlockBreak); - registerCallback(GameEventType.BLOCK_DESTROY_EVENT, GameEventPriority.MONITOR, this::onBlockDestroy); registerCallback(GameEventType.PLAYER_FILL_BUCKET_EVENT, GameEventPriority.MONITOR, this::onBucketFill); registerCallback(GameEventType.ENTITY_SPAWN_EVENT, GameEventPriority.MONITOR, this::onEntitySpawn); registerCallback(GameEventType.PISTON_EXTEND_EVENT, GameEventPriority.MONITOR, this::onPistonExtend); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index a45476fdae..359c5544fb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -199,12 +199,6 @@ public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { } catch (ClassNotFoundException ignored) { } - try { - Class.forName("com.destroystokyo.paper.event.block.BlockDestroyEvent"); - createEventListener(GameEventType.BLOCK_DESTROY_EVENT, com.destroystokyo.paper.event.block.BlockDestroyEvent.class, new BlockDestroyEventFunction()); - } catch (ClassNotFoundException ignored) { - } - try { Class.forName("com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent"); createEventListener(GameEventType.ENTITY_DEATH_EVENT, com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent.class, new EntityRemoveFromWorldEventFunction()); @@ -893,19 +887,6 @@ public GameEvent execute(GameEventType { - - @Override - public GameEvent execute(GameEventType eventType, GameEventPriority priority, com.destroystokyo.paper.event.block.BlockDestroyEvent e) { - if (e.getNewState().getMaterial() != Material.AIR) - return null; - - GameEventArgs.BlockDestroyEvent blockDestroyEvent = new GameEventArgs.BlockDestroyEvent(); - blockDestroyEvent.block = e.getBlock(); - return eventType.createEvent(blockDestroyEvent); - } - } - private class EntityRemoveFromWorldEventFunction implements GameEventCreator { @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java index 84c4b5354d..0a8c5b1d36 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java @@ -8,7 +8,66 @@ import java.util.LinkedList; import java.util.List; -import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.*; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockBreakEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockBurnEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockDispenseEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockFadeEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockFormEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockFromToEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockGrowEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockIgniteEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockPhysicsEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockPlaceEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockRedstoneEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockSpreadEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ChunkLoadEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ChunkUnloadEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityBlockFormEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityChangeBlockEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityCollisionEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityDamageEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityDeathEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityEnterPortalEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityExplodeEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityMoveEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityPortalEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityRideEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntitySpawnEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityTargetEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityTeleportEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.HangingBreakEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.HangingPlaceEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.InventoryClickEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.InventoryCloseEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.InventoryOpenEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.LeavesDecayEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PistonExtendEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PistonRetractEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerChangedWorldEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerChatEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerCommandEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerDropItemEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerEmptyBucketEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerFillBucketEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerGamemodeChangeEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerInteractEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerItemConsumeEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerJoinEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerLeashEntityEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerLoginEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerPickupArrowEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerPickupItemEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerQuitEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerRespawnEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerShearEntityEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.PlayerUnleashEntityEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ProjectileHitEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ProjectileLaunchEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.RaidTriggerEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.SignChangeEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.SpongeAbsorbEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.StructureGrowEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.WorldUnloadEvent; public class GameEventType extends EventType> { @@ -17,7 +76,6 @@ public class GameEventType extends EventType BLOCK_BREAK_EVENT = register(BlockBreakEvent.class); public static final GameEventType BLOCK_BURN_EVENT = register(BlockBurnEvent.class); - public static final GameEventType BLOCK_DESTROY_EVENT = register(BlockDestroyEvent.class); public static final GameEventType BLOCK_DISPENSE_EVENT = register(BlockDispenseEvent.class); public static final GameEventType BLOCK_FADE_EVENT = register(BlockFadeEvent.class); public static final GameEventType BLOCK_FORM_EVENT = register(BlockFormEvent.class); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java index dcac9b0e60..d0541a2160 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java @@ -213,10 +213,6 @@ public static class BlockBreakEvent extends BlockEvent { } - public static class BlockDestroyEvent extends BlockEvent { - - } - public static class EntityDeathEvent extends EntityEvent { } From d233b54e857039de263deeb8ba78ec75ebcf1349 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 2 Jan 2026 15:34:42 +0200 Subject: [PATCH 465/600] Fixed chorus flower detected twice (EntityChangeBlockEvent and ProjectileHitEvent) when hit by a projectile (#2816) --- .../listener/BlockChangesListener.java | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index 68c9d996f7..c41daa2d4d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -502,21 +502,6 @@ private void onEntityExplode(GameEvent e) { } } - private void onChorusHit(GameEvent e) { - Entity entity = e.getArgs().entity; - - // We do not care about spawn island, and therefore only island worlds are relevant. - if (!plugin.getGrid().isIslandsWorld(entity.getWorld())) - return; - - BukkitEntities.getPlayerSource(entity).ifPresent(shooter -> { - Block hitBlock = e.getArgs().hitBlock; - if (hitBlock != null && hitBlock.getType() == CHORUS_FLOWER) { - this.worldRecordService.get().recordBlockBreak(hitBlock, 1, REGULAR_RECORD_FLAGS); - } - }); - } - private void onSpongeAbsorb(GameEvent e) { Block block = e.getArgs().block; @@ -556,7 +541,6 @@ private void registerListeners() { registerCallback(GameEventType.BLOCK_FROM_TO_EVENT, GameEventPriority.MONITOR, this::onBlockFromTo); registerCallback(GameEventType.BLOCK_FADE_EVENT, GameEventPriority.MONITOR, this::onBlockFade); registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.MONITOR, this::onEntityExplode); - registerCallback(GameEventType.PROJECTILE_HIT_EVENT, GameEventPriority.MONITOR, this::onChorusHit); registerCallback(GameEventType.SPONGE_ABSORB_EVENT, GameEventPriority.MONITOR, this::onSpongeAbsorb); } From f723f00c9da5ad8953430038ae27de9d204544b6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 2 Jan 2026 21:49:17 +0200 Subject: [PATCH 466/600] Better detection to block changes in the world due to game events (#2816) --- .../api/hooks/WorldsProvider.java | 11 +++ .../hooks/listener/IWorldLoadListener.java | 22 ++++++ .../api/hooks/world/WorldLoadFlags.java | 31 ++++++++ .../nms/v1_12_R1/NMSWorldImpl.java | 11 +++ .../nms/v1_16_R3/NMSWorldImpl.java | 14 ++++ .../world/BlockTickListServerTracker.java | 68 ++++++++++++++++++ .../nms/v1_17/NMSWorldImpl.java | 15 +++- .../world/BlockServerTickListTracker.java | 64 +++++++++++++++++ .../nms/v1_18/NMSWorldImpl.java | 24 ++++++- .../v1_18/world/BlockLevelTicksTracker.java | 53 ++++++++++++++ .../nms/v1_19/NMSWorldImpl.java | 22 ++++++ .../v1_19/world/BlockLevelTicksTracker.java | 69 ++++++++++++++++++ .../CollectingNeighborUpdaterTracker.java | 43 ++++++++++++ .../nms/v1_20_3/NMSWorldImpl.java | 20 ++++++ .../v1_20_3/world/BlockLevelTicksTracker.java | 69 ++++++++++++++++++ .../CollectingNeighborUpdaterTracker.java | 43 ++++++++++++ .../nms/v1_20_4/NMSWorldImpl.java | 20 ++++++ .../v1_20_4/world/BlockLevelTicksTracker.java | 69 ++++++++++++++++++ .../CollectingNeighborUpdaterTracker.java | 43 ++++++++++++ .../nms/v1_21/NMSWorldImpl.java | 20 ++++++ .../v1_21/world/BlockLevelTicksTracker.java | 70 +++++++++++++++++++ .../CollectingNeighborUpdaterTracker.java | 43 ++++++++++++ .../nms/v1_21_10/NMSWorldImpl.java | 21 +++++- .../world/BlockLevelTicksTracker.java | 45 ++++++++++++ .../CollectingNeighborUpdaterTracker.java | 44 ++++++++++++ .../nms/v1_21_3/NMSWorldImpl.java | 20 ++++++ .../v1_21_3/world/BlockLevelTicksTracker.java | 69 ++++++++++++++++++ .../CollectingNeighborUpdaterTracker.java | 43 ++++++++++++ .../nms/v1_21_4/NMSWorldImpl.java | 20 ++++++ .../v1_21_4/world/BlockLevelTicksTracker.java | 69 ++++++++++++++++++ .../CollectingNeighborUpdaterTracker.java | 44 ++++++++++++ .../nms/v1_21_5/NMSWorldImpl.java | 20 ++++++ .../v1_21_5/world/BlockLevelTicksTracker.java | 45 ++++++++++++ .../CollectingNeighborUpdaterTracker.java | 44 ++++++++++++ .../nms/v1_21_7/NMSWorldImpl.java | 20 ++++++ .../v1_21_7/world/BlockLevelTicksTracker.java | 45 ++++++++++++ .../CollectingNeighborUpdaterTracker.java | 44 ++++++++++++ .../nms/v1_21_9/NMSWorldImpl.java | 17 +++++ .../v1_21_9/world/BlockLevelTicksTracker.java | 45 ++++++++++++ .../CollectingNeighborUpdaterTracker.java | 44 ++++++++++++ .../nms/v1_8_R3/NMSWorldImpl.java | 11 +++ .../button/impl/CountsPagedObjectButton.java | 2 + .../external/ProvidersManagerImpl.java | 11 ++- .../worlds/DefaultWorldLoadListener.java | 49 +++++++++++++ .../worlds/WorldsProvider_Default.java | 38 +++++----- .../listener/BlockChangesListener.java | 46 +++++++----- .../superiorskyblock/nms/NMSWorld.java | 2 + .../platform/event/GameEventType.java | 2 + .../platform/event/args/GameEventArgs.java | 6 ++ 49 files changed, 1672 insertions(+), 38 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/listener/IWorldLoadListener.java create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/world/WorldLoadFlags.java create mode 100644 NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockTickListServerTracker.java create mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockServerTickListTracker.java create mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockLevelTicksTracker.java create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockLevelTicksTracker.java create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/CollectingNeighborUpdaterTracker.java create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockLevelTicksTracker.java create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/CollectingNeighborUpdaterTracker.java create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockLevelTicksTracker.java create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/CollectingNeighborUpdaterTracker.java create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockLevelTicksTracker.java create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/CollectingNeighborUpdaterTracker.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/BlockLevelTicksTracker.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/CollectingNeighborUpdaterTracker.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockLevelTicksTracker.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/CollectingNeighborUpdaterTracker.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockLevelTicksTracker.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/CollectingNeighborUpdaterTracker.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockLevelTicksTracker.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/CollectingNeighborUpdaterTracker.java create mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockLevelTicksTracker.java create mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/CollectingNeighborUpdaterTracker.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/BlockLevelTicksTracker.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/CollectingNeighborUpdaterTracker.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/external/worlds/DefaultWorldLoadListener.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/WorldsProvider.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/WorldsProvider.java index 95bc9bbade..c1f1a4de45 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/WorldsProvider.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/WorldsProvider.java @@ -2,6 +2,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; +import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; @@ -154,4 +155,14 @@ default boolean isEndUnlocked() { */ boolean isDimensionUnlocked(Dimension dimension); + /** + * Add a listener to when worlds are loaded by the provider. + * This is called by the plugin to listen to changes and fix things within island worlds. + * + * @param worldLoadListener The callback to listener. + */ + default void addWorldLoadListener(IWorldLoadListener worldLoadListener) { + throw new UnsupportedOperationException("This operation is not supported by this WorldProvider."); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/listener/IWorldLoadListener.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/listener/IWorldLoadListener.java new file mode 100644 index 0000000000..383c7b63b1 --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/listener/IWorldLoadListener.java @@ -0,0 +1,22 @@ +package com.bgsoftware.superiorskyblock.api.hooks.listener; + +import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; +import com.bgsoftware.superiorskyblock.api.hooks.world.WorldLoadFlags; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import org.bukkit.World; + +/** + * Listener used for {@link WorldsProvider#addWorldLoadListener(IWorldLoadListener)} + */ +public interface IWorldLoadListener { + + /** + * The method to be called when a world is loaded. + * + * @param world The world that was loaded. + * @param worldDimension The dimension of the world. + * @param flags Flags to what the listener can do. More info at {@link WorldLoadFlags} + */ + void onWorldLoad(World world, Dimension worldDimension, @WorldLoadFlags int flags); + +} diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/world/WorldLoadFlags.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/world/WorldLoadFlags.java new file mode 100644 index 0000000000..fd28375a75 --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/hooks/world/WorldLoadFlags.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.api.hooks.world; + +import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener; + +/** + * The integer value element annotated with {@link WorldLoadFlags} represents flags related to what to do + * when a world is loaded. It is mainly used within the default {@link IWorldLoadListener} interface of the plugin. + */ +public @interface WorldLoadFlags { + + /** + * Enable dragon fights for end worlds. + */ + int END_DRAGON_FIGHT = 1 << 0; + + /** + * Remove the anti-xray world patches. + */ + int REMOVE_ANTI_XRAY = 1 << 1; + + /** + * Update the ocean level of the world to the configured islands-height. + */ + int UPDATE_OCEAN_LEVEL = 1 << 2; + + /** + * Make the plugin listen to block neighbor changes and self-changing blocks. + */ + int LISTEN_BLOCK_CHANGES = 1 << 3; + +} diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java index eb382ceac7..6559f82fda 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import com.bgsoftware.superiorskyblock.nms.NMSWorld; @@ -58,6 +59,8 @@ public class NMSWorldImpl implements NMSWorld { private static final ReflectField MOB_SPAWNER_ABSTRACT = new ReflectField( TileEntityMobSpawner.class, MobSpawnerAbstract.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static boolean alreadyWarned = false; + private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { @@ -343,4 +346,12 @@ public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } + @Override + public void listenBlockStateChanges(org.bukkit.World world) { + if (!alreadyWarned) { + Log.warn("This version is old and you may experience issues with block changes detection"); + alreadyWarned = true; + } + } + } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java index 2b36cbee07..adf738a68d 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import com.bgsoftware.superiorskyblock.nms.NMSWorld; @@ -18,6 +19,7 @@ import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.spawners.TileEntityMobSpawnerNotifier; +import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.BlockTickListServerTracker; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.world.WorldEditSessionImpl; @@ -67,6 +69,8 @@ public class NMSWorldImpl implements NMSWorld { private static final ReflectField CHUNK_PACKET_BLOCK_CONTROLLER = new ReflectField<>(World.class, Object.class, "chunkPacketBlockController").removeFinal(); + private static boolean alreadyWarned = false; + private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { @@ -343,4 +347,14 @@ public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } + @Override + public void listenBlockStateChanges(org.bukkit.World world) { + WorldServer worldServer = ((CraftWorld) world).getHandle(); + BlockTickListServerTracker.listenForTicks(worldServer); + if (!alreadyWarned) { + Log.warn("This version is old and you may experience issues with block changes detection"); + alreadyWarned = true; + } + } + } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockTickListServerTracker.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockTickListServerTracker.java new file mode 100644 index 0000000000..78203cbd23 --- /dev/null +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockTickListServerTracker.java @@ -0,0 +1,68 @@ +package com.bgsoftware.superiorskyblock.nms.v1_16_R3.world; + +import com.bgsoftware.common.reflection.ClassInfo; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.server.v1_16_R3.Block; +import net.minecraft.server.v1_16_R3.BlockPosition; +import net.minecraft.server.v1_16_R3.IBlockData; +import net.minecraft.server.v1_16_R3.NextTickListEntry; +import net.minecraft.server.v1_16_R3.TickListServer; +import net.minecraft.server.v1_16_R3.WorldServer; +import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlock; +import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlockState; + +import java.lang.reflect.Modifier; +import java.util.function.Consumer; + +public class BlockTickListServerTracker { + + private static final ReflectField>> TICK_FUNCTION_SPIGOT = + new ReflectField>>(TickListServer.class, + Consumer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField>> TICK_FUNCTION_PAPER = + new ReflectField>>( + new ClassInfo("com.destroystokyo.paper.server.ticklist.PaperTickList", ClassInfo.PackageType.UNKNOWN), + Consumer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private BlockTickListServerTracker() { + + } + + public static void listenForTicks(WorldServer worldServer) { + TickListServer blockTicks = worldServer.getBlockTickList(); + if (TICK_FUNCTION_PAPER.isValid()) { + TICK_FUNCTION_PAPER.set(blockTicks, nextTickData -> tick(worldServer, nextTickData)); + } else { + TICK_FUNCTION_SPIGOT.set(blockTicks, nextTickData -> tick(worldServer, nextTickData)); + } + } + + private static void tick(WorldServer worldServer, NextTickListEntry nextTickData) { + BlockPosition blockPosition = nextTickData.getPosition(); + IBlockData blockState = worldServer.getType(blockPosition); + if (blockState.a(nextTickData.b())) { + IBlockData oldData = worldServer.getType(blockPosition); + blockState.a(worldServer, blockPosition, worldServer.random); + IBlockData newData = worldServer.getType(blockPosition); + if (oldData.getBlock() != newData.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(worldServer, blockPosition); + CraftBlockState oldState = CraftBlockState.getBlockState(worldServer, blockPosition, 3); + oldState.setData(oldData); + blockUpdateShapeEvent.oldState = oldState; + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + } + +} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java index 0257ff3f92..201642a2fc 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSWorldImpl.java @@ -2,8 +2,9 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.nms.v1_17.NMSUtils; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.nms.v1_17.vibration.IslandSculkSensorBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_17.world.BlockServerTickListTracker; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; @@ -14,11 +15,14 @@ import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSWorld { + private static boolean alreadyWarned = false; + public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @@ -65,5 +69,14 @@ public void replaceSculkSensorListener(Island island, Location location) { serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity)); } + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + BlockServerTickListTracker.listenForTicks(serverLevel); + if (!alreadyWarned) { + Log.warn("This version is old and you may experience issues with block changes detection"); + alreadyWarned = true; + } + } } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockServerTickListTracker.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockServerTickListTracker.java new file mode 100644 index 0000000000..5bd684a383 --- /dev/null +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockServerTickListTracker.java @@ -0,0 +1,64 @@ +package com.bgsoftware.superiorskyblock.nms.v1_17.world; + +import com.bgsoftware.common.reflection.ClassInfo; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ServerTickList; +import net.minecraft.world.level.TickNextTickData; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; +import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlockStates; + +import java.lang.reflect.Modifier; +import java.util.function.Consumer; + +public class BlockServerTickListTracker { + + private static final ReflectField>> TICK_FUNCTION_SPIGOT = + new ReflectField>>(ServerTickList.class, + Consumer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField>> TICK_FUNCTION_PAPER = + new ReflectField>>( + new ClassInfo("com.destroystokyo.paper.server.ticklist.PaperTickList", ClassInfo.PackageType.UNKNOWN), + Consumer.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private BlockServerTickListTracker() { + + } + + public static void listenForTicks(ServerLevel serverLevel) { + ServerTickList blockTicks = serverLevel.getBlockTicks(); + if (TICK_FUNCTION_PAPER.isValid()) { + TICK_FUNCTION_PAPER.set(blockTicks, nextTickData -> tick(serverLevel, nextTickData)); + } else { + TICK_FUNCTION_SPIGOT.set(blockTicks, nextTickData -> tick(serverLevel, nextTickData)); + } + } + + private static void tick(ServerLevel serverLevel, TickNextTickData nextTickData) { + BlockState blockState = serverLevel.getBlockState(nextTickData.pos); + if (blockState.is(nextTickData.getType())) { + BlockState oldState = serverLevel.getBlockState(nextTickData.pos); + blockState.tick(serverLevel, nextTickData.pos, serverLevel.random); + BlockState newState = serverLevel.getBlockState(nextTickData.pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(serverLevel, nextTickData.pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(nextTickData.pos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + } + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java index 26a4a9fc8e..bbb2f6405d 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSWorldImpl.java @@ -1,11 +1,14 @@ package com.bgsoftware.superiorskyblock.nms.v1_18; +import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.nms.v1_18.NMSUtils; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.nms.v1_18.vibration.IslandSculkSensorBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_18.world.BlockLevelTicksTracker; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.border.WorldBorder; @@ -13,12 +16,21 @@ import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.craftbukkit.v1_18_R2.CraftWorld; import org.bukkit.craftbukkit.v1_18_R2.generator.CustomChunkGenerator; +import java.lang.reflect.Modifier; + public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSWorld { + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + + private static boolean alreadyWarned = false; + public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @@ -65,5 +77,15 @@ public void replaceSculkSensorListener(Island island, Location location) { serverLevel.setBlockEntity(new IslandSculkSensorBlockEntity(island, sculkSensorBlockEntity)); } + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + if (!alreadyWarned) { + Log.warn("This version is old and you may experience issues with block changes detection"); + alreadyWarned = true; + } + } + } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockLevelTicksTracker.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..428ac531bf --- /dev/null +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockLevelTicksTracker.java @@ -0,0 +1,53 @@ +package com.bgsoftware.superiorskyblock.nms.v1_18.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; +import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlockStates; + +import java.util.function.BiConsumer; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(chunkPos -> isPositionTickingWithEntitiesLoaded(serverLevel, chunkPos), + serverLevel.getProfilerSupplier()); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + ticker.accept(blockPos, block); + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(blockPos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } + + private static boolean isPositionTickingWithEntitiesLoaded(ServerLevel serverLevel, long chunkPos) { + ChunkHolder chunkHolder = serverLevel.chunkSource.chunkMap.getVisibleChunkIfPresent(chunkPos); + return chunkHolder != null && chunkHolder.isTickingReady() && serverLevel.areEntitiesLoaded(chunkPos); + } + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java index 5bf801071a..903aef6958 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSWorldImpl.java @@ -1,12 +1,17 @@ package com.bgsoftware.superiorskyblock.nms.v1_19; +import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_19.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_19.vibration.IslandSculkSensorBlockEntity; +import com.bgsoftware.superiorskyblock.nms.v1_19.world.BlockLevelTicksTracker; +import com.bgsoftware.superiorskyblock.nms.v1_19.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.border.WorldBorder; @@ -14,14 +19,24 @@ import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.redstone.NeighborUpdater; +import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; import org.bukkit.craftbukkit.v1_19_R3.CraftWorld; import org.bukkit.craftbukkit.v1_19_R3.generator.CustomChunkGenerator; +import java.lang.reflect.Modifier; + public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSWorld { + private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( + Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @@ -78,4 +93,11 @@ else if (sign instanceof WallHangingSign) return super.getSignType(sign); } + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + } + } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockLevelTicksTracker.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..14a796df5c --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockLevelTicksTracker.java @@ -0,0 +1,69 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; +import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockStates; + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final BiFunction IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION = + initializePositionTickingWithEntitiesLoaded(); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos), + serverLevel.getProfilerSupplier()); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + ticker.accept(blockPos, block); + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getUnplacedBlockState(this.serverLevel, blockPos, oldState); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } + + private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) { + return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos); + } + + private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) { + io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder = serverLevel.chunkTaskScheduler.chunkHolderManager.getChunkHolder(chunkPos); + return chunkHolder != null && chunkHolder.isTickingReady(); + } + + private static BiFunction initializePositionTickingWithEntitiesLoaded() { + try { + Class.forName("io.papermc.paper.chunk.system.scheduling.NewChunkHolder"); + return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper; + } catch (Throwable error) { + return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot; + } + } + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/CollectingNeighborUpdaterTracker.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/CollectingNeighborUpdaterTracker.java new file mode 100644 index 0000000000..ec0f7a0070 --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/CollectingNeighborUpdaterTracker.java @@ -0,0 +1,43 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; +import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockStates; + +public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Level level; + + public CollectingNeighborUpdaterTracker(Level level) { + super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); + this.level = level; + } + + @Override + public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { + BlockState oldState = this.level.getBlockState(pos); + super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); + BlockState newState = this.level.getBlockState(pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getUnplacedBlockState(this.level, pos, oldState); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java index e06a38c883..3b3cd8ce33 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSWorldImpl.java @@ -5,8 +5,13 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_20_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_3.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.BlockLevelTicksTracker; +import com.bgsoftware.superiorskyblock.nms.v1_20_3.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.border.WorldBorder; @@ -15,9 +20,13 @@ import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.redstone.NeighborUpdater; +import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -26,6 +35,10 @@ public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.Ab private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( + Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -80,4 +93,11 @@ else if (sign instanceof WallHangingSign) return super.getSignType(sign); } + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + } + } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockLevelTicksTracker.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..8b42d22288 --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockLevelTicksTracker.java @@ -0,0 +1,69 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockStates; + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final BiFunction IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION = + initializePositionTickingWithEntitiesLoaded(); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos), + serverLevel.getProfilerSupplier()); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + ticker.accept(blockPos, block); + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getUnplacedBlockState(this.serverLevel, blockPos, oldState); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } + + private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) { + return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos); + } + + private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) { + io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder = serverLevel.chunkTaskScheduler.chunkHolderManager.getChunkHolder(chunkPos); + return chunkHolder != null && chunkHolder.isTickingReady(); + } + + private static BiFunction initializePositionTickingWithEntitiesLoaded() { + try { + Class.forName("io.papermc.paper.chunk.system.scheduling.NewChunkHolder"); + return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper; + } catch (Throwable error) { + return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot; + } + } + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/CollectingNeighborUpdaterTracker.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/CollectingNeighborUpdaterTracker.java new file mode 100644 index 0000000000..9293b9a594 --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/CollectingNeighborUpdaterTracker.java @@ -0,0 +1,43 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockStates; + +public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Level level; + + public CollectingNeighborUpdaterTracker(Level level) { + super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); + this.level = level; + } + + @Override + public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { + BlockState oldState = this.level.getBlockState(pos); + super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); + BlockState newState = this.level.getBlockState(pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getUnplacedBlockState(this.level, pos, oldState); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java index 94c5f6f200..5565ceeeb4 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSWorldImpl.java @@ -5,8 +5,13 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.nms.v1_20_4.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_20_4.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.BlockLevelTicksTracker; +import com.bgsoftware.superiorskyblock.nms.v1_20_4.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; import net.minecraft.world.level.border.WorldBorder; @@ -15,9 +20,13 @@ import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.redstone.NeighborUpdater; +import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -26,6 +35,10 @@ public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.Ab private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( + Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -80,4 +93,11 @@ else if (sign instanceof WallHangingSign) return super.getSignType(sign); } + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + } + } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockLevelTicksTracker.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..d58c400ae7 --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockLevelTicksTracker.java @@ -0,0 +1,69 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final BiFunction IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION = + initializePositionTickingWithEntitiesLoaded(); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos), + serverLevel.getProfilerSupplier()); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + ticker.accept(blockPos, block); + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } + + private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) { + return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos); + } + + private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) { + io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder = serverLevel.chunkTaskScheduler.chunkHolderManager.getChunkHolder(chunkPos); + return chunkHolder != null && chunkHolder.isTickingReady(); + } + + private static BiFunction initializePositionTickingWithEntitiesLoaded() { + try { + Class.forName("io.papermc.paper.chunk.system.scheduling.NewChunkHolder"); + return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper; + } catch (Throwable error) { + return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot; + } + } + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/CollectingNeighborUpdaterTracker.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/CollectingNeighborUpdaterTracker.java new file mode 100644 index 0000000000..f514c5a344 --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/CollectingNeighborUpdaterTracker.java @@ -0,0 +1,43 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Level level; + + public CollectingNeighborUpdaterTracker(Level level) { + super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); + this.level = level; + } + + @Override + public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { + BlockState oldState = this.level.getBlockState(pos); + super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); + BlockState newState = this.level.getBlockState(pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java index 82b37892c5..db253b20cb 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSWorldImpl.java @@ -6,8 +6,13 @@ import com.bgsoftware.superiorskyblock.nms.v1_21.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v1_21.world.BlockLevelTicksTracker; +import com.bgsoftware.superiorskyblock.nms.v1_21.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -22,9 +27,13 @@ import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.redstone.NeighborUpdater; +import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -33,6 +42,10 @@ public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.Abst private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( + Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -131,4 +144,11 @@ public void replaceTrialBlockPlayerDetector(Island island, Location location) { } } + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + } + } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockLevelTicksTracker.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..0b7699cbef --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockLevelTicksTracker.java @@ -0,0 +1,70 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final BiFunction IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION = + initializePositionTickingWithEntitiesLoaded(); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos), + serverLevel.getProfilerSupplier()); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + ticker.accept(blockPos, block); + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } + + private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) { + return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos); + } + + private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) { + ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = + serverLevel.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos); + return chunkHolder != null && chunkHolder.isTickingReady(); + } + + private static BiFunction initializePositionTickingWithEntitiesLoaded() { + try { + Class.forName("ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder"); + return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper; + } catch (Throwable error) { + return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot; + } + } + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/CollectingNeighborUpdaterTracker.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/CollectingNeighborUpdaterTracker.java new file mode 100644 index 0000000000..cde1d28776 --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/CollectingNeighborUpdaterTracker.java @@ -0,0 +1,43 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Level level; + + public CollectingNeighborUpdaterTracker(Level level) { + super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); + this.level = level; + } + + @Override + public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { + BlockState oldState = this.level.getBlockState(pos); + super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); + BlockState newState = this.level.getBlockState(pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSWorldImpl.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSWorldImpl.java index b5f2b9de49..d1aa692b7a 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSWorldImpl.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSWorldImpl.java @@ -6,8 +6,13 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_10.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_10.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_10.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v1_21_10.world.BlockLevelTicksTracker; +import com.bgsoftware.superiorskyblock.nms.v1_21_10.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -22,9 +27,13 @@ import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -33,7 +42,10 @@ public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.A private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); - + private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( + Level.class, CollectingNeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -123,4 +135,11 @@ else if (sign instanceof WallHangingSign) return super.getSignType(sign); } + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + } + } diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/BlockLevelTicksTracker.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..155881199f --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/BlockLevelTicksTracker.java @@ -0,0 +1,45 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +import java.util.function.BiConsumer; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(serverLevel::isPositionTickingWithEntitiesLoaded); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + ticker.accept(blockPos, block); + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/CollectingNeighborUpdaterTracker.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/CollectingNeighborUpdaterTracker.java new file mode 100644 index 0000000000..01f9aa4f7b --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/CollectingNeighborUpdaterTracker.java @@ -0,0 +1,44 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Level level; + + public CollectingNeighborUpdaterTracker(Level level) { + super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); + this.level = level; + } + + @Override + public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, @Block.UpdateFlags int flags, int recursionLeft) { + BlockState oldState = this.level.getBlockState(pos); + super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); + BlockState newState = this.level.getBlockState(pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java index bdde657f5e..6e816a2331 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSWorldImpl.java @@ -6,8 +6,13 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_3.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_3.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_3.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.BlockLevelTicksTracker; +import com.bgsoftware.superiorskyblock.nms.v1_21_3.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -22,9 +27,13 @@ import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.redstone.NeighborUpdater; +import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -33,6 +42,10 @@ public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.Ab private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( + Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -131,4 +144,11 @@ public void replaceTrialBlockPlayerDetector(Island island, Location location) { } } + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + } + } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockLevelTicksTracker.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..1000ab5468 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockLevelTicksTracker.java @@ -0,0 +1,69 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final BiFunction IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION = + initializePositionTickingWithEntitiesLoaded(); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos)); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + ticker.accept(blockPos, block); + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } + + private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) { + return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos); + } + + private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) { + ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = + serverLevel.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos); + return chunkHolder != null && chunkHolder.isTickingReady(); + } + + private static BiFunction initializePositionTickingWithEntitiesLoaded() { + try { + Class.forName("ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder"); + return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper; + } catch (Throwable error) { + return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot; + } + } + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/CollectingNeighborUpdaterTracker.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/CollectingNeighborUpdaterTracker.java new file mode 100644 index 0000000000..cfeda34153 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/CollectingNeighborUpdaterTracker.java @@ -0,0 +1,43 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Level level; + + public CollectingNeighborUpdaterTracker(Level level) { + super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); + this.level = level; + } + + @Override + public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { + BlockState oldState = this.level.getBlockState(pos); + super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); + BlockState newState = this.level.getBlockState(pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java index 8c4bc8b1c5..bfaee1e805 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSWorldImpl.java @@ -6,8 +6,13 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_4.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_4.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_4.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.BlockLevelTicksTracker; +import com.bgsoftware.superiorskyblock.nms.v1_21_4.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -22,9 +27,13 @@ import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.redstone.NeighborUpdater; +import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -33,6 +42,10 @@ public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.Ab private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( + Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -131,4 +144,11 @@ public void replaceTrialBlockPlayerDetector(Island island, Location location) { } } + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + } + } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockLevelTicksTracker.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..97d2e66bd5 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockLevelTicksTracker.java @@ -0,0 +1,69 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +import java.util.function.BiConsumer; +import java.util.function.BiFunction; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final BiFunction IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION = + initializePositionTickingWithEntitiesLoaded(); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(chunkPos -> IS_POSITION_TICKING_WITH_ENTITIES_LOADED_FUNCTION.apply(serverLevel, chunkPos)); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + ticker.accept(blockPos, block); + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } + + private static boolean isPositionTickingWithEntitiesLoadedSpigot(ServerLevel serverLevel, long chunkPos) { + return serverLevel.areEntitiesLoaded(chunkPos) && serverLevel.chunkSource.isPositionTicking(chunkPos); + } + + private static boolean isPositionTickingWithEntitiesLoadedPaper(ServerLevel serverLevel, long chunkPos) { + ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = + serverLevel.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos); + return chunkHolder != null && chunkHolder.isTickingReady(); + } + + private static BiFunction initializePositionTickingWithEntitiesLoaded() { + try { + Class.forName("ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder"); + return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedPaper; + } catch (Throwable error) { + return BlockLevelTicksTracker::isPositionTickingWithEntitiesLoadedSpigot; + } + } + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/CollectingNeighborUpdaterTracker.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/CollectingNeighborUpdaterTracker.java new file mode 100644 index 0000000000..2dbf542352 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/CollectingNeighborUpdaterTracker.java @@ -0,0 +1,44 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Level level; + + public CollectingNeighborUpdaterTracker(Level level) { + super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); + this.level = level; + } + + @Override + public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { + BlockState oldState = this.level.getBlockState(pos); + super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); + BlockState newState = this.level.getBlockState(pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java index eea8117d71..0f2540acb8 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSWorldImpl.java @@ -6,8 +6,13 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_5.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_5.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_5.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.BlockLevelTicksTracker; +import com.bgsoftware.superiorskyblock.nms.v1_21_5.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -22,9 +27,13 @@ import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.redstone.NeighborUpdater; +import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -33,6 +42,10 @@ public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.Ab private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( + Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -131,4 +144,11 @@ public void replaceTrialBlockPlayerDetector(Island island, Location location) { } } + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + } + } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockLevelTicksTracker.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..fd826e7ff9 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockLevelTicksTracker.java @@ -0,0 +1,45 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +import java.util.function.BiConsumer; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(serverLevel::isPositionTickingWithEntitiesLoaded); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + ticker.accept(blockPos, block); + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/CollectingNeighborUpdaterTracker.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/CollectingNeighborUpdaterTracker.java new file mode 100644 index 0000000000..39af52ed38 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/CollectingNeighborUpdaterTracker.java @@ -0,0 +1,44 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Level level; + + public CollectingNeighborUpdaterTracker(Level level) { + super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); + this.level = level; + } + + @Override + public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { + BlockState oldState = this.level.getBlockState(pos); + super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); + BlockState newState = this.level.getBlockState(pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + +} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java index e74ede3bd5..91190b3b0b 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSWorldImpl.java @@ -6,8 +6,13 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_7.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_7.vibration.IslandVibrationUser; import com.bgsoftware.superiorskyblock.nms.v1_21_7.trial.IslandPlayerDetector; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.BlockLevelTicksTracker; +import com.bgsoftware.superiorskyblock.nms.v1_21_7.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -22,9 +27,13 @@ import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.redstone.NeighborUpdater; +import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import java.lang.reflect.Modifier; @@ -33,6 +42,10 @@ public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.Ab private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( + Level.class, NeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -122,4 +135,11 @@ else if (sign instanceof WallHangingSign) return super.getSignType(sign); } + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + } + } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockLevelTicksTracker.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..d07cac7c92 --- /dev/null +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockLevelTicksTracker.java @@ -0,0 +1,45 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +import java.util.function.BiConsumer; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(serverLevel::isPositionTickingWithEntitiesLoaded); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + ticker.accept(blockPos, block); + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } +} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/CollectingNeighborUpdaterTracker.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/CollectingNeighborUpdaterTracker.java new file mode 100644 index 0000000000..028cb9dbed --- /dev/null +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/CollectingNeighborUpdaterTracker.java @@ -0,0 +1,44 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_7.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Level level; + + public CollectingNeighborUpdaterTracker(Level level) { + super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); + this.level = level; + } + + @Override + public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { + BlockState oldState = this.level.getBlockState(pos); + super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); + BlockState newState = this.level.getBlockState(pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java index 52043b8eec..ea505c4914 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSWorldImpl.java @@ -6,9 +6,13 @@ import com.bgsoftware.superiorskyblock.nms.v1_21_9.NMSUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_9.trial.IslandPlayerDetector; import com.bgsoftware.superiorskyblock.nms.v1_21_9.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v1_21_9.world.BlockLevelTicksTracker; +import com.bgsoftware.superiorskyblock.nms.v1_21_9.world.CollectingNeighborUpdaterTracker; import com.bgsoftware.superiorskyblock.world.SignType; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; import net.minecraft.world.level.block.entity.SignBlockEntity; @@ -23,6 +27,8 @@ import net.minecraft.world.level.levelgen.FlatLevelSource; import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import net.minecraft.world.ticks.LevelTicks; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.data.type.HangingSign; @@ -37,6 +43,10 @@ public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.Ab private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( + Level.class, CollectingNeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { super(plugin); @@ -126,4 +136,11 @@ else if (sign instanceof WallHangingSign) return super.getSignType(sign); } + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + } + } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/BlockLevelTicksTracker.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..dcca461db4 --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/BlockLevelTicksTracker.java @@ -0,0 +1,45 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +import java.util.function.BiConsumer; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(serverLevel::isPositionTickingWithEntitiesLoaded); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + ticker.accept(blockPos, block); + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/CollectingNeighborUpdaterTracker.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/CollectingNeighborUpdaterTracker.java new file mode 100644 index 0000000000..0ca4b9c004 --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/CollectingNeighborUpdaterTracker.java @@ -0,0 +1,44 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Level level; + + public CollectingNeighborUpdaterTracker(Level level) { + super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); + this.level = level; + } + + @Override + public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, int flags, int recursionLeft) { + BlockState oldState = this.level.getBlockState(pos); + super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); + BlockState newState = this.level.getBlockState(pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + +} diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java index 4e5c6261ff..7ba4c3a09c 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; import com.bgsoftware.superiorskyblock.nms.NMSWorld; @@ -57,6 +58,8 @@ public class NMSWorldImpl implements NMSWorld { private static final ReflectField MOB_SPAWNER_ABSTRACT = new ReflectField( TileEntityMobSpawner.class, MobSpawnerAbstract.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static boolean alreadyWarned = false; + private final SuperiorSkyblockPlugin plugin; public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { @@ -345,4 +348,12 @@ public ChunkReader createChunkReader(Chunk chunk) { return new ChunkReaderImpl(chunk); } + @Override + public void listenBlockStateChanges(org.bukkit.World world) { + if (!alreadyWarned) { + Log.warn("This version is old and you may experience issues with block changes detection"); + alreadyWarned = true; + } + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java index db993a43de..3851962846 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java @@ -63,6 +63,8 @@ public class CountsPagedObjectButton extends AbstractPagedMenuButton { @@ -185,6 +192,8 @@ public WorldsProvider getWorldsProvider() { public void setWorldsProvider(WorldsProvider worldsProvider) { Preconditions.checkNotNull(worldsProvider, "worldsProvider parameter cannot be null."); this.worldsProvider = worldsProvider; + this.worldsProvider.addWorldLoadListener(DefaultWorldLoadListener.INSTANCE); + this.isCustomWorldsProvider = !(worldsProvider instanceof WorldsProvider_Default); PluginEventsFactory.callWorldsProviderUpdateEvent(); } @@ -416,7 +425,7 @@ public EconomyProvider.EconomyResult withdrawMoneyForBanks(SuperiorPlayer superi } public boolean hasCustomWorldsSupport() { - return !(worldsProvider instanceof WorldsProvider_Default); + return this.isCustomWorldsProvider; } public boolean isAFK(Player player) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/DefaultWorldLoadListener.java b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/DefaultWorldLoadListener.java new file mode 100644 index 0000000000..aa45bb10b5 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/DefaultWorldLoadListener.java @@ -0,0 +1,49 @@ +package com.bgsoftware.superiorskyblock.external.worlds; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.config.SettingsManager; +import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener; +import com.bgsoftware.superiorskyblock.api.hooks.world.WorldLoadFlags; +import com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.LazyReference; +import org.bukkit.World; + +public class DefaultWorldLoadListener implements IWorldLoadListener { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final LazyReference dragonBattleService = new LazyReference() { + @Override + protected DragonBattleService create() { + return plugin.getServices().getService(DragonBattleService.class); + } + }; + + public static final DefaultWorldLoadListener INSTANCE = new DefaultWorldLoadListener(); + + private DefaultWorldLoadListener() { + + } + + @Override + public void onWorldLoad(World world, Dimension worldDimension, @WorldLoadFlags int flags) { + if ((flags & WorldLoadFlags.END_DRAGON_FIGHT) != 0) { + SettingsManager.Worlds.DimensionConfig dimensionConfig = + plugin.getSettings().getWorlds().getDimensionConfig(worldDimension); + + if (worldDimension.getEnvironment() == World.Environment.THE_END && + dimensionConfig instanceof SettingsManager.Worlds.End && + ((SettingsManager.Worlds.End) dimensionConfig).isDragonFight()) { + dragonBattleService.get().prepareEndWorld(world); + } + } + if ((flags & WorldLoadFlags.REMOVE_ANTI_XRAY) != 0) + plugin.getNMSWorld().removeAntiXray(world); + if ((flags & WorldLoadFlags.UPDATE_OCEAN_LEVEL) != 0) + plugin.getNMSWorld().setOceanLevel(world); + if ((flags & WorldLoadFlags.LISTEN_BLOCK_CHANGES) != 0) + plugin.getNMSWorld().listenBlockStateChanges(world); + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java index cbd223e080..a741257ea7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java @@ -3,11 +3,11 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; +import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener; +import com.bgsoftware.superiorskyblock.api.hooks.world.WorldLoadFlags; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; -import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; @@ -25,28 +25,29 @@ import org.bukkit.block.BlockFace; import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; public class WorldsProvider_Default implements WorldsProvider { + @WorldLoadFlags + private static final int SUPPORTED_LOAD_FLAGS = WorldLoadFlags.END_DRAGON_FIGHT | WorldLoadFlags.REMOVE_ANTI_XRAY | + WorldLoadFlags.UPDATE_OCEAN_LEVEL | WorldLoadFlags.LISTEN_BLOCK_CHANGES; + private final Set servedPositions = Sets.newHashSet(); private final EnumerateMap islandWorlds = new EnumerateMap<>(Dimension.values()); private final Map islandWorldsToDimensions = new HashMap<>(); + private final List worldLoadListenerList = new LinkedList<>(); private final SuperiorSkyblockPlugin plugin; private World islandsWorld; - private final LazyReference dragonBattleService = new LazyReference() { - @Override - protected DragonBattleService create() { - return plugin.getServices().getService(DragonBattleService.class); - } - }; - public WorldsProvider_Default(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; + this.worldLoadListenerList.add(DefaultWorldLoadListener.INSTANCE); } @Override @@ -57,11 +58,6 @@ public void prepareWorlds() { if (dimensionConfig != null && dimensionConfig.isEnabled()) { String worldName = dimensionConfig.getName(); World world = loadWorld(worldName, difficulty, dimension); - if (dimension.getEnvironment() == World.Environment.THE_END && - dimensionConfig instanceof SettingsManager.Worlds.End && - ((SettingsManager.Worlds.End) dimensionConfig).isDragonFight()) { - dragonBattleService.get().prepareEndWorld(world); - } if (dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension()) this.islandsWorld = world; } @@ -162,6 +158,17 @@ public boolean isDimensionUnlocked(Dimension dimension) { return dimensionConfig != null && dimensionConfig.isEnabled() && dimensionConfig.isUnlocked(); } + @Override + public void addWorldLoadListener(IWorldLoadListener worldLoadListener) { + Preconditions.checkNotNull(worldLoadListener, "worldLoadListener parameter cannot be null"); + this.worldLoadListenerList.add(worldLoadListener); + } + + private void notifyWorldLoadListeners(World world, Dimension worldDimension) { + for (IWorldLoadListener worldLoadListener : this.worldLoadListenerList) + worldLoadListener.onWorldLoad(world, worldDimension, SUPPORTED_LOAD_FLAGS); + } + private BlockFace getIslandFace(BlockPosition blockPosition) { //Possibilities: North / East if (blockPosition.getX() >= blockPosition.getZ()) { @@ -190,8 +197,7 @@ private World loadWorld(String worldName, Difficulty difficulty, Dimension dimen islandWorlds.put(dimension, world); islandWorldsToDimensions.put(world.getUID(), dimension); - plugin.getNMSWorld().removeAntiXray(world); - plugin.getNMSWorld().setOceanLevel(world); + notifyWorldLoadListeners(world, dimension); if (Bukkit.getPluginManager().isPluginEnabled("Multiverse-Core")) { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "mv import " + worldName + " normal -g " + plugin.getName()); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index c41daa2d4d..37a5bc8faa 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -50,16 +50,10 @@ public class BlockChangesListener extends AbstractGameEventListener { @Nullable private static final Material CHORUS_FLOWER = EnumHelper.getEnum(Material.class, "CHORUS_FLOWER"); @Nullable - private static final Material BAMBOO = EnumHelper.getEnum(Material.class, "BAMBOO"); - @Nullable - private static final Material BAMBOO_SAPLING = EnumHelper.getEnum(Material.class, "BAMBOO_SAPLING"); - @Nullable private static final CreatureSpawnEvent.SpawnReason BUILD_COPPERGOLEM = EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "BUILD_COPPERGOLEM"); @WorldRecordFlags private static final int REGULAR_RECORD_FLAGS = WorldRecordFlags.SAVE_BLOCK_COUNT | WorldRecordFlags.DIRTY_CHUNKS; - @WorldRecordFlags - private static final int ALL_RECORD_FLAGS = REGULAR_RECORD_FLAGS | WorldRecordFlags.HANDLE_NEARBY_BLOCKS; static { for (Material material : Material.values()) { @@ -199,15 +193,6 @@ private void onBlockSpread(GameEvent e) { alreadyChorusFlowerTracked.add(spreadBlockLocation.clone()); } } - } else if (newStateType == BAMBOO && sourceType == BAMBOO_SAPLING) { - // Bamboo saplings are turned into a bamboo. - // We want to record an additional block place for that sapling. - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - this.worldRecordService.get().recordBlockPlace(ConstantKeys.BAMBOO, - block.getLocation(wrapper.getHandle()), - 1, source.getState(), REGULAR_RECORD_FLAGS); - - } } if (spreadBlock == null) { @@ -218,7 +203,31 @@ private void onBlockSpread(GameEvent e) { this.worldRecordService.get().recordBlockPlace(spreadBlock, block.getLocation(wrapper.getHandle()), 1, block.getState(), REGULAR_RECORD_FLAGS); + } + } + private void onBlockShapeUpdate(GameEvent e) { + Block block = e.getArgs().block; + + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(block.getWorld())) + return; + + Key newStateKey = Keys.of(block); + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location blockLocation = block.getLocation(wrapper.getHandle()); + + if (newStateKey.equals(ConstantKeys.AIR)) { + // New state is AIR, so this is a block break + Key oldStateKey = Keys.of(e.getArgs().oldState); + this.worldRecordService.get().recordBlockBreak(oldStateKey, blockLocation, + 1, REGULAR_RECORD_FLAGS); + } else { + this.worldRecordService.get().recordBlockPlace(newStateKey, + block.getLocation(wrapper.getHandle()), + 1, e.getArgs().oldState, REGULAR_RECORD_FLAGS); + } } } @@ -300,12 +309,12 @@ private void onEntityChangeBlock(GameEvent if (!oldBlockKey.equals(ConstantKeys.AIR)) { this.worldRecordService.get().recordBlockBreak(oldBlockKey, blockLocation, plugin.getNMSWorld().getDefaultAmount(block), - ALL_RECORD_FLAGS); + REGULAR_RECORD_FLAGS); } if (!newBlockKey.equals(ConstantKeys.AIR)) { this.worldRecordService.get().recordBlockPlace(newBlockKey, blockLocation, 1, - null, ALL_RECORD_FLAGS); + null, REGULAR_RECORD_FLAGS); } } } @@ -319,7 +328,7 @@ private void onBlockBreak(GameEvent e) { if (!plugin.getGrid().isIslandsWorld(block.getWorld())) return; - this.worldRecordService.get().recordBlockBreak(block, ALL_RECORD_FLAGS); + this.worldRecordService.get().recordBlockBreak(block, REGULAR_RECORD_FLAGS); } private void onBucketFill(GameEvent e) { @@ -531,6 +540,7 @@ private void registerListeners() { registerCallback(GameEventType.BLOCK_GROW_EVENT, GameEventPriority.MONITOR, this::onBlockGrow); registerCallback(GameEventType.BLOCK_FORM_EVENT, GameEventPriority.MONITOR, this::onBlockForm); registerCallback(GameEventType.BLOCK_SPREAD_EVENT, GameEventPriority.MONITOR, this::onBlockSpread); + registerCallback(GameEventType.BLOCK_UPDATE_SHAPE_EVENT, GameEventPriority.MONITOR, this::onBlockShapeUpdate); registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.MONITOR, this::onSpawnerChange); registerCallback(GameEventType.ENTITY_CHANGE_BLOCK_EVENT, GameEventPriority.MONITOR, this::onEntityChangeBlock); registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.MONITOR, this::onBlockBreak); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java index cfb24b88d9..3373471704 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java @@ -70,6 +70,8 @@ default SignType getSignType(Block block) { void setOceanLevel(World world); + void listenBlockStateChanges(World world); + IslandsGenerator createGenerator(Dimension dimension); WorldEditSession createEditSession(World world); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java index 0a8c5b1d36..8332d92f19 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java @@ -20,6 +20,7 @@ import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockPlaceEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockRedstoneEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockSpreadEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.BlockUpdateShapeEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ChunkLoadEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.ChunkUnloadEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityBlockFormEvent; @@ -86,6 +87,7 @@ public class GameEventType extends EventType BLOCK_PLACE_EVENT = register(BlockPlaceEvent.class); public static final GameEventType BLOCK_REDSTONE_EVENT = register(BlockRedstoneEvent.class); public static final GameEventType BLOCK_SPREAD_EVENT = register(BlockSpreadEvent.class); + public static final GameEventType BLOCK_UPDATE_SHAPE_EVENT = register(BlockUpdateShapeEvent.class); public static final GameEventType LEAVES_DECAY_EVENT = register(LeavesDecayEvent.class); public static final GameEventType PISTON_EXTEND_EVENT = register(PistonExtendEvent.class); public static final GameEventType PISTON_RETRACT_EVENT = register(PistonRetractEvent.class); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java index d0541a2160..a544f5f033 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java @@ -385,6 +385,12 @@ public static class BlockPhysicsEvent extends BlockEvent { } + public static class BlockUpdateShapeEvent extends BlockEvent { + + public BlockState oldState; + + } + private static class BlockEvent extends GameEventArgs { public Block block; From fbe6a52ff0123ab42b82387a7c438999bb746c54 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 Jan 2026 00:55:55 +0200 Subject: [PATCH 467/600] Fix errors when loading the plugin due to recent commit (#2816) --- .../external/ProvidersManagerImpl.java | 20 ++++++++++--------- .../worlds/DefaultWorldLoadListener.java | 8 +++----- .../worlds/WorldsProvider_Default.java | 1 - 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java index 2f57e2e972..9070c430a6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java @@ -19,6 +19,7 @@ import com.bgsoftware.superiorskyblock.api.hooks.WorldsProvider; import com.bgsoftware.superiorskyblock.api.hooks.listener.ISkinsListener; import com.bgsoftware.superiorskyblock.api.hooks.listener.IStackedBlocksListener; +import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldLoadListener; import com.bgsoftware.superiorskyblock.api.hooks.listener.IWorldsListener; import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -80,7 +81,6 @@ public class ProvidersManagerImpl extends Manager implements ProvidersManager { private List pricesLoadCallbacks = new LinkedList<>(); private SpawnersProvider spawnersProvider = new SpawnersProvider_Default(); private StackedBlocksProvider stackedBlocksProvider = new StackedBlocksProvider_Default(); - private List entitiesProviders = new LinkedList<>(); private EconomyProvider economyProvider = new EconomyProvider_Default(); private EconomyProvider bankEconomyProvider = new EconomyProvider_Default(); private PermissionsProvider permissionsProvider = new PermissionsProvider_Default(); @@ -104,18 +104,16 @@ protected PlaceholdersService create() { private final List stackedBlocksListeners = new LinkedList<>(); private final List worldsListeners = new LinkedList<>(); private final List customBlocksProviders = new LinkedList<>(); + private final List entitiesProviders = new LinkedList<>(); + + private final IWorldLoadListener DEFAULT_WORLD_LOAD_LISTENER = new DefaultWorldLoadListener(plugin); public ProvidersManagerImpl(SuperiorSkyblockPlugin plugin) { super(plugin); - this.worldsProvider = new WorldsProvider_Default(plugin); - this.isCustomWorldsProvider = false; + setWorldsProviderInternal(new WorldsProvider_Default(plugin)); this.menusProvider = new MenusProvider_Default(plugin); } - private void hookDefaultWorldLoadCallbacks() { - - } - @Override public void loadData() { BukkitExecutor.sync(() -> { @@ -191,10 +189,14 @@ public WorldsProvider getWorldsProvider() { @Override public void setWorldsProvider(WorldsProvider worldsProvider) { Preconditions.checkNotNull(worldsProvider, "worldsProvider parameter cannot be null."); + setWorldsProviderInternal(worldsProvider); + PluginEventsFactory.callWorldsProviderUpdateEvent(); + } + + private void setWorldsProviderInternal(WorldsProvider worldsProvider) { this.worldsProvider = worldsProvider; - this.worldsProvider.addWorldLoadListener(DefaultWorldLoadListener.INSTANCE); + this.worldsProvider.addWorldLoadListener(DEFAULT_WORLD_LOAD_LISTENER); this.isCustomWorldsProvider = !(worldsProvider instanceof WorldsProvider_Default); - PluginEventsFactory.callWorldsProviderUpdateEvent(); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/DefaultWorldLoadListener.java b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/DefaultWorldLoadListener.java index aa45bb10b5..25c6cf0cb9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/DefaultWorldLoadListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/DefaultWorldLoadListener.java @@ -11,8 +11,6 @@ public class DefaultWorldLoadListener implements IWorldLoadListener { - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private final LazyReference dragonBattleService = new LazyReference() { @Override protected DragonBattleService create() { @@ -20,10 +18,10 @@ protected DragonBattleService create() { } }; - public static final DefaultWorldLoadListener INSTANCE = new DefaultWorldLoadListener(); - - private DefaultWorldLoadListener() { + private final SuperiorSkyblockPlugin plugin; + public DefaultWorldLoadListener(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java index a741257ea7..85556de1bc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java @@ -47,7 +47,6 @@ public class WorldsProvider_Default implements WorldsProvider { public WorldsProvider_Default(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; - this.worldLoadListenerList.add(DefaultWorldLoadListener.INSTANCE); } @Override From e7def2a6ef567d6ec72d25104343e70938f55dae Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 Jan 2026 01:11:56 +0200 Subject: [PATCH 468/600] Fixed mission progress not saved to disk in some cases, causing progress to revert (#2827) --- .../mission/MissionsManagerImpl.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java index 54570113a5..1609c9f7b0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java @@ -405,13 +405,19 @@ public void saveMissionsData() { continue; } - if (data.getKeys(true).isEmpty()) - continue; + boolean anyDataToWrite = !data.getKeys(true).isEmpty(); File dataFile = new File(dataFolder, mission.getName() + ".yml"); + boolean dataFileExists = dataFile.exists(); + + if (!anyDataToWrite) { + if (dataFileExists) + dataFile.delete(); + continue; + } try { - if (!dataFile.exists()) + if (!dataFileExists) dataFile.createNewFile(); synchronized (DATA_FOLDER_MUTEX) { data.save(dataFile); From cf3bb7ab7fa76badbf86420dd4f638db5ef6f73c Mon Sep 17 00:00:00 2001 From: Magic_Bili <124496967+addpromax@users.noreply.github.com> Date: Sat, 3 Jan 2026 23:22:14 +0800 Subject: [PATCH 469/600] Optimize loading schematics (#2826) --- .../SuperiorSkyblockPlugin.java | 19 +++--- .../schematic/SchematicsManagerImpl.java | 60 +++++++++++++++++-- 2 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index 6f7a1c9b6a..1e077cab4a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -82,7 +82,6 @@ import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.WorldGenerator; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; -import com.bgsoftware.superiorskyblock.world.entity.EntityCategories; import com.bgsoftware.superiorskyblock.world.schematic.SchematicsManagerImpl; import com.bgsoftware.superiorskyblock.world.schematic.container.DefaultSchematicsContainer; import org.bstats.bukkit.Metrics; @@ -272,15 +271,19 @@ public void onEnable() { loadingStage = PluginLoadingStage.CHUNKS_PROVIDER_INITIALIZED; - if (updater.isOutdated()) { - Log.info(""); - Log.info("A new version is available (v", updater.getLatestVersion(), ")!"); - Log.info("Version's description: \"", updater.getVersionDescription(), "\""); - Log.info(""); - } + // Check for updates asynchronously + BukkitExecutor.async(() -> { + if (updater.isOutdated()) { + Log.info(""); + Log.info("A new version is available (v", updater.getLatestVersion(), ")!"); + Log.info("Version's description: \"", updater.getVersionDescription(), "\""); + Log.info(""); + } + }); // Calculate the maximum amount of islands that fit into the world. - if (calculateMaxPossibleIslands() < 1000) { + long maxIslands = calculateMaxPossibleIslands(); + if (maxIslands < 1000) { Log.warn("It seems like you configured your max-world-size in server.properties to be a small number (", nmsAlgorithms.getMaxWorldSize(), ")."); Log.warn("This can lead to weird behaviors when new islands are generated beyond this limit."); Log.warn("Increase the value to for better experience (Default: 29999984)"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java index e512ac7beb..7913380e44 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/SchematicsManagerImpl.java @@ -37,6 +37,7 @@ import com.bgsoftware.superiorskyblock.world.schematic.impl.SuperiorSchematic; import com.bgsoftware.superiorskyblock.world.schematic.parser.DefaultSchematicParser; import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.ThreadFactoryBuilder; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; @@ -51,11 +52,15 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.function.Consumer; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -86,7 +91,6 @@ public void loadData() throws ManagerLoadException { } loadDefaultSchematicParsers(); - loadSchematics(); } @@ -94,12 +98,55 @@ public void loadSchematics() throws ManagerLoadException { this.schematicsContainer.clearSchematics(); File schematicsFolder = new File(plugin.getDataFolder(), "schematics"); + List schematicFilesList = Files.listFolderFiles(schematicsFolder, false); - for (File schemFile : Files.listFolderFiles(schematicsFolder, false)) { - String schemName = Files.getFileName(schemFile).toLowerCase(Locale.ENGLISH); - Schematic schematic = loadFromFile(schemName, schemFile); - if (schematic != null) { - this.schematicsContainer.addSchematic(schematic); + if (!schematicFilesList.isEmpty()) { + int schematicFilesCount = schematicFilesList.size(); + List loadedSchematics = Collections.synchronizedList(new LinkedList<>()); + + CountDownLatch latch = new CountDownLatch(schematicFilesCount); + + int threadCount = Math.min(schematicFilesCount, Runtime.getRuntime().availableProcessors() * 2); + ExecutorService loadService = Executors.newFixedThreadPool(threadCount, + new ThreadFactoryBuilder().setNameFormat("SuperiorSkyblock Load Schematic Worker #%d").build()); + + Log.info("Loading " + schematicFilesCount + " schematics using " + threadCount + " threads..."); + + try { + for (File schemFile : schematicFilesList) { + loadService.submit(() -> { + String schemName = Files.getFileName(schemFile).toLowerCase(Locale.ENGLISH); + try { + Schematic schematic = loadFromFile(schemName, schemFile); + if (schematic != null) { + loadedSchematics.add(schematic); + } + } catch (Throwable error) { + Log.error(error, "An unexpected error occurred while loading schematic " + schemName); + } finally { + latch.countDown(); + + long remaining = latch.getCount(); + if (remaining > 0 && remaining % 50 == 0) { + Log.info("Schematic loading progress: " + (schematicFilesCount - remaining) + "/" + schematicFilesCount); + } + } + }); + } + + latch.await(); + + loadService.shutdown(); + + Log.info("Successfully loaded " + loadedSchematics.size() + " schematics."); + + for (Schematic schematic : loadedSchematics) { + this.schematicsContainer.addSchematic(schematic); + } + } catch (InterruptedException e) { + Log.error("Schematic loading thread was interrupted."); + loadService.shutdownNow(); + Thread.currentThread().interrupt(); } } @@ -108,6 +155,7 @@ public void loadSchematics() throws ManagerLoadException { ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); } + // Force garbage collection to release file handles on Windows System.gc(); } From 2768e0f7b216a6237f591081577fbaa425c1ec1a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 Jan 2026 18:03:27 +0200 Subject: [PATCH 470/600] Fix potential counting blocks removal twice (#2816) --- .../world/BlockTickListServerTracker.java | 12 +- .../world/BlockServerTickListTracker.java | 16 +- .../v1_18/world/BlockLevelTicksTracker.java | 16 +- .../v1_19/world/BlockLevelTicksTracker.java | 16 +- .../v1_20_3/world/BlockLevelTicksTracker.java | 16 +- .../v1_20_4/world/BlockLevelTicksTracker.java | 16 +- .../v1_21/world/BlockLevelTicksTracker.java | 16 +- .../world/BlockLevelTicksTracker.java | 16 +- .../v1_21_3/world/BlockLevelTicksTracker.java | 16 +- .../v1_21_4/world/BlockLevelTicksTracker.java | 16 +- .../v1_21_5/world/BlockLevelTicksTracker.java | 16 +- .../v1_21_7/world/BlockLevelTicksTracker.java | 16 +- .../v1_21_9/world/BlockLevelTicksTracker.java | 16 +- .../core/events/EventsDispatcher.java | 19 +++ .../platform/event/GameEventFlags.java | 13 ++ .../platform/event/GameEventType.java | 139 ++++++++++-------- .../platform/event/GameEventsDispatcher.java | 18 +++ 17 files changed, 315 insertions(+), 78 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventFlags.java diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockTickListServerTracker.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockTickListServerTracker.java index 78203cbd23..64b348e219 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockTickListServerTracker.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/world/BlockTickListServerTracker.java @@ -17,6 +17,7 @@ import org.bukkit.craftbukkit.v1_16_R3.block.CraftBlockState; import java.lang.reflect.Modifier; +import java.util.List; import java.util.function.Consumer; public class BlockTickListServerTracker { @@ -50,7 +51,16 @@ private static void tick(WorldServer worldServer, NextTickListEntry nextT IBlockData blockState = worldServer.getType(blockPosition); if (blockState.a(nextTickData.b())) { IBlockData oldData = worldServer.getType(blockPosition); - blockState.a(worldServer, blockPosition, worldServer.random); + try { + plugin.getGameEventsDispatcher().startCaptureEvents(); + blockState.a(worldServer, blockPosition, worldServer.random); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in that tick. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } IBlockData newData = worldServer.getType(blockPosition); if (oldData.getBlock() != newData.getBlock()) { // Block was changed, let's call an update diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockServerTickListTracker.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockServerTickListTracker.java index 5bd684a383..690a47ffc8 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockServerTickListTracker.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/world/BlockServerTickListTracker.java @@ -4,6 +4,7 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; @@ -16,6 +17,7 @@ import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlockStates; import java.lang.reflect.Modifier; +import java.util.List; import java.util.function.Consumer; public class BlockServerTickListTracker { @@ -48,7 +50,19 @@ private static void tick(ServerLevel serverLevel, TickNextTickData nextTi BlockState blockState = serverLevel.getBlockState(nextTickData.pos); if (blockState.is(nextTickData.getType())) { BlockState oldState = serverLevel.getBlockState(nextTickData.pos); - blockState.tick(serverLevel, nextTickData.pos, serverLevel.random); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + blockState.tick(serverLevel, nextTickData.pos, serverLevel.random); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } BlockState newState = serverLevel.getBlockState(nextTickData.pos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockLevelTicksTracker.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockLevelTicksTracker.java index 428ac531bf..e206b6af9e 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockLevelTicksTracker.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/world/BlockLevelTicksTracker.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; @@ -14,6 +15,7 @@ import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlock; import org.bukkit.craftbukkit.v1_18_R2.block.CraftBlockStates; +import java.util.List; import java.util.function.BiConsumer; public class BlockLevelTicksTracker extends LevelTicks { @@ -32,7 +34,19 @@ public BlockLevelTicksTracker(ServerLevel serverLevel) { public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); - ticker.accept(blockPos, block); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockLevelTicksTracker.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockLevelTicksTracker.java index 14a796df5c..1e919342b1 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockLevelTicksTracker.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/world/BlockLevelTicksTracker.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; @@ -13,6 +14,7 @@ import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_19_R3.block.CraftBlockStates; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -35,7 +37,19 @@ public BlockLevelTicksTracker(ServerLevel serverLevel) { public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); - ticker.accept(blockPos, block); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockLevelTicksTracker.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockLevelTicksTracker.java index 8b42d22288..c6f59d8a53 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockLevelTicksTracker.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/world/BlockLevelTicksTracker.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; @@ -13,6 +14,7 @@ import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockStates; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -35,7 +37,19 @@ public BlockLevelTicksTracker(ServerLevel serverLevel) { public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); - ticker.accept(blockPos, block); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockLevelTicksTracker.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockLevelTicksTracker.java index d58c400ae7..ff09a18394 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockLevelTicksTracker.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/world/BlockLevelTicksTracker.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; @@ -13,6 +14,7 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -35,7 +37,19 @@ public BlockLevelTicksTracker(ServerLevel serverLevel) { public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); - ticker.accept(blockPos, block); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockLevelTicksTracker.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockLevelTicksTracker.java index 0b7699cbef..763af85a51 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockLevelTicksTracker.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/world/BlockLevelTicksTracker.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; @@ -13,6 +14,7 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -35,7 +37,19 @@ public BlockLevelTicksTracker(ServerLevel serverLevel) { public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); - ticker.accept(blockPos, block); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/BlockLevelTicksTracker.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/BlockLevelTicksTracker.java index 155881199f..bbef55e5f6 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/BlockLevelTicksTracker.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/world/BlockLevelTicksTracker.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; @@ -13,6 +14,7 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; +import java.util.List; import java.util.function.BiConsumer; public class BlockLevelTicksTracker extends LevelTicks { @@ -30,7 +32,19 @@ public BlockLevelTicksTracker(ServerLevel serverLevel) { public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); - ticker.accept(blockPos, block); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockLevelTicksTracker.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockLevelTicksTracker.java index 1000ab5468..ee62996688 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockLevelTicksTracker.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/world/BlockLevelTicksTracker.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; @@ -13,6 +14,7 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -34,7 +36,19 @@ public BlockLevelTicksTracker(ServerLevel serverLevel) { public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); - ticker.accept(blockPos, block); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockLevelTicksTracker.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockLevelTicksTracker.java index 97d2e66bd5..2fee4738ed 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockLevelTicksTracker.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/world/BlockLevelTicksTracker.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; @@ -13,6 +14,7 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; +import java.util.List; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -34,7 +36,19 @@ public BlockLevelTicksTracker(ServerLevel serverLevel) { public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); - ticker.accept(blockPos, block); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockLevelTicksTracker.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockLevelTicksTracker.java index fd826e7ff9..5092a157c4 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockLevelTicksTracker.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/world/BlockLevelTicksTracker.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; @@ -13,6 +14,7 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; +import java.util.List; import java.util.function.BiConsumer; public class BlockLevelTicksTracker extends LevelTicks { @@ -30,7 +32,19 @@ public BlockLevelTicksTracker(ServerLevel serverLevel) { public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); - ticker.accept(blockPos, block); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockLevelTicksTracker.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockLevelTicksTracker.java index d07cac7c92..f500e27cc3 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockLevelTicksTracker.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/world/BlockLevelTicksTracker.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; @@ -13,6 +14,7 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; +import java.util.List; import java.util.function.BiConsumer; public class BlockLevelTicksTracker extends LevelTicks { @@ -30,7 +32,19 @@ public BlockLevelTicksTracker(ServerLevel serverLevel) { public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); - ticker.accept(blockPos, block); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/BlockLevelTicksTracker.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/BlockLevelTicksTracker.java index dcca461db4..c6fef8538c 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/BlockLevelTicksTracker.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/world/BlockLevelTicksTracker.java @@ -2,6 +2,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; @@ -13,6 +14,7 @@ import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockStates; +import java.util.List; import java.util.function.BiConsumer; public class BlockLevelTicksTracker extends LevelTicks { @@ -30,7 +32,19 @@ public BlockLevelTicksTracker(ServerLevel serverLevel) { public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { BlockState oldState = this.serverLevel.getBlockState(blockPos); - ticker.accept(blockPos, block); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } BlockState newState = this.serverLevel.getBlockState(blockPos); if (oldState.getBlock() != newState.getBlock()) { // Block was changed, let's call an update diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java index b2f3fe4a7d..695d974836 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java @@ -18,6 +18,8 @@ public class EventsDispatcher, P extends Enum

    , E protected final SuperiorSkyblockPlugin plugin; protected final Class

    priorityClass; + private List capturedEvents = null; + protected EventsDispatcher(SuperiorSkyblockPlugin plugin, Class

    priorityClass, Collection allTypes) { this.plugin = plugin; this.priorityClass = priorityClass; @@ -34,6 +36,16 @@ public void clearCallbacks() { this.callbacks.clear(); } + public void startCaptureEvents() { + this.capturedEvents = new LinkedList<>(); + } + + public List stopCaptureEvents() { + List capturedEvents = this.capturedEvents; + this.capturedEvents = null; + return capturedEvents; + } + public void onGameEvent(E event, P priority) { if (event.isCancelled()) return; @@ -55,6 +67,13 @@ public void onGameEvent(E event, P priority) { } } } + + if (this.capturedEvents != null && filterCapturedEvent(event)) + this.capturedEvents.add(event); + } + + protected boolean filterCapturedEvent(E event) { + return true; } public Map> getCallbacks(T eventType) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventFlags.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventFlags.java new file mode 100644 index 0000000000..3867dd5d94 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventFlags.java @@ -0,0 +1,13 @@ +package com.bgsoftware.superiorskyblock.platform.event; + +public @interface GameEventFlags { + + int ENTITY_EVENT = 1 << 0; + int MAYBE_ENTITY_EVENT = 1 << 1; + int BLOCK_EVENT = 1 << 2; + int MAYBE_BLOCK_EVENT = 1 << 3; + int PLAYER_EVENT = 1 << 4; + int GENERIC_WORLD_EVENT = 1 << 5; + int INVENTORY_EVENT = 1 << 5; + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java index 8332d92f19..9cfaaaf010 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java @@ -75,85 +75,94 @@ public class GameEventType extends EventType> ALL_TYPES = new LinkedList<>(); // Block Events - public static final GameEventType BLOCK_BREAK_EVENT = register(BlockBreakEvent.class); - public static final GameEventType BLOCK_BURN_EVENT = register(BlockBurnEvent.class); - public static final GameEventType BLOCK_DISPENSE_EVENT = register(BlockDispenseEvent.class); - public static final GameEventType BLOCK_FADE_EVENT = register(BlockFadeEvent.class); - public static final GameEventType BLOCK_FORM_EVENT = register(BlockFormEvent.class); - public static final GameEventType BLOCK_FROM_TO_EVENT = register(BlockFromToEvent.class); - public static final GameEventType BLOCK_GROW_EVENT = register(BlockGrowEvent.class); - public static final GameEventType BLOCK_IGNITE_EVENT = register(BlockIgniteEvent.class); - public static final GameEventType BLOCK_PHYSICS_EVENT = register(BlockPhysicsEvent.class); - public static final GameEventType BLOCK_PLACE_EVENT = register(BlockPlaceEvent.class); - public static final GameEventType BLOCK_REDSTONE_EVENT = register(BlockRedstoneEvent.class); - public static final GameEventType BLOCK_SPREAD_EVENT = register(BlockSpreadEvent.class); - public static final GameEventType BLOCK_UPDATE_SHAPE_EVENT = register(BlockUpdateShapeEvent.class); - public static final GameEventType LEAVES_DECAY_EVENT = register(LeavesDecayEvent.class); - public static final GameEventType PISTON_EXTEND_EVENT = register(PistonExtendEvent.class); - public static final GameEventType PISTON_RETRACT_EVENT = register(PistonRetractEvent.class); + public static final GameEventType BLOCK_BREAK_EVENT = register(BlockBreakEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.PLAYER_EVENT); + public static final GameEventType BLOCK_BURN_EVENT = register(BlockBurnEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType BLOCK_DISPENSE_EVENT = register(BlockDispenseEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType BLOCK_FADE_EVENT = register(BlockFadeEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType BLOCK_FORM_EVENT = register(BlockFormEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType BLOCK_FROM_TO_EVENT = register(BlockFromToEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType BLOCK_GROW_EVENT = register(BlockGrowEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType BLOCK_IGNITE_EVENT = register(BlockIgniteEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType BLOCK_PHYSICS_EVENT = register(BlockPhysicsEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType BLOCK_PLACE_EVENT = register(BlockPlaceEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.PLAYER_EVENT); + public static final GameEventType BLOCK_REDSTONE_EVENT = register(BlockRedstoneEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType BLOCK_SPREAD_EVENT = register(BlockSpreadEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType BLOCK_UPDATE_SHAPE_EVENT = register(BlockUpdateShapeEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType LEAVES_DECAY_EVENT = register(LeavesDecayEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType PISTON_EXTEND_EVENT = register(PistonExtendEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType PISTON_RETRACT_EVENT = register(PistonRetractEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType SIGN_CHANGE_EVENT = register(SignChangeEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.PLAYER_EVENT); + public static final GameEventType SPONGE_ABSORB_EVENT = register(SpongeAbsorbEvent.class, GameEventFlags.BLOCK_EVENT); + public static final GameEventType STRUCTURE_GROW_EVENT = register(StructureGrowEvent.class, GameEventFlags.BLOCK_EVENT); // World Events - public static final GameEventType CHUNK_LOAD_EVENT = register(ChunkLoadEvent.class); - public static final GameEventType CHUNK_UNLOAD_EVENT = register(ChunkUnloadEvent.class); - public static final GameEventType SIGN_CHANGE_EVENT = register(SignChangeEvent.class); - public static final GameEventType SPONGE_ABSORB_EVENT = register(SpongeAbsorbEvent.class); - public static final GameEventType STRUCTURE_GROW_EVENT = register(StructureGrowEvent.class); - public static final GameEventType WORLD_UNLOAD_EVENT = register(WorldUnloadEvent.class); + public static final GameEventType CHUNK_LOAD_EVENT = register(ChunkLoadEvent.class, GameEventFlags.GENERIC_WORLD_EVENT); + public static final GameEventType CHUNK_UNLOAD_EVENT = register(ChunkUnloadEvent.class, GameEventFlags.GENERIC_WORLD_EVENT); + public static final GameEventType WORLD_UNLOAD_EVENT = register(WorldUnloadEvent.class, GameEventFlags.GENERIC_WORLD_EVENT); + public static final GameEventType RAID_TRIGGER_EVENT = register(RaidTriggerEvent.class, GameEventFlags.GENERIC_WORLD_EVENT | GameEventFlags.PLAYER_EVENT); // Entity Events - public static final GameEventType ENTITY_BLOCK_FORM_EVENT = register(EntityBlockFormEvent.class); - public static final GameEventType ENTITY_CHANGE_BLOCK_EVENT = register(EntityChangeBlockEvent.class); - public static final GameEventType ENTITY_COLLISION_EVENT = register(EntityCollisionEvent.class); - public static final GameEventType ENTITY_DAMAGE_EVENT = register(EntityDamageEvent.class); - public static final GameEventType ENTITY_DEATH_EVENT = register(EntityDeathEvent.class); - public static final GameEventType ENTITY_ENTER_PORTAL_EVENT = register(EntityEnterPortalEvent.class); - public static final GameEventType ENTITY_EXPLODE_EVENT = register(EntityExplodeEvent.class); - public static final GameEventType ENTITY_MOVE_EVENT = register(EntityMoveEvent.class); - public static final GameEventType ENTITY_PORTAL_EVENT = register(EntityPortalEvent.class); - public static final GameEventType ENTITY_RIDE_EVENT = register(EntityRideEvent.class); - public static final GameEventType ENTITY_SPAWN_EVENT = register(EntitySpawnEvent.class); - public static final GameEventType ENTITY_TARGET_EVENT = register(EntityTargetEvent.class); - public static final GameEventType ENTITY_TELEPORT_EVENT = register(EntityTeleportEvent.class); - public static final GameEventType HANGING_BREAK_EVENT = register(HangingBreakEvent.class); - public static final GameEventType HANGING_PLACE_EVENT = register(HangingPlaceEvent.class); - public static final GameEventType PROJECTILE_HIT_EVENT = register(ProjectileHitEvent.class); - public static final GameEventType PROJECTILE_LAUNCH_EVENT = register(ProjectileLaunchEvent.class); - public static final GameEventType RAID_TRIGGER_EVENT = register(RaidTriggerEvent.class); + public static final GameEventType ENTITY_BLOCK_FORM_EVENT = register(EntityBlockFormEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_CHANGE_BLOCK_EVENT = register(EntityChangeBlockEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_COLLISION_EVENT = register(EntityCollisionEvent.class, GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_DAMAGE_EVENT = register(EntityDamageEvent.class, GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_DEATH_EVENT = register(EntityDeathEvent.class, GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_ENTER_PORTAL_EVENT = register(EntityEnterPortalEvent.class, GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_EXPLODE_EVENT = register(EntityExplodeEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_MOVE_EVENT = register(EntityMoveEvent.class, GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_PORTAL_EVENT = register(EntityPortalEvent.class, GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_RIDE_EVENT = register(EntityRideEvent.class, GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_SPAWN_EVENT = register(EntitySpawnEvent.class, GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_TARGET_EVENT = register(EntityTargetEvent.class, GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_TELEPORT_EVENT = register(EntityTeleportEvent.class, GameEventFlags.ENTITY_EVENT); + public static final GameEventType HANGING_BREAK_EVENT = register(HangingBreakEvent.class, GameEventFlags.ENTITY_EVENT); + public static final GameEventType HANGING_PLACE_EVENT = register(HangingPlaceEvent.class, GameEventFlags.ENTITY_EVENT); + public static final GameEventType PROJECTILE_HIT_EVENT = register(ProjectileHitEvent.class, GameEventFlags.ENTITY_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + public static final GameEventType PROJECTILE_LAUNCH_EVENT = register(ProjectileLaunchEvent.class, GameEventFlags.ENTITY_EVENT); // Inventory Events - public static final GameEventType INVENTORY_CLICK_EVENT = register(InventoryClickEvent.class); - public static final GameEventType INVENTORY_CLOSE_EVENT = register(InventoryCloseEvent.class); - public static final GameEventType INVENTORY_OPEN_EVENT = register(InventoryOpenEvent.class); + public static final GameEventType INVENTORY_CLICK_EVENT = register(InventoryClickEvent.class, GameEventFlags.INVENTORY_EVENT | GameEventFlags.PLAYER_EVENT); + public static final GameEventType INVENTORY_CLOSE_EVENT = register(InventoryCloseEvent.class, GameEventFlags.INVENTORY_EVENT | GameEventFlags.PLAYER_EVENT); + public static final GameEventType INVENTORY_OPEN_EVENT = register(InventoryOpenEvent.class, GameEventFlags.INVENTORY_EVENT | GameEventFlags.PLAYER_EVENT); // Player Events - public static final GameEventType PLAYER_CHANGED_WORLD_EVENT = register(PlayerChangedWorldEvent.class); - public static final GameEventType PLAYER_CHAT_EVENT = register(PlayerChatEvent.class); - public static final GameEventType PLAYER_COMMAND_EVENT = register(PlayerCommandEvent.class); - public static final GameEventType PLAYER_DROP_ITEM_EVENT = register(PlayerDropItemEvent.class); - public static final GameEventType PLAYER_EMPTY_BUCKET_EVENT = register(PlayerEmptyBucketEvent.class); - public static final GameEventType PLAYER_FILL_BUCKET_EVENT = register(PlayerFillBucketEvent.class); - public static final GameEventType PLAYER_GAMEMODE_CHANGE = register(PlayerGamemodeChangeEvent.class); - public static final GameEventType PLAYER_INTERACT_EVENT = register(PlayerInteractEvent.class); - public static final GameEventType PLAYER_ITEM_CONSUME_EVENT = register(PlayerItemConsumeEvent.class); - public static final GameEventType PLAYER_JOIN_EVENT = register(PlayerJoinEvent.class); - public static final GameEventType PLAYER_LEASH_ENTITY_EVENT = register(PlayerLeashEntityEvent.class); - public static final GameEventType PLAYER_LOGIN_EVENT = register(PlayerLoginEvent.class); - public static final GameEventType PLAYER_PICKUP_ARROW_EVENT = register(PlayerPickupArrowEvent.class); - public static final GameEventType PLAYER_PICKUP_ITEM_EVENT = register(PlayerPickupItemEvent.class); - public static final GameEventType PLAYER_QUIT_EVENT = register(PlayerQuitEvent.class); - public static final GameEventType PLAYER_RESPAWN_EVENT = register(PlayerRespawnEvent.class); - public static final GameEventType PLAYER_SHEAR_ENTITY_EVENT = register(PlayerShearEntityEvent.class); - public static final GameEventType PLAYER_UNLEASH_ENTITY_EVENT = register(PlayerUnleashEntityEvent.class); - - private GameEventType() { + public static final GameEventType PLAYER_CHANGED_WORLD_EVENT = register(PlayerChangedWorldEvent.class, GameEventFlags.PLAYER_EVENT); + public static final GameEventType PLAYER_CHAT_EVENT = register(PlayerChatEvent.class, GameEventFlags.PLAYER_EVENT); + public static final GameEventType PLAYER_COMMAND_EVENT = register(PlayerCommandEvent.class, GameEventFlags.PLAYER_EVENT); + public static final GameEventType PLAYER_DROP_ITEM_EVENT = register(PlayerDropItemEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT); + public static final GameEventType PLAYER_EMPTY_BUCKET_EVENT = register(PlayerEmptyBucketEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.BLOCK_EVENT); + public static final GameEventType PLAYER_FILL_BUCKET_EVENT = register(PlayerFillBucketEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.BLOCK_EVENT); + public static final GameEventType PLAYER_GAMEMODE_CHANGE = register(PlayerGamemodeChangeEvent.class, GameEventFlags.PLAYER_EVENT); + public static final GameEventType PLAYER_INTERACT_EVENT = register(PlayerInteractEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT | GameEventFlags.MAYBE_ENTITY_EVENT); + public static final GameEventType PLAYER_ITEM_CONSUME_EVENT = register(PlayerItemConsumeEvent.class, GameEventFlags.PLAYER_EVENT); + public static final GameEventType PLAYER_JOIN_EVENT = register(PlayerJoinEvent.class, GameEventFlags.PLAYER_EVENT); + public static final GameEventType PLAYER_LEASH_ENTITY_EVENT = register(PlayerLeashEntityEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT); + public static final GameEventType PLAYER_LOGIN_EVENT = register(PlayerLoginEvent.class, GameEventFlags.PLAYER_EVENT); + public static final GameEventType PLAYER_PICKUP_ARROW_EVENT = register(PlayerPickupArrowEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT); + public static final GameEventType PLAYER_PICKUP_ITEM_EVENT = register(PlayerPickupItemEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT); + public static final GameEventType PLAYER_QUIT_EVENT = register(PlayerQuitEvent.class, GameEventFlags.PLAYER_EVENT); + public static final GameEventType PLAYER_RESPAWN_EVENT = register(PlayerRespawnEvent.class, GameEventFlags.PLAYER_EVENT); + public static final GameEventType PLAYER_SHEAR_ENTITY_EVENT = register(PlayerShearEntityEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT); + public static final GameEventType PLAYER_UNLEASH_ENTITY_EVENT = register(PlayerUnleashEntityEvent.class, GameEventFlags.PLAYER_EVENT | GameEventFlags.ENTITY_EVENT); + + @GameEventFlags + private final int flags; + + private GameEventType(@GameEventFlags int flags) { + this.flags = flags; + } + + @GameEventFlags + public int getFlags() { + return this.flags; } public GameEvent createEvent(Args args) { return new GameEvent<>(this, args); } - private static GameEventType register(Class eventArgsType) { - GameEventType eventType = new GameEventType<>(); + private static GameEventType register(Class eventArgsType, @GameEventFlags int flags) { + GameEventType eventType = new GameEventType<>(flags); ALL_TYPES.add(eventType); return eventType; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventsDispatcher.java index a3149a6947..61e4377ebc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventsDispatcher.java @@ -10,8 +10,26 @@ public class GameEventsDispatcher extends EventsDispatcher< GameEventPriority, GameEvent> { + @GameEventFlags + private int capturedEventsFlags = 0; + public GameEventsDispatcher(SuperiorSkyblockPlugin plugin) { super(plugin, GameEventPriority.class, GameEventType.values()); } + @Override + public void startCaptureEvents() { + this.startCaptureEvents(0xFFFFFFFF); + } + + public void startCaptureEvents(@GameEventFlags int capturedEventsFlags) { + super.startCaptureEvents(); + this.capturedEventsFlags = capturedEventsFlags; + } + + @Override + protected boolean filterCapturedEvent(GameEvent event) { + return this.capturedEventsFlags == 0xFFFFFFFF || (event.getType().getFlags() & this.capturedEventsFlags) != 0; + } + } From 88ea8253d722a21f6630c826a3894baea56ead8f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 Jan 2026 18:07:14 +0200 Subject: [PATCH 471/600] Do not record chorus flower breaks on wind charge explosions (#2816) --- .../superiorskyblock/listener/BlockChangesListener.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index 37a5bc8faa..fe1a44f0d3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -485,6 +485,9 @@ private void onBlockFade(GameEvent e) { } private void onEntityExplode(GameEvent e) { + if (e.getArgs().isSoftExplosion) + return; + Entity entity = e.getArgs().entity; // We do not care about spawn island, and therefore only island worlds are relevant. @@ -493,11 +496,6 @@ private void onEntityExplode(GameEvent e) { KeyMap blockCounts = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); e.getArgs().blocks.forEach(block -> { - Material blockType = block.getType(); - // Soft explosions only break chorus flowers and pointed drip-stones - if (e.getArgs().isSoftExplosion && blockType != CHORUS_FLOWER) - return; - Key blockKey = Keys.of(block); blockCounts.put(blockKey, blockCounts.getOrDefault(blockKey, 0) + 1); }); From 1d897914e52d65f6e198219e953566323b4cebe9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 Jan 2026 19:43:25 +0200 Subject: [PATCH 472/600] Better detection for block changes with Eyeblossom (#2816) --- .../AbstractNMSAlgorithms.java.template | 14 +++++++ .../core/key/ConstantKeys.java | 9 ++-- .../listener/BlockChangesListener.java | 41 +++++++++++++++++++ .../listener/BukkitEventsListener.java | 9 +++- .../superiorskyblock/nms/NMSAlgorithms.java | 5 +++ .../platform/event/GameEventType.java | 2 + .../platform/event/args/GameEventArgs.java | 7 ++++ 7 files changed, 83 insertions(+), 4 deletions(-) diff --git a/NMS/src/main/templates/AbstractNMSAlgorithms.java.template b/NMS/src/main/templates/AbstractNMSAlgorithms.java.template index 245debbc66..0b4c757298 100644 --- a/NMS/src/main/templates/AbstractNMSAlgorithms.java.template +++ b/NMS/src/main/templates/AbstractNMSAlgorithms.java.template @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; +import com.bgsoftware.superiorskyblock.listener.BukkitEventsListener; import com.bgsoftware.superiorskyblock.nms.NMSAlgorithms; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuBrewingStandBlockEntity; @@ -19,6 +20,7 @@ import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuFurnaceBlockE import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.menu.MenuHopperBlockEntity; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.BlockEntityCache; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.KeyBlocksCache; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.google.common.collect.Multimap; import com.google.common.collect.MultimapBuilder; import io.papermc.paper.chat.ChatRenderer; @@ -48,6 +50,7 @@ import ${CRAFTBUKKIT_PACKAGE}.util.CraftMagicNumbers; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.world.GenericGameEvent; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.PotionMeta; @@ -264,6 +267,17 @@ public abstract class AbstractNMSAlgorithms implements NMSAlgorithms { return BIOME_ENUM_BRIDGE; } + @Override + public BukkitEventsListener.GameEventCreator getGenericGameCreator() { + return (eventType, priority, event) -> { + GameEventArgs.GenericGameEvent genericGameEvent = new GameEventArgs.GenericGameEvent(); + genericGameEvent.world = ((GenericGameEvent) event).getWorld(); + genericGameEvent.gameEvent = ((GenericGameEvent) event).getEvent().getKey().getKey(); + genericGameEvent.location = ((GenericGameEvent) event).getLocation(); + return eventType.createEvent(genericGameEvent); + }; + } + private interface MenuCreator extends BiFunction { } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java index 2283010663..60c57a6226 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java @@ -13,9 +13,6 @@ public class ConstantKeys { public static final Key AIR = Keys.of(Material.AIR); @Nullable - public static final Key BAMBOO = Optional.ofNullable(EnumHelper.getEnum(Material.class, "BAMBOO")) - .map(Keys::of).orElse(null); - @Nullable public static final Key BASALT = Optional.ofNullable(EnumHelper.getEnum(Material.class, "BASALT")) .map(Keys::of).orElse(null); public static final Key CARVED_PUMPKIN = Keys.of(EnumHelper.getEnum(Material.class, "CARVED_PUMPKIN", "PUMPKIN")); @@ -24,6 +21,9 @@ public class ConstantKeys { @Nullable public static final Key CHORUS_PLANT = Optional.ofNullable(EnumHelper.getEnum(Material.class, "CHORUS_PLANT")) .map(Keys::of).orElse(null); + @Nullable + public static final Key CLOSED_EYEBLOSSOM = Optional.ofNullable(EnumHelper.getEnum(Material.class, "CLOSED_EYEBLOSSOM")) + .map(Keys::of).orElse(null); public static final Key COBBLESTONE = Keys.of(Material.COBBLESTONE); public static final Key COMMAND_BLOCK = Keys.of(EnumHelper.getEnum(Material.class, "COMMAND_BLOCK", "COMMAND")); public static final Key EGG_MOB_SPAWNER = Keys.ofSpawner("EGG"); @@ -36,6 +36,9 @@ public class ConstantKeys { public static final Key LAVA = Keys.of(Material.LAVA); public static final Key MOB_SPAWNER = Keys.of(Materials.SPAWNER.toBukkitType()); public static final Key OBSIDIAN = Keys.of(Material.OBSIDIAN); + @Nullable + public static final Key OPEN_EYEBLOSSOM = Optional.ofNullable(EnumHelper.getEnum(Material.class, "OPEN_EYEBLOSSOM")) + .map(Keys::of).orElse(null); public static final Key SNOW_BLOCK = Keys.of(Material.SNOW_BLOCK); public static final Key SOUL_SAND = Keys.of(Material.SOUL_SAND); public static final Key TNT = Keys.of(Material.TNT); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index fe1a44f0d3..d11ca2dd7a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -49,6 +49,12 @@ public class BlockChangesListener extends AbstractGameEventListener { @Nullable private static final Material CHORUS_FLOWER = EnumHelper.getEnum(Material.class, "CHORUS_FLOWER"); + + @Nullable + private static final Material CLOSED_EYEBLOSSOM = EnumHelper.getEnum(Material.class, "CLOSED_EYEBLOSSOM"); + + @Nullable + private static final Material OPEN_EYEBLOSSOM = EnumHelper.getEnum(Material.class, "OPEN_EYEBLOSSOM"); @Nullable private static final CreatureSpawnEvent.SpawnReason BUILD_COPPERGOLEM = EnumHelper.getEnum(CreatureSpawnEvent.SpawnReason.class, "BUILD_COPPERGOLEM"); @@ -529,6 +535,38 @@ private void onSpongeAbsorb(GameEvent e) { } } + private void onGenericGame(GameEvent e) { + // We do not care about spawn island, and therefore only island worlds are relevant. + if (!plugin.getGrid().isIslandsWorld(e.getArgs().world)) + return; + + // We only care about block_change + if (!e.getArgs().gameEvent.equals("block_change")) + return; + + Location blockLocation = e.getArgs().location; + Block block = blockLocation.getBlock(); + Material blockType = block.getType(); + + Key newBlockKey; + Key oldBlockKey; + + if (blockType == OPEN_EYEBLOSSOM) { + // OPEN_EYEBLOSSOM was changed, we want to remove CLOSED_EYEBLOSSOM and replace it with OPEN_EYEBLOSSOM + newBlockKey = ConstantKeys.OPEN_EYEBLOSSOM; + oldBlockKey = ConstantKeys.CLOSED_EYEBLOSSOM; + } else if (blockType == CLOSED_EYEBLOSSOM) { + // CLOSED_EYEBLOSSOM was changed, we want to remove OPEN_EYEBLOSSOM and replace it with CLOSED_EYEBLOSSOM + newBlockKey = ConstantKeys.CLOSED_EYEBLOSSOM; + oldBlockKey = ConstantKeys.OPEN_EYEBLOSSOM; + } else { + return; + } + + worldRecordService.get().recordBlockPlace(newBlockKey, blockLocation, 1, null, 0); + worldRecordService.get().recordBlockBreak(oldBlockKey, blockLocation, 1, REGULAR_RECORD_FLAGS); + } + /* INTERNAL */ private void registerListeners() { @@ -550,6 +588,9 @@ private void registerListeners() { registerCallback(GameEventType.BLOCK_FADE_EVENT, GameEventPriority.MONITOR, this::onBlockFade); registerCallback(GameEventType.ENTITY_EXPLODE_EVENT, GameEventPriority.MONITOR, this::onEntityExplode); registerCallback(GameEventType.SPONGE_ABSORB_EVENT, GameEventPriority.MONITOR, this::onSpongeAbsorb); + + if (CLOSED_EYEBLOSSOM != null || OPEN_EYEBLOSSOM != null) + registerCallback(GameEventType.GENERIC_GAME_EVENT, GameEventPriority.MONITOR, this::onGenericGame); } @Nullable diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index 359c5544fb..8d493f27d6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -236,6 +236,13 @@ public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { createEventListener(GameEventType.RAID_TRIGGER_EVENT, org.bukkit.event.raid.RaidTriggerEvent.class, new RaidTriggerEventFunctions()); } catch (Exception ignored) { } + + + try { + Class genericGameEventClass = Class.forName("org.bukkit.event.world.GenericGameEvent"); + createEventListener(GameEventType.GENERIC_GAME_EVENT, genericGameEventClass, plugin.getNMSAlgorithms().getGenericGameCreator()); + } catch (Exception ignored) { + } } /* @@ -859,7 +866,7 @@ private static ItemStack getHandItem(Player player, PlayerHand usedHand, boolean return itemStack; } - private interface GameEventCreator { + public interface GameEventCreator { @Nullable GameEvent execute(GameEventType eventType, GameEventPriority priority, E e); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java index d67656858e..32f1a9ab54 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java @@ -3,6 +3,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.io.ClassProcessor; +import com.bgsoftware.superiorskyblock.listener.BukkitEventsListener; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Biome; @@ -97,6 +98,10 @@ default EnumBridge getBiomeBridge() { return BIOME_ENUM_BRIDGE; } + default BukkitEventsListener.GameEventCreator getGenericGameCreator() { + throw new UnsupportedOperationException("Not supported in this version"); + } + interface EnumBridge { T[] getValues(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java index 9cfaaaf010..cd23989a72 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java @@ -36,6 +36,7 @@ import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntitySpawnEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityTargetEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityTeleportEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.GenericGameEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.HangingBreakEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.HangingPlaceEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.InventoryClickEvent; @@ -100,6 +101,7 @@ public class GameEventType extends EventType CHUNK_UNLOAD_EVENT = register(ChunkUnloadEvent.class, GameEventFlags.GENERIC_WORLD_EVENT); public static final GameEventType WORLD_UNLOAD_EVENT = register(WorldUnloadEvent.class, GameEventFlags.GENERIC_WORLD_EVENT); public static final GameEventType RAID_TRIGGER_EVENT = register(RaidTriggerEvent.class, GameEventFlags.GENERIC_WORLD_EVENT | GameEventFlags.PLAYER_EVENT); + public static final GameEventType GENERIC_GAME_EVENT = register(GenericGameEvent.class, GameEventFlags.GENERIC_WORLD_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT | GameEventFlags.MAYBE_ENTITY_EVENT); // Entity Events public static final GameEventType ENTITY_BLOCK_FORM_EVENT = register(EntityBlockFormEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.ENTITY_EVENT); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java index a544f5f033..980744a378 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java @@ -391,6 +391,13 @@ public static class BlockUpdateShapeEvent extends BlockEvent { } + public static class GenericGameEvent extends WorldEvent { + + public String gameEvent; + public Location location; + + } + private static class BlockEvent extends GameEventArgs { public Block block; From 32f73e780cdd98e0f719ac251f7f90ab955a8857 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 3 Jan 2026 20:05:03 +0200 Subject: [PATCH 473/600] Fixed errors with creating new schematics (#2830) --- .../world/schematic/parser/DefaultSchematicParser.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/parser/DefaultSchematicParser.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/parser/DefaultSchematicParser.java index 0e9903c124..a7394acdb2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/parser/DefaultSchematicParser.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/parser/DefaultSchematicParser.java @@ -14,14 +14,14 @@ import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; public class DefaultSchematicParser implements SchematicParser { private static final DefaultSchematicParser INSTANCE = new DefaultSchematicParser(); - private static final Map HASHED_SCHEMATIC = new HashMap<>(); + private static final Map HASHED_SCHEMATIC = new ConcurrentHashMap<>(); public static DefaultSchematicParser getInstance() { return INSTANCE; From e303499b41adf9ab8492d376963d8e86681c0a0f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 Jan 2026 16:01:28 +0200 Subject: [PATCH 474/600] Fixed IslandChatEvent is not called when using `/is tc ` command (#2833) --- .../commands/player/CmdTeamChat.java | 13 ++-------- .../superiorskyblock/island/IslandUtils.java | 25 +++++++++++++++++++ .../listener/PlayersListener.java | 18 +------------ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeamChat.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeamChat.java index 8d90917a6c..cdc73848c8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeamChat.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdTeamChat.java @@ -9,9 +9,7 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; -import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; import java.util.Arrays; import java.util.Collections; @@ -77,15 +75,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ superiorPlayer.toggleTeamChat(); } else { - String message = CommandArguments.buildLongString(args, 1, superiorPlayer.hasPermissionWithoutOP("superior.chat.color")); - IslandUtils.sendMessage(island, Message.TEAM_CHAT_FORMAT, Collections.emptyList(), superiorPlayer.getPlayerRole(), - superiorPlayer.getName(), message); - Message.SPY_TEAM_CHAT_FORMAT.send(Bukkit.getConsoleSender(), superiorPlayer.getPlayerRole(), superiorPlayer.getName(), message); - for (Player _onlinePlayer : Bukkit.getOnlinePlayers()) { - SuperiorPlayer onlinePlayer = plugin.getPlayers().getSuperiorPlayer(_onlinePlayer); - if (onlinePlayer.hasAdminSpyEnabled()) - Message.SPY_TEAM_CHAT_FORMAT.send(onlinePlayer, superiorPlayer.getPlayerRole(), superiorPlayer.getName(), message); - } + String message = CommandArguments.buildLongString(args, 1, false); + IslandUtils.handleIslandChat(island, superiorPlayer, message); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java index 51925f78f1..5cf5c00700 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java @@ -17,6 +17,8 @@ import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; +import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -24,10 +26,12 @@ import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; +import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Biome; +import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; @@ -336,4 +340,25 @@ public static List getDefaultWorldBiomes() { return new SequentialListBuilder().build(DEFAULT_WORLD_BIOMES.values()); } + public static void handleIslandChat(Island island, SuperiorPlayer superiorPlayer, String message) { + PluginEvent event = PluginEventsFactory.callIslandChatEvent(island, superiorPlayer, + superiorPlayer.hasPermissionWithoutOP("superior.chat.color") ? Formatters.COLOR_FORMATTER.format(message) : message); + + if (event.isCancelled()) + return; + + IslandUtils.sendMessage(island, Message.TEAM_CHAT_FORMAT, Collections.emptyList(), + superiorPlayer.getPlayerRole(), superiorPlayer.getName(), event.getArgs().message); + + Message.SPY_TEAM_CHAT_FORMAT.send(Bukkit.getConsoleSender(), superiorPlayer.getPlayerRole().getDisplayName(), + superiorPlayer.getName(), event.getArgs().message); + + for (Player _onlinePlayer : Bukkit.getOnlinePlayers()) { + SuperiorPlayer onlinePlayer = plugin.getPlayers().getSuperiorPlayer(_onlinePlayer); + if (onlinePlayer.hasAdminSpyEnabled()) + Message.SPY_TEAM_CHAT_FORMAT.send(onlinePlayer, superiorPlayer.getPlayerRole().getDisplayName(), + superiorPlayer.getName(), event.getArgs().message); + } + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java index 93ef6aa78f..3d68c36c46 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java @@ -407,23 +407,7 @@ private void onPlayerChat(GameEvent e) { String message = e.getArgs().message; - PluginEvent event = PluginEventsFactory.callIslandChatEvent(island, superiorPlayer, - superiorPlayer.hasPermissionWithoutOP("superior.chat.color") ? Formatters.COLOR_FORMATTER.format(message) : message); - - if (event.isCancelled()) - return; - - IslandUtils.sendMessage(island, Message.TEAM_CHAT_FORMAT, Collections.emptyList(), - superiorPlayer.getPlayerRole(), superiorPlayer.getName(), event.getArgs().message); - - Message.SPY_TEAM_CHAT_FORMAT.send(Bukkit.getConsoleSender(), superiorPlayer.getPlayerRole().getDisplayName(), - superiorPlayer.getName(), event.getArgs().message); - for (Player _onlinePlayer : Bukkit.getOnlinePlayers()) { - SuperiorPlayer onlinePlayer = plugin.getPlayers().getSuperiorPlayer(_onlinePlayer); - if (onlinePlayer.hasAdminSpyEnabled()) - Message.SPY_TEAM_CHAT_FORMAT.send(onlinePlayer, superiorPlayer.getPlayerRole().getDisplayName(), - superiorPlayer.getName(), event.getArgs().message); - } + IslandUtils.handleIslandChat(island, superiorPlayer, message); } else if (e.getArgs().format != null) { e.getArgs().format = Formatters.CHAT_FORMATTER.format(new ChatFormatter.ChatFormatArgs(e.getArgs().format, superiorPlayer, island)); } From 6aebeb0c6da5a72521447d4650c6acc75ddf917e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 Jan 2026 17:28:30 +0200 Subject: [PATCH 475/600] Fix errors when creating new islands due to NoSuchNextElement error (#2830) --- .../bgsoftware/superiorskyblock/core/VarintArray.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/VarintArray.java b/src/main/java/com/bgsoftware/superiorskyblock/core/VarintArray.java index 073560289f..85fd1a0bcb 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/VarintArray.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/VarintArray.java @@ -7,7 +7,8 @@ public class VarintArray { - private static final byte[] VARINT_BUF = new byte[10]; + private static final ThreadLocal VARINT_BUF = ThreadLocal.withInitial(() -> new byte[10]); + private static final byte[] ZERO_BYTE = new byte[]{0}; private final ByteBigArray backend; @@ -44,13 +45,15 @@ private static byte[] serializeVarint(long value) { if (value == 0) return ZERO_BYTE; + byte[] varintBuf = VARINT_BUF.get(); + int varintBytesCount = 0; while (value != 0) { byte nextByte = (byte) (value & 0x7f); value >>= 7; - VARINT_BUF[varintBytesCount++] = value == 0 ? nextByte : (byte) (nextByte | 0x80); + varintBuf[varintBytesCount++] = value == 0 ? nextByte : (byte) (nextByte | 0x80); } - return Arrays.copyOf(VARINT_BUF, varintBytesCount); + return Arrays.copyOf(varintBuf, varintBytesCount); } public class Itr { From df09d3731aa7fdbe1bb0bc3cfbd9c3701e89ac3c Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 Jan 2026 17:37:46 +0200 Subject: [PATCH 476/600] Fixed duped block count tracking of cobblestone generated by a generator (#2839) --- .../superiorskyblock/listener/BlockChangesListener.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java index d11ca2dd7a..45f31af2bc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BlockChangesListener.java @@ -463,8 +463,12 @@ private void onBlockFromTo(GameEvent e) { this.worldRecordService.get().recordBlockBreak(toBlock, 1, WorldRecordFlags.DIRTY_CHUNKS); } else { BukkitExecutor.sync(() -> { - // Do not save block counts - this.worldRecordService.get().recordBlockPlace(toBlock, 1, null, WorldRecordFlags.DIRTY_CHUNKS); + // Ignore cobblestone blocks, otherwise it will add +1 to the count of cobblestone when generated + // from cobblestone generator + if (toBlock.getType() != Material.COBBLESTONE) { + // Do not save block counts + this.worldRecordService.get().recordBlockPlace(toBlock, 1, null, WorldRecordFlags.DIRTY_CHUNKS); + } }); } } From 615a7e840c566a58c775860eb897e12535e5181f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 Jan 2026 17:39:14 +0200 Subject: [PATCH 477/600] Ignore UnsupportedOperationException when thrown from WorldsProvider#addWorldLoadListener (#2831) --- .../superiorskyblock/external/ProvidersManagerImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java index 9070c430a6..17572591f9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java @@ -195,8 +195,12 @@ public void setWorldsProvider(WorldsProvider worldsProvider) { private void setWorldsProviderInternal(WorldsProvider worldsProvider) { this.worldsProvider = worldsProvider; - this.worldsProvider.addWorldLoadListener(DEFAULT_WORLD_LOAD_LISTENER); this.isCustomWorldsProvider = !(worldsProvider instanceof WorldsProvider_Default); + try { + this.worldsProvider.addWorldLoadListener(DEFAULT_WORLD_LOAD_LISTENER); + } catch (UnsupportedOperationException ignored) { + // Ignore UnsupportedOperationException + } } @Override From 8ca42da389be362a4f8a6db62d235e233d781bda Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 Jan 2026 18:37:00 +0200 Subject: [PATCH 478/600] Fix custom layout order does not affect button clicks (#2838) --- .../api/menu/button/PagedMenuTemplateButton.java | 7 +++++++ .../core/menu/button/PagedMenuTemplateButtonImpl.java | 9 ++++++++- .../core/menu/layout/PagedMenuLayoutImpl.java | 11 +++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/button/PagedMenuTemplateButton.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/button/PagedMenuTemplateButton.java index 91e636aea2..ed7b57d33e 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/button/PagedMenuTemplateButton.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/menu/button/PagedMenuTemplateButton.java @@ -24,6 +24,13 @@ public interface PagedMenuTemplateButton, E> extends Me */ int getButtonIndex(); + /** + * Sets the index within the menu of this paged object button. + * + * @param buttonIndex The new index to set. + */ + void setButtonIndex(int buttonIndex); + /** * Create a view-button object to be used by the provided menu view. * Unlike the template button, the view button handles the logic for buttons within the view. diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/PagedMenuTemplateButtonImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/PagedMenuTemplateButtonImpl.java index 121f3cb695..cb1446a6b4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/PagedMenuTemplateButtonImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/PagedMenuTemplateButtonImpl.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; +import com.google.common.base.Preconditions; import org.bukkit.inventory.ItemStack; import java.util.List; @@ -16,8 +17,8 @@ public class PagedMenuTemplateButtonImpl, E> extends Ab protected static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private final TemplateItem nullItem; - private final int buttonIndex; private final PagedMenuViewButtonCreator viewButtonCreator; + private int buttonIndex; public PagedMenuTemplateButtonImpl(TemplateItem buttonItem, GameSound clickSound, List commands, String requiredPermission, GameSound lackPermissionSound, TemplateItem nullItem, @@ -42,6 +43,12 @@ public int getButtonIndex() { return this.buttonIndex; } + @Override + public void setButtonIndex(int buttonIndex) { + Preconditions.checkArgument(buttonIndex >= 0, "buttonIndex cannot be negative."); + this.buttonIndex = buttonIndex; + } + @Override public PagedMenuViewButton createViewButton(V menuView) { return ensureCorrectType(this.viewButtonCreator.create(this, menuView)); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/PagedMenuLayoutImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/PagedMenuLayoutImpl.java index 6920cabd52..dea518867b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/PagedMenuLayoutImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/layout/PagedMenuLayoutImpl.java @@ -33,6 +33,17 @@ private PagedMenuLayoutImpl(String title, InventoryType inventoryType, MenuTempl super(title, inventoryType, buttons); this.customLayoutOrder = layoutOrder; this.objectsPerPageCount = layoutOrder == null ? countPagedButtons(buttons) : layoutOrder.getObjectsPerPageCount(); + if (this.customLayoutOrder != null) { + // Update button indexes with the custom layout order + PagedLayoutOrder.MenuButtonsIterator buttonsIterator = this.customLayoutOrder.createIterator(this.buttons); + int buttonIndex = 0; + while (buttonsIterator.hasNext()) { + MenuTemplateButton templateButton = buttonsIterator.next(); + + if (templateButton instanceof PagedMenuTemplateButton) + ((PagedMenuTemplateButton) templateButton).setButtonIndex(buttonIndex++); + } + } } @Override From 36cc5e7115957c8cbd654964f1b5d954446981a3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 Jan 2026 18:53:27 +0200 Subject: [PATCH 479/600] Fixed the ability to change spawner types even if the spawner block type limit was reached (#2796) --- .../upgrades/type/UpgradeTypeBlockLimits.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java index 093e4f748d..3adf00408c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java @@ -138,9 +138,17 @@ private boolean onSpawnerChangeInternal(PlayerInteractEvent e, Material clickedB island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation(wrapper.getHandle())); } - if (island != null && island.hasReachedBlockLimit(newSpawnerKey)) { - Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(newSpawnerKey.toString())); - return true; + if (island == null) + return false; + + try { + island.handleBlockBreak(oldSpawnerKey, 1, 0); + if (island.hasReachedBlockLimit(newSpawnerKey)) { + Message.REACHED_BLOCK_LIMIT.send(e.getPlayer(), Formatters.CAPITALIZED_FORMATTER.format(newSpawnerKey.toString())); + return true; + } + } finally { + island.handleBlockPlace(oldSpawnerKey, 1, 0); } return false; From cb22454e4794cff6a964a31a35a1ff7f567c0c62 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 Jan 2026 19:07:42 +0200 Subject: [PATCH 480/600] Fix using OfflinePlayerData causing players to teleport to 0,0,0 (#2823) --- .../nms/v1_21_10/utils/NMSUtilsVersioned.java | 11 +++++++++-- .../nms/v1_21_9/utils/NMSUtilsVersioned.java | 11 +++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java index f1e11adcfd..328628ee17 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java @@ -150,7 +150,7 @@ public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); - if(readData != null) { + if (readData != null) { CompoundTag entityData = switch (readData.result()) { case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); case SYNC_READ -> readData.syncRead(); @@ -351,7 +351,14 @@ public static PalettedContainer> createBiomesContainer(Holder loadPlayerData(ServerPlayer serverPlayer) { - return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId()); + try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) { + return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId()) + .map(playerData -> { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData); + serverPlayer.load(valueInput); + return playerData; + }); + } } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java index 9aa7b43404..1f490d7b28 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java @@ -152,7 +152,7 @@ public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( int chunkZ = chunkPosition.getZ(); MoonriseRegionFileIO.RegionDataController.ReadData readData = regionDataController.readData(chunkX, chunkZ); - if(readData != null) { + if (readData != null) { CompoundTag entityData = switch (readData.result()) { case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); case SYNC_READ -> readData.syncRead(); @@ -353,7 +353,14 @@ public static PalettedContainer> createBiomesContainer(Holder loadPlayerData(ServerPlayer serverPlayer) { - return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId()); + try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) { + return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId()) + .map(playerData -> { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData); + serverPlayer.load(valueInput); + return playerData; + }); + } } public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { From ab058df2481c4dd8896d4edbab2620ebcbc9680e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 Jan 2026 19:20:47 +0200 Subject: [PATCH 481/600] Fixed admin teleport command not teleporting to the correct world (#2797) --- .../commands/admin/CmdAdminTeleport.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java index 63f4741127..c6990d3502 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java @@ -98,12 +98,12 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (dimension != plugin.getSettings().getWorlds().getDefaultWorldDimension()) { if (!island.wasSchematicGenerated(dimension)) { PortalType portalType = dimension.getEnvironment() == World.Environment.NETHER ? PortalType.NETHER : PortalType.ENDER; - WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, dimension); - Location homeLocation = island.getIslandHomePosition(dimension).toLocation(worldInfo); - IslandWorlds.accessIslandWorldAsync(island, homeLocation, true, islandWorldResult -> { + IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { - homeLocation.setWorld(world); - portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, homeLocation, portalType, false); + Location simulatedPortalLocation = island.getCenter( + plugin.getSettings().getWorlds().getDefaultWorldDimension()); + portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, + simulatedPortalLocation, portalType, false); }); }); return; From 737ee959adbe399012335195f3f815848ab9dc59 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 9 Jan 2026 20:31:11 +0200 Subject: [PATCH 482/600] Fixed the ability to bypass stop-leaving when riding horses and similar entities (#2791) --- .../superiorskyblock/listener/IslandOutsideListener.java | 7 ++++++- .../superiorskyblock/listener/PlayersListener.java | 9 ++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java index 09c229c899..440425e6b6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandOutsideListener.java @@ -127,10 +127,15 @@ private boolean handlePlayerMove(SuperiorPlayer superiorPlayer, Location from, L private void handlePlayerMoveOutsideIslandTeleport(SuperiorPlayer superiorPlayer, Location from, boolean forceTeleport) { Island fromIsland = plugin.getGrid().getIslandAt(from); + Player player = superiorPlayer.asPlayer(); + // We don't teleport in case we're inside the island, we just cancel the event. - if (!forceTeleport && fromIsland != null && fromIsland.isInsideRange(from)) + // However, if the player is in vehicle, we want to eject him and teleport. + if (!forceTeleport && fromIsland != null && fromIsland.isInsideRange(from) && !player.isInsideVehicle()) return; + player.eject(); + if (fromIsland != null) { superiorPlayer.teleport(fromIsland, result -> { if (!result) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java index 3d68c36c46..753f16840d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PlayersListener.java @@ -13,8 +13,6 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.events.args.PluginEventArgs; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.formatting.impl.ChatFormatter; @@ -35,7 +33,6 @@ import com.bgsoftware.superiorskyblock.player.permissions.PlayerPermissionsStore; import com.bgsoftware.superiorskyblock.player.respawn.RespawnActions; import com.bgsoftware.superiorskyblock.world.BukkitEntities; -import org.bukkit.Bukkit; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.block.Block; @@ -254,6 +251,12 @@ private void onPlayerMove(GameEvent e) { case VOID_TELEPORT: case SUCCESS: break; + case LEAVE_ISLAND_TO_OUTSIDE: + // Only cancel the event if player is not inside vehicle. If the player is inside the vehicle, + // IslandOutsideListener will detect it and teleport him away. + if (!player.isInsideVehicle()) + e.setCancelled(); + break; default: e.setCancelled(); break; From 09ac63ab1f5d54e52694fd5596de9c10fc4b7965 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 10 Jan 2026 00:56:07 +0200 Subject: [PATCH 483/600] Fixed players able to open barrel menus from WildStacker on other islands (#1108) --- .../StackedBlocksProvider_WildStacker.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java index b0b24fc77e..06aba17252 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.SuperiorSkyblockAPI; import com.bgsoftware.superiorskyblock.api.hooks.StackedBlocksSnapshotProvider; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.CustomKeyParser; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; @@ -32,6 +33,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.ItemStack; import java.util.Collection; @@ -184,6 +186,26 @@ public void onBarrelPlace(BarrelPlaceInventoryEvent e) { } } + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) + public void onBarrelInteract(PlayerInteractEvent e) { + if (e.getClickedBlock() == null || WildStackerAPI.getStackedBarrel(e.getClickedBlock()) == null) + return; + + Island island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation()); + + if (island == null) + return; + + Player player = e.getPlayer(); + + IslandPrivilege privilege = player.isSneaking() ? IslandPrivileges.BUILD : IslandPrivileges.BREAK; + + if (!island.hasPermission(player, privilege)) { + e.setCancelled(true); + ProtectionHelper.sendProtectionMessage(player); + } + } + } private static Key getBarrelKey(StackedBarrel barrel) { From 5789a16cccad96e398f450a88a03031959a271a9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 12 Jan 2026 22:42:31 +0200 Subject: [PATCH 484/600] Fix stacked blocks can be broken without VALUABLE_BREAK (#2843) --- .../StackedBlocksProvider_WildStacker.java | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java index 06aba17252..9a459fdbf6 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; @@ -28,6 +29,7 @@ import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -155,7 +157,12 @@ public void onBarrelUnstackOnOtherIsland(BarrelUnstackEvent e) { if (island == null) return; - if (!island.hasPermission(player, IslandPrivileges.BREAK)) { + Key blockKey = getBarrelKey(e.getBarrel()); + + IslandPrivilege islandPrivilege = plugin.getSettings().getValuableBlocks().contains(blockKey) ? + IslandPrivileges.VALUABLE_BREAK : IslandPrivileges.BREAK; + + if (!island.hasPermission(player, islandPrivilege)) { e.setCancelled(true); ProtectionHelper.sendProtectionMessage(player); } @@ -188,17 +195,32 @@ public void onBarrelPlace(BarrelPlaceInventoryEvent e) { @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true) public void onBarrelInteract(PlayerInteractEvent e) { - if (e.getClickedBlock() == null || WildStackerAPI.getStackedBarrel(e.getClickedBlock()) == null) + Block block = e.getClickedBlock(); + if (block == null) return; - Island island = plugin.getGrid().getIslandAt(e.getClickedBlock().getLocation()); + StackedBarrel stackedBarrel; + Island island; + + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location location = block.getLocation(wrapper.getHandle()); + + stackedBarrel = WildStackerAPI.getWildStacker().getSystemManager().getStackedBarrel(location); + if (stackedBarrel == null) + return; + + island = plugin.getGrid().getIslandAt(location); + } if (island == null) return; Player player = e.getPlayer(); + Key blockKey = getBarrelKey(stackedBarrel); - IslandPrivilege privilege = player.isSneaking() ? IslandPrivileges.BUILD : IslandPrivileges.BREAK; + IslandPrivilege privilege = player.isSneaking() ? IslandPrivileges.BUILD : + plugin.getSettings().getValuableBlocks().contains(blockKey) ? + IslandPrivileges.VALUABLE_BREAK : IslandPrivileges.BREAK; if (!island.hasPermission(player, privilege)) { e.setCancelled(true); From 7145553825c5d880bae5d351f2bef5b2eef4209c Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 12 Jan 2026 22:45:54 +0200 Subject: [PATCH 485/600] Fix errors when using WildStacker (#2842) --- .../stackedblocks/StackedBlocksProvider_WildStacker.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java index 9a459fdbf6..a3042794d4 100644 --- a/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java +++ b/Hooks/WildStacker/src/main/java/com/bgsoftware/superiorskyblock/external/stackedblocks/StackedBlocksProvider_WildStacker.java @@ -205,10 +205,10 @@ public void onBarrelInteract(PlayerInteractEvent e) { try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location location = block.getLocation(wrapper.getHandle()); - stackedBarrel = WildStackerAPI.getWildStacker().getSystemManager().getStackedBarrel(location); - if (stackedBarrel == null) + if(!WildStackerAPI.getWildStacker().getSystemManager().isStackedBarrel(location)) return; + stackedBarrel = WildStackerAPI.getWildStacker().getSystemManager().getStackedBarrel(location); island = plugin.getGrid().getIslandAt(location); } From bdd0dbb4cb03ff6c890695449e6040723c292f60 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 16 Jan 2026 17:55:23 +0200 Subject: [PATCH 486/600] Added debug messages to when `markChunkDirty` or `markChunkEmpty` fails (#2836) --- .../java/com/bgsoftware/superiorskyblock/island/SIsland.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 5055f51ae1..3d95ce168f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -2813,7 +2813,7 @@ public void markChunkDirty(World world, int chunkX, int chunkZ, boolean save) { @Override public void markChunkDirty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { Preconditions.checkNotNull(worldInfo, "worldInfo parameter cannot be null."); - Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk must be within the island boundaries."); + Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk {" + worldInfo.getName() + "," + chunkX + "," + chunkZ + "} must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) { this.dirtyChunksContainer.markDirty(chunkPosition, save); } @@ -2827,7 +2827,7 @@ public void markChunkEmpty(World world, int chunkX, int chunkZ, boolean save) { @Override public void markChunkEmpty(WorldInfo worldInfo, int chunkX, int chunkZ, boolean save) { - Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk must be within the island boundaries."); + Preconditions.checkArgument(isInside(worldInfo, chunkX, chunkZ), "Chunk {" + worldInfo.getName() + "," + chunkX + "," + chunkZ + "} must be within the island boundaries."); try (ChunkPosition chunkPosition = ChunkPosition.of(worldInfo, chunkX, chunkZ)) { this.dirtyChunksContainer.markEmpty(chunkPosition, save); } From 38911d2ec57641912abfea5419e81a093bc6a4eb Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 30 Jan 2026 20:44:39 +0200 Subject: [PATCH 487/600] Ensure no corrupted records of islands and players exist in database when it loads --- .../core/database/DataManager.java | 54 ++++++++++++++++-- .../bridge/IslandsDatabaseBridge.java | 42 ++++++++------ .../bridge/PlayersDatabaseBridge.java | 40 +++++++------- .../core/database/cache/DatabaseCache.java | 35 +++++++++--- .../serialization/IslandsDeserializer.java | 55 +++++++++++-------- .../serialization/PlayersDeserializer.java | 13 ++++- 6 files changed, 161 insertions(+), 78 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java index cedbf38472..e11958e309 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.core.Manager; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.database.bridge.GridDatabaseBridge; +import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.cache.DatabaseCache; import com.bgsoftware.superiorskyblock.core.database.loader.DatabaseLoader; @@ -136,13 +137,19 @@ private void loadPlayers() { return; } - plugin.getPlayers().getPlayersContainer().addPlayer(databaseCache.computeIfAbsentInfo(uuid.get(), SuperiorPlayer::newBuilder) + DatabaseCache.Record playerRecord = + databaseCache.computeIfAbsentInfo(uuid.get(), SuperiorPlayer::newBuilder); + + playerRecord.get() .setUniqueId(uuid.get()) .setName(databaseResult.getString("last_used_name").orElse("null")) .setDisbands(databaseResult.getInt("disbands").orElse(0)) .setTextureValue(databaseResult.getString("last_used_skin").orElse("")) - .setLastTimeUpdated(databaseResult.getLong("last_time_updated").orElse(System.currentTimeMillis() / 1000)) - .build()); + .setLastTimeUpdated(databaseResult.getLong("last_time_updated").orElse(System.currentTimeMillis() / 1000)); + + checkCorruptedPlayerRecord(playerRecord); + + plugin.getPlayers().getPlayersContainer().addPlayer(playerRecord.get().build()); playersCount.incrementAndGet(); }); @@ -152,6 +159,18 @@ private void loadPlayers() { Log.info("Finished loading " + playersCount.get() + " players (Took " + (endTime - startTime) + "ms)"); } + private void checkCorruptedPlayerRecord(DatabaseCache.Record playerRecord) { + if (playerRecord.getRecordedTables().contains("players_settings")) + return; + + // We create a temporary SuperiorPlayer for inserting the corrupted record + SuperiorPlayer superiorPlayer = playerRecord.get().build(); + + Log.warn("The player " + superiorPlayer.getUniqueId() + " does not have a players_settings record - fixing it..."); + + PlayersDatabaseBridge.insertPlayerSettings(superiorPlayer); + } + private void loadIslands() { Log.info("Starting to load islands..."); @@ -212,7 +231,10 @@ private void loadIslands() { return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new) + DatabaseCache.Record islandRecord = + databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + + Island.Builder builder = islandRecord.get() .setOwner(owner) .setUniqueId(uuid.get()) .setCenter(center.get()) @@ -228,7 +250,6 @@ private void loadIslands() { .setDescription(databaseResult.getString("description").orElse("")) .setLastTimeUpdated(databaseResult.getLong("last_time_updated").orElse(System.currentTimeMillis() / 1000L)); - EnumerateSet generatedSchematics = LegacyMasks.convertGeneratedSchematicsMask( databaseResult.getInt("generated_schematics").orElse(0)); EnumerateSet unlockedWorlds = LegacyMasks.convertUnlockedWorldsMask( @@ -251,6 +272,8 @@ private void loadIslands() { IslandsDeserializer.deserializeEntityCounts(builder, entityCounts); }); + checkCorruptedIslandRecord(islandRecord); + plugin.getGrid().getIslandsContainer().addIsland(builder.build()); islandsCount.incrementAndGet(); @@ -261,6 +284,27 @@ private void loadIslands() { Log.info("Finished loading " + islandsCount.get() + " islands (Took " + (endTime - startTime) + "ms)"); } + private void checkCorruptedIslandRecord(DatabaseCache.Record islandRecord) { + boolean hasIslandsBanks = islandRecord.getRecordedTables().contains("islands_banks"); + boolean hasIslandsSettings = islandRecord.getRecordedTables().contains("islands_settings"); + + if (hasIslandsBanks && hasIslandsSettings) + return; + + // We create a temporary Island for inserting the corrupted record + Island island = islandRecord.get().build(); + + if (!hasIslandsBanks) { + Log.warn("The island " + island.getUniqueId() + " does not have a islands_banks record - fixing it..."); + IslandsDatabaseBridge.insertIslandBanks(island); + } + + if (!hasIslandsSettings) { + Log.warn("The island " + island.getUniqueId() + " does not have a islands_banks record - fixing it..."); + IslandsDatabaseBridge.insertIslandSettings(island); + } + } + private void loadGrid() { Log.info("Starting to load grid..."); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index 36f66225dd..b0b8184b5f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -32,7 +32,6 @@ import com.bgsoftware.superiorskyblock.island.IslandNames; import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; import com.bgsoftware.superiorskyblock.world.Dimensions; -import org.bukkit.Location; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; @@ -662,25 +661,32 @@ public static void insertIsland(Island island, @Nullable List dir new Pair<>("block_counts", IslandsSerializer.serializeBlockCounts(island.getBlockCountsAsBigInteger())), new Pair<>("entity_counts", IslandsSerializer.serializeEntityCounts(island.getEntitiesTracker().getEntitiesCounts())) ); + }); - databaseBridge.insertObject("islands_banks", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("balance", island.getIslandBank().getBalance() + ""), - new Pair<>("last_interest_time", island.getLastInterestTime()) - ); + insertIslandBanks(island); + insertIslandSettings(island); + } - databaseBridge.insertObject("islands_settings", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("size", island.getIslandSizeRaw()), - new Pair<>("bank_limit", island.getBankLimitRaw() + ""), - new Pair<>("coops_limit", island.getCoopLimitRaw()), - new Pair<>("members_limit", island.getTeamLimitRaw()), - new Pair<>("warps_limit", island.getWarpsLimitRaw()), - new Pair<>("crop_growth_multiplier", island.getCropGrowthRaw()), - new Pair<>("spawner_rates_multiplier", island.getSpawnerRatesRaw()), - new Pair<>("mob_drops_multiplier", island.getMobDropsRaw()) - ); - }); + public static void insertIslandBanks(Island island) { + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_banks", + new Pair<>("island", island.getUniqueId().toString()), + new Pair<>("balance", island.getIslandBank().getBalance() + ""), + new Pair<>("last_interest_time", island.getLastInterestTime()) + )); + } + + public static void insertIslandSettings(Island island) { + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_settings", + new Pair<>("island", island.getUniqueId().toString()), + new Pair<>("size", island.getIslandSizeRaw()), + new Pair<>("bank_limit", island.getBankLimitRaw() + ""), + new Pair<>("coops_limit", island.getCoopLimitRaw()), + new Pair<>("members_limit", island.getTeamLimitRaw()), + new Pair<>("warps_limit", island.getWarpsLimitRaw()), + new Pair<>("crop_growth_multiplier", island.getCropGrowthRaw()), + new Pair<>("spawner_rates_multiplier", island.getSpawnerRatesRaw()), + new Pair<>("mob_drops_multiplier", island.getMobDropsRaw()) + )); } public static void deleteIsland(Island island) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/PlayersDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/PlayersDatabaseBridge.java index 0e3ee4f236..32aea7c78d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/PlayersDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/PlayersDatabaseBridge.java @@ -133,26 +133,26 @@ public static void removePersistentDataContainer(SuperiorPlayer superiorPlayer) } public static void insertPlayer(SuperiorPlayer superiorPlayer) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { - Locale userLocale = superiorPlayer.getUserLocale(); - - databaseBridge.insertObject("players", - new Pair<>("uuid", superiorPlayer.getUniqueId().toString()), - new Pair<>("last_used_name", superiorPlayer.getName()), - new Pair<>("last_used_skin", superiorPlayer.getTextureValue()), - new Pair<>("disbands", superiorPlayer.getDisbands()), - new Pair<>("last_time_updated", superiorPlayer.getLastTimeStatus()) - ); - - databaseBridge.insertObject("players_settings", - new Pair<>("player", superiorPlayer.getUniqueId().toString()), - new Pair<>("language", userLocale.getLanguage() + "-" + userLocale.getCountry()), - new Pair<>("toggled_panel", superiorPlayer.hasToggledPanel()), - new Pair<>("border_color", superiorPlayer.getBorderColor().name()), - new Pair<>("toggled_border", superiorPlayer.hasWorldBorderEnabled()), - new Pair<>("island_fly", superiorPlayer.hasIslandFlyEnabled()) - ); - }); + runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("players", + new Pair<>("uuid", superiorPlayer.getUniqueId().toString()), + new Pair<>("last_used_name", superiorPlayer.getName()), + new Pair<>("last_used_skin", superiorPlayer.getTextureValue()), + new Pair<>("disbands", superiorPlayer.getDisbands()), + new Pair<>("last_time_updated", superiorPlayer.getLastTimeStatus()) + )); + insertPlayerSettings(superiorPlayer); + } + + public static void insertPlayerSettings(SuperiorPlayer superiorPlayer) { + Locale userLocale = superiorPlayer.getUserLocale(); + runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("players_settings", + new Pair<>("player", superiorPlayer.getUniqueId().toString()), + new Pair<>("language", userLocale.getLanguage() + "-" + userLocale.getCountry()), + new Pair<>("toggled_panel", superiorPlayer.hasToggledPanel()), + new Pair<>("border_color", superiorPlayer.getBorderColor().name()), + new Pair<>("toggled_border", superiorPlayer.hasWorldBorderEnabled()), + new Pair<>("island_fly", superiorPlayer.hasIslandFlyEnabled()) + )); } public static void replacePlayer(SuperiorPlayer originalPlayer, SuperiorPlayer newPlayer) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/cache/DatabaseCache.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/cache/DatabaseCache.java index 64192602cc..324e7cf380 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/cache/DatabaseCache.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/cache/DatabaseCache.java @@ -1,27 +1,46 @@ package com.bgsoftware.superiorskyblock.core.database.cache; -import com.bgsoftware.common.annotations.Nullable; - import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.function.Supplier; public class DatabaseCache { - private final Map cache = new HashMap<>(); + private final Map> cache = new HashMap<>(); public DatabaseCache() { } - public V computeIfAbsentInfo(UUID uuid, Supplier value) { - return cache.computeIfAbsent(uuid, u -> value.get()); + public Record computeIfAbsentInfo(UUID uuid, Supplier value) { + return cache.computeIfAbsent(uuid, u -> new Record<>(value.get())); } - @Nullable - public V getCachedInfo(UUID uuid) { - return cache.get(uuid); + public static class Record { + + private final Set recordedTables = new HashSet<>(); + + private final T handle; + + private Record(T handle) { + this.handle = handle; + } + + public T get() { + return this.handle; + } + + public void recordTable(String tableName) { + this.recordedTables.add(tableName); + } + + public Set getRecordedTables() { + return this.recordedTables; + } + } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java index 9f897a913a..1f3b1f2c1c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java @@ -71,12 +71,11 @@ public static void deserializeMembers(DatabaseBridge databaseBridge, DatabaseCac return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_members"); PlayerRole playerRole = members.getInt("role").map(SPlayerRole::fromId) .orElse(SPlayerRole.defaultRole()); - superiorPlayer.setPlayerRole(playerRole); builder.addIslandMember(superiorPlayer); }); @@ -104,7 +103,7 @@ public static void deserializeBanned(DatabaseBridge databaseBridge, DatabaseCach return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_bans"); builder.addBannedPlayer(superiorPlayer); }); } @@ -131,7 +130,7 @@ public static void deserializeVisitors(DatabaseBridge databaseBridge, DatabaseCa return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(islandUUID.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_visitors"); long visitTime = visitors.getLong("visit_time").orElse(System.currentTimeMillis()); builder.addUniqueVisitor(visitorPlayer, visitTime); }); @@ -174,7 +173,7 @@ public static void deserializePlayerPermissions(DatabaseBridge databaseBridge, D return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_player_permissions"); builder.setPlayerPermission(superiorPlayer, islandPrivilege, status.get() == 1); }); } @@ -204,7 +203,7 @@ public static void deserializeRolePermissions(DatabaseBridge databaseBridge, Dat } }).orElseThrow(IllegalStateException::new); - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_role_permissions"); builder.setRolePermission(islandPrivilege, playerRole.get()); }); } @@ -231,7 +230,7 @@ public static void deserializeUpgrades(DatabaseBridge databaseBridge, DatabaseCa return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_upgrades"); builder.setUpgrade(upgrade.get(), level.get()); }); } @@ -260,7 +259,7 @@ public static void deserializeWarps(DatabaseBridge databaseBridge, DatabaseCache return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_warps"); builder.addWarp(name.get(), islandWarp.getString("category").orElse(""), location.get(), islandWarp.getBoolean("private").orElse(!plugin.getSettings().isPublicWarps()), islandWarp.getString("icon").map(Serializers.ITEM_STACK_SERIALIZER::deserialize).orElse(null)); @@ -334,7 +333,7 @@ public static void deserializeBlockLimits(DatabaseBridge databaseBridge, Databas return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_block_limits"); builder.setBlockLimit(block.get(), limit.get()); }); } @@ -361,7 +360,7 @@ public static void deserializeEntityLimits(DatabaseBridge databaseBridge, Databa return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_entity_limits"); builder.setEntityLimit(entity.get(), limit.get()); }); } @@ -400,7 +399,7 @@ public static void deserializeRatings(DatabaseBridge databaseBridge, DatabaseCac return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(islandUUID.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_ratings"); builder.setRating(ratingPlayer, rating.get()); }); } @@ -433,7 +432,7 @@ public static void deserializeMissions(DatabaseBridge databaseBridge, DatabaseCa return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_missions"); builder.setCompletedMission(mission.get(), finishCount.get()); }); } @@ -463,7 +462,7 @@ public static void deserializeIslandFlags(DatabaseBridge databaseBridge, Databas return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_flags"); builder.setIslandFlag(islandFlag, status.get() == 1); }); } @@ -496,7 +495,7 @@ public static void deserializeGenerators(DatabaseBridge databaseBridge, Database return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_generators"); builder.setGeneratorRate(block.get(), rate.get(), dimension.get()); }); } @@ -523,7 +522,7 @@ public static void deserializeIslandHomes(DatabaseBridge databaseBridge, Databas return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_homes"); builder.setIslandHome(dimension.get(), location.get()); }); } @@ -550,7 +549,7 @@ public static void deserializeVisitorHomes(DatabaseBridge databaseBridge, Databa return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_visitor_homes"); builder.setVisitorHome(dimension.get(), location.get()); }); } @@ -578,7 +577,7 @@ public static void deserializeEffects(DatabaseBridge databaseBridge, DatabaseCac return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_effects"); builder.setIslandEffect(effectType.get(), level.get()); }); } @@ -623,7 +622,7 @@ public static void deserializeIslandChest(DatabaseBridge databaseBridge, Databas chestContents = contents.get(); } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_chests"); builder.setIslandChest(index.get(), chestContents); }); } @@ -650,7 +649,7 @@ public static void deserializeRoleLimits(DatabaseBridge databaseBridge, Database return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_role_limits"); builder.setRoleLimit(playerRole.get(), limit.get()); }); } @@ -671,7 +670,7 @@ public static void deserializeWarpCategories(DatabaseBridge databaseBridge, Data return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_warp_categories"); builder.addWarpCategory(name.get(), warpCategory.getInt("slot").orElse(-1), warpCategory.getString("icon").map(Serializers.ITEM_STACK_SERIALIZER::deserialize).orElse(null)); }); @@ -695,7 +694,7 @@ public static void deserializeIslandBank(DatabaseBridge databaseBridge, Database long currentTime = System.currentTimeMillis() / 1000; - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_banks"); builder.setBalance(balance.get()); long lastInterestTime = islandBank.getLong("last_interest_time").orElse(currentTime); builder.setLastInterestTime(lastInterestTime > currentTime ? lastInterestTime / 1000 : lastInterestTime); @@ -713,7 +712,7 @@ public static void deserializeIslandSettings(DatabaseBridge databaseBridge, Data } UUID uuid = UUID.fromString(island.get()); - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid, IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid, "islands_settings"); builder.setIslandSize(islandSettings.getInt("size").orElse(-1)); builder.setTeamLimit(islandSettings.getInt("members_limit").orElse(-1)); @@ -740,7 +739,7 @@ public static void deserializeBankTransactions(DatabaseBridge databaseBridge, Da return; } - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "bank_transactions"); SBankTransaction.fromDatabase(bankTransaction).ifPresent(builder::addBankTransaction); }); } @@ -760,8 +759,16 @@ public static void deserializePersistentDataContainer(DatabaseBridge databaseBri if (persistentData.length == 0) return; - Island.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), IslandBuilderImpl::new); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_custom_data"); builder.setPersistentData(persistentData); }); } + + private static Island.Builder lookupIsland(DatabaseCache databaseCache, UUID uuid, String tableName) { + DatabaseCache.Record islandRecord = + databaseCache.computeIfAbsentInfo(uuid, IslandBuilderImpl::new); + islandRecord.recordTable(tableName); + return islandRecord.get(); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/PlayersDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/PlayersDeserializer.java index f357a56cd2..f7bf844cd5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/PlayersDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/PlayersDeserializer.java @@ -33,7 +33,7 @@ public static void deserializeMissions(DatabaseBridge databaseBridge, DatabaseCa } UUID uuid = UUID.fromString(player.get()); - SuperiorPlayer.Builder builder = databaseCache.computeIfAbsentInfo(uuid, SuperiorPlayer::newBuilder); + SuperiorPlayer.Builder builder = lookupPlayer(databaseCache, uuid, "players_missions"); Optional name = missions.getString("name"); @@ -68,7 +68,7 @@ public static void deserializePlayerSettings(DatabaseBridge databaseBridge, Data } UUID uuid = UUID.fromString(player.get()); - SuperiorPlayer.Builder builder = databaseCache.computeIfAbsentInfo(uuid, SuperiorPlayer::newBuilder); + SuperiorPlayer.Builder builder = lookupPlayer(databaseCache, uuid, "players_settings"); playerSettings.getBoolean("toggled_panel").ifPresent(builder::setToggledPanel); playerSettings.getBoolean("island_fly").ifPresent(builder::setIslandFly); playerSettings.getEnum("border_color", BorderColor.class).ifPresent(builder::setBorderColor); @@ -92,9 +92,16 @@ public static void deserializePersistentDataContainer(DatabaseBridge databaseBri if (persistentData.length == 0) return; - SuperiorPlayer.Builder builder = databaseCache.computeIfAbsentInfo(uuid.get(), SuperiorPlayer::newBuilder); + SuperiorPlayer.Builder builder = lookupPlayer(databaseCache, uuid.get(), "players_custom_data"); builder.setPersistentData(persistentData); }); } + private static SuperiorPlayer.Builder lookupPlayer(DatabaseCache databaseCache, UUID uuid, String tableName) { + DatabaseCache.Record playerRecord = + databaseCache.computeIfAbsentInfo(uuid, SuperiorPlayer::newBuilder); + playerRecord.recordTable(tableName); + return playerRecord.get(); + } + } From 37dc92207bd445e1ca3a2d3bd805ef23064e7384 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 31 Jan 2026 13:41:12 +0200 Subject: [PATCH 488/600] Reuse Pair objects when doing db actions --- .../superiorskyblock/core/ObjectsPools.java | 34 + .../core/database/DBColumn.java | 17 + .../database/bridge/GridDatabaseBridge.java | 39 +- .../bridge/IslandsDatabaseBridge.java | 889 ++++++++++-------- .../bridge/PlayersDatabaseBridge.java | 197 ++-- .../bridge/StackedBlocksDatabaseBridge.java | 29 +- 6 files changed, 717 insertions(+), 488 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/DBColumn.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java index f57b012a81..3bb8c868d4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ObjectsPools.java @@ -1,15 +1,20 @@ package com.bgsoftware.superiorskyblock.core; +import com.bgsoftware.superiorskyblock.core.database.DBColumn; import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; import org.bukkit.Location; import javax.annotation.Nullable; +import java.util.LinkedList; +import java.util.List; import java.util.function.Consumer; public class ObjectsPools { public static final ObjectsPool> LOCATION = createNewPool(() -> new Location(null, 0D, 0D, 0D)); public static final ObjectsPool> LAZY_LOCATION = createNewPool(() -> new LazyWorldLocation(null, 0D, 0D, 0D)); + public static final ObjectsPool> DB_COLUMN = createNewPool(() -> new DBColumn("", null)); + public static final ObjectsPool> DB_COLUMN_BATCH = new ObjectsPool<>(() -> new Batch<>(DB_COLUMN)); private ObjectsPools() { @@ -57,4 +62,33 @@ public void close() { } } + public static class Batch implements ObjectsPool.Releasable, AutoCloseable { + + private final ObjectsPool> pool; + + private final List> obtainedObjects = new LinkedList<>(); + + public Batch(ObjectsPool> pool) { + this.pool = pool; + } + + public T obtain() { + Wrapper obj = this.pool.obtain(); + this.obtainedObjects.add(obj); + return obj.getHandle(); + } + + @Override + public void release() { + obtainedObjects.forEach(Wrapper::release); + obtainedObjects.clear(); + } + + @Override + public void close() { + release(); + } + + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/DBColumn.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/DBColumn.java new file mode 100644 index 0000000000..6b7c9ea2d1 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/DBColumn.java @@ -0,0 +1,17 @@ +package com.bgsoftware.superiorskyblock.core.database; + +import com.bgsoftware.superiorskyblock.api.objects.Pair; + +public class DBColumn extends Pair { + + public DBColumn(String columnName, Object value) { + super(columnName, value); + } + + public DBColumn withNameAndValue(String columnName, Object value) { + setKey(columnName); + setValue(value); + return this; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/GridDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/GridDatabaseBridge.java index c48f4deabf..a3bfba557f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/GridDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/GridDatabaseBridge.java @@ -4,13 +4,13 @@ import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; -import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.database.DBColumn; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import java.util.function.Consumer; -@SuppressWarnings("unchecked") public class GridDatabaseBridge { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @@ -19,25 +19,34 @@ private GridDatabaseBridge() { } public static void saveLastIsland(GridManager gridManager, BlockPosition lastIsland) { - runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> - databaseBridge.updateObject("grid", null, - new Pair<>("last_island", Serializers.BLOCK_POSITION_SERIALIZER.serialize(lastIsland)))); + runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { + DBColumn column = wrapper.getHandle().withNameAndValue("last_island", Serializers.BLOCK_POSITION_SERIALIZER.serialize(lastIsland)); + databaseBridge.updateObject("grid", null, column); + } + }); } public static void updateVersion(GridManager gridManager, int version) { - runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> - databaseBridge.deleteObject("ssb_metadata", null)); - runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("ssb_metadata", - new Pair<>("version", version) - )); + runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> { + databaseBridge.deleteObject("ssb_metadata", null); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { + DBColumn column = wrapper.getHandle().withNameAndValue("version", version); + databaseBridge.insertObject("ssb_metadata", column); + } + }); } public static void insertGrid(GridManager gridManager) { - runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("grid", - new Pair<>("last_island", Serializers.BLOCK_POSITION_SERIALIZER.serialize(gridManager.getLastIslandPosition())), - new Pair<>("max_island_size", plugin.getSettings().getMaxIslandSize()), - new Pair<>("world", plugin.getSettings().getWorlds().getDefaultWorldName()) - )); + runOperationIfRunning(gridManager.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("grid", + pool.obtain().withNameAndValue("last_island", Serializers.BLOCK_POSITION_SERIALIZER.serialize(gridManager.getLastIslandPosition())), + pool.obtain().withNameAndValue("max_island_size", plugin.getSettings().getMaxIslandSize()), + pool.obtain().withNameAndValue("world", plugin.getSettings().getWorlds().getDefaultWorldName()) + ); + } + }); } public static void deleteGrid(GridManager gridManager) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index b0b8184b5f..6d30bfd4fd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -27,6 +27,7 @@ import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.LegacyMasks; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.database.DBColumn; import com.bgsoftware.superiorskyblock.core.database.serialization.IslandsSerializer; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.island.IslandNames; @@ -35,7 +36,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; -import java.util.Arrays; +import java.util.Collections; import java.util.EnumMap; import java.util.HashSet; import java.util.LinkedList; @@ -47,7 +48,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; -@SuppressWarnings("unchecked") public class IslandsDatabaseBridge { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @@ -58,563 +58,671 @@ private IslandsDatabaseBridge() { } public static void addMember(Island island, SuperiorPlayer superiorPlayer, long addTime) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_members", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("player", superiorPlayer.getUniqueId().toString()), - new Pair<>("role", superiorPlayer.getPlayerRole().getId()), - new Pair<>("join_time", addTime) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_members", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), + pool.obtain().withNameAndValue("role", superiorPlayer.getPlayerRole().getId()), + pool.obtain().withNameAndValue("join_time", addTime) + ); + } + }); } public static void removeMember(Island island, SuperiorPlayer superiorPlayer) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_members", - createFilter("island", island, new Pair<>("player", superiorPlayer.getUniqueId().toString())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.deleteObject("islands_members", + createFilter(pool, "island", island, pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()))); + } + }); } public static void saveMemberRole(Island island, SuperiorPlayer superiorPlayer) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_members", - createFilter("island", island, new Pair<>("player", superiorPlayer.getUniqueId().toString())), - new Pair<>("role", superiorPlayer.getPlayerRole().getId()) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.updateObject("islands_members", + createFilter(pool, "island", island, pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString())), + pool.obtain().withNameAndValue("role", superiorPlayer.getPlayerRole().getId()) + ); + } + }); } public static void addBannedPlayer(Island island, SuperiorPlayer superiorPlayer, UUID banner, long banTime) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_bans", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("player", superiorPlayer.getUniqueId().toString()), - new Pair<>("banned_by", banner.toString()), - new Pair<>("banned_time", banTime) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_bans", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), + pool.obtain().withNameAndValue("banned_by", banner.toString()), + pool.obtain().withNameAndValue("banned_time", banTime) + ); + } + }); } public static void removeBannedPlayer(Island island, SuperiorPlayer superiorPlayer) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_bans", - createFilter("island", island, new Pair<>("player", superiorPlayer.getUniqueId().toString())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()); + databaseBridge.deleteObject("islands_bans", createFilter(pool, "island", island, column)); + } + }); } public static void saveCoopLimit(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_settings", - createFilter("island", island), - new Pair<>("coops_limit", island.getCoopLimit()) - )); + updateIslandSettingsValue(island, "coops_limit", island.getCoopLimit()); } public static void saveIslandHome(Island island, Dimension dimension, @Nullable WorldPosition worldPosition) { if (worldPosition == null) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_homes", - createFilter("island", island, new Pair<>("environment", dimension.getName())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("environment", dimension.getName()); + databaseBridge.deleteObject("islands_homes", createFilter(pool, "island", island, column)); + } + }); } else { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_homes", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("environment", dimension.getName()), - new Pair<>("location", Serializers.WORLD_POSITION_SERIALIZER.serialize(worldPosition)) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_homes", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("environment", dimension.getName()), + pool.obtain().withNameAndValue("location", Serializers.WORLD_POSITION_SERIALIZER.serialize(worldPosition)) + ); + } + }); } } public static void saveVisitorLocation(Island island, Dimension dimension, @Nullable WorldPosition worldPosition) { if (worldPosition == null) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_visitor_homes", - createFilter("island", island, new Pair<>("environment", dimension.getName())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("environment", dimension.getName()); + databaseBridge.deleteObject("islands_visitor_homes", createFilter(pool, "island", island, column)); + } + }); } else { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_visitor_homes", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("environment", dimension.getName()), - new Pair<>("location", Serializers.WORLD_POSITION_SERIALIZER.serialize(worldPosition)) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_visitor_homes", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("environment", dimension.getName()), + pool.obtain().withNameAndValue("location", Serializers.WORLD_POSITION_SERIALIZER.serialize(worldPosition)) + ); + } + }); } } public static void saveUnlockedWorlds(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("unlocked_worlds", LegacyMasks.convertUnlockedWorldsMask(island.getUnlockedWorlds())) - )); + updateIslandValue(island, "unlocked_worlds", + LegacyMasks.convertUnlockedWorldsMask(island.getUnlockedWorlds())); } public static void savePlayerPermission(Island island, SuperiorPlayer superiorPlayer, IslandPrivilege privilege, boolean status) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_player_permissions", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("player", superiorPlayer.getUniqueId().toString()), - new Pair<>("permission", privilege.getName()), - new Pair<>("status", status) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_player_permissions", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), + pool.obtain().withNameAndValue("permission", privilege.getName()), + pool.obtain().withNameAndValue("status", status) + ); + } + }); } public static void clearPlayerPermission(Island island, SuperiorPlayer superiorPlayer) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_player_permissions", - createFilter("island", island, new Pair<>("player", superiorPlayer.getUniqueId().toString())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()); + databaseBridge.deleteObject("islands_player_permissions", createFilter(pool, "island", island, column)); + } + }); } public static void saveRolePermission(Island island, PlayerRole playerRole, IslandPrivilege privilege) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_role_permissions", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("role", playerRole.getId()), - new Pair<>("permission", privilege.getName()) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_role_permissions", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("role", playerRole.getId()), + pool.obtain().withNameAndValue("permission", privilege.getName()) + ); + } + }); } public static void clearRolePermissions(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_role_permissions", - createFilter("island", island))); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> + databaseBridge.deleteObject("islands_role_permissions", createFilter("island", island))); } public static void saveName(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("name", IslandNames.getNameForDatabase(island)) - )); + updateIslandValue(island, "name", IslandNames.getNameForDatabase(island)); } public static void saveDescription(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("description", island.getDescription()) - )); + updateIslandValue(island, "description", island.getDescription()); } public static void saveSize(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_settings", - createFilter("island", island), - new Pair<>("size", island.getIslandSize()) - )); + updateIslandValue(island, "size", island.getIslandSize()); } public static void saveDiscord(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("discord", island.getDiscord()) - )); + updateIslandValue(island, "discord", island.getDiscord()); } public static void savePaypal(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("paypal", island.getPaypal()) - )); + updateIslandValue(island, "paypal", island.getPaypal()); } public static void saveLockedStatus(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("locked", island.isLocked()) - )); + updateIslandValue(island, "locked", island.isLocked()); } public static void saveIgnoredStatus(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("ignored", island.isIgnored()) - )); + updateIslandValue(island, "ignored", island.isIgnored()); } public static void saveLastTimeUpdate(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("last_time_updated", island.getLastTimeUpdate()) - )); + updateIslandValue(island, "last_time_updated", island.getLastTimeUpdate()); } public static void saveBankLimit(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_settings", - createFilter("island", island), - new Pair<>("bank_limit", island.getBankLimit() + "") - )); + updateIslandValue(island, "bank_limit", island.getBankLimit() + ""); } public static void saveBonusWorth(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("worth_bonus", island.getBonusWorth() + "") - )); + updateIslandValue(island, "worth_bonus", island.getBonusWorth() + ""); } public static void saveBonusLevel(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("levels_bonus", island.getBonusLevel() + "") - )); + updateIslandValue(island, "levels_bonus", island.getBonusLevel() + ""); } public static void saveUpgrade(Island island, Upgrade upgrade, int level) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_upgrades", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("upgrade", upgrade.getName()), - new Pair<>("level", level) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_upgrades", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("upgrade", upgrade.getName()), + pool.obtain().withNameAndValue("level", level) + ); + } + }); } public static void saveCropGrowth(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_settings", - createFilter("island", island), - new Pair<>("crop_growth_multiplier", island.getCropGrowthMultiplier()) - )); + updateIslandSettingsValue(island, "crop_growth_multiplier", island.getCropGrowthMultiplier()); } public static void saveSpawnerRates(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_settings", - createFilter("island", island), - new Pair<>("spawner_rates_multiplier", island.getSpawnerRatesMultiplier()) - )); + updateIslandSettingsValue(island, "spawner_rates_multiplier", island.getSpawnerRatesMultiplier()); } public static void saveMobDrops(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_settings", - createFilter("island", island), - new Pair<>("mob_drops_multiplier", island.getMobDropsMultiplier()) - )); + updateIslandSettingsValue(island, "mob_drops_multiplier", island.getMobDropsMultiplier()); } public static void saveBlockLimit(Island island, Key block, int limit) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_block_limits", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("block", block.toString()), - new Pair<>("limit", limit) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_block_limits", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("block", block.toString()), + pool.obtain().withNameAndValue("limit", limit) + ); + } + }); } public static void clearBlockLimits(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_block_limits", - createFilter("island", island))); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> + databaseBridge.deleteObject("islands_block_limits", createFilter("island", island))); } public static void removeBlockLimit(Island island, Key block) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_block_limits", - createFilter("island", island, new Pair<>("block", block.toString())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("block", block.toString()); + databaseBridge.deleteObject("islands_block_limits", createFilter(pool, "island", island, column)); + } + }); } public static void saveEntityLimit(Island island, Key entityType, int limit) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_entity_limits", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("entity", entityType.toString()), - new Pair<>("limit", limit) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_entity_limits", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("entity", entityType.toString()), + pool.obtain().withNameAndValue("limit", limit) + ); + } + }); } public static void clearEntityLimits(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_entity_limits", - createFilter("island", island))); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> + databaseBridge.deleteObject("islands_entity_limits", createFilter("island", island))); } public static void removeEntityLimit(Island island, Key entity) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_entity_limits", - createFilter("island", island, new Pair<>("entity", entity.toString())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("entity", entity.toString()); + databaseBridge.deleteObject("islands_entity_limits", createFilter(pool, "island", island, column)); + } + }); } public static void saveTeamLimit(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_settings", - createFilter("island", island), - new Pair<>("members_limit", island.getTeamLimit()) - )); + updateIslandSettingsValue(island, "members_limit", island.getTeamLimit()); } public static void saveWarpsLimit(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_settings", - createFilter("island", island), - new Pair<>("warps_limit", island.getWarpsLimit()) - )); + updateIslandSettingsValue(island, "warps_limit", island.getWarpsLimit()); } public static void saveIslandEffect(Island island, PotionEffectType potionEffectType, int level) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_effects", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("effect_type", potionEffectType.getName()), - new Pair<>("level", level) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_effects", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("effect_type", potionEffectType.getName()), + pool.obtain().withNameAndValue("level", level) + ); + } + }); } public static void removeIslandEffect(Island island, PotionEffectType potionEffectType) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_effects", - createFilter("island", island, new Pair<>("effect_type", potionEffectType.getName())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("effect_type", potionEffectType.getName()); + databaseBridge.deleteObject("islands_effects", createFilter(pool, "island", island, column)); + } + }); } public static void clearIslandEffects(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_effects", - createFilter("island", island))); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> + databaseBridge.deleteObject("islands_effects", createFilter("island", island))); } public static void saveRoleLimit(Island island, PlayerRole playerRole, int limit) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_role_limits", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("role", playerRole.getId()), - new Pair<>("limit", limit) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_role_limits", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("role", playerRole.getId()), + pool.obtain().withNameAndValue("limit", limit) + ); + } + }); } public static void removeRoleLimit(Island island, PlayerRole playerRole) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_role_limits", - createFilter("island", island, new Pair<>("role", playerRole.getId())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("role", playerRole.getId()); + databaseBridge.deleteObject("islands_role_limits", createFilter(pool, "island", island, column)); + } + }); } public static void saveWarp(Island island, IslandWarp islandWarp) { WarpCategory category = islandWarp.getCategory(); ItemStack icon = islandWarp.getRawIcon(); runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain(); + ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { databaseBridge.insertObject("islands_warps", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("name", islandWarp.getName()), - new Pair<>("category", category == null ? "" : category.getName()), - new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(wrapper.getHandle()))), - new Pair<>("private", islandWarp.hasPrivateFlag()), - new Pair<>("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(icon)) + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("name", islandWarp.getName()), + pool.obtain().withNameAndValue("category", category == null ? "" : category.getName()), + pool.obtain().withNameAndValue("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(wrapper.getHandle()))), + pool.obtain().withNameAndValue("private", islandWarp.hasPrivateFlag()), + pool.obtain().withNameAndValue("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(icon)) ); } }); } public static void updateWarpName(Island island, IslandWarp islandWarp, String oldName) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_warps", - createFilter("island", island, new Pair<>("name", oldName)), - new Pair<>("name", islandWarp.getName()) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.updateObject("islands_warps", + createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", oldName)), + pool.obtain().withNameAndValue("name", islandWarp.getName()) + ); + } + }); } public static void updateWarpLocation(Island island, IslandWarp islandWarp) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain(); + ObjectsPools.Wrapper wrapper = ObjectsPools.LAZY_LOCATION.obtain()) { + String islandWarpLocation = Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(wrapper.getHandle())); databaseBridge.updateObject("islands_warps", - createFilter("island", island, new Pair<>("name", islandWarp.getName())), - new Pair<>("location", Serializers.LOCATION_SERIALIZER.serialize(islandWarp.getLocation(wrapper.getHandle()))) + createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", islandWarp.getName())), + pool.obtain().withNameAndValue("location", islandWarpLocation) ); } }); } public static void updateWarpPrivateStatus(Island island, IslandWarp islandWarp) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_warps", - createFilter("island", island, new Pair<>("name", islandWarp.getName())), - new Pair<>("private", islandWarp.hasPrivateFlag()) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.updateObject("islands_warps", + createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", islandWarp.getName())), + pool.obtain().withNameAndValue("private", islandWarp.hasPrivateFlag()) + ); + } + }); } public static void updateWarpIcon(Island island, IslandWarp islandWarp) { - ItemStack icon = islandWarp.getRawIcon(); - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_warps", - createFilter("island", island, new Pair<>("name", islandWarp.getName())), - new Pair<>("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(icon)) - )); + + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + ItemStack icon = islandWarp.getRawIcon(); + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.updateObject("islands_warps", + createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", islandWarp.getName())), + pool.obtain().withNameAndValue("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(icon)) + ); + } + }); } public static void removeWarp(Island island, IslandWarp islandWarp) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_warps", - createFilter("island", island, new Pair<>("name", islandWarp.getName())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("name", islandWarp.getName()); + databaseBridge.deleteObject("islands_warps", createFilter(pool, "island", island, column)); + } + }); } public static void saveRating(Island island, SuperiorPlayer superiorPlayer, Rating rating, long rateTime) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_ratings", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("player", superiorPlayer.getUniqueId().toString()), - new Pair<>("rating", rating.getValue()), - new Pair<>("rating_time", rateTime) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_ratings", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), + pool.obtain().withNameAndValue("rating", rating.getValue()), + pool.obtain().withNameAndValue("rating_time", rateTime) + ); + } + }); } public static void removeRating(Island island, SuperiorPlayer superiorPlayer) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_ratings", - createFilter("island", island, new Pair<>("player", superiorPlayer.getUniqueId().toString())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()); + databaseBridge.deleteObject("islands_ratings", createFilter(pool, "island", island, column)); + } + }); } public static void clearRatings(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_ratings", - createFilter("island", island) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> + databaseBridge.deleteObject("islands_ratings", createFilter("island", island))); } public static void saveMission(Island island, Mission mission, int finishCount) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_missions", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("name", mission.getName().toLowerCase(Locale.ENGLISH)), - new Pair<>("finish_count", finishCount) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_missions", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("name", mission.getName().toLowerCase(Locale.ENGLISH)), + pool.obtain().withNameAndValue("finish_count", finishCount) + ); + } + }); } public static void removeMission(Island island, Mission mission) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_missions", - createFilter("island", island, new Pair<>("name", mission.getName())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("name", mission.getName()); + databaseBridge.deleteObject("islands_missions", createFilter(pool, "island", island, column)); + } + }); } public static void saveIslandFlag(Island island, IslandFlag islandFlag, int status) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_flags", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("name", islandFlag.getName()), - new Pair<>("status", status) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_flags", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("name", islandFlag.getName()), + pool.obtain().withNameAndValue("status", status) + ); + } + }); } public static void removeIslandFlag(Island island, IslandFlag islandFlag) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_flags", - createFilter("island", island, new Pair<>("name", islandFlag.getName())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("name", islandFlag.getName()); + databaseBridge.deleteObject("islands_flags", createFilter(pool, "island", island, column)); + } + }); } public static void clearIslandFlags(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_flags", - createFilter("island", island))); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> + databaseBridge.deleteObject("islands_flags", createFilter("island", island))); } public static void saveGeneratorRate(Island island, Dimension dimension, Key blockKey, int rate) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_generators", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("environment", dimension.getName()), - new Pair<>("block", blockKey.toString()), - new Pair<>("rate", rate) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_generators", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("environment", dimension.getName()), + pool.obtain().withNameAndValue("block", blockKey.toString()), + pool.obtain().withNameAndValue("rate", rate) + ); + } + }); } public static void removeGeneratorRate(Island island, Dimension dimension, Key blockKey) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_generators", - createFilter("island", island, - new Pair<>("environment", dimension.getName()), - new Pair<>("block", blockKey.toString())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.deleteObject("islands_generators", createFilter(pool, "island", island, + pool.obtain().withNameAndValue("environment", dimension.getName()), + pool.obtain().withNameAndValue("block", blockKey.toString())) + ); + } + }); } public static void clearGeneratorRates(Island island, Dimension dimension) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_generators", - createFilter("island", island, new Pair<>("environment", dimension.getName())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("environment", dimension.getName()); + databaseBridge.deleteObject("islands_generators", createFilter(pool, "island", island, column)); + } + }); } public static void saveGeneratedSchematics(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("generated_schematics", LegacyMasks.convertGeneratedSchematicsMask(island.getGeneratedSchematics())) - )); + updateIslandValue(island, "generated_schematics", + LegacyMasks.convertGeneratedSchematicsMask(island.getGeneratedSchematics())); } public static void saveDirtyChunks(DirtyChunksContainer dirtyChunksContainer) { - runOperationIfRunning(dirtyChunksContainer.getIsland().getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", dirtyChunksContainer.getIsland()), - new Pair<>("dirty_chunks", IslandsSerializer.serializeDirtyChunkPositions(dirtyChunksContainer)) - )); + updateIslandValue(dirtyChunksContainer.getIsland(), "dirty_chunks", + IslandsSerializer.serializeDirtyChunkPositions(dirtyChunksContainer)); } public static void saveBlockCounts(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("block_counts", IslandsSerializer.serializeBlockCounts(island.getBlockCountsAsBigInteger())) - )); + updateIslandValue(island, "block_counts", + IslandsSerializer.serializeBlockCounts(island.getBlockCountsAsBigInteger())); } public static void saveEntityCounts(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("entity_counts", IslandsSerializer.serializeEntityCounts(island.getEntitiesTracker().getEntitiesCounts())) - )); + updateIslandValue(island, "entity_counts", + IslandsSerializer.serializeEntityCounts(island.getEntitiesTracker().getEntitiesCounts())); } public static void saveIslandChest(Island island, IslandChest islandChest) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_chests", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("index", islandChest.getIndex()), - new Pair<>("contents", Serializers.INVENTORY_SERIALIZER.serialize(islandChest.getContents())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_chests", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("index", islandChest.getIndex()), + pool.obtain().withNameAndValue("contents", Serializers.INVENTORY_SERIALIZER.serialize(islandChest.getContents())) + ); + } + }); } public static void saveLastInterestTime(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_banks", - createFilter("island", island), - new Pair<>("last_interest_time", island.getLastInterestTime() * 1000) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { + DBColumn column = wrapper.getHandle().withNameAndValue("last_interest_time", island.getLastInterestTime() * 1000); + databaseBridge.updateObject("islands_banks", createFilter("island", island), column); + } + }); } public static void saveVisitor(Island island, SuperiorPlayer visitor, long visitTime) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_visitors", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("player", visitor.getUniqueId().toString()), - new Pair<>("visit_time", visitTime) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_visitors", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("player", visitor.getUniqueId().toString()), + pool.obtain().withNameAndValue("visit_time", visitTime) + ); + } + }); } public static void saveWarpCategory(Island island, WarpCategory warpCategory) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_warp_categories", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("name", warpCategory.getName()), - new Pair<>("slot", warpCategory.getSlot()), - new Pair<>("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(warpCategory.getRawIcon())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_warp_categories", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("name", warpCategory.getName()), + pool.obtain().withNameAndValue("slot", warpCategory.getSlot()), + pool.obtain().withNameAndValue("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(warpCategory.getRawIcon())) + ); + } + }); } public static void updateWarpCategory(Island island, IslandWarp islandWarp, String oldCategoryName) { WarpCategory category = islandWarp.getCategory(); - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_warps", - createFilter("island", island, new Pair<>("category", oldCategoryName)), - new Pair<>("category", category == null ? "" : category.getName()) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.updateObject("islands_warps", + createFilter(pool, "island", island, pool.obtain().withNameAndValue("category", oldCategoryName)), + pool.obtain().withNameAndValue("category", category == null ? "" : category.getName()) + ); + } + }); } public static void updateWarpCategoryName(Island island, WarpCategory warpCategory, String oldName) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_warp_categories", - createFilter("island", island, new Pair<>("name", oldName)), - new Pair<>("name", warpCategory.getName()) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.updateObject("islands_warp_categories", + createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", oldName)), + pool.obtain().withNameAndValue("name", warpCategory.getName()) + ); + } + }); } public static void updateWarpCategorySlot(Island island, WarpCategory warpCategory) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_warp_categories", - createFilter("island", island, new Pair<>("name", warpCategory.getName())), - new Pair<>("slot", warpCategory.getSlot()) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.updateObject("islands_warp_categories", + createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", warpCategory.getName())), + pool.obtain().withNameAndValue("slot", warpCategory.getSlot()) + ); + } + }); } public static void updateWarpCategoryIcon(Island island, WarpCategory warpCategory) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_warp_categories", - createFilter("island", island, new Pair<>("name", warpCategory.getName())), - new Pair<>("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(warpCategory.getRawIcon())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.updateObject("islands_warp_categories", + createFilter(pool, "island", island, pool.obtain().withNameAndValue("name", warpCategory.getName())), + pool.obtain().withNameAndValue("icon", Serializers.ITEM_STACK_SERIALIZER.serialize(warpCategory.getRawIcon())) + ); + } + }); } public static void removeWarpCategory(Island island, WarpCategory warpCategory) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("islands_warp_categories", - createFilter("island", island, new Pair<>("name", warpCategory.getName())) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("name", warpCategory.getName()); + databaseBridge.deleteObject("islands_warp_categories", createFilter(pool, "island", island, column)); + } + }); } public static void saveIslandLeader(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands", - createFilter("uuid", island), - new Pair<>("owner", island.getOwner().getUniqueId().toString()) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { + DBColumn column = wrapper.getHandle().withNameAndValue("owner", island.getOwner().getUniqueId().toString()); + databaseBridge.updateObject("islands", createFilter("uuid", island), column); + } + }); } public static void saveBankBalance(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_banks", - createFilter("island", island), - new Pair<>("balance", island.getIslandBank().getBalance() + "") - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { + DBColumn column = wrapper.getHandle().withNameAndValue("balance", island.getIslandBank().getBalance() + ""); + databaseBridge.updateObject("islands_banks", createFilter("island", island), column); + } + }); } public static void saveBankTransaction(Island island, BankTransaction bankTransaction) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("bank_transactions", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("player", bankTransaction.getPlayer() == null ? "" : bankTransaction.getPlayer().toString()), - new Pair<>("bank_action", bankTransaction.getAction().name()), - new Pair<>("position", bankTransaction.getPosition()), - new Pair<>("time", bankTransaction.getTime()), - new Pair<>("failure_reason", bankTransaction.getFailureReason()), - new Pair<>("amount", bankTransaction.getAmount() + "") - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("bank_transactions", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("player", bankTransaction.getPlayer() == null ? "" : bankTransaction.getPlayer().toString()), + pool.obtain().withNameAndValue("bank_action", bankTransaction.getAction().name()), + pool.obtain().withNameAndValue("position", bankTransaction.getPosition()), + pool.obtain().withNameAndValue("time", bankTransaction.getTime()), + pool.obtain().withNameAndValue("failure_reason", bankTransaction.getFailureReason()), + pool.obtain().withNameAndValue("amount", bankTransaction.getAmount() + "") + ); + } + }); } public static void savePersistentDataContainer(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_custom_data", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("data", island.getPersistentDataContainer().serialize()) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_custom_data", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("data", island.getPersistentDataContainer().serialize()) + ); + } + }); } public static void removePersistentDataContainer(Island island) { @@ -623,44 +731,50 @@ public static void removePersistentDataContainer(Island island) { } public static void clearIslandSettings(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("islands_settings", - createFilter("island", island), - new Pair<>("size", -1), - new Pair<>("bank_limit", "-2"), - new Pair<>("coops_limit", -1), - new Pair<>("members_limit", -1), - new Pair<>("warps_limit", -1), - new Pair<>("crop_growth_multiplier", -1D), - new Pair<>("spawner_rates_multiplier", -1D), - new Pair<>("mob_drops_multiplier", -1D) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.updateObject("islands_settings", + createFilter("island", island), + pool.obtain().withNameAndValue("size", -1), + pool.obtain().withNameAndValue("bank_limit", "-2"), + pool.obtain().withNameAndValue("coops_limit", -1), + pool.obtain().withNameAndValue("members_limit", -1), + pool.obtain().withNameAndValue("warps_limit", -1), + pool.obtain().withNameAndValue("crop_growth_multiplier", -1D), + pool.obtain().withNameAndValue("spawner_rates_multiplier", -1D), + pool.obtain().withNameAndValue("mob_drops_multiplier", -1D) + ); + } + }); } public static void insertIsland(Island island, @Nullable List dirtyChunks) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { BlockPosition centerPosition = island.getCenterPosition(); WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, Dimensions.NORMAL); - databaseBridge.insertObject("islands", - new Pair<>("uuid", island.getUniqueId().toString()), - new Pair<>("owner", island.getOwner().getUniqueId().toString()), - new Pair<>("center", Serializers.LOCATION_SERIALIZER.serialize(LazyWorldLocation.of(worldInfo, centerPosition))), - new Pair<>("creation_time", island.getCreationTime()), - new Pair<>("island_type", island.getSchematicName()), - new Pair<>("discord", island.getDiscord()), - new Pair<>("paypal", island.getPaypal()), - new Pair<>("worth_bonus", island.getBonusWorth() + ""), - new Pair<>("levels_bonus", island.getBonusLevel() + ""), - new Pair<>("locked", island.isLocked()), - new Pair<>("ignored", island.isIgnored()), - new Pair<>("name", IslandNames.getNameForDatabase(island)), - new Pair<>("description", island.getDescription()), - new Pair<>("generated_schematics", LegacyMasks.convertGeneratedSchematicsMask(island.getGeneratedSchematics())), - new Pair<>("unlocked_worlds", LegacyMasks.convertUnlockedWorldsMask(island.getUnlockedWorlds())), - new Pair<>("last_time_updated", System.currentTimeMillis() / 1000L), - new Pair<>("dirty_chunks", dirtyChunks == null ? "" : IslandsSerializer.serializeDirtyChunkPositions(dirtyChunks)), - new Pair<>("block_counts", IslandsSerializer.serializeBlockCounts(island.getBlockCountsAsBigInteger())), - new Pair<>("entity_counts", IslandsSerializer.serializeEntityCounts(island.getEntitiesTracker().getEntitiesCounts())) - ); + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands", + pool.obtain().withNameAndValue("uuid", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("owner", island.getOwner().getUniqueId().toString()), + pool.obtain().withNameAndValue("center", Serializers.LOCATION_SERIALIZER.serialize(LazyWorldLocation.of(worldInfo, centerPosition))), + pool.obtain().withNameAndValue("creation_time", island.getCreationTime()), + pool.obtain().withNameAndValue("island_type", island.getSchematicName()), + pool.obtain().withNameAndValue("discord", island.getDiscord()), + pool.obtain().withNameAndValue("paypal", island.getPaypal()), + pool.obtain().withNameAndValue("worth_bonus", island.getBonusWorth() + ""), + pool.obtain().withNameAndValue("levels_bonus", island.getBonusLevel() + ""), + pool.obtain().withNameAndValue("locked", island.isLocked()), + pool.obtain().withNameAndValue("ignored", island.isIgnored()), + pool.obtain().withNameAndValue("name", IslandNames.getNameForDatabase(island)), + pool.obtain().withNameAndValue("description", island.getDescription()), + pool.obtain().withNameAndValue("generated_schematics", LegacyMasks.convertGeneratedSchematicsMask(island.getGeneratedSchematics())), + pool.obtain().withNameAndValue("unlocked_worlds", LegacyMasks.convertUnlockedWorldsMask(island.getUnlockedWorlds())), + pool.obtain().withNameAndValue("last_time_updated", System.currentTimeMillis() / 1000L), + pool.obtain().withNameAndValue("dirty_chunks", dirtyChunks == null ? "" : IslandsSerializer.serializeDirtyChunkPositions(dirtyChunks)), + pool.obtain().withNameAndValue("block_counts", IslandsSerializer.serializeBlockCounts(island.getBlockCountsAsBigInteger())), + pool.obtain().withNameAndValue("entity_counts", IslandsSerializer.serializeEntityCounts(island.getEntitiesTracker().getEntitiesCounts())) + ); + } }); insertIslandBanks(island); @@ -668,25 +782,33 @@ public static void insertIsland(Island island, @Nullable List dir } public static void insertIslandBanks(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_banks", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("balance", island.getIslandBank().getBalance() + ""), - new Pair<>("last_interest_time", island.getLastInterestTime()) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_banks", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("balance", island.getIslandBank().getBalance() + ""), + pool.obtain().withNameAndValue("last_interest_time", island.getLastInterestTime()) + ); + } + }); } public static void insertIslandSettings(Island island) { - runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("islands_settings", - new Pair<>("island", island.getUniqueId().toString()), - new Pair<>("size", island.getIslandSizeRaw()), - new Pair<>("bank_limit", island.getBankLimitRaw() + ""), - new Pair<>("coops_limit", island.getCoopLimitRaw()), - new Pair<>("members_limit", island.getTeamLimitRaw()), - new Pair<>("warps_limit", island.getWarpsLimitRaw()), - new Pair<>("crop_growth_multiplier", island.getCropGrowthRaw()), - new Pair<>("spawner_rates_multiplier", island.getSpawnerRatesRaw()), - new Pair<>("mob_drops_multiplier", island.getMobDropsRaw()) - )); + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("islands_settings", + pool.obtain().withNameAndValue("island", island.getUniqueId().toString()), + pool.obtain().withNameAndValue("size", island.getIslandSizeRaw()), + pool.obtain().withNameAndValue("bank_limit", island.getBankLimitRaw() + ""), + pool.obtain().withNameAndValue("coops_limit", island.getCoopLimitRaw()), + pool.obtain().withNameAndValue("members_limit", island.getTeamLimitRaw()), + pool.obtain().withNameAndValue("warps_limit", island.getWarpsLimitRaw()), + pool.obtain().withNameAndValue("crop_growth_multiplier", island.getCropGrowthRaw()), + pool.obtain().withNameAndValue("spawner_rates_multiplier", island.getSpawnerRatesRaw()), + pool.obtain().withNameAndValue("mob_drops_multiplier", island.getMobDropsRaw()) + ); + } + }); } public static void deleteIsland(Island island) { @@ -826,11 +948,40 @@ public static void executeFutureSaves(Island island, FutureSave futureSave) { } } - private static DatabaseFilter createFilter(String id, Island island, Pair... others) { + private static void updateIslandValue(Island island, String columnName, Object value) { + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { + DBColumn column = wrapper.getHandle().withNameAndValue(columnName, value); + databaseBridge.updateObject("islands", createFilter("uuid", island), column); + } + }); + } + + private static void updateIslandSettingsValue(Island island, String columnName, Object value) { + runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { + DBColumn column = wrapper.getHandle().withNameAndValue(columnName, value); + databaseBridge.updateObject("islands_settings", createFilter("island", island), column); + } + }); + } + + private static DatabaseFilter createFilter(String id, Island island) { + return DatabaseFilter.fromFilter(id, island.getUniqueId().toString()); + } + + private static DatabaseFilter createFilter(ObjectsPools.Batch pool, String id, Island island, DBColumn column) { + List> filters = new LinkedList<>(); + filters.add(pool.obtain().withNameAndValue(id, island.getUniqueId().toString())); + filters.add(column); + return DatabaseFilter.fromFilters(filters); + } + + private static DatabaseFilter createFilter(ObjectsPools.Batch pool, String id, Island island, DBColumn... others) { List> filters = new LinkedList<>(); - filters.add(new Pair<>(id, island.getUniqueId().toString())); - if (others != null) - filters.addAll(Arrays.asList(others)); + filters.add(pool.obtain().withNameAndValue(id, island.getUniqueId().toString())); + if (others != null && others.length > 0) + Collections.addAll(filters, others); return DatabaseFilter.fromFilters(filters); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/PlayersDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/PlayersDatabaseBridge.java index 32aea7c78d..d15d9e4923 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/PlayersDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/PlayersDatabaseBridge.java @@ -8,8 +8,9 @@ import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.database.DBColumn; -import java.util.Arrays; import java.util.EnumMap; import java.util.HashSet; import java.util.LinkedList; @@ -21,7 +22,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; -@SuppressWarnings("unchecked") public class PlayersDatabaseBridge { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @@ -43,88 +43,72 @@ public static DatabaseBridge getGlobalPlayersBridge() { } public static void saveTextureValue(SuperiorPlayer superiorPlayer) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("players", - createFilter("uuid", superiorPlayer), - new Pair<>("last_used_skin", superiorPlayer.getTextureValue()) - )); + updatePlayerValue(superiorPlayer, "last_used_skin", superiorPlayer.getTextureValue()); } public static void savePlayerName(SuperiorPlayer superiorPlayer) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("players", - createFilter("uuid", superiorPlayer), - new Pair<>("last_used_name", superiorPlayer.getName()) - )); + updatePlayerValue(superiorPlayer, "last_used_name", superiorPlayer.getName()); } public static void saveUserLocale(SuperiorPlayer superiorPlayer) { Locale userLocale = superiorPlayer.getUserLocale(); - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("players_settings", - createFilter("player", superiorPlayer), - new Pair<>("language", userLocale.getLanguage() + "-" + userLocale.getCountry()) - )); + updatePlayerSettingsValue(superiorPlayer, "language", userLocale.getLanguage() + "-" + userLocale.getCountry()); } public static void saveToggledBorder(SuperiorPlayer superiorPlayer) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("players_settings", - createFilter("player", superiorPlayer), - new Pair<>("toggled_border", superiorPlayer.hasWorldBorderEnabled()) - )); + updatePlayerSettingsValue(superiorPlayer, "toggled_border", superiorPlayer.hasWorldBorderEnabled()); } public static void saveDisbands(SuperiorPlayer superiorPlayer) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("players", - createFilter("uuid", superiorPlayer), - new Pair<>("disbands", superiorPlayer.getDisbands()) - )); + updatePlayerValue(superiorPlayer, "disbands", superiorPlayer.getDisbands()); } public static void saveToggledPanel(SuperiorPlayer superiorPlayer) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("players_settings", - createFilter("player", superiorPlayer), - new Pair<>("toggled_panel", superiorPlayer.hasToggledPanel()) - )); + updatePlayerSettingsValue(superiorPlayer, "toggled_panel", superiorPlayer.hasToggledPanel()); } public static void saveIslandFly(SuperiorPlayer superiorPlayer) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("players_settings", - createFilter("player", superiorPlayer), - new Pair<>("island_fly", superiorPlayer.hasIslandFlyEnabled()) - )); + updatePlayerSettingsValue(superiorPlayer, "island_fly", superiorPlayer.hasIslandFlyEnabled()); } public static void saveBorderColor(SuperiorPlayer superiorPlayer) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("players_settings", - createFilter("player", superiorPlayer), - new Pair<>("border_color", superiorPlayer.getBorderColor().name()) - )); + updatePlayerSettingsValue(superiorPlayer, "border_color", superiorPlayer.getBorderColor().name()); } public static void saveLastTimeStatus(SuperiorPlayer superiorPlayer) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.updateObject("players", - createFilter("uuid", superiorPlayer), - new Pair<>("last_time_updated", superiorPlayer.getLastTimeStatus()) - )); + updatePlayerValue(superiorPlayer, "last_time_updated", superiorPlayer.getLastTimeStatus()); } public static void saveMission(SuperiorPlayer superiorPlayer, Mission mission, int finishCount) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("players_missions", - new Pair<>("player", superiorPlayer.getUniqueId().toString()), - new Pair<>("name", mission.getName().toLowerCase(Locale.ENGLISH)), - new Pair<>("finish_count", finishCount) - )); + runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("players_missions", + pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), + pool.obtain().withNameAndValue("name", mission.getName().toLowerCase(Locale.ENGLISH)), + pool.obtain().withNameAndValue("finish_count", finishCount) + ); + } + }); } public static void removeMission(SuperiorPlayer superiorPlayer, Mission mission) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("players_missions", - createFilter("player", superiorPlayer, new Pair<>("name", mission.getName().toLowerCase(Locale.ENGLISH))) - )); + runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn column = pool.obtain().withNameAndValue("name", mission.getName().toLowerCase(Locale.ENGLISH)); + databaseBridge.deleteObject("players_missions", createFilter(pool, "player", superiorPlayer, column)); + } + }); } public static void savePersistentDataContainer(SuperiorPlayer superiorPlayer) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("players_custom_data", - new Pair<>("player", superiorPlayer.getUniqueId().toString()), - new Pair<>("data", superiorPlayer.getPersistentDataContainer().serialize()) - )); + runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("players_custom_data", + pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), + pool.obtain().withNameAndValue("data", superiorPlayer.getPersistentDataContainer().serialize()) + ); + } + }); } public static void removePersistentDataContainer(SuperiorPlayer superiorPlayer) { @@ -133,58 +117,70 @@ public static void removePersistentDataContainer(SuperiorPlayer superiorPlayer) } public static void insertPlayer(SuperiorPlayer superiorPlayer) { - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("players", - new Pair<>("uuid", superiorPlayer.getUniqueId().toString()), - new Pair<>("last_used_name", superiorPlayer.getName()), - new Pair<>("last_used_skin", superiorPlayer.getTextureValue()), - new Pair<>("disbands", superiorPlayer.getDisbands()), - new Pair<>("last_time_updated", superiorPlayer.getLastTimeStatus()) - )); + runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("players", + pool.obtain().withNameAndValue("uuid", superiorPlayer.getUniqueId().toString()), + pool.obtain().withNameAndValue("last_used_name", superiorPlayer.getName()), + pool.obtain().withNameAndValue("last_used_skin", superiorPlayer.getTextureValue()), + pool.obtain().withNameAndValue("disbands", superiorPlayer.getDisbands()), + pool.obtain().withNameAndValue("last_time_updated", superiorPlayer.getLastTimeStatus()) + ); + } + }); insertPlayerSettings(superiorPlayer); } public static void insertPlayerSettings(SuperiorPlayer superiorPlayer) { Locale userLocale = superiorPlayer.getUserLocale(); - runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("players_settings", - new Pair<>("player", superiorPlayer.getUniqueId().toString()), - new Pair<>("language", userLocale.getLanguage() + "-" + userLocale.getCountry()), - new Pair<>("toggled_panel", superiorPlayer.hasToggledPanel()), - new Pair<>("border_color", superiorPlayer.getBorderColor().name()), - new Pair<>("toggled_border", superiorPlayer.hasWorldBorderEnabled()), - new Pair<>("island_fly", superiorPlayer.hasIslandFlyEnabled()) - )); + runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("players_settings", + pool.obtain().withNameAndValue("player", superiorPlayer.getUniqueId().toString()), + pool.obtain().withNameAndValue("language", userLocale.getLanguage() + "-" + userLocale.getCountry()), + pool.obtain().withNameAndValue("toggled_panel", superiorPlayer.hasToggledPanel()), + pool.obtain().withNameAndValue("border_color", superiorPlayer.getBorderColor().name()), + pool.obtain().withNameAndValue("toggled_border", superiorPlayer.hasWorldBorderEnabled()), + pool.obtain().withNameAndValue("island_fly", superiorPlayer.hasIslandFlyEnabled()) + ); + } + }); } public static void replacePlayer(SuperiorPlayer originalPlayer, SuperiorPlayer newPlayer) { DatabaseBridge playersReplacer = getGlobalPlayersBridge(); - Pair uuidColumn = new Pair<>("uuid", newPlayer.getUniqueId().toString()); - DatabaseFilter uuidFilter = createFilter("uuid", originalPlayer); + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + DBColumn uuidColumn = pool.obtain().withNameAndValue("uuid", newPlayer.getUniqueId().toString()); + DatabaseFilter uuidFilter = createFilter("uuid", originalPlayer); - Pair playerColumn = new Pair<>("player", newPlayer.getUniqueId().toString()); - DatabaseFilter playerFilter = createFilter("player", originalPlayer); + DBColumn playerColumn = pool.obtain().withNameAndValue("player", newPlayer.getUniqueId().toString()); + DatabaseFilter playerFilter = createFilter("player", originalPlayer); - // We go through all possible tables (both island and players) and replace the player uuids. - playersReplacer.updateObject("players", uuidFilter, uuidColumn); - playersReplacer.updateObject("players_settings", playerFilter, playerColumn); + // We go through all possible tables (both island and players) and replace the player uuids. + playersReplacer.updateObject("players", uuidFilter, uuidColumn); + playersReplacer.updateObject("players_settings", playerFilter, playerColumn); - playersReplacer.updateObject("bank_transactions", playerFilter, playerColumn); - playersReplacer.updateObject("islands_bans", playerFilter, playerColumn); - playersReplacer.updateObject("islands_bans", createFilter("banned_by", originalPlayer), new Pair<>("banned_by", newPlayer.getUniqueId().toString())); - playersReplacer.updateObject("islands_player_permissions", playerFilter, playerColumn); - playersReplacer.updateObject("islands_ratings", playerFilter, playerColumn); - playersReplacer.updateObject("islands_visitors", playerFilter, playerColumn); + playersReplacer.updateObject("bank_transactions", playerFilter, playerColumn); + playersReplacer.updateObject("islands_bans", playerFilter, playerColumn); + playersReplacer.updateObject("islands_bans", createFilter("banned_by", originalPlayer), + pool.obtain().withNameAndValue("banned_by", newPlayer.getUniqueId().toString())); + playersReplacer.updateObject("islands_player_permissions", playerFilter, playerColumn); + playersReplacer.updateObject("islands_ratings", playerFilter, playerColumn); + playersReplacer.updateObject("islands_visitors", playerFilter, playerColumn); - if (newPlayer.hasIsland()) { - playersReplacer.updateObject("islands", createFilter("owner", originalPlayer), new Pair<>("owner", newPlayer.getUniqueId().toString())); - playersReplacer.updateObject("islands_members", playerFilter, playerColumn); - } + if (newPlayer.hasIsland()) { + playersReplacer.updateObject("islands", createFilter("owner", originalPlayer), + pool.obtain().withNameAndValue("owner", newPlayer.getUniqueId().toString())); + playersReplacer.updateObject("islands_members", playerFilter, playerColumn); + } - if (!newPlayer.isPersistentDataContainerEmpty()) - playersReplacer.updateObject("players_custom_data", playerFilter, playerColumn); - if (!newPlayer.getCompletedMissions().isEmpty()) - playersReplacer.updateObject("players_missions", playerFilter, playerColumn); + if (!newPlayer.isPersistentDataContainerEmpty()) + playersReplacer.updateObject("players_custom_data", playerFilter, playerColumn); + if (!newPlayer.getCompletedMissions().isEmpty()) + playersReplacer.updateObject("players_missions", playerFilter, playerColumn); + } } public static void deletePlayer(SuperiorPlayer superiorPlayer) { @@ -267,11 +263,32 @@ public static void executeFutureSaves(SuperiorPlayer superiorPlayer, FutureSave } } - private static DatabaseFilter createFilter(String id, SuperiorPlayer superiorPlayer, Pair... others) { + private static void updatePlayerValue(SuperiorPlayer superiorPlayer, String columnName, Object value) { + runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { + DBColumn column = wrapper.getHandle().withNameAndValue(columnName, value); + databaseBridge.updateObject("players", createFilter("uuid", superiorPlayer), column); + } + }); + } + + private static void updatePlayerSettingsValue(SuperiorPlayer superiorPlayer, String columnName, Object value) { + runOperationIfRunning(superiorPlayer.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.DB_COLUMN.obtain()) { + DBColumn column = wrapper.getHandle().withNameAndValue(columnName, value); + databaseBridge.updateObject("players_settings", createFilter("player", superiorPlayer), column); + } + }); + } + + private static DatabaseFilter createFilter(String id, SuperiorPlayer superiorPlayer) { + return DatabaseFilter.fromFilter(id, superiorPlayer.getUniqueId().toString()); + } + + private static DatabaseFilter createFilter(ObjectsPools.Batch pool, String id, SuperiorPlayer superiorPlayer, DBColumn column) { List> filters = new LinkedList<>(); - filters.add(new Pair<>(id, superiorPlayer.getUniqueId().toString())); - if (others != null) - filters.addAll(Arrays.asList(others)); + filters.add(pool.obtain().withNameAndValue(id, superiorPlayer.getUniqueId().toString())); + filters.add(column); return DatabaseFilter.fromFilters(filters); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/StackedBlocksDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/StackedBlocksDatabaseBridge.java index e7f071b344..f82f56c30c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/StackedBlocksDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/StackedBlocksDatabaseBridge.java @@ -4,32 +4,33 @@ import com.bgsoftware.superiorskyblock.api.data.DatabaseBridgeMode; import com.bgsoftware.superiorskyblock.api.data.DatabaseFilter; import com.bgsoftware.superiorskyblock.api.handlers.StackedBlocksManager; -import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.database.DBColumn; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.core.stackedblocks.StackedBlock; -import java.util.Arrays; import java.util.function.Consumer; -@SuppressWarnings("unchecked") public class StackedBlocksDatabaseBridge { + private StackedBlocksDatabaseBridge() { + } + public static void saveStackedBlock(StackedBlocksManager stackedBlocks, StackedBlock stackedBlock) { - runOperationIfRunning(stackedBlocks.getDatabaseBridge(), databaseBridge -> databaseBridge.insertObject("stacked_blocks", - new Pair<>("location", Serializers.LOCATION_SPACED_SERIALIZER.serialize(stackedBlock.getLocation())), - new Pair<>("amount", stackedBlock.getAmount()), - new Pair<>("block_type", stackedBlock.getBlockKey().toString()) - )); + runOperationIfRunning(stackedBlocks.getDatabaseBridge(), databaseBridge -> { + try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { + databaseBridge.insertObject("stacked_blocks", + pool.obtain().withNameAndValue("location", Serializers.LOCATION_SPACED_SERIALIZER.serialize(stackedBlock.getLocation())), + pool.obtain().withNameAndValue("amount", stackedBlock.getAmount()), + pool.obtain().withNameAndValue("block_type", stackedBlock.getBlockKey().toString()) + ); + } + }); } public static void deleteStackedBlock(StackedBlocksManager stackedBlocks, StackedBlock stackedBlock) { runOperationIfRunning(stackedBlocks.getDatabaseBridge(), databaseBridge -> databaseBridge.deleteObject("stacked_blocks", - createFilter(new Pair<>("location", Serializers.LOCATION_SPACED_SERIALIZER.serialize(stackedBlock.getLocation()))) - )); - } - - private static DatabaseFilter createFilter(Pair... others) { - return DatabaseFilter.fromFilters(Arrays.asList(others)); + DatabaseFilter.fromFilter("location", Serializers.LOCATION_SPACED_SERIALIZER.serialize(stackedBlock.getLocation())))); } private static void runOperationIfRunning(DatabaseBridge databaseBridge, Consumer databaseBridgeConsumer) { From cc426d668440011f67bf62b2ec4ec2b6d4ced3a1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 31 Jan 2026 15:27:52 +0200 Subject: [PATCH 489/600] Fixed issues regarding some colored signs throwing errors with schematics (#2830) --- .../core/schematic/SchematicBlock.java | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java index 3b506738a7..dda1593705 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java @@ -8,15 +8,20 @@ import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.tag.StringTag; +import com.bgsoftware.superiorskyblock.tag.Tag; +import com.google.gson.Gson; +import com.google.gson.JsonObject; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.event.inventory.InventoryType; import java.util.Collections; +import java.util.Map; public class SchematicBlock { private static final ListTag EMPTY_LIST_TAG = ListTag.of(Collections.emptyList()); + private static final Gson GSON = new Gson(); private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @@ -147,11 +152,19 @@ private static void backFrontSignLinesReplace(CompoundTag tileEntityData, Island if (i < plugin.getSettings().getDefaultSign().size()) { line = plugin.getSettings().getDefaultSign().get(i); } else { - line = ((StringTag) messages.getValue().get(realIndex)).getValue(); + Tag tag = messages.getValue().get(realIndex); + if (tag instanceof CompoundTag) { + JsonObject jsonObject = new JsonObject(); + for (Map.Entry> entry : ((CompoundTag) tag).entrySet()) { + jsonObject.addProperty(entry.getKey(), String.valueOf(entry.getValue().getValue())); + } + line = GSON.toJson(jsonObject); + } else { + line = ((StringTag) tag).getValue(); + } } - line = line.replace("{player}", island.getOwner().getName()) - .replace("{island}", island.getName().isEmpty() ? island.getOwner().getName() : island.getName()); + line = parseSignPlaceholders(island, line); newMessages.addTag(StringTag.of(line)); } @@ -178,10 +191,8 @@ private static void legacySignLinesReplace(CompoundTag tileEntityData, Island is } if (line != null) { - tileEntityData.setString((isDefaultSignLine ? "SSB.Text" : "Text") + i, line - .replace("{player}", island.getOwner().getName()) - .replace("{island}", island.getName().isEmpty() ? island.getOwner().getName() : island.getName()) - ); + tileEntityData.setString((isDefaultSignLine ? "SSB.Text" : "Text") + i, + parseSignPlaceholders(island, line)); } } @@ -189,6 +200,11 @@ private static void legacySignLinesReplace(CompoundTag tileEntityData, Island is tileEntityData.setByte("SSB.HasSignLines", (byte) 1); } + private static String parseSignPlaceholders(Island island, String val) { + return val.replace("{player}", island.getOwner().getName()) + .replace("{island}", island.getName().isEmpty() ? island.getOwner().getName() : island.getName()); + } + public SchematicBlock setLocation(Location newBlockLoc) { return new SchematicBlock(newBlockLoc, this.blockId, this.extra); } From 71a50f1d4ed153b23e8746d86cf536ba486b6a8d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 31 Jan 2026 17:01:46 +0200 Subject: [PATCH 490/600] Fixed issues with dragon boss bar not updated correctly (#2849) --- .../dragon/IslandEndDragonFight.java.template | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template b/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template index 8eb131eb63..c512f7a5b1 100644 --- a/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template +++ b/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template @@ -41,11 +41,9 @@ import java.util.UUID; public class IslandEndDragonFight extends EndDragonFight { - private static final ReflectField DRAGON_BATTLE = new ReflectField( - EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1) - .removeFinal(); + private static final ReflectField DRAGON_BATTLE = initializeDragonBattleField(); private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 4); + EndDragonFight.class, boolean.class, Modifier.PRIVATE, 3); private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); @@ -212,4 +210,18 @@ public class IslandEndDragonFight extends EndDragonFight { return entityEnderDragon; } + private static ReflectField initializeDragonBattleField() { + ReflectField dragonBattleField = new ReflectField( + EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + if(dragonBattleField.isValid()) { + dragonBattleField = dragonBattleField.removeFinal(); + } else { + dragonBattleField = new ReflectField( + EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE, 1); + } + + return dragonBattleField; + } + } From a744579524174c678775ff7ead1664cf9393efc1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 31 Jan 2026 17:19:35 +0200 Subject: [PATCH 491/600] Fixed errors regarding chunk must be inbounds when loading chunks (#2836) --- .../island/container/DefaultIslandsContainer.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index 328b6c6181..0f6b97bdb8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -156,23 +156,21 @@ public int getIslandsAmount() { @Nullable @Override public Island getIslandAt(Location location) { - return plugin.getProviders().hasCustomWorldsSupport() ? + Island island = plugin.getProviders().hasCustomWorldsSupport() ? customWorldsSupportIslandLookup(location) : nativeIslandLookup(location); + return island == null || !island.isInside(SWorldPosition.of(location)) ? null : island; } private Island customWorldsSupportIslandLookup(Location location) { long packedPos = IslandPosition.calculatePackedPosFromLocation(location.getBlockX(), location.getBlockZ()); String worldName = LazyWorldLocation.getWorldName(location); - Island island = this.islandsGrid.getIslandAt(worldName, packedPos); - // We already checked for the world by calling `IslandsGrid#getIslandAt` with the world name parameter. - // We will only check that the location's position is inside the island. - return island == null || !island.isInside(SWorldPosition.of(location)) ? null : island; + return this.islandsGrid.getIslandAt(worldName, packedPos); } private Island nativeIslandLookup(Location location) { // We first check that the world is an islands world. World world = location.getWorld(); - if(world == null || !plugin.getGrid().isIslandsWorld(world)) + if (world == null || !plugin.getGrid().isIslandsWorld(world)) return null; long packedPos = IslandPosition.calculatePackedPosFromLocation(location.getBlockX(), location.getBlockZ()); From 7a0adf25dd7298399c5dbecc7fad5ddd5ec4a2fb Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 7 Feb 2026 17:53:38 +0200 Subject: [PATCH 492/600] Fixed errors from the capturedEvents mechanism (#2863) --- .../core/events/EventsDispatcher.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java index 695d974836..21b9977a7c 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/EventsDispatcher.java @@ -18,7 +18,11 @@ public class EventsDispatcher, P extends Enum

    , E protected final SuperiorSkyblockPlugin plugin; protected final Class

    priorityClass; - private List capturedEvents = null; + // This must be thread-safe, as it can be accessed from multiple threads. + // We don't actually want it to be thread-safe, but per-thread captured events. + // If we don't do that, weird behaviors can occur. For reference: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2863 + private final ThreadLocal> capturedEvents = new ThreadLocal<>(); protected EventsDispatcher(SuperiorSkyblockPlugin plugin, Class

    priorityClass, Collection allTypes) { this.plugin = plugin; @@ -37,12 +41,12 @@ public void clearCallbacks() { } public void startCaptureEvents() { - this.capturedEvents = new LinkedList<>(); + this.capturedEvents.set(new LinkedList<>()); } public List stopCaptureEvents() { - List capturedEvents = this.capturedEvents; - this.capturedEvents = null; + List capturedEvents = this.capturedEvents.get(); + this.capturedEvents.remove(); return capturedEvents; } @@ -68,8 +72,9 @@ public void onGameEvent(E event, P priority) { } } - if (this.capturedEvents != null && filterCapturedEvent(event)) - this.capturedEvents.add(event); + List capturedEvents = this.capturedEvents.get(); + if (capturedEvents != null && filterCapturedEvent(event)) + capturedEvents.add(event); } protected boolean filterCapturedEvent(E event) { From 1c6417254d92ed175c48e12a98ddf60db4c454c5 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 7 Feb 2026 18:22:19 +0200 Subject: [PATCH 493/600] Fixed detection of hanging signs and trapped chests as not signs and chests in schematics (#2830) --- .../superiorskyblock/core/schematic/SchematicBlock.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java index dda1593705..b5f1b82f41 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java @@ -210,11 +210,11 @@ public SchematicBlock setLocation(Location newBlockLoc) { } private static boolean isSignId(String id) { - return id.equals("Sign") || id.equals("minecraft:sign"); + return id.equals("Sign") || id.equals("minecraft:sign") || id.equals("minecraft:hanging_sign"); } private static boolean isChestId(String id) { - return id.equals("Chest") || id.equals("minecraft:chest"); + return id.equals("Chest") || id.equals("minecraft:chest") || id.equals("minecraft:trapped_chest"); } public static class Extra { From 6fb3287bc39f90f9c2652cf996eea5e580931d8e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 7 Feb 2026 18:22:50 +0200 Subject: [PATCH 494/600] Fixed errors when using underline or any other formatting in signs (#2830) --- .../superiorskyblock/core/schematic/SchematicBlock.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java index b5f1b82f41..deefa5e415 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/schematic/SchematicBlock.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; +import com.bgsoftware.superiorskyblock.tag.NumberTag; import com.bgsoftware.superiorskyblock.tag.StringTag; import com.bgsoftware.superiorskyblock.tag.Tag; import com.google.gson.Gson; @@ -156,7 +157,13 @@ private static void backFrontSignLinesReplace(CompoundTag tileEntityData, Island if (tag instanceof CompoundTag) { JsonObject jsonObject = new JsonObject(); for (Map.Entry> entry : ((CompoundTag) tag).entrySet()) { - jsonObject.addProperty(entry.getKey(), String.valueOf(entry.getValue().getValue())); + Tag valueTag = entry.getValue(); + if (valueTag instanceof NumberTag) { + // Booleans are parsed as NumberTag + jsonObject.addProperty(entry.getKey(), ((NumberTag) valueTag).getValue().intValue() == 1); + } else { + jsonObject.addProperty(entry.getKey(), String.valueOf(valueTag.getValue())); + } } line = GSON.toJson(jsonObject); } else { From 8f293288a4d74c85fa822d417ec877feb5f75fef Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 7 Feb 2026 18:42:49 +0200 Subject: [PATCH 495/600] Fixed saving "size" and "bank_limit" in incorrect table, causing errors (#2862) --- .../core/database/bridge/IslandsDatabaseBridge.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index 6d30bfd4fd..6afb7ec655 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -212,7 +212,7 @@ public static void saveDescription(Island island) { } public static void saveSize(Island island) { - updateIslandValue(island, "size", island.getIslandSize()); + updateIslandSettingsValue(island, "size", island.getIslandSize()); } public static void saveDiscord(Island island) { @@ -236,7 +236,7 @@ public static void saveLastTimeUpdate(Island island) { } public static void saveBankLimit(Island island) { - updateIslandValue(island, "bank_limit", island.getBankLimit() + ""); + updateIslandSettingsValue(island, "bank_limit", island.getBankLimit() + ""); } public static void saveBonusWorth(Island island) { From 92116db4d7c8d01e80ec865e3e426da9408ddc95 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 7 Feb 2026 21:20:02 +0200 Subject: [PATCH 496/600] Fix reset-after-finish not working as it should (#2861) --- .../api/missions/Mission.java | 6 +- .../superiorskyblock/island/SIsland.java | 12 +- .../superiorskyblock/mission/MissionData.java | 8 +- .../mission/MissionsManagerImpl.java | 191 ++++++++++-------- .../player/SSuperiorPlayer.java | 12 +- .../resources/modules/missions/BlocksMissions | Bin 40179 -> 41443 bytes .../modules/missions/BrewingMissions | Bin 28709 -> 30011 bytes .../modules/missions/CraftingMissions | Bin 24768 -> 26028 bytes .../modules/missions/EnchantingMissions | Bin 28920 -> 30075 bytes .../modules/missions/FarmingMissions | Bin 37432 -> 38717 bytes .../modules/missions/FishingMissions | Bin 21749 -> 23055 bytes .../resources/modules/missions/IslandMissions | Bin 27227 -> 28661 bytes .../resources/modules/missions/ItemsMissions | Bin 23207 -> 24510 bytes .../resources/modules/missions/KillsMissions | Bin 21930 -> 23231 bytes .../modules/missions/StatisticsMissions | Bin 23054 -> 24470 bytes 15 files changed, 133 insertions(+), 96 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/Mission.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/Mission.java index c25d80697d..188fea92e0 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/Mission.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/missions/Mission.java @@ -264,7 +264,7 @@ protected SuperiorPlayer getDataKey(SuperiorPlayer superiorPlayer) { * @param superiorPlayer The player to change it's data. * @param value The data to insert. */ - protected void insertData(SuperiorPlayer superiorPlayer, V value) { + public void insertData(SuperiorPlayer superiorPlayer, V value) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(value, "value parameter cannot be null."); SuperiorPlayer dataKey = getDataKey(superiorPlayer); @@ -279,7 +279,7 @@ protected void insertData(SuperiorPlayer superiorPlayer, V value) { * @param createFunction The function that will be run when data doesn't exist yet. */ @Nullable - protected V getOrCreate(SuperiorPlayer superiorPlayer, Function createFunction) { + public V getOrCreate(SuperiorPlayer superiorPlayer, Function createFunction) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); Preconditions.checkNotNull(createFunction, "createFunction parameter cannot be null."); @@ -297,7 +297,7 @@ protected V getOrCreate(SuperiorPlayer superiorPlayer, Function mission) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkArgument(mission.getIslandMission(), "mission parameter must be island-mission."); - this.changeAmountMissionsCompletedInternal(mission, counter -> counter.inc(1)); + this.changeAmountMissionsCompletedInternal(mission, false, counter -> counter.inc(1)); } @Override public void resetMission(Mission mission) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkArgument(mission.getIslandMission(), "mission parameter must be island-mission."); - this.changeAmountMissionsCompletedInternal(mission, counter -> counter.inc(-1)); + this.changeAmountMissionsCompletedInternal(mission, true, counter -> counter.inc(-1)); } @Override @@ -4796,10 +4796,10 @@ public int getAmountMissionCompleted(Mission mission) { public void setAmountMissionCompleted(Mission mission, int finishCount) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkArgument(mission.getIslandMission(), "mission parameter must be island-mission."); - this.changeAmountMissionsCompletedInternal(mission, counter -> counter.set(finishCount)); + this.changeAmountMissionsCompletedInternal(mission, true, counter -> counter.set(finishCount)); } - private void changeAmountMissionsCompletedInternal(Mission mission, Function action) { + private void changeAmountMissionsCompletedInternal(Mission mission, boolean clearData, Function action) { String missionName = mission.getName(); MissionReference missionReference = new MissionReference(mission); @@ -4810,8 +4810,8 @@ private void changeAmountMissionsCompletedInternal(Mission mission, Function< Log.debug(Debug.SET_ISLAND_MISSION_COMPLETED, missionName, finishCount); - // We always want to reset data - mission.clearData(getOwner()); + if (clearData) + mission.clearData(getOwner()); if (newFinishCount > 0) { if (newFinishCount == oldFinishCount) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java index 9aeaf594e0..a25850c6d1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionData.java @@ -24,6 +24,8 @@ public class MissionData { private final boolean islandMission; private final boolean disbandReset; private final boolean leaveReset; + private final boolean resetAfterFinish; + private final int resetAmount; @Nullable private final TemplateItem notCompleted; @Nullable @@ -32,7 +34,6 @@ public class MissionData { private final TemplateItem locked; @Nullable private final TemplateItem completed; - private final int resetAmount; MissionData(Mission mission, String missionCategoryName, ConfigurationSection section) { this.index = currentIndex++; @@ -42,6 +43,7 @@ public class MissionData { this.disbandReset = section.getBoolean("disband-reset", false); this.leaveReset = section.getBoolean("leave-reset", false); this.resetAmount = section.getInt("reset-amount", 1); + this.resetAfterFinish = section.getBoolean("reset-after-finish", true); if (section.isConfigurationSection("rewards.items")) { for (String key : section.getConfigurationSection("rewards.items").getKeys(false)) { @@ -100,6 +102,10 @@ public int getResetAmount() { return resetAmount; } + public boolean isResetAfterFinish() { + return resetAfterFinish; + } + public boolean hasLocked() { return locked != null; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java index 1609c9f7b0..606a396a6a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java @@ -43,6 +43,7 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Optional; @@ -245,11 +246,6 @@ public void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); - if (Bukkit.isPrimaryThread()) { - BukkitExecutor.async(() -> rewardMission(mission, superiorPlayer, checkAutoReward, forceReward, result)); - return; - } - Optional missionDataOptional = getMissionData(mission); if (!missionDataOptional.isPresent()) { @@ -260,95 +256,136 @@ public void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, Log.debug(Debug.REWARD_MISSION, mission.getName(), superiorPlayer.getName(), checkAutoReward, forceReward); - synchronized (superiorPlayer) { - MissionData missionData = missionDataOptional.get(); + MissionData missionData = missionDataOptional.get(); + + IMissionsHolder missionsHolder = missionData.isIslandMission() ? superiorPlayer.getIsland() : superiorPlayer; - IMissionsHolder missionsHolder = missionData.isIslandMission() ? superiorPlayer.getIsland() : superiorPlayer; + if (missionsHolder == null) { + mission.onCompleteFail(superiorPlayer); + if (result != null) + result.accept(false); + throw new IllegalStateException("Cannot reward island mission " + mission.getName() + " as the player " + superiorPlayer.getName() + " does not have island."); + } - if (missionsHolder == null) { + if (Bukkit.isPrimaryThread()) { + BukkitExecutor.async(() -> rewardMissionAsyncInternal(mission, missionData, superiorPlayer, + missionsHolder, checkAutoReward, forceReward, result)); + } else { + rewardMissionAsyncInternal(mission, missionData, superiorPlayer, missionsHolder, checkAutoReward, forceReward, result); + } + } + + private void rewardMissionAsyncInternal(Mission mission, MissionData missionData, SuperiorPlayer superiorPlayer, + IMissionsHolder missionsHolder, boolean checkAutoReward, boolean forceReward, + @Nullable Consumer result) { + boolean rewarded; + synchronized (superiorPlayer) { + rewarded = tryRewardMissionLockedInternal(mission, missionData, superiorPlayer, missionsHolder, checkAutoReward, forceReward); + } + if (result != null) + result.accept(rewarded); + } + + private boolean tryRewardMissionLockedInternal(Mission mission, MissionData missionData, SuperiorPlayer superiorPlayer, + IMissionsHolder missionsHolder, boolean checkAutoReward, boolean forceReward) { + if (!forceReward) { + if (!canCompleteAgain(superiorPlayer, mission)) { mission.onCompleteFail(superiorPlayer); - if (result != null) - result.accept(false); - throw new IllegalStateException("Cannot reward island mission " + mission.getName() + " as the player " + superiorPlayer.getName() + " does not have island."); + return false; } - if (!forceReward) { - if (!canCompleteAgain(superiorPlayer, mission)) { - mission.onCompleteFail(superiorPlayer); - if (result != null) - result.accept(false); - return; - } + if (!canComplete(superiorPlayer, mission)) { + return false; + } - if (!canComplete(superiorPlayer, mission)) { - if (result != null) - result.accept(false); - return; + if (checkAutoReward) { + boolean shouldAutoReward = isAutoReward(mission); + if (shouldAutoReward && !BuiltinModules.MISSIONS.getConfiguration().isAutoRewardOutsideIslands() && + !plugin.getGrid().isIslandsWorld(superiorPlayer.getWorld())) { + return false; } - if (checkAutoReward) { - boolean shouldAutoReward = isAutoReward(mission); - if (shouldAutoReward && !BuiltinModules.MISSIONS.getConfiguration().isAutoRewardOutsideIslands() && - !plugin.getGrid().isIslandsWorld(superiorPlayer.getWorld())) { - if (result != null) - result.accept(false); - return; - } - - if (!shouldAutoReward) { - if (canCompleteAgain(superiorPlayer, mission)) { - Message.MISSION_NO_AUTO_REWARD.send(superiorPlayer, mission.getName()); - if (result != null) - result.accept(false); - return; - } + if (!shouldAutoReward) { + if (canCompleteAgain(superiorPlayer, mission)) { + Message.MISSION_NO_AUTO_REWARD.send(superiorPlayer, mission.getName()); + return false; } } } + } - List itemRewards = new ArrayList<>(); - List commandRewards; - - //noinspection SynchronizationOnLocalVariableOrMethodParameter - synchronized (missionData) { - missionData.getItemRewards().forEach(itemStack -> itemRewards.add(itemStack.clone())); - commandRewards = new ArrayList<>(missionData.getCommandRewards()); - } + List itemRewards = new ArrayList<>(); + List commandRewards; - PluginEvent event = PluginEventsFactory.callMissionCompleteEvent( - superiorPlayer, missionsHolder, mission, itemRewards, commandRewards); + //noinspection SynchronizationOnLocalVariableOrMethodParameter + synchronized (missionData) { + missionData.getItemRewards().forEach(itemStack -> itemRewards.add(itemStack.clone())); + commandRewards = new LinkedList<>(missionData.getCommandRewards()); + } - if (event.isCancelled()) { - if (!forceReward) - mission.onCompleteFail(superiorPlayer); - if (result != null) - result.accept(false); - return; - } + PluginEvent event = PluginEventsFactory.callMissionCompleteEvent( + superiorPlayer, missionsHolder, mission, itemRewards, commandRewards); + if (event.isCancelled()) { if (!forceReward) - mission.onComplete(superiorPlayer); + mission.onCompleteFail(superiorPlayer); + return false; + } - missionsHolder.completeMission(mission); + if (!forceReward) + mission.onComplete(superiorPlayer); - if (result != null) - result.accept(true); - - for (ItemStack itemStack : event.getArgs().itemRewards) { - ItemStack toGive = new ItemBuilder(itemStack) - .replaceAll("{0}", mission.getName()) - .replaceAll("{1}", superiorPlayer.getName()) - .replaceAll("{2}", getIslandPlaceholder(missionsHolder)) - .build(); - toGive.setAmount(itemStack.getAmount()); - BukkitExecutor.ensureMain(() -> superiorPlayer.runIfOnline(player -> { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - BukkitItems.addItem(toGive, player.getInventory(), player.getLocation(wrapper.getHandle())); + missionsHolder.completeMission(mission); + + if (missionData.isResetAfterFinish()) { + mission.clearData(superiorPlayer); + } else { + // We want to add the data to the next missions as well + Object playerMissionProgress = mission.get(superiorPlayer); + for (Mission otherMission : mission.getMissionCategory().getMissions()) { + if (otherMission.getRequiredMissions().contains(mission.getName()) && + canCompleteNoProgress(superiorPlayer, otherMission)) { + try { + otherMission.insertData(superiorPlayer, playerMissionProgress); + } catch (ClassCastException error) { + // We use raw parameterized values, therefore cast-errors can occur. + // In this case, we'll just ignore these. } - })); + } + } + } + + List rewardedItems = new LinkedList<>(); + for (ItemStack itemStack : event.getArgs().itemRewards) { + ItemStack toGive = new ItemBuilder(itemStack) + .replaceAll("{0}", mission.getName()) + .replaceAll("{1}", superiorPlayer.getName()) + .replaceAll("{2}", getIslandPlaceholder(missionsHolder)) + .build(); + toGive.setAmount(itemStack.getAmount()); + rewardedItems.add(toGive); + } + + // Auto complete other missions that depend on the mission that was just completed + for (Mission otherMission : getAllMissions()) { + if (otherMission.getRequiredMissions().contains(mission.getName()) && otherMission.canComplete(superiorPlayer)) { + // Auto reward the next mission + rewardMission(otherMission, superiorPlayer, true); } + } + if (!rewardedItems.isEmpty() || !event.getArgs().commandRewards.isEmpty()) { BukkitExecutor.ensureMain(() -> { + if (!rewardedItems.isEmpty()) { + superiorPlayer.runIfOnline(player -> { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + for (ItemStack toGive : itemRewards) { + BukkitItems.addItem(toGive, player.getInventory(), player.getLocation(wrapper.getHandle())); + } + } + }); + } + for (String command : event.getArgs().commandRewards) { Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command .replace("%mission%", mission.getName()) @@ -357,15 +394,9 @@ public void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, ); } }); - - // Auto complete other missions that depend on the mission that was just completed - for (Mission otherMission : getAllMissions()) { - if (otherMission.getRequiredMissions().contains(mission.getName()) && otherMission.canComplete(superiorPlayer)) { - // Auto reward the next mission - rewardMission(otherMission, superiorPlayer, true); - } - } } + + return true; } private boolean moveOldDataFolder(File newDataFolder) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index e132fb9fe7..dde361be99 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -1045,14 +1045,14 @@ public void savePersistentDataContainer() { public void completeMission(Mission mission) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkArgument(!mission.getIslandMission(), "mission parameter must be player-mission."); - this.changeAmountMissionsCompletedInternal(mission, counter -> counter.inc(1)); + this.changeAmountMissionsCompletedInternal(mission, false, counter -> counter.inc(1)); } @Override public void resetMission(Mission mission) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkArgument(!mission.getIslandMission(), "mission parameter must be player-mission."); - this.changeAmountMissionsCompletedInternal(mission, counter -> counter.inc(-1)); + this.changeAmountMissionsCompletedInternal(mission, true, counter -> counter.inc(-1)); } @Override @@ -1087,10 +1087,10 @@ public int getAmountMissionCompleted(Mission mission) { public void setAmountMissionCompleted(Mission mission, int finishCount) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); Preconditions.checkArgument(!mission.getIslandMission(), "mission parameter must be player-mission."); - this.changeAmountMissionsCompletedInternal(mission, counter -> counter.set(finishCount)); + this.changeAmountMissionsCompletedInternal(mission, true, counter -> counter.set(finishCount)); } - private void changeAmountMissionsCompletedInternal(Mission mission, Function action) { + private void changeAmountMissionsCompletedInternal(Mission mission, boolean clearData, Function action) { Preconditions.checkNotNull(mission, "mission parameter cannot be null."); MissionReference missionReference = new MissionReference(mission); @@ -1101,8 +1101,8 @@ private void changeAmountMissionsCompletedInternal(Mission mission, Function< Log.debug(Debug.SET_PLAYER_MISSION_COMPLETED, getName(), mission.getName(), newFinishCount); - // We always want to reset data - mission.clearData(this); + if (clearData) + mission.clearData(this); if (newFinishCount > 0) { if (newFinishCount == oldFinishCount) diff --git a/src/main/resources/modules/missions/BlocksMissions b/src/main/resources/modules/missions/BlocksMissions index d33dd4c5a91832785c3b0d4da6003d80cee3bef4..f1b7a9b210f4cc15fefcdffed622ecd5b35bf345 100644 GIT binary patch delta 15652 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 S0z&rwr2WNcO|ZxHqWLvjXxOkCG!@f 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 delta 13313 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 diff --git a/src/main/resources/modules/missions/CraftingMissions b/src/main/resources/modules/missions/CraftingMissions index 76a1a3c49ca31ed5a401898726241655af54c1ca..4e26cdfe3bef6fc954d33f4ba4a6c44181b608e8 100644 GIT binary patch delta 10754 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 XMnxX($w?51s${oniF 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 diff --git a/src/main/resources/modules/missions/EnchantingMissions b/src/main/resources/modules/missions/EnchantingMissions index eb71ec3d6e15bcbb044ff474d0512678a42dde46..af297de64af6b1e8fae1d428d0650ba3a00fabeb 100644 GIT binary patch delta 14380 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 VAwT#*K=404U*SInZuaNt{{Z4oBklkI diff --git a/src/main/resources/modules/missions/FarmingMissions b/src/main/resources/modules/missions/FarmingMissions index c975df6a13f4b0fac8a3f1c4d2c1fc8283a439e7..a23e2dbd703929b4e7f8eefb9745be2fe839e189 100644 GIT binary patch delta 11896 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 E0Dz>% delta 10730 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 diff --git a/src/main/resources/modules/missions/FishingMissions b/src/main/resources/modules/missions/FishingMissions index d30452373a6cf3adb4dbe0f6e6c2dce3bb608892..837a5bcfc5ca48607d467cb416545200e791c7a3 100644 GIT binary patch delta 8140 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ක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 PT;Gd0AP|Pq@2CF*gid5d diff --git a/src/main/resources/modules/missions/IslandMissions b/src/main/resources/modules/missions/IslandMissions index 799d0c7b632c8c76f6bd6542d089d72875067c25..ef69894d35bce9e62add690258ac25f0e962513b 100644 GIT binary patch delta 7592 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 b#PXQPZY{F<~^6q=W?ru&XMwB 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�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 delta 7164 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 diff --git a/src/main/resources/modules/missions/StatisticsMissions b/src/main/resources/modules/missions/StatisticsMissions index c63dad017df7a477ad40f71fcb4e22460eccd643..1823a51d0be6b67dad564ef8eb6da14a5b043095 100644 GIT binary patch delta 9158 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 From 7837767404a717fcb9b03ba2782d13772a01c478 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 7 Feb 2026 20:21:54 +0100 Subject: [PATCH 497/600] Fixed using /is warp for players who don't have an island (#2859) --- .../superiorskyblock/commands/player/CmdWarp.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java index 4394266dcb..6c28b4e137 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdWarp.java @@ -61,6 +61,8 @@ public boolean canBeExecutedByConsole() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); + Island targetIsland = null; String targetWarpName = null; @@ -71,9 +73,14 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ break; } case 2: { - IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); - targetIsland = arguments.getIsland(); - targetWarpName = args[1]; + if (superiorPlayer.hasIsland()) { + IslandArgument arguments = CommandArguments.getSenderIsland(plugin, sender); + targetIsland = arguments.getIsland(); + targetWarpName = args[1]; + } else { + IslandArgument arguments = CommandArguments.getIsland(plugin, sender, args[1]); + targetIsland = arguments.getIsland(); + } break; } case 3: { @@ -87,8 +94,6 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ if (targetIsland == null) return; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); - IslandWarp islandWarp = targetWarpName == null ? null : targetIsland.getWarp(targetWarpName); if (islandWarp == null) { From 86e7ebc324cab091120c6169ffda7045d35a3445 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 7 Feb 2026 20:25:06 +0100 Subject: [PATCH 498/600] Improved display of island descriptions in the global-warps menu (#2858) --- .../api/config/SettingsManager.java | 6 +++ .../config/SettingsContainer.java | 2 + .../config/section/VisitorsSignSection.java | 5 ++ .../impl/GlobalWarpsPagedObjectButton.java | 52 +++++++------------ .../core/menu/impl/MenuGlobalWarps.java | 2 - .../core/messages/Message.java | 1 + .../island/signs/IslandSigns.java | 6 ++- src/main/resources/config.yml | 4 ++ src/main/resources/lang/de-DE.yml | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/tr-TR.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + 20 files changed, 54 insertions(+), 36 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 197f67b420..80dbd5ff32 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -1045,6 +1045,12 @@ interface VisitorsSign { */ String getInactive(); + /** + * The format in which the island description lines will be saved. + * Config-path: visitors-sign.description-line-format + */ + String getDescriptionLineFormat(); + } interface Worlds { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 18a0ee837f..b775735630 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -120,6 +120,7 @@ public class SettingsContainer { public final String visitorsSignLine; public final String visitorsSignActive; public final String visitorsSignInactive; + public final String visitorsSignDescriptionLineFormat; public final Dimension defaultWorldDimension; public final String defaultWorldName; public final String islandWorldName; @@ -342,6 +343,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config visitorsSignLine = config.getString("visitors-sign.line", "[Welcome]"); visitorsSignActive = Formatters.COLOR_FORMATTER.format(config.getString("visitors-sign.active", "&a[Welcome]")); visitorsSignInactive = Formatters.COLOR_FORMATTER.format(config.getString("visitors-sign.inactive", "&c[Welcome]")); + visitorsSignDescriptionLineFormat = Formatters.COLOR_FORMATTER.format(config.getString("visitors-sign.description-line-format", "{0}")); islandWorldName = config.getString("worlds.world-name", "SuperiorWorld"); { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/VisitorsSignSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/VisitorsSignSection.java index 0880ea575c..60b222f6ca 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/VisitorsSignSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/VisitorsSignSection.java @@ -25,4 +25,9 @@ public String getInactive() { return getContainer().visitorsSignInactive; } + @Override + public String getDescriptionLineFormat() { + return getContainer().visitorsSignDescriptionLineFormat; + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java index c034cdc29d..2b5d0744e8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/GlobalWarpsPagedObjectButton.java @@ -3,8 +3,6 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.menu.button.MenuTemplateButton; import com.bgsoftware.superiorskyblock.api.menu.button.PagedMenuTemplateButton; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; import com.bgsoftware.superiorskyblock.core.menu.Menus; @@ -12,11 +10,11 @@ import com.bgsoftware.superiorskyblock.core.menu.button.PagedMenuTemplateButtonImpl; import com.bgsoftware.superiorskyblock.core.menu.impl.MenuGlobalWarps; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; +import com.bgsoftware.superiorskyblock.core.messages.Message; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import java.util.Locale; -import java.util.Map; public class GlobalWarpsPagedObjectButton extends AbstractPagedMenuButton { @@ -40,42 +38,32 @@ public void onButtonClick(InventoryClickEvent clickEvent) { @Override public ItemStack modifyViewItem(ItemStack buttonItem) { - final SuperiorPlayer viewer = menuView.getInventoryViewer(); - final SuperiorPlayer owner = pagedObject.getOwner(); - final String ownerName = owner.getName(); - String islandName = pagedObject.getName(); - if (Text.isBlank(islandName)) islandName = ownerName; + String ownerName = pagedObject.getOwner().getName(); + String islandName = pagedObject.getName().isEmpty() ? ownerName : pagedObject.getName(); - final int warpsCount = pagedObject.getIslandWarps().size(); + Locale locale = menuView.getInventoryViewer().getUserLocale(); + String[] description; - Locale userLocale = viewer.getUserLocale(); - String levelNum = Formatters.NUMBER_FORMATTER.format(pagedObject.getIslandLevel()); - String worthNum = Formatters.NUMBER_FORMATTER.format(pagedObject.getWorth()); - String levelFancy = Formatters.FANCY_NUMBER_FORMATTER.format(pagedObject.getIslandLevel(), userLocale); - String worthFancy = Formatters.FANCY_NUMBER_FORMATTER.format(pagedObject.getWorth(), userLocale); - - int ratingCount = pagedObject.getRatingAmount(); - - String ratingAvgNum = Formatters.NUMBER_FORMATTER.format(pagedObject.getTotalRating()); - String ratingAvgFancy = Formatters.RATING_FORMATTER.format(pagedObject.getTotalRating(), userLocale); - - String[] descLines = Text.isBlank(pagedObject.getDescription()) - ? EMPTY_STRING_ARRAY - : pagedObject.getDescription().split("\n"); + if (!pagedObject.getDescription().isEmpty()) + description = pagedObject.getDescription().split("\n"); + else if (!Message.ISLAND_DESCRIPTION_NONE.isEmpty(locale)) + description = new String[] {Message.ISLAND_DESCRIPTION_NONE.getMessage(locale)}; + else + description = EMPTY_STRING_ARRAY; return new ItemBuilder(buttonItem) .asSkullOf(pagedObject.getOwner()) .replaceAll("{0}", ownerName) - .replaceLoreWithLines("{1}", descLines) - .replaceAll("{2}", String.valueOf(warpsCount)) + .replaceLoreWithLines("{1}", description) + .replaceAll("{2}", String.valueOf(pagedObject.getIslandWarps().size())) .replaceAll("{3}", islandName) - .replaceAll("{4}", levelNum) - .replaceAll("{5}", levelFancy) - .replaceAll("{6}", worthNum) - .replaceAll("{7}", worthFancy) - .replaceAll("{8}", ratingAvgNum) - .replaceAll("{9}", ratingAvgFancy) - .replaceAll("{10}", String.valueOf(ratingCount)) + .replaceAll("{4}", Formatters.NUMBER_FORMATTER.format(pagedObject.getIslandLevel())) + .replaceAll("{5}", Formatters.FANCY_NUMBER_FORMATTER.format(pagedObject.getIslandLevel(), locale)) + .replaceAll("{6}", Formatters.NUMBER_FORMATTER.format(pagedObject.getWorth())) + .replaceAll("{7}", Formatters.FANCY_NUMBER_FORMATTER.format(pagedObject.getWorth(), locale)) + .replaceAll("{8}", Formatters.NUMBER_FORMATTER.format(pagedObject.getTotalRating())) + .replaceAll("{9}", Formatters.RATING_FORMATTER.format(pagedObject.getTotalRating(), locale)) + .replaceAll("{10}", String.valueOf(pagedObject.getRatingAmount())) .build(pagedObject.getOwner()); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java index 158144ba91..139e9aab98 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuGlobalWarps.java @@ -3,11 +3,9 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.island.SortingType; import com.bgsoftware.superiorskyblock.api.menu.Menu; import com.bgsoftware.superiorskyblock.api.menu.layout.PagedMenuLayout; import com.bgsoftware.superiorskyblock.api.menu.view.MenuView; -import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 6712f6d261..591a9a0070 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -482,6 +482,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { ISLAND_CLOSED, ISLAND_CREATE_PROCCESS_REQUEST, ISLAND_CREATE_PROCESS_FAIL, + ISLAND_DESCRIPTION_NONE, ISLAND_FLY_DISABLED, ISLAND_FLY_ENABLED, ISLAND_GOT_DELETED_WHILE_INSIDE, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java b/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java index dc09679757..78019a96c5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java @@ -150,8 +150,10 @@ private static Result handleVisitorsSignPlace(SuperiorPlayer superiorPlayer, Isl for (int i = 1; i < 4; i++) { String line = warpLines[i]; - if (!line.isEmpty()) - descriptionBuilder.append("\n").append(ChatColor.RESET).append(line); + if (!line.isEmpty()) { + String formattedLine = plugin.getSettings().getVisitorsSign().getDescriptionLineFormat().replace("{0}", line); + descriptionBuilder.append("\n").append(ChatColor.RESET).append(formattedLine); + } } String description = descriptionBuilder.length() < 1 ? "" : descriptionBuilder.substring(1); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 5b562b8e55..b44ba83010 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -324,6 +324,10 @@ visitors-sign: active: '&a[Welcome]' # The line that will be displayed when the sign is inactive. inactive: '&c[Welcome]' + # The format in which the island description lines will be saved, players can set the island description + # by entering it in the next lines of the Visitors Sign. Useful if you want to display a description + # in the global-warps menu and want to give it a default color. {0} represents the text on that line. + description-line-format: '{0}' # Settings related to the island worlds. worlds: diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 559019da7b..0a4b86c345 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -553,6 +553,7 @@ ISLAND_BEING_CALCULATED: '&c&lError | &7Du kannst nicht mit Blöcken interagiere ISLAND_CLOSED: '&e&lInsel | &7Die Insel wurde erfolgreich für die Öffentlichkeit geschlossen.' ISLAND_CREATE_PROCESS_FAIL: '&c&lError | &7Du hast eine bereits laufende Inselerstellungsaufgabe.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lInsel | &7Deine Anfrage wird bearbeitet...' +ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lFly | &7Inselflug wurde automatisch &cdeaktiviert&7.' ISLAND_FLY_ENABLED: '&e&lFly | &7Inselflug wurde automatisch &aktiviert&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lInsel | &7&oDu warst auf einer Insel, die aufgelöst diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 57b0526291..66bf601eab 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -438,6 +438,7 @@ ISLAND_BEING_CALCULATED: '&c&lError | &7You cannot interact with blocks when isl ISLAND_CLOSED: '&e&lIsland | &7Successfully closed the island to the public.' ISLAND_CREATE_PROCESS_FAIL: '&c&lError | &7You have an already ongoing island creation task.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lIsland | &7Processing your request...' +ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lFly | &7Island fly was automatically &cdisabled&7.' ISLAND_FLY_ENABLED: '&e&lFly | &7Island fly was automatically &aenabled&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIsland | &7&oYou had been inside an island that been disbanded, so you were teleported back to spawn...' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index fb27623dac..eb688f9091 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -438,6 +438,7 @@ ISLAND_BEING_CALCULATED: '&c&lError | &7¡No puedes interactuar con bloques cuan ISLAND_CLOSED: '&e&lIsla | &7Cerró con éxito la isla al público.' ISLAND_CREATE_PROCESS_FAIL: '&c&lError | &7Ya tienes una tarea de creación de islas en curso.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lIsla | &7Procesando su solicitud...' +ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lVuelo | &7El vuelo de la isla fue automáticamente &cdesactivado&7.' ISLAND_FLY_ENABLED: '&e&lVuelo | &7El vuelo de la isla fue automáticamente &aactivado&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIsla | &7&oEstabas dentro de una isla que se disolvio, por lo que se te teletransporto de regreso al spawn...' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 7b58677f7a..720fc048f0 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -438,6 +438,7 @@ ISLAND_BEING_CALCULATED: '&c&lErreur | &7Vous ne pouvez pas interagir avec des b ISLAND_CLOSED: '&e&lIle | &7L''île est désormais fermée au public.' ISLAND_CREATE_PROCESS_FAIL: '&c&lErreur | &7Votre île est déjà en cours de création.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lIle | &7Requête en cours de traitement...' +ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lVol | &7Le mode vol de l''île a été &cdésactivé &7automatiquement.' ISLAND_FLY_ENABLED: '&e&lVol | &7Le mode vol de l''île &aactivé &7automatiquement.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIle | &7&oVous vous trouviez sur une île ayant été supprimée, vous avez donc été téléporté(e) au spawn...' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 3299eb2dc0..48a2afee7d 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -442,6 +442,7 @@ ISLAND_BEING_CALCULATED: '&c&lErrore | &7Non è possibile interagire con i blocc ISLAND_CLOSED: '&e&lIsola | &7Chiusa con successo l''isola al pubblico.' ISLAND_CREATE_PROCESS_FAIL: '&c&lErrore | &7Hai un''attività di creazione dell''isola già in corso.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lIsola | &7Elaborazione della richiesta...' +ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lFly | &7La modalità volo dell''isola è stata &cdisattivata&7 automaticamente.' ISLAND_FLY_ENABLED: '&e&lFly | &7La modalità volo dell''isola è stata &aattivata&7 automaticamente.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIsola | &7&oSei stato all''interno di un''isola che è stata sciolta, quindi sei stato teletrasportato allo spawn...' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index 39e28c3207..f7fc4d9bc7 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -454,6 +454,7 @@ ISLAND_BEING_CALCULATED: '&c&lהאיגש | &7שדחמ בשוחמ יאהש ןמז ISLAND_CLOSED: '&e&lיא | &7החלצהב רוביצל רגסנ יאה.' ISLAND_CREATE_PROCESS_FAIL: '&c&lError | &7You have an already ongoing island creation task.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lיא | &7ךתשקב תא דבעמ...' +ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lהפועת | &7יטמוטוא הפועת בצמ &cקספוה&7.' ISLAND_FLY_ENABLED: '&e&lהפועת | &7יטמוטוא הפועת בצמ &aלעפוה&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lיא | &7&oןואפסה לא תרגוש ןכל ,קחמנש יא ךותב diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 09444deefa..2ed0ff5bdb 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -438,6 +438,7 @@ ISLAND_BEING_CALCULATED: '&c&lBlad | &7Nie mozesz wchodzic w interakcje z blokam ISLAND_CLOSED: '&e&lWyspa | &7Pomyslnie zamknelismy wyspe dla publicznosci.' ISLAND_CREATE_PROCESS_FAIL: '&c&lBlad | &7Masz juz trwajace zadanie tworzenia wyspy.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lWyspa | &7Przetwarzanie zadania...' +ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lFly | &7Mucha na wyspe zostala automatycznie &cwylaczona&7.' ISLAND_FLY_ENABLED: '&e&lFly | &7Lot na wyspe zostal automatycznie &wlaczony&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lWyspa | &7&oByles na wyspie, która zostala rozwiazana, wiec zostales przeteleportowany z powrotem na miejsce odrodzenia...' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index c9ba89f723..3a1c9ca8b9 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -438,6 +438,7 @@ ISLAND_BEING_CALCULATED: '&c&lErro | &7Você não pode interagir com blocos quan ISLAND_CLOSED: '&e&lIsland | &7A ilha foi fechada com sucesso para o público.' ISLAND_CREATE_PROCESS_FAIL: '&c&lErro | &7Você já tem uma tarefa de criação de ilha em andamento.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lIlha | &7Processando sua solicitação...' +ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lVoar | &7Voar na ilha foi automaticamente &cdesabilitado&7.' ISLAND_FLY_ENABLED: '&e&lVoar | &7Voar na ilha foi automaticamente &ahabilitado&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lIlha | &7&oVocê estava dentro de uma ilha que foi apagada, então você foi teletransportado de volta para spawn...' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index e6522c795a..f430b76ae5 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -438,6 +438,7 @@ ISLAND_BEING_CALCULATED: '&c&lОшибка | &7Вы не можете взаим ISLAND_CLOSED: '&e&lОстров | &7Остров успешно закрыт для публики.' ISLAND_CREATE_PROCESS_FAIL: '&c&lОшибка | &7У вас уже есть запущенная задача создания острова.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lОстров | &7Обработка вашего запроса...' +ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lПолёт | &7Полёт на острове автоматически &cвыключен&7.' ISLAND_FLY_ENABLED: '&e&lПолёт | &7Полёт на острове автоматически &aвключён&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lОстров | &7&oВы были внутри острова, который был расформирован, поэтому вы были телепортированы обратно в спаун...' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index e945c02009..8ecb0508a4 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -524,6 +524,7 @@ ISLAND_CLOSED: '&e&lAda | &7Ada başarıyla halka kapatıldı.' ISLAND_CREATE_PROCESS_FAIL: '&c&lHata | &7Zaten devam eden bir ada oluşturma görevin var.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lAda | &7İsteğiniz işleniyor...' +ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lUçuş | &7Ada uçuşu otomatik olarak &ckapatıldı&7.' ISLAND_FLY_ENABLED: '&e&lUçuş | &7Ada uçuşu otomatik olarak &aaçıldı&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lAda | &7&oDağıtılan bir adanın içindeydin, bu diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 7d2c7a9f26..76ac0fc754 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -492,6 +492,7 @@ ISLAND_BEING_CALCULATED: '&c&lLỗi | &7Bạn không thể tương tác với c ISLAND_CLOSED: '&e&lĐảo | &7Thành công đóng cửa đảo cho công cộng.' ISLAND_CREATE_PROCESS_FAIL: '&c&lLỗi | &7Bạn đã có một nhiệm vụ tạo đảo đang diễn ra.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&lĐảo | &7Đang xử lý yêu cầu của bạn...' +ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&lBay | &7Bay trong đảo đã tự động &cvô hiệu hóad&7.' ISLAND_FLY_ENABLED: '&e&lBay | &7Bay trong đảo đã tự động &akích hoạt&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&lĐảo | &7&oBạn đã ở trong một hòn đảo đã diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 58161461fc..aa2344b94a 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -438,6 +438,7 @@ ISLAND_BEING_CALCULATED: '&c&l错误 | &7正在进行计算, 不可以与方块 ISLAND_CLOSED: '&e&l岛屿 | &7成功将岛屿设置为不对公众开放.' ISLAND_CREATE_PROCESS_FAIL: '&c&l错误 | &7你已经有一个正在进行的岛屿创建进程了.' ISLAND_CREATE_PROCCESS_REQUEST: '&e&l岛屿 | &7正在处理你的请求...' +ISLAND_DESCRIPTION_NONE: None ISLAND_FLY_DISABLED: '&e&l飞行 | &7岛屿飞行已自动 &c关闭&7.' ISLAND_FLY_ENABLED: '&e&l飞行 | &7岛屿飞行已自动 &a打开&7.' ISLAND_GOT_DELETED_WHILE_INSIDE: '&e&l岛屿 | &7&o你正处于一个被解散的岛屿, 正在将你传送回主城...' From 886ed164586f635bd88fa546c11412577f03ac60 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 7 Feb 2026 21:46:49 +0200 Subject: [PATCH 499/600] Fixed the ability to interact with wooden redstone components using projectiles (#2854) --- .../listener/BukkitEventsListener.java | 9 +++++ .../listener/ProtectionListener.java | 34 ++++++++++++++----- .../platform/event/GameEventType.java | 2 ++ .../platform/event/args/GameEventArgs.java | 7 ++++ 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index 8d493f27d6..a9fb5c9a74 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -52,6 +52,7 @@ import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.entity.EntityInteractEvent; import org.bukkit.event.entity.EntityPortalEnterEvent; import org.bukkit.event.entity.EntityPortalEvent; import org.bukkit.event.entity.EntityTargetEvent; @@ -150,6 +151,7 @@ public BukkitEventsListener(SuperiorSkyblockPlugin plugin) { createEventListener(GameEventType.ENTITY_DAMAGE_EVENT, VehicleDamageEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_ENTER_PORTAL_EVENT, EntityPortalEnterEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_EXPLODE_EVENT, EntityExplodeEvent.class, this::createGameEvent); + createEventListener(GameEventType.ENTITY_INTERACT_EVENT, EntityInteractEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_MOVE_EVENT, PlayerMoveEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_MOVE_EVENT, VehicleMoveEvent.class, this::createGameEvent); createEventListener(GameEventType.ENTITY_PORTAL_EVENT, EntityPortalEvent.class, this::createGameEvent); @@ -475,6 +477,13 @@ private GameEvent createGameEvent(GameEventTyp return eventType.createEvent(entityExplodeEvent); } + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, EntityInteractEvent e) { + GameEventArgs.EntityInteractEvent entityExplodeEvent = new GameEventArgs.EntityInteractEvent(); + entityExplodeEvent.entity = e.getEntity(); + entityExplodeEvent.block = e.getBlock(); + return eventType.createEvent(entityExplodeEvent); + } + private GameEvent createGameEvent(GameEventType eventType, GameEventPriority priority, PlayerMoveEvent e) { Location from = e.getFrom(); Location to = e.getTo(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index eb8f7a4811..04a77d727d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -37,12 +37,14 @@ import org.bukkit.entity.Hanging; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; import org.bukkit.entity.Vehicle; import org.bukkit.event.block.Action; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.bukkit.projectiles.ProjectileSource; import org.bukkit.util.Vector; import java.util.Iterator; @@ -92,7 +94,23 @@ private void onPlayerInteract(GameEvent e) { if (handleBrushUse(e)) return; if (handleMinecartPlace(e)) return; if (handleEntityInteract(e)) return; - handleBlockInteract(e); + handleBlockInteract(e, e.getArgs().player, e.getArgs().action, e.getArgs().clickedBlock, e.getArgs().usedItem); + } + + private void onEntityInteractBlock(GameEvent e) { + Block clickedBlock = e.getArgs().block; + if (clickedBlock == null) + return; + + Entity entity = e.getArgs().entity; + if (!(entity instanceof Projectile)) + return; + + ProjectileSource projectileSource = ((Projectile) entity).getShooter(); + if (!(projectileSource instanceof Player)) + return; + + handleBlockInteract(e, (Player) projectileSource, Action.PHYSICAL, clickedBlock, null); } private boolean handleBlockFertilize(GameEvent e) { @@ -218,15 +236,14 @@ private boolean handleEntityInteract(GameEvent e) { - if (e.getArgs().clickedBlock == null) + private void handleBlockInteract(GameEvent e, Player player, Action action, + @Nullable Block clickedBlock, @Nullable ItemStack usedItem) { + if (clickedBlock == null) return; - ItemStack usedItem = e.getArgs().usedItem; - - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); - InteractionResult interactionResult = this.protectionManager.get().handleBlockInteract(superiorPlayer, - e.getArgs().clickedBlock, e.getArgs().action, usedItem); + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); + InteractionResult interactionResult = this.protectionManager.get().handleBlockInteract( + superiorPlayer, clickedBlock, action, usedItem); if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) e.setCancelled(); } @@ -588,6 +605,7 @@ private void onRaidTrigger(GameEvent e) { private void registerListeners() { registerCallback(GameEventType.BLOCK_PLACE_EVENT, GameEventPriority.NORMAL, this::onBlockPlace); registerCallback(GameEventType.PLAYER_INTERACT_EVENT, GameEventPriority.NORMAL, this::onPlayerInteract); + registerCallback(GameEventType.ENTITY_INTERACT_EVENT, GameEventPriority.NORMAL, this::onEntityInteractBlock); registerCallback(GameEventType.BLOCK_BREAK_EVENT, GameEventPriority.NORMAL, this::onBlockBreak); registerCallback(GameEventType.ENTITY_BLOCK_FORM_EVENT, GameEventPriority.NORMAL, this::onFrostWalker); registerCallback(GameEventType.PLAYER_EMPTY_BUCKET_EVENT, GameEventPriority.NORMAL, this::onBucketEmpty); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java index cd23989a72..51d2c6b079 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/GameEventType.java @@ -30,6 +30,7 @@ import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityDeathEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityEnterPortalEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityExplodeEvent; +import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityInteractEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityMoveEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityPortalEvent; import static com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs.EntityRideEvent; @@ -111,6 +112,7 @@ public class GameEventType extends EventType ENTITY_DEATH_EVENT = register(EntityDeathEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_ENTER_PORTAL_EVENT = register(EntityEnterPortalEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_EXPLODE_EVENT = register(EntityExplodeEvent.class, GameEventFlags.BLOCK_EVENT | GameEventFlags.ENTITY_EVENT); + public static final GameEventType ENTITY_INTERACT_EVENT = register(EntityInteractEvent.class, GameEventFlags.ENTITY_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); public static final GameEventType ENTITY_MOVE_EVENT = register(EntityMoveEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_PORTAL_EVENT = register(EntityPortalEvent.class, GameEventFlags.ENTITY_EVENT); public static final GameEventType ENTITY_RIDE_EVENT = register(EntityRideEvent.class, GameEventFlags.ENTITY_EVENT); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java index 980744a378..00588af56e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/platform/event/args/GameEventArgs.java @@ -398,6 +398,13 @@ public static class GenericGameEvent extends WorldEvent { } + public static class EntityInteractEvent extends EntityEvent { + + @Nullable + public Block block; + + } + private static class BlockEvent extends GameEventArgs { public Block block; From d0e2724e5eea6c6f0709f13242952e9914b0bc76 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 7 Feb 2026 20:48:05 +0100 Subject: [PATCH 500/600] Removed [logs] argument from the /is bank command, when logs are disabled (#2853) --- .../module/bank/commands/CmdBank.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdBank.java b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdBank.java index 6c87734fed..f4500a5dd4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdBank.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/bank/commands/CmdBank.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.commands.arguments.IslandArgument; import com.bgsoftware.superiorskyblock.core.menu.view.MenuViewWrapper; import com.bgsoftware.superiorskyblock.core.messages.Message; +import com.bgsoftware.superiorskyblock.module.BuiltinModules; import org.bukkit.command.CommandSender; import java.util.Collections; @@ -28,7 +29,10 @@ public String getPermission() { @Override public String getUsage(java.util.Locale locale) { - return "bank [logs]"; + if (BuiltinModules.BANK.getConfiguration().isBankLogs()) + return "bank [logs]"; + else + return "bank"; } @Override @@ -43,7 +47,7 @@ public int getMinArgs() { @Override public int getMaxArgs() { - return 2; + return BuiltinModules.BANK.getConfiguration().isBankLogs() ? 2 : 1; } @Override @@ -62,7 +66,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ SuperiorPlayer superiorPlayer = arguments.getSuperiorPlayer(); - if (args.length == 2 && args[1].equalsIgnoreCase("logs")) { + if (args.length == 2 && args[1].equalsIgnoreCase("logs") && + BuiltinModules.BANK.getConfiguration().isBankLogs()) { plugin.getMenus().openBankLogs(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); } else { plugin.getMenus().openIslandBank(superiorPlayer, MenuViewWrapper.fromView(superiorPlayer.getOpenedView()), island); @@ -71,7 +76,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ @Override public List tabComplete(SuperiorSkyblockPlugin plugin, CommandSender sender, String[] args) { - return args.length != 2 ? Collections.emptyList() : CommandTabCompletes.getCustomComplete(args[1], "logs"); + return args.length != 2 || !BuiltinModules.BANK.getConfiguration().isBankLogs() + ? Collections.emptyList() : CommandTabCompletes.getCustomComplete(args[1], "logs"); } } From 6df5c1e99d3bfa6c4d247fd33a4090288bcfecdd Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sun, 8 Feb 2026 21:34:52 +0100 Subject: [PATCH 501/600] Added the ability to disable coop limit and warp limit (#2855) --- .../superiorskyblock/commands/player/CmdAccept.java | 3 ++- .../superiorskyblock/commands/player/CmdCoop.java | 3 ++- .../superiorskyblock/commands/player/CmdInvite.java | 3 ++- .../superiorskyblock/commands/player/CmdSetWarp.java | 3 ++- .../superiorskyblock/island/bank/SIslandBank.java | 6 ++++-- .../superiorskyblock/island/signs/IslandSigns.java | 6 ++++-- 6 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java index 73cf1dd778..56bd53567a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java @@ -82,7 +82,8 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ return; } - if (island.getTeamLimit() >= 0 && island.getIslandMembers(true).size() >= island.getTeamLimit()) { + int teamLimit = island.getTeamLimit(); + if (teamLimit >= 0 && island.getIslandMembers(true).size() >= teamLimit) { Message.JOIN_FULL_ISLAND.send(superiorPlayer); island.revokeInvite(superiorPlayer); return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCoop.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCoop.java index 19fd345ab3..e254b655dc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCoop.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdCoop.java @@ -90,7 +90,8 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer return; } - if (island.getCoopPlayers().size() >= island.getCoopLimit()) { + int coopLimit = island.getCoopLimit(); + if (coopLimit >= 0 && island.getCoopPlayers().size() >= coopLimit) { Message.COOP_LIMIT_EXCEED.send(superiorPlayer); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdInvite.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdInvite.java index fd88298e18..3fe1ddabb3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdInvite.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdInvite.java @@ -87,7 +87,8 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer announcementMessage = Message.REVOKE_INVITE_ANNOUNCEMENT; Message.GOT_REVOKED.send(targetPlayer, superiorPlayer.getName()); } else { - if (island.getTeamLimit() >= 0 && island.getIslandMembers(true).size() >= island.getTeamLimit()) { + int teamLimit = island.getTeamLimit(); + if (teamLimit >= 0 && island.getIslandMembers(true).size() >= teamLimit) { Message.INVITE_TO_FULL_ISLAND.send(superiorPlayer); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java index 2e16a8ce52..656b956d8d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdSetWarp.java @@ -75,7 +75,8 @@ public Message getPermissionLackMessage() { @Override public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer, Island island, String[] args) { - if (island.getIslandWarps().size() >= island.getWarpsLimit()) { + int warpsLimit = island.getWarpsLimit(); + if (warpsLimit >= 0 && island.getIslandWarps().size() >= warpsLimit) { Message.NO_MORE_WARPS.send(superiorPlayer); return; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java index e16a9d4135..d305745ece 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java @@ -165,8 +165,10 @@ public BankTransaction depositAdminMoney(CommandSender commandSender, BigDecimal @Override public boolean canDepositMoney(BigDecimal amount) { Preconditions.checkNotNull(amount, "amount parameter cannot be null."); - return this.island.getBankLimit().compareTo(NO_BANK_LIMIT) <= 0 || - this.balance.get().add(amount).compareTo(this.island.getBankLimit()) <= 0; + + BigDecimal bankLimit = this.island.getBankLimit(); + return bankLimit.compareTo(NO_BANK_LIMIT) <= 0 || + this.balance.get().add(amount).compareTo(bankLimit) <= 0; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java b/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java index 78019a96c5..b79a959460 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/signs/IslandSigns.java @@ -86,7 +86,8 @@ public static Result handleSignBreak(@Nullable Island island, @Nullable Superior private static Reason handleWarpSignPlace(SuperiorPlayer superiorPlayer, Island island, Location warpLocation, String[] signLines, boolean sendMessage) { - if (island.getIslandWarps().size() >= island.getWarpsLimit()) { + int warpsLimit = island.getWarpsLimit(); + if (warpsLimit >= 0 && island.getIslandWarps().size() >= warpsLimit) { if (sendMessage) Message.NO_MORE_WARPS.send(superiorPlayer); @@ -133,7 +134,8 @@ private static Reason handleWarpSignPlace(SuperiorPlayer superiorPlayer, Island private static Result handleVisitorsSignPlace(SuperiorPlayer superiorPlayer, Island island, Location visitorsLocation, String[] warpLines, boolean sendMessage) { - if (island.getIslandWarps().size() >= island.getWarpsLimit()) { + int warpsLimit = island.getWarpsLimit(); + if (warpsLimit >= 0 && island.getIslandWarps().size() >= warpsLimit) { if (sendMessage) Message.NO_MORE_WARPS.send(superiorPlayer); From 1c6a3eacdafcfabdfed90a91a93d77d345ff3c5e Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Mon, 9 Feb 2026 21:59:59 +0100 Subject: [PATCH 502/600] Added the ability to toggle when a player should receive help (#2857) --- .../api/config/SettingsManager.java | 14 +++++++ .../commands/CommandsManagerImpl.java | 40 +++++++++---------- .../commands/player/CmdAdmin.java | 20 ++++++++-- .../config/SettingsContainer.java | 4 ++ .../config/SettingsManagerImpl.java | 10 +++++ .../config/section/GlobalSection.java | 8 ++++ .../core/messages/Message.java | 1 + src/main/resources/config.yml | 8 ++++ src/main/resources/lang/de-DE.yml | 1 + src/main/resources/lang/en-US.yml | 1 + src/main/resources/lang/es-ES.yml | 1 + src/main/resources/lang/fr-FR.yml | 1 + src/main/resources/lang/it-IT.yml | 1 + src/main/resources/lang/iw-IL.yml | 1 + src/main/resources/lang/pl-PL.yml | 1 + src/main/resources/lang/pt-BR.yml | 1 + src/main/resources/lang/ru-RU.yml | 1 + src/main/resources/lang/tr-TR.yml | 1 + src/main/resources/lang/vi-VN.yml | 1 + src/main/resources/lang/zh-CN.yml | 1 + 20 files changed, 93 insertions(+), 24 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 80dbd5ff32..542645076a 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -749,6 +749,20 @@ public interface SettingsManager { */ int getCommandsPerPage(); + /** + * Whether players should receive a help instead of a `INVALID_COMMAND` message + * when using a command that doesn't exist or not. + * Config-path: help-on-invalid-command + */ + boolean isHelpOnInvalidCommand(); + + /** + * Whether players should receive a help instead of a `NO_COMMAND_PERMISSION` message + * when using a command they don't have permission for or not. + * Config-path: help-on-no-permission + */ + boolean isHelpOnNoPermission(); + /** * Whether the plugin should cache schematics for faster placement of schematics. * Config-path: cache-schematics diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java index d840409cfb..3cc0a23469 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/CommandsManagerImpl.java @@ -4,7 +4,6 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.commands.SuperiorCommand; import com.bgsoftware.superiorskyblock.api.handlers.CommandsManager; -import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Manager; @@ -247,7 +246,7 @@ private class PluginCommand extends BukkitCommand { public boolean execute(CommandSender sender, String label, String[] args) { java.util.Locale locale = PlayerLocales.getLocale(sender); - String executedSubCommand = null; + String executedSubCommand; if (args.length > 0) { executedSubCommand = args[0]; @@ -263,7 +262,12 @@ public boolean execute(CommandSender sender, String label, String[] args) { if (!CommandsHelper.hasCommandAccess(command, sender)) { Log.debugResult(Debug.EXECUTE_COMMAND, "Return Missing Permission", command.getPermission()); - Message.NO_COMMAND_PERMISSION.send(sender, locale, command.getPermission()); + + if (!plugin.getSettings().isHelpOnNoPermission()) + Message.NO_COMMAND_PERMISSION.send(sender, locale, command.getPermission()); + else if (!"help".equalsIgnoreCase(executedSubCommand)) + dispatchSubCommand(sender, "help"); + return false; } @@ -305,39 +309,33 @@ public boolean execute(CommandSender sender, String label, String[] args) { command.execute(plugin, sender, args); return false; } + + if (!plugin.getSettings().isHelpOnInvalidCommand()) + Message.INVALID_COMMAND.send(sender, locale, executedSubCommand); + else if (!"help".equalsIgnoreCase(executedSubCommand)) + dispatchSubCommand(sender, "help"); + + return false; } if (sender instanceof Player) { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); if (superiorPlayer != null) { - Island island = superiorPlayer.getIsland(); - String subCommandToExecute; - if (args.length != 0) { - subCommandToExecute = "help"; - } else if (island == null) { + + if (!superiorPlayer.hasIsland()) subCommandToExecute = "create"; - } else if (superiorPlayer.hasToggledPanel()) { + else if (superiorPlayer.hasToggledPanel()) subCommandToExecute = "panel"; - } else { + else subCommandToExecute = "tp"; - } - - // We don't want to end up in an infinite loop - if (!subCommandToExecute.equalsIgnoreCase(executedSubCommand)) { - dispatchSubCommand(sender, subCommandToExecute); - } + dispatchSubCommand(sender, subCommandToExecute); return false; } } - // We don't want to end up in an infinite loop - if (!"help".equalsIgnoreCase(executedSubCommand)) { - dispatchSubCommand(sender, "help"); - } - return false; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java index 095c05d737..9e34034eef 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java @@ -74,9 +74,11 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ java.util.Locale locale = PlayerLocales.getLocale(sender); if (args.length > 1 && !isNumber(args[1])) { - Log.debug(Debug.EXECUTE_COMMAND, sender.getName(), args[1]); + String executedSubCommand = args[1]; - SuperiorCommand command = plugin.getCommands().getAdminCommand(args[1]); + Log.debug(Debug.EXECUTE_COMMAND, sender.getName(), executedSubCommand); + + SuperiorCommand command = plugin.getCommands().getAdminCommand(executedSubCommand); if (command != null) { if (!(sender instanceof Player) && !command.canBeExecutedByConsole()) { Message.CUSTOM.send(sender, "&cCan be executed only by players!", true); @@ -85,7 +87,12 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ if (!CommandsHelper.hasCommandAccess(command, sender)) { Log.debugResult(Debug.EXECUTE_COMMAND, "Return Missing Permission", command.getPermission()); - Message.NO_COMMAND_PERMISSION.send(sender, locale, command.getPermission()); + + if (!plugin.getSettings().isHelpOnNoPermission()) + Message.NO_COMMAND_PERMISSION.send(sender, locale, command.getPermission()); + else + plugin.getCommands().dispatchSubCommand(sender, "admin"); + return; } @@ -98,6 +105,13 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ command.execute(plugin, sender, args); return; } + + if (!plugin.getSettings().isHelpOnInvalidCommand()) + Message.INVALID_COMMAND.send(sender, locale, executedSubCommand); + else + plugin.getCommands().dispatchSubCommand(sender, "admin"); + + return; } int page = 1; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index b775735630..5a0981f1fe 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -237,6 +237,8 @@ public class SettingsContainer { public final BigInteger blockCountsSaveThreshold; public final boolean chatSigningSupport; public final int commandsPerPage; + public final boolean helpOnNoPermission; + public final boolean helpOnInvalidCommand; public final boolean cacheSchematics; public final Map entityCategories; @@ -617,6 +619,8 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config blockCountsSaveThreshold = BigInteger.valueOf(config.getInt("block-counts-save-threshold", 100)); chatSigningSupport = config.getBoolean("chat-signing-support", true); commandsPerPage = config.getInt("commands-per-page", 7); + helpOnInvalidCommand = config.getBoolean("help-on-invalid-command", true); + helpOnNoPermission = config.getBoolean("help-on-no-permission", false); cacheSchematics = config.getBoolean("cache-schematics", true); entityCategories = parseEntityCategories(config.getConfigurationSection("entity-categories")); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index 5daaf7a9f3..c6c6e0a535 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -672,6 +672,16 @@ public int getCommandsPerPage() { return this.global.getCommandsPerPage(); } + @Override + public boolean isHelpOnInvalidCommand() { + return this.global.isHelpOnInvalidCommand(); + } + + @Override + public boolean isHelpOnNoPermission() { + return this.global.isHelpOnNoPermission(); + } + @Override public boolean isCacheSchematics() { return this.global.isCacheSchematics(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index c25c4c6ce5..7ebf7d0abc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -415,6 +415,14 @@ public int getCommandsPerPage() { return getContainer().commandsPerPage; } + public boolean isHelpOnInvalidCommand() { + return getContainer().helpOnInvalidCommand; + } + + public boolean isHelpOnNoPermission() { + return getContainer().helpOnNoPermission; + } + public boolean isCacheSchematics() { return getContainer().cacheSchematics; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java index 591a9a0070..8a8b496875 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/Message.java @@ -433,6 +433,7 @@ public void send(CommandSender sender, Locale locale, Object... args) { INVALID_BIOME, INVALID_BLOCK, INVALID_BORDER_COLOR, + INVALID_COMMAND, INVALID_EFFECT, INVALID_ENTITY, INVALID_ENVIRONMENT, diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index b44ba83010..84e6e140c4 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -943,6 +943,14 @@ chat-signing-support: true # Setting this to 0 or below will result all commands to be shown in a single page. commands-per-page: 7 +# Should players receive a help instead of an `INVALID_COMMAND` message +# when using a command that doesn't exist? +help-on-invalid-command: true + +# Should players receive a help instead of a `NO_COMMAND_PERMISSION` message +# when using a command they don't have permission for? +help-on-no-permission: false + # Configure custom entity categories. # By default, there are two entity categories - ANIMALS and MONSTER # You can add your own custom categories in here, and configure which entities are part of the category. diff --git a/src/main/resources/lang/de-DE.yml b/src/main/resources/lang/de-DE.yml index 0a4b86c345..3e4f526758 100644 --- a/src/main/resources/lang/de-DE.yml +++ b/src/main/resources/lang/de-DE.yml @@ -489,6 +489,7 @@ INVALID_AMOUNT: '&c&lError | &7Ungültiger Betrag {0}.' INVALID_BIOME: '&c&lError | &7Ungültiges Biom {0}.' INVALID_BLOCK: '&c&lError | &7Ungültige Blockposition {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' +INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lError | &7Ungültige Wirkung {0}.' INVALID_ENTITY: '&c&lError | &7Ungültige Entität {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' diff --git a/src/main/resources/lang/en-US.yml b/src/main/resources/lang/en-US.yml index 66bf601eab..968fe4c632 100644 --- a/src/main/resources/lang/en-US.yml +++ b/src/main/resources/lang/en-US.yml @@ -379,6 +379,7 @@ INVALID_AMOUNT: '&c&lError | &7Invalid amount {0}.' INVALID_BIOME: '&c&lError | &7Invalid biome {0}.' INVALID_BLOCK: '&c&lError | &7Invalid block location {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' +INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lError | &7Invalid effect {0}.' INVALID_ENTITY: '&c&lError | &7Invalid entity {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' diff --git a/src/main/resources/lang/es-ES.yml b/src/main/resources/lang/es-ES.yml index eb688f9091..e27c09e593 100644 --- a/src/main/resources/lang/es-ES.yml +++ b/src/main/resources/lang/es-ES.yml @@ -379,6 +379,7 @@ INVALID_AMOUNT: '&c&lError | &7Cantidad no válida {0}.' INVALID_BIOME: '&c&lError | &7Bioma no válido {0}.' INVALID_BLOCK: '&c&lError | &7Ubicación de bloque no válida {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' +INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lError | &7Efecto no válido {0}.' INVALID_ENTITY: '&c&lError | &7Entidad no válida {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' diff --git a/src/main/resources/lang/fr-FR.yml b/src/main/resources/lang/fr-FR.yml index 720fc048f0..3eafe9d8ca 100644 --- a/src/main/resources/lang/fr-FR.yml +++ b/src/main/resources/lang/fr-FR.yml @@ -379,6 +379,7 @@ INVALID_AMOUNT: '&c&lErreur | &7Nombre invalide {0}.' INVALID_BIOME: '&c&lErreur | &7Biome invalide {0}.' INVALID_BLOCK: '&c&lErreur | &7Emplacement {0} du bloc invalide.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' +INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lErreur | &7Effet invalide {0}.' INVALID_ENTITY: '&c&lErreur | &7Entité invalide {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' diff --git a/src/main/resources/lang/it-IT.yml b/src/main/resources/lang/it-IT.yml index 48a2afee7d..2c0c2204cb 100644 --- a/src/main/resources/lang/it-IT.yml +++ b/src/main/resources/lang/it-IT.yml @@ -383,6 +383,7 @@ INVALID_AMOUNT: '&c&lErrore | &7Importo invalido {0}.' INVALID_BIOME: '&c&lErrore | &7Bioma invalido {0}.' INVALID_BLOCK: '&c&lErrore| &7Posizione del blocco invalida {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Colore del bordo non valido: {0}' +INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lErrore| &7Effetto invalido {0}.' INVALID_ENTITY: '&c&lErrore | &7Entità invalida {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' diff --git a/src/main/resources/lang/iw-IL.yml b/src/main/resources/lang/iw-IL.yml index f7fc4d9bc7..20c9aa263c 100644 --- a/src/main/resources/lang/iw-IL.yml +++ b/src/main/resources/lang/iw-IL.yml @@ -395,6 +395,7 @@ INVALID_AMOUNT: '&c&lהאיגש | &7{0} תיקוח אל תומכ.' INVALID_BIOME: '&c&lError | &7Invalid biome {0}.' INVALID_BLOCK: '&c&lError | &7Invalid block location {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' +INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lError | &7Invalid effect {0}.' INVALID_ENTITY: '&c&lError | &7Invalid entity {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' diff --git a/src/main/resources/lang/pl-PL.yml b/src/main/resources/lang/pl-PL.yml index 2ed0ff5bdb..f495e3a47e 100644 --- a/src/main/resources/lang/pl-PL.yml +++ b/src/main/resources/lang/pl-PL.yml @@ -379,6 +379,7 @@ INVALID_AMOUNT: '&c&lBlad | &7Nieprawidlowa kwota {0}.' INVALID_BIOME: '&c&lBlad | &7Nieprawidlowy biom {0}.' INVALID_BLOCK: '&c&lBlad | &7Nieprawidlowa lokalizacja bloku {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' +INVALID_COMMAND: '&c&lBlad | &7Nieprawidlowa komenda {0}.' INVALID_EFFECT: '&c&lBlad | &7Nieprawidlowy efekt {0}.' INVALID_ENTITY: '&c&lBlad | &7Nieprawidlowa jednostka {0}.' INVALID_ENVIRONMENT: '&c&lBlad | &7Nieprawidlowy wymiar {0}.' diff --git a/src/main/resources/lang/pt-BR.yml b/src/main/resources/lang/pt-BR.yml index 3a1c9ca8b9..84ae4c1fef 100644 --- a/src/main/resources/lang/pt-BR.yml +++ b/src/main/resources/lang/pt-BR.yml @@ -379,6 +379,7 @@ INVALID_AMOUNT: '&c&lErro | &7Valor inválido {0}.' INVALID_BIOME: '&c&lErro | &7Bioma inválido {0}.' INVALID_BLOCK: '&c&lErro | &7Localização de bloco inválida {0}.' INVALID_BORDER_COLOR: '&c&lErro | &7Cor da borda inválida {0}.' +INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lErro | &7Efeito inválido {0}.' INVALID_ENTITY: '&c&lErro | &7Entidade inválida {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' diff --git a/src/main/resources/lang/ru-RU.yml b/src/main/resources/lang/ru-RU.yml index f430b76ae5..7edb4d97d7 100644 --- a/src/main/resources/lang/ru-RU.yml +++ b/src/main/resources/lang/ru-RU.yml @@ -379,6 +379,7 @@ INVALID_AMOUNT: '&c&lОшибка | &7Недопустимая сумма {0}.' INVALID_BIOME: '&c&lОшибка | &7Недопустимый биом {0}.' INVALID_BLOCK: '&c&lОшибка | &7Недопустимое местоположение блока {0}.' INVALID_BORDER_COLOR: '&c&lОшибка | &7Недопустимый цвет границы {0}.' +INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lОшибка | &7Недопустимый эффект {0}.' INVALID_ENTITY: '&c&lОшибка | &7Недопустимое существо {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' diff --git a/src/main/resources/lang/tr-TR.yml b/src/main/resources/lang/tr-TR.yml index 8ecb0508a4..2ffa286f3d 100644 --- a/src/main/resources/lang/tr-TR.yml +++ b/src/main/resources/lang/tr-TR.yml @@ -463,6 +463,7 @@ INVALID_AMOUNT: '&c&lHata | &7Geçersiz miktar {0}.' INVALID_BIOME: '&c&lHata | &7Geçersiz biyom {0}.' INVALID_BLOCK: '&c&lHata | &7Geçersiz blok konumu {0}.' INVALID_BORDER_COLOR: '&c&lHata | &7Geçersiz sınır rengi {0}.' +INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lHata | &7Geçersiz efekt {0}.' INVALID_ENTITY: '&c&lHata | &7Geçersiz varlık {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' diff --git a/src/main/resources/lang/vi-VN.yml b/src/main/resources/lang/vi-VN.yml index 76ac0fc754..0cac096240 100644 --- a/src/main/resources/lang/vi-VN.yml +++ b/src/main/resources/lang/vi-VN.yml @@ -431,6 +431,7 @@ INVALID_AMOUNT: '&c&lLỗi | &7Số lượng không hợp lệ {0}.' INVALID_BIOME: '&c&lLỗi | &7Quần xã không chính xác {0}.' INVALID_BLOCK: '&c&lLỗi | &7Vị trí khối không hợp lệ {0}.' INVALID_BORDER_COLOR: '&c&lError | &7Invalid border color {0}.' +INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&lLỗi | &7Hiệu ứng không hợp lệ {0}.' INVALID_ENTITY: '&c&lLỗi | &7Vật thể không chính xác {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index aa2344b94a..6470f2d633 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -379,6 +379,7 @@ INVALID_AMOUNT: '&c&l错误 | &7无效数量 {0}.' INVALID_BIOME: '&c&l错误 | &7无效生物群系 {0}.' INVALID_BLOCK: '&c&l错误 | &7无效方块位置 {0}.' INVALID_BORDER_COLOR: '&c&l错误 | &7无效边界颜色 {0}.' +INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' INVALID_EFFECT: '&c&l错误 | &7无效效果 {0}.' INVALID_ENTITY: '&c&l错误 | &7无效实体 {0}.' INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' From 9d0ed68726771558c3972327d6273bed1d0d35ac Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 9 Feb 2026 23:11:09 +0200 Subject: [PATCH 503/600] Delete the projectile when it interacts with a block and it is not allowed --- .../listener/ProtectionListener.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 04a77d727d..4055cfad7a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -110,7 +110,10 @@ private void onEntityInteractBlock(GameEvent if (!(projectileSource instanceof Player)) return; - handleBlockInteract(e, (Player) projectileSource, Action.PHYSICAL, clickedBlock, null); + if (handleBlockInteract(e, (Player) projectileSource, Action.PHYSICAL, clickedBlock, null)) { + // We want to remove the projectile as well when it is not possible to interact + entity.remove(); + } } private boolean handleBlockFertilize(GameEvent e) { @@ -236,16 +239,20 @@ private boolean handleEntityInteract(GameEvent e, Player player, Action action, - @Nullable Block clickedBlock, @Nullable ItemStack usedItem) { + private boolean handleBlockInteract(GameEvent e, Player player, Action action, + @Nullable Block clickedBlock, @Nullable ItemStack usedItem) { if (clickedBlock == null) - return; + return false; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); InteractionResult interactionResult = this.protectionManager.get().handleBlockInteract( superiorPlayer, clickedBlock, action, usedItem); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { e.setCancelled(); + return true; + } + + return false; } private void onBlockBreak(GameEvent e) { From 93bd5eb453fe5930d40cd2d7a4e1875147684218 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 9 Feb 2026 23:16:28 +0200 Subject: [PATCH 504/600] Fixed the ability to shoot target blocks on other islands (#2854) --- .../superiorskyblock/listener/ProtectionListener.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 4055cfad7a..9028eb5532 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -65,6 +65,8 @@ public class ProtectionListener extends AbstractGameEventListener { private static final EntityType TRIDENT = EnumHelper.getEnum(EntityType.class, "TRIDENT"); @Nullable private static final Material DECORATED_POT = EnumHelper.getEnum(Material.class, "DECORATED_POT"); + @Nullable + private static final Material TARGET = EnumHelper.getEnum(Material.class, "TARGET"); private final LazyReference protectionManager = new LazyReference() { @Override @@ -537,11 +539,12 @@ private void onProjectileHit(GameEvent e) { hitBlock = null; } else { hitBlock = e.getArgs().hitBlock; - if (hitBlock == null || (hitBlock.getType() != CHORUS_FLOWER && hitBlock.getType() != DECORATED_POT)) + Material hitBlockType = hitBlock == null ? null : hitBlock.getType(); + if (hitBlockType != CHORUS_FLOWER && hitBlockType != DECORATED_POT && hitBlockType != TARGET) return; location = hitBlock.getLocation(wrapper.getHandle()); - islandPrivilege = IslandPrivileges.BREAK; + islandPrivilege = hitBlockType == TARGET ? IslandPrivileges.INTERACT : IslandPrivileges.BREAK; } if (islandPrivilege == null) From 7ceaa8b235c9ac36dcf423b3994c7bee03131b68 Mon Sep 17 00:00:00 2001 From: Katorly <70022443+katorly@users.noreply.github.com> Date: Sat, 21 Feb 2026 21:27:03 +0800 Subject: [PATCH 505/600] chore(i8n): update zh-CN translation (#2866) --- src/main/resources/lang/zh-CN.yml | 119 +++++++++++++++--------------- 1 file changed, 61 insertions(+), 58 deletions(-) diff --git a/src/main/resources/lang/zh-CN.yml b/src/main/resources/lang/zh-CN.yml index 6470f2d633..bc8c51ac95 100644 --- a/src/main/resources/lang/zh-CN.yml +++ b/src/main/resources/lang/zh-CN.yml @@ -60,12 +60,12 @@ CHANGED_BLOCK_AMOUNT: '&e&lBlocks | &7成功将 {0} 的方块数量设置为了 CHANGED_BLOCK_LIMIT: '&e&l升级 | &7成功更新了岛屿 {1} 的方块 {0} 限制.' CHANGED_BLOCK_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的方块 {0} 限制.' CHANGED_BLOCK_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的方块 {0} 限制.' -CHANGED_BONUS_LEVEL: '&e&lIsland | &7Successfully updated the level bonus of {0}''s island.' -CHANGED_BONUS_LEVEL_ALL: '&e&lIsland | &7Successfully updated the level bonus of all the islands.' -CHANGED_BONUS_LEVEL_NAME: '&e&lIsland | &7Successfully updated the level bonus of {0}.' -CHANGED_BONUS_WORTH: '&e&lIsland | &7Successfully updated the worth bonus of {0}''s island.' -CHANGED_BONUS_WORTH_ALL: '&e&lIsland | &7Successfully updated the worth bonus of all the islands.' -CHANGED_BONUS_WORTH_NAME: '&e&lIsland | &7Successfully updated the worth bonus of {0}.' +CHANGED_BONUS_LEVEL: '&e&l岛屿 | &7成功更新了玩家 {0} 的岛屿等级奖励.' +CHANGED_BONUS_LEVEL_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的等级奖励.' +CHANGED_BONUS_LEVEL_NAME: '&e&l岛屿 | &7成功更新了岛屿 {0} 的等级奖励.' +CHANGED_BONUS_WORTH: '&e&l岛屿 | &7成功更新了玩家 {0} 的岛屿价值奖励.' +CHANGED_BONUS_WORTH_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的价值奖励.' +CHANGED_BONUS_WORTH_NAME: '&e&l岛屿 | &7成功更新了岛屿 {0} 的价值奖励.' CHANGED_CHEST_SIZE: '&e&lChest | &7成功将玩家 {2} 的岛屿仓库 #{0} 的行数更新为了 {1}.' CHANGED_CHEST_SIZE_ALL: '&e&lChest | &7成功将所有岛屿的岛屿仓库 #{0} 的行数更新为了 {1}.' CHANGED_CHEST_SIZE_NAME: '&e&lChest | &7成功将岛屿 {2} 的岛屿仓库 #{0} 的行数更新为了 {1}.' @@ -84,7 +84,7 @@ CHANGED_ISLAND_EFFECT_LEVEL_ALL: '&e&l升级 | &7成功将所有岛屿的效果 CHANGED_ISLAND_EFFECT_LEVEL_NAME: '&e&l升级 | &7成功将岛屿 {1} 的效果等级修改为了 {0}.' CHANGED_ISLAND_SIZE: '&e&l升级 | &7成功修改了玩家 {0} 的岛屿边界大小.' CHANGED_ISLAND_SIZE_ALL: '&e&l升级 | &7成功更新了所有岛屿的边界大小.' -CHANGED_ISLAND_SIZE_NAME: '&e&l升级 | &成功更新了岛屿 {0} 的边界大小.' +CHANGED_ISLAND_SIZE_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的边界大小.' CHANGED_ISLAND_SIZE_BUILD_OUTSIDE: '&7&o玩家可以在他们岛屿的外部进行建筑行为, 所以岛屿大小限制功能无效. 可以在配置文本对这些设置进行调整以使其再次有效.' CHANGED_LANGUAGE: '&e&l语言 | &7成功将你的语言修改为了简体中文.' CHANGED_MOB_DROPS: '&e&l升级 | &7成功更新了玩家 {0} 的岛屿掉落物翻倍量.' @@ -99,7 +99,7 @@ CHANGED_ROLE_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的角色 {0} CHANGED_ROLE_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的角色 {0} 限制.' CHANGED_SPAWNER_RATES: '&e&l升级 | &7成功更新了玩家 {0} 岛屿的刷怪翻倍量.' CHANGED_SPAWNER_RATES_ALL: '&e&l升级 | &7成功更新了所有岛屿的刷怪翻倍量.' -CHANGED_SPAWNER_RATES_NAME: '&e&l升级 | &7S成功更新了岛屿 {0} 的刷怪翻倍量.' +CHANGED_SPAWNER_RATES_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的刷怪翻倍量.' CHANGED_TEAM_LIMIT: '&e&l升级 | &7成功更新了玩家 {0} 岛屿的团队限制.' CHANGED_TEAM_LIMIT_ALL: '&e&l升级 | &7成功更新了所有岛屿的团队限制.' CHANGED_TEAM_LIMIT_NAME: '&e&l升级 | &7成功更新了岛屿 {0} 的团队限制.' @@ -115,11 +115,11 @@ COMMAND_ARGUMENT_AMOUNT: '数量' COMMAND_ARGUMENT_BIOME: '群系' COMMAND_ARGUMENT_BORDER_COLOR: '边界颜色' COMMAND_ARGUMENT_COMMAND: '命令...' -COMMAND_ARGUMENT_DIMENSION: 'dimension' +COMMAND_ARGUMENT_DIMENSION: '维度' COMMAND_ARGUMENT_DISCORD: 'discord...' COMMAND_ARGUMENT_EFFECT: '药水效果' COMMAND_ARGUMENT_EMAIL: '邮箱' -COMMAND_ARGUMENT_ENTITY: '实体y' +COMMAND_ARGUMENT_ENTITY: '实体' COMMAND_ARGUMENT_ISLAND_NAME: '岛屿名称' COMMAND_ARGUMENT_ISLAND_ROLE: '岛屿角色' COMMAND_ARGUMENT_LEADER: '领袖' @@ -128,7 +128,7 @@ COMMAND_ARGUMENT_LIMIT: '限制' COMMAND_ARGUMENT_MATERIAL: '材料' COMMAND_ARGUMENT_MENU: '菜单名称' COMMAND_ARGUMENT_MESSAGE: '消息...' -COMMAND_ARGUMENT_MISSION_CATEGORY: 'mission-category' +COMMAND_ARGUMENT_MISSION_CATEGORY: '任务分类' COMMAND_ARGUMENT_MISSION_NAME: '任务名称' COMMAND_ARGUMENT_MODULE_NAME: '模块名称' COMMAND_ARGUMENT_MULTIPLIER: '翻倍卡' @@ -158,7 +158,7 @@ COMMAND_COOLDOWN_FORMAT: '&c&l错误 | &7你只能在 {0} 中使用该命令.' COMMAND_DESCRIPTION_ACCEPT: '接受玩家的邀请.' COMMAND_DESCRIPTION_ADMIN: '使用管理员命令.' COMMAND_DESCRIPTION_ADMIN_ADD: '将玩家添加至岛屿.' -COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: 'Increase the bank limit for another player''s island.' +COMMAND_DESCRIPTION_ADMIN_ADD_BANK_LIMIT: '为指定玩家的岛屿增加银行存款上限.' COMMAND_DESCRIPTION_ADMIN_ADD_BLOCK_LIMIT: '为指定玩家的岛屿增加方块数量上限.' COMMAND_DESCRIPTION_ADMIN_ADD_BONUS: '向指定玩家添加奖励.' COMMAND_DESCRIPTION_ADMIN_ADD_COOP_LIMIT: '为指定玩家的岛屿增加合作玩家数量上限.' @@ -184,7 +184,7 @@ COMMAND_DESCRIPTION_ADMIN_DEL_WARP: '删除指定岛屿的传送点.' COMMAND_DESCRIPTION_ADMIN_DEMOTE: '将岛屿中的指定玩家升职.' COMMAND_DESCRIPTION_ADMIN_DEPOSIT: '向指定岛屿的银行中存款.' COMMAND_DESCRIPTION_ADMIN_DISBAND: '永久解散指定岛屿.' -COMMAND_DESCRIPTION_ADMIN_FLY: 'Toggle island fly for a player.' +COMMAND_DESCRIPTION_ADMIN_FLY: '切换指定玩家的岛屿飞行.' COMMAND_DESCRIPTION_ADMIN_GIVE_DISBANDS: '使指定玩家从其团队中解散.' COMMAND_DESCRIPTION_ADMIN_IGNORE: '将指定岛屿设置为不参与排行榜排名.' COMMAND_DESCRIPTION_ADMIN_JOIN: '强制加入岛屿.' @@ -202,13 +202,13 @@ COMMAND_DESCRIPTION_ADMIN_RANKUP: '为指定岛屿提升等级.' COMMAND_DESCRIPTION_ADMIN_RECALC: '重新计算指定岛屿的价值.' COMMAND_DESCRIPTION_ADMIN_RELOAD: '重载本插件的所有配置和进程.' COMMAND_DESCRIPTION_ADMIN_REMOVE_BLOCK_LIMIT: '去除指定岛屿的方块数量限制.' -COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: 'Remove an entity limit from an island.' +COMMAND_DESCRIPTION_ADMIN_REMOVE_ENTITY_LIMIT: '去除指定岛屿的实体数量限制.' COMMAND_DESCRIPTION_ADMIN_REMOVE_RATINGS: '去除指定玩家的所有评分.' -COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: 'Reset all island permissions for a specific island.' -COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: 'Reset all island settings for a specific island.' +COMMAND_DESCRIPTION_ADMIN_RESET_PERMISSIONS: '重置指定岛屿的所有权限.' +COMMAND_DESCRIPTION_ADMIN_RESET_SETTINGS: '重置指定岛屿的所有设置.' COMMAND_DESCRIPTION_ADMIN_RESET_WORLD: '重置指定岛屿所在的世界.' COMMAND_DESCRIPTION_ADMIN_SCHEMATIC: '从插件创建结构文件.' -COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: 'Set the bank limit for another player''s island.' +COMMAND_DESCRIPTION_ADMIN_SET_BANK_LIMIT: '设置指定玩家的岛屿银行存款上限.' COMMAND_DESCRIPTION_ADMIN_SET_BIOME: '设置指定岛屿的生物群系.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_AMOUNT: '设置指定位置的方块数量.' COMMAND_DESCRIPTION_ADMIN_SET_BLOCK_LIMIT: '设置指定岛屿的方块数量限制.' @@ -218,7 +218,7 @@ COMMAND_DESCRIPTION_ADMIN_SET_CROP_GROWTH: '设置指定岛屿的作物生长倍 COMMAND_DESCRIPTION_ADMIN_SET_DISBANDS: '设置岛屿解散所需玩家数量.' COMMAND_DESCRIPTION_ADMIN_SET_EFFECT: '设置指定岛屿的效果等级.' COMMAND_DESCRIPTION_ADMIN_SET_ENTITY_LIMIT: '设置指定岛屿的实体数量限制.' -COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: 'Set the preview location for an island.' +COMMAND_DESCRIPTION_ADMIN_SET_ISLAND_PREVIEW: '设置岛屿的预览位置.' COMMAND_DESCRIPTION_ADMIN_SET_LEADER: '将岛屿所有权转移给其他玩家.' COMMAND_DESCRIPTION_ADMIN_SET_MOB_DROPS: '设置指定岛屿的生物掉落物倍率.' COMMAND_DESCRIPTION_ADMIN_SET_PERMISSION: '设置所有岛屿上的指定权限所需的职位.' @@ -248,7 +248,7 @@ COMMAND_DESCRIPTION_ADMIN_WITHDRAW: '从指定岛屿的银行中取款.' COMMAND_DESCRIPTION_BALANCE: '检查指定岛屿银行中的存款.' COMMAND_DESCRIPTION_BAN: '将指定玩家从你的岛屿上封禁.' COMMAND_DESCRIPTION_BANK: '打开岛屿银行.' -COMMAND_DESCRIPTION_BANS: 'Open the bans menu.' +COMMAND_DESCRIPTION_BANS: '打开封禁菜单.' COMMAND_DESCRIPTION_BIOME: '更换岛屿生物群系.' COMMAND_DESCRIPTION_BORDER: '更换岛屿边界颜色.' COMMAND_DESCRIPTION_CHEST: '打开岛屿仓库.' @@ -379,10 +379,10 @@ INVALID_AMOUNT: '&c&l错误 | &7无效数量 {0}.' INVALID_BIOME: '&c&l错误 | &7无效生物群系 {0}.' INVALID_BLOCK: '&c&l错误 | &7无效方块位置 {0}.' INVALID_BORDER_COLOR: '&c&l错误 | &7无效边界颜色 {0}.' -INVALID_COMMAND: '&c&lError | &7Invalid command {0}.' +INVALID_COMMAND: '&c&l错误 | &7无效命令 {0}.' INVALID_EFFECT: '&c&l错误 | &7无效效果 {0}.' INVALID_ENTITY: '&c&l错误 | &7无效实体 {0}.' -INVALID_ENVIRONMENT: '&c&lError | &7Invalid dimension {0}.' +INVALID_ENVIRONMENT: '&c&l错误 | &7无效维度 {0}.' INVALID_INTERVAL: '&c&l错误 | &7无效间隔 {0}.' INVALID_ISLAND: '&c&l错误 | &7你没有岛屿.' INVALID_ISLAND_LOCATION: '&c&l错误 | &7你当前位置没有岛屿.' @@ -395,9 +395,9 @@ INVALID_LEVEL: '&c&l错误 | &7无效等级 {0}.' INVALID_LIMIT: '&c&l错误 | &7无效限制 {0}.' INVALID_MATERIAL: '&c&l错误 | &7无效材料名 {0}.' INVALID_MATERIAL_DATA: '&c&l错误 | &7无效材料数据 {0}.' -INVALID_MENU: '&c&lError | &7Invalid menu {0}.' +INVALID_MENU: '&c&l错误 | &7无效菜单 {0}.' INVALID_MISSION: '&c&l错误 | &7无效任务 {0}.' -INVALID_MISSION_CATEGORY: '&c&lError | &7Invalid mission category {0}.' +INVALID_MISSION_CATEGORY: '&c&l错误 | &7无效任务分类 {0}.' INVALID_MODULE: '&c&l错误 | &7无效模块 {0}.' INVALID_MULTIPLIER: '&c&l错误 | &7无效翻倍 {0}.' INVALID_PAGE: '&c&l错误 | &7无效页码 {0}.' @@ -428,9 +428,9 @@ INVALID_WORLD: '&c&l错误 | &7I无效世界 {0}.' INVITE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 将玩家 {1} 邀请至了岛屿.' INVITE_BANNED_PLAYER: '&c&l错误 | &7该玩家已从岛屿被封禁, 不可接受任何邀请.' INVITE_TO_FULL_ISLAND: '&c&l错误 | &7你不能再向岛屿邀请更多成员了.' -ISLAND_ALREADY_CLOSED: '&c&lError | &7The island is already closed to the public.' +ISLAND_ALREADY_CLOSED: '&c&l错误 | &7该岛屿已经设置为不对公众开放了.' ISLAND_ALREADY_EXIST: '&c&l错误 | &7已存在名称相同的岛屿.' -ISLAND_ALREADY_OPENED: '&c&lError | &7The island is already opened to the public.' +ISLAND_ALREADY_OPENED: '&c&l错误 | &7该岛屿已经设置为对公众开放了.' ISLAND_BANK_EMPTY: '&e&l银行 | &7岛屿银行中没有存款.' ISLAND_BANK_SHOW: '&e&l银行 | &7你的岛屿银行存款为 ${0}.' ISLAND_BANK_SHOW_OTHER: '&e&l银行 | &7玩家 {0} 的岛屿银行存款为 ${1}.' @@ -507,17 +507,17 @@ ISLAND_INFO_RATE_FIVE_COLOR: '&2' ISLAND_INFO_ROLES: | &e&l岛屿 | &7{0}s: {1} -ISLAND_INFO_VISITORS_COUNT: '&e&l岛屿 | &7访客数量: {0} ({1} unique visitors)' +ISLAND_INFO_VISITORS_COUNT: '&e&l岛屿 | &7访客数量: {0} ({1} 位独立访客)' ISLAND_INFO_WORTH: '&e&l岛屿 | &7价值: {0}' ISLAND_NAME_NONE: None ISLAND_OPENED: '&e&l岛屿 | &7成功将岛屿设置为对公众开放.' ISLAND_OWNER_NONE: None -ISLAND_PREVIEW_BLOCK_COMMAND: '&c&lError | &7You cannot use that command in preview mode.' +ISLAND_PREVIEW_BLOCK_COMMAND: '&c&l错误 | &7你不能在预览模式中使用该命令.' ISLAND_PREVIEW_CANCEL_DISTANCE: '&e&l结构 | &7你离得太远离了, 已自动退出预览模式.' ISLAND_PREVIEW_CANCEL: '&e&l结构 | &7你退出了预览模式.' ISLAND_PREVIEW_CONFIRM_TEXT: '确认' ISLAND_PREVIEW_CANCEL_TEXT: '取消' -ISLAND_PREVIEW_SET: '&e&lPreview | &7Successfully updated the preview location for {0} schematic to {1}.' +ISLAND_PREVIEW_SET: '&e&l预览 | &7成功将结构 {0} 的预览位置设置为 {1}.' ISLAND_PREVIEW_START: | &e&l结构 | &7你正在预览结构 {0}. &e&l结构 | &7输入 &a&lCONFIRM &7来创建一个新岛屿, 或 &c&lCANCEL &7取消预览模式. @@ -558,9 +558,9 @@ LEAVE_ISLAND_AS_LEADER: |- LEFT_ISLAND: '&e&l岛屿 | &7你离开了你的岛屿.' LEFT_ISLAND_COOP: '&e&l岛屿 | &7你不再是玩家 {0} 的岛屿合作成员.' LEFT_ISLAND_COOP_NAME: '&e&l岛屿 | &7你不再是岛屿 {0} 的合作成员.' -LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now locked for all islands!' -LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now locked for the island {1}!' -LOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now locked for {1}''s island!' +LOCK_WORLD_ANNOUNCEMENT_ALL: '&e&l世界 | &7世界 {0} 已对所有岛屿锁定!' +LOCK_WORLD_ANNOUNCEMENT_NAME: '&e&l世界 | &7世界 {0} 已对岛屿 {1} 锁定!' +LOCK_WORLD_ANNOUNCEMENT: '&e&l世界 | &7世界 {0} 已对玩家 {1} 的岛屿锁定!' MATERIAL_NOT_SOLID: '&c&l错误 | &7你必须提供一个固体方块材料名.' MAXIMUM_LEVEL: '&c&l错误 | &7该功能的最大等级为 {0}.' MESSAGE_SENT: '&e&l岛屿 | &7成功将消息发送给了 {0}!' @@ -583,8 +583,8 @@ MODULES_LIST: '&f模块 ({0}): {1}' MODULES_LIST_MODULE_NAME: '&a{0}' MODULES_LIST_SEPARATOR: '&f, ' NAME_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 将岛屿名称修改为了 {1}&7.' -NAME_ANNOUNCEMENT_OTHER: '&e&lIsland | &7{0} changed the {1} island''s name to {2}&7.' -NAME_ANNOUNCEMENT_OTHER_NAME: '&e&lIsland | &7{0} changed the name of {1}&7 to {2}&7.' +NAME_ANNOUNCEMENT_OTHER: '&e&l岛屿 | &7{0} 将玩家 {1} 的岛屿名称修改为了 {2}&7.' +NAME_ANNOUNCEMENT_OTHER_NAME: '&e&l岛屿 | &7{0} 将岛屿 {1}&7 的名称修改为了 {2}&7.' NAME_BLACKLISTED: '&c&l错误 | &7你不能使用该名称.' NAME_CHAT_FORMAT: '&8[&e{0}&8] &r' NAME_SAME_AS_PLAYER: '&c&l错误 | &7你不能将玩家名称作为岛屿名称.' @@ -593,7 +593,7 @@ NAME_TOO_SHORT: '&c&l错误 | &7岛屿名称不能短于 {0} 个字符.' NO_BAN_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可封禁玩家.' NO_CLOSE_BYPASS: '&c&l错误 | &7该岛屿不对公众开放.' NO_CLOSE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将岛屿对公众开放.' -NO_COMMAND_PERMISSION: '&c&lError | &7You don''t have permission to use that command. ({0})' +NO_COMMAND_PERMISSION: '&c&l错误 | &7你没有权限使用该命令. ({0})' NO_COOP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可将玩家添加为合作成员.' NO_DELETE_WARP_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可删除传送点.' NO_DEMOTE_PERMISSION: '&c&l错误 | &7你的职位必须至少为 {0} 才可降职玩家.' @@ -644,9 +644,9 @@ PERSISTENT_DATA_SHOW_PATH: '&b{0}&f: ' PERSISTENT_DATA_SHOW_SPACER: '&f, ' PERSISTENT_DATA_SHOW_VALUE: '&6{0}&c{1}&f' PERSISTENT_DATA_REMOVED: '&e&l数据 | &7成功删除了路径 {1} 下的数据 {0}.' -PERMISSIONS_RESET: '&e&lIsland | &7Successfully reset all the permissions of {0}''s island to default values!' -PERMISSIONS_RESET_ALL: '&e&lIsland | &7Successfully reset all the permissions of all the islands to default values!' -PERMISSIONS_RESET_NAME: '&e&lIsland | &7Successfully reset all the permissions of the island {0} to default values!' +PERMISSIONS_RESET: '&e&l岛屿 | &7成功将玩家 {0} 的岛屿所有权限重置为默认值!' +PERMISSIONS_RESET_ALL: '&e&l岛屿 | &7成功将所有岛屿的所有权限重置为默认值!' +PERMISSIONS_RESET_NAME: '&e&l岛屿 | &7成功将岛屿 {0} 的所有权限重置为默认值!' PERMISSIONS_RESET_PLAYER: '&e&l岛屿 | &7成功将玩家 {0} 的权限重置回默认状态!' PERMISSIONS_RESET_ROLES: '&e&l岛屿 | &7成功将该岛屿上的所有权限重置为默认状态!' PLACEHOLDER_NO: '否' @@ -671,7 +671,7 @@ PURGED_ISLANDS: |- RANKUP_SUCCESS: '&e&l岛屿 | &7成功更新了玩家 {1} 的岛屿功能 {0} 等级.' RANKUP_SUCCESS_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的功能 {0} 等级.' RANKUP_SUCCESS_NAME: '&e&l岛屿 | &7成功更新了岛屿 {1} 的功能 {0} 等级.' -RATE_ALREADY_GIVEN: '&c&lError | &7You already rated this island.' +RATE_ALREADY_GIVEN: '&c&l错误 | &7你已经为该岛屿评过分了.' RATE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 为你的岛屿评分 {1}, 满分为 5!.' RATE_CHANGE_OTHER: '&e&l岛屿 | &7你将 {0} 的评分修改为了 {1}.' RATE_OWN_ISLAND: '&c&l错误 | &7你不能对着自己的岛屿评分.' @@ -691,9 +691,12 @@ REVOKE_INVITE_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 撤回了对玩家 {1} 的邀请 RESET_WORLD_SUCCEED: '&e&l岛屿 | &7成功重置了玩家 {1} 的岛屿世界 {0}.' RESET_WORLD_SUCCEED_ALL: '&e&l岛屿 | &7成功为所有岛屿重置了世界 {0}.' RESET_WORLD_SUCCEED_NAME: '&e&l岛屿 | &7成功为岛屿 {1} 重置了世界 {0}.' +RESET_SETTINGS: '&e&l岛屿 | &7成功重置了玩家 {0} 的岛屿设置.' +RESET_SETTINGS_ALL: '&e&l岛屿 | &7成功重置了所有岛屿的设置.' +RESET_SETTINGS_NAME: '&e&l岛屿 | &7成功重置了岛屿 {0} 的设置.' SAME_NAME_CHANGE: '&c&l错误 | &7你必须输入一个不与当前岛屿名称重复的名称.' SCHEMATIC_LEFT_SELECT: '&e&l结构 | &7已选中 #2 位点 ({0})' -SCHEMATIC_NOT_ADDED: '&c&lError | &7The server hasn''t added a {0} schematic. Please contact administrator to solve the problem. The format for {0} schematic is "{1}".' +SCHEMATIC_NOT_ADDED: '&c&l错误 | &7服务器尚未添加 {0} 的结构文件. 请联系管理员解决此问题. {0} 结构文件的格式为 "{1}".' SCHEMATIC_NOT_READY: '&c&l错误 | &7你尚未选中两点.' SCHEMATIC_PROCCESS_REQUEST: '&e&l结构 | &7正在处理你的请求...' SCHEMATIC_READY_TO_CREATE: | @@ -703,20 +706,20 @@ SCHEMATIC_RIGHT_SELECT: '&e&l结构 | &7已选中 #1 位点 ({0})' SCHEMATIC_SAVED: '&e&l结构 | &7结构文件成功保存!' SELF_ROLE_CHANGE: '&c&l错误 | &7你不能修改自己的职位.' SET_UPGRADE_LEVEL: '&e&l升级 | &7成功更新了玩家 {1} 的岛屿等级 {0}.' -SET_UPGRADE_LEVEL_ALL: '&e&lUpgrades | &7Successfully updated the level of {0} for all islands.' +SET_UPGRADE_LEVEL_ALL: '&e&l升级 | &7成功更新了所有岛屿的等级 {0}.' SET_UPGRADE_LEVEL_NAME: '&e&l升级 | &7成功更新了岛屿 {1} 的等级 {0}.' SET_WARP: '&e&l岛屿 | &7成功在 {0} 处设置了传送点.' SET_WARP_OUTSIDE: '&c&l错误 | &7你不能在岛屿外设置传送点.' -SETTINGS_RESET: '&e&lIsland | &7Successfully reset all the settings of {0}''s island to default values!' -SETTINGS_RESET_ALL: '&e&lIsland | &7Successfully reset all the settings of all the islands to default values!' -SETTINGS_RESET_NAME: '&e&lIsland | &7Successfully reset all the settings of the island {0} to default values!' -SETTINGS_RESET_SELF: '&e&lIsland | &7Successfully reset all the settings of the island to default values!' +SETTINGS_RESET: '&e&l岛屿 | &7成功将玩家 {0} 的岛屿的所有设置重置为默认值!' +SETTINGS_RESET_ALL: '&e&l岛屿 | &7成功将所有岛屿的所有设置重置为默认值!' +SETTINGS_RESET_NAME: '&e&l岛屿 | &7成功将岛屿 {0} 的所有设置重置为默认值!' +SETTINGS_RESET_SELF: '&e&l岛屿 | &7成功将该岛屿的所有设置重置为默认值!' SETTINGS_UPDATED: '&e&l岛屿 | &7成功修改了玩家 {1} 的岛屿设置 {0}.' -SETTINGS_UPDATED_NAME: '&e&l岛屿 | &7S成功修改了岛屿 {1} 的设置 {0}.' +SETTINGS_UPDATED_NAME: '&e&l岛屿 | &7成功修改了岛屿 {1} 的设置 {0}.' SETTINGS_UPDATED_ALL: '&e&l岛屿 | &7成功更新了所有岛屿的 {0} 设置.' SIZE_BIGGER_MAX: '&c&l错误 | &7你不能将大小设置为超出岛屿最大大小的数值.' -SPAWN_PROTECTED: '&c&lError | &7Spawn is protected.' -SPAWN_PROTECTED_OPPED: '&7&oYou can bypass this restriction by using "/is admin bypass".' +SPAWN_PROTECTED: '&c&l错误 | &7出生点受到保护.' +SPAWN_PROTECTED_OPPED: '&7&o你可通过输入命令 "/is admin bypass" 来绕过该限制.' SPAWN_TELEPORT_SUCCESS: '&e&l主城 | &7成功将玩家 {0} 传送至主城.' SPAWN_SET_SUCCESS: '&e&l主城 | &7成功将出生点位置设置为了 {0}.' SPY_TEAM_CHAT_FORMAT: '&7[窃听] &e[{0}] {1}&f: &7{2}' @@ -737,8 +740,8 @@ TOGGLED_BYPASS_OFF: '&e&l绕过 | &7绕过模式已 &c关闭&7.' TOGGLED_BYPASS_ON: '&e&l绕过 | &7绕过模式已 &a开启&7.' TOGGLED_FLY_OFF: '&e&l飞行 | &7岛屿飞行已 &c关闭&7.' TOGGLED_FLY_ON: '&e&l飞行 | &7岛屿飞行已 &a开启&7.' -TOGGLED_FLY_OFF_OTHER: '&e&lFly | &7Toggled island fly &cOFF&7 for {0}.' -TOGGLED_FLY_ON_OTHER: '&e&lFly | &7Toggled island fly &aON&7 for {0}.' +TOGGLED_FLY_OFF_OTHER: '&e&l飞行 | &7已为 {0} &c关闭&7岛屿飞行.' +TOGGLED_FLY_ON_OTHER: '&e&l飞行 | &7已为 {0} &a开启&7岛屿飞行.' TOGGLED_SCHEMATIC_OFF: '&e&l结构 | &7结构模式已 &c关闭&7.' TOGGLED_SCHEMATIC_ON: |- &e&l结构 | &7结构模式已 &a开启&7. @@ -763,14 +766,14 @@ UNCOOP_AUTO_ANNOUNCEMENT: '&e&l岛屿 | &7没有岛屿成员在线, 你已被自 UNCOOP_LEFT_ANNOUNCEMENT: '&e&l岛屿 | &7{0} 离开了游戏, 自动取消其成员关系.' UNIGNORED_ISLAND: '&e&l岛屿 | &7{0} 的岛屿现在已重新参与岛屿排行榜计算.' UNIGNORED_ISLAND_NAME: '&e&l岛屿 | &7岛屿 {0} 现在已重新参与岛屿排行榜计算.' -UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&lWorlds | &7The world {0} is now unlocked for all islands!' -UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&lWorlds | &7The world {0} is now unlocked for the island {1}!' -UNLOCK_WORLD_ANNOUNCEMENT: '&e&lWorlds | &7The world {0} is now unlocked for {1}''s island!' +UNLOCK_WORLD_ANNOUNCEMENT_ALL: '&e&l世界 | &7世界 {0} 已对所有岛屿解锁!' +UNLOCK_WORLD_ANNOUNCEMENT_NAME: '&e&l世界 | &7世界 {0} 已对岛屿 {1} 解锁!' +UNLOCK_WORLD_ANNOUNCEMENT: '&e&l世界 | &7世界 {0} 已对玩家 {1} 的岛屿解锁!' UNSAFE_WARP: '&e&l岛屿 | &7&o看起来该传送点不安全. 请尝试使用其他传送点.' UPDATED_PERMISSION: '&e&l岛屿 | &7更新了 {0} 的权限.' UPDATED_SETTINGS: '&e&l岛屿 | &7更新了岛屿设置 {0}.' UPGRADE_COOLDOWN_FORMAT: '&c&l错误 | &7你只能在 {0} 之后才可继续进行升级操作.' -VAULT_NOT_INSTALLED: '&c&lError | &7Server doesn''t have vault installed so transactions are disabled.' +VAULT_NOT_INSTALLED: '&c&l错误 | &7服务器未安装 Vault 插件, 交易功能已禁用.' VISITOR_BLOCK_COMMAND: '&c&l错误 | &7你不能对其他岛屿使用该命令.' WARP_ALREADY_EXIST: '&c&l错误 | &7已存在同名传送点.' WARP_CATEGORY_ICON_NEW_LORE: | @@ -780,7 +783,7 @@ WARP_CATEGORY_ICON_NEW_NAME: '&e&l传送 | &7输入新的分类图标名称 (输 WARP_CATEGORY_ICON_NEW_TYPE: '&e&l传送 | &7输入新的材料名称 (输入 "-cancel" 取消本次操作):' WARP_CATEGORY_ICON_UPDATED: '&e&l传送 | &7成功更新了分类图标的样式.' WARP_CATEGORY_ILLEGAL_NAME: '&c&l错误 | &7传送点分类名称不能为空.' -WARP_CATEGORY_NAME_TOO_LONG: '&c&l错误 | 传送点分类名称长度不能大于 255 个字符.' +WARP_CATEGORY_NAME_TOO_LONG: '&c&l错误 | &7传送点分类名称长度不能大于 255 个字符.' WARP_CATEGORY_SLOT: '&e&l传送 | &7输入一个新的格子位置 (输入 "-cancel" 取消本次操作):' WARP_CATEGORY_SLOT_ALREADY_TAKEN: '&c&l错误 | &7该槽位已有其他分类图标占用.' WARP_CATEGORY_SLOT_SUCCESS: '&e&l传送 | &7成功将该分类的位置转移至 {0}.' @@ -795,7 +798,7 @@ WARP_ICON_NEW_TYPE: '&e&l传送 | &7输入新的材料名称 (输入 "-cancel" WARP_ICON_UPDATED: '&e&l传送 | &7成功更新了传送点的图标样式.' WARP_ILLEGAL_NAME: '&c&l错误 | &7传送点名称不能为空.' WARP_LOCATION_UPDATE: '&e&l传送 | &7成功将传送点的位置转移至你当前的位置.' -WARP_NAME_TOO_LONG: '&c&l错误 | W传送蒂娜名称长度不能大于 255 个字符.' +WARP_NAME_TOO_LONG: '&c&l错误 | &7传送点名称长度不能大于 255 个字符.' WARP_PUBLIC_UPDATE: '&e&l传送 | &7成功将传送点设置为对公众开放.' WARP_PRIVATE_UPDATE: '&e&l传送 | &7成功将传送点设置为不对公众开放.' WARP_RENAME: '&e&l传送 | &7输入传送点的新名称 (输入 "-cancel" 取消本次操作):' @@ -803,10 +806,10 @@ WARP_RENAME_ALREADY_EXIST: '&c&l错误 | &7已存在名称相同的其他传送 WARP_RENAME_SUCCESS: '&e&l传送 | &7成功将传送点重命名为 {0}.' WITHDRAW_ALL_MONEY: |- &e&l银行 | &7岛屿银行余额为 ${0}. - &e&l银行 | &7&o正在取出所有钱..." + &e&l银行 | &7&o正在取出所有钱... WITHDRAW_ANNOUNCEMENT: '&e&l银行 | &7玩家 {0} 从岛屿银行中取出了 ${1}!' WITHDRAW_ERROR: '&c&l错误 | &7{0}.' WITHDRAWN_MONEY: '&e&l银行 | &7你从玩家 {1} 的岛屿银行中取出 ${0}!' -WITHDRAWN_MONEY_NAME: '&e&l银行 | &7你从岛屿 {1} 的银行中取出 ${0} {1}!' -WORLD_NOT_ENABLED: '&e&lWorlds | &7The {0} world is not enabled on the server.' +WITHDRAWN_MONEY_NAME: '&e&l银行 | &7你从岛屿 {1} 的银行中取出 ${0}!' +WORLD_NOT_ENABLED: '&e&l世界 | &7世界 {0} 未在服务器上启用.' WORLD_NOT_UNLOCKED: '&e&l世界 | &7世界 {0} 尚未解锁!' From 0abfad40c6121d1ac6f556af72af76a3173505b4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 21 Feb 2026 17:38:25 +0200 Subject: [PATCH 506/600] Fixed upgrades cannot have lower values than the previous upgrade, or set -1 for unlimited limits (#2856) --- .../api/upgrades/UpgradeLevel.java | 40 +++++ .../superiorskyblock/island/SIsland.java | 148 +++++++++++------- .../island/upgrade/DefaultUpgradeLevel.java | 21 +-- .../island/upgrade/SUpgrade.java | 22 +-- .../island/upgrade/SUpgradeLevel.java | 99 ++++++++---- .../module/upgrades/UpgradesModule.java | 44 ++++-- 6 files changed, 259 insertions(+), 115 deletions(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/UpgradeLevel.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/UpgradeLevel.java index bc7cc8ddfe..aba7f710cf 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/UpgradeLevel.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/UpgradeLevel.java @@ -52,16 +52,31 @@ public interface UpgradeLevel { */ String checkRequirements(SuperiorPlayer superiorPlayer); + /** + * Checks if this level has a custom crop growth multiplier. + */ + boolean hasCropGrowth(); + /** * Get the crop growth multiplier of this level. */ double getCropGrowth(); + /** + * Checks if this level has a custom spawner rates multiplier. + */ + boolean hasSpawnerRates(); + /** * Get the spawner rates multiplier of this level. */ double getSpawnerRates(); + /** + * Checks if this level has a custom mob drops multiplier. + */ + boolean hasMobDrops(); + /** * Get the mob drops multiplier of this level. */ @@ -105,21 +120,41 @@ public interface UpgradeLevel { */ Map getEntityLimitsAsKeys(); + /** + * Checks if this level has a custom team limit. + */ + boolean hasTeamLimit(); + /** * Get the team limit of this level. */ int getTeamLimit(); + /** + * Checks if this level has a custom warps limit. + */ + boolean hasWarpsLimit(); + /** * Get the warps limit of this level. */ int getWarpsLimit(); + /** + * Checks if this level has a custom coop limit. + */ + boolean hasCoopLimit(); + /** * Get the coop players limit of this level. */ int getCoopLimit(); + /** + * Checks if this level has a custom border size. + */ + boolean hasBorderSize(); + /** * Get the border size of this level. */ @@ -169,6 +204,11 @@ public interface UpgradeLevel { */ Map getPotionEffects(); + /** + * Checks if this level has a custom bank limit. + */ + boolean hasBankLimit(); + /** * Get the bank limit of this level. */ diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index fae7c0bcb3..52812aa9fa 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -5065,65 +5065,91 @@ private void clearUpgrades(boolean overrideCustom) { } private void syncUpgrade(SUpgradeLevel upgradeLevel, boolean overrideCustom) { - cropGrowth.set(cropGrowth -> { - if ((overrideCustom || cropGrowth.isSynced()) && cropGrowth.get() < upgradeLevel.getCropGrowth()) { - notifyCropGrowthChange(upgradeLevel.getCropGrowth()); - return upgradeLevel.getCropGrowthUpgradeValue(); - } + if (upgradeLevel.hasCropGrowth()) { + cropGrowth.set(cropGrowth -> { + if (overrideCustom || cropGrowth.isSynced()) { + notifyCropGrowthChange(upgradeLevel.getCropGrowth()); + return upgradeLevel.getCropGrowthUpgradeValue(); + } - return cropGrowth; - }); + return cropGrowth; + }); + } - spawnerRates.set(spawnerRates -> { - if ((overrideCustom || spawnerRates.isSynced()) && spawnerRates.get() < upgradeLevel.getSpawnerRates()) - return upgradeLevel.getSpawnerRatesUpgradeValue(); - return spawnerRates; - }); + if (upgradeLevel.hasSpawnerRates()) { + spawnerRates.set(spawnerRates -> { + if (overrideCustom || spawnerRates.isSynced()) + return upgradeLevel.getSpawnerRatesUpgradeValue(); + return spawnerRates; + }); + } - mobDrops.set(mobDrops -> { - if ((overrideCustom || mobDrops.isSynced()) && mobDrops.get() < upgradeLevel.getMobDrops()) - return upgradeLevel.getMobDropsUpgradeValue(); - return mobDrops; - }); + if (upgradeLevel.hasMobDrops()) { + mobDrops.set(mobDrops -> { + if (overrideCustom || mobDrops.isSynced()) + return upgradeLevel.getMobDropsUpgradeValue(); + return mobDrops; + }); + } - teamLimit.set(teamLimit -> { - if ((overrideCustom || teamLimit.isSynced()) && teamLimit.get() < upgradeLevel.getTeamLimit()) - return upgradeLevel.getTeamLimitUpgradeValue(); - return teamLimit; - }); + if (upgradeLevel.hasTeamLimit()) { + teamLimit.set(teamLimit -> { + if (overrideCustom || teamLimit.isSynced()) + return upgradeLevel.getTeamLimitUpgradeValue(); + return teamLimit; + }); + } - warpsLimit.set(warpsLimit -> { - if ((overrideCustom || warpsLimit.isSynced()) && warpsLimit.get() < upgradeLevel.getWarpsLimit()) - return upgradeLevel.getWarpsLimitUpgradeValue(); - return warpsLimit; - }); + if (upgradeLevel.hasWarpsLimit()) { + warpsLimit.set(warpsLimit -> { + if (overrideCustom || warpsLimit.isSynced()) + return upgradeLevel.getWarpsLimitUpgradeValue(); + return warpsLimit; + }); + } - coopLimit.set(coopLimit -> { - if ((overrideCustom || coopLimit.isSynced()) && coopLimit.get() < upgradeLevel.getCoopLimit()) - return upgradeLevel.getCoopLimitUpgradeValue(); - return coopLimit; - }); + if (upgradeLevel.hasCoopLimit()) { + coopLimit.set(coopLimit -> { + if (overrideCustom || coopLimit.isSynced()) + return upgradeLevel.getCoopLimitUpgradeValue(); + return coopLimit; + }); + } - IntValue islandSize = this.islandSize.get(); - if ((overrideCustom || islandSize.isSynced()) && islandSize.get() < upgradeLevel.getBorderSize()) - setIslandSizeInternal(upgradeLevel.getBorderSizeUpgradeValue()); + if (upgradeLevel.hasBorderSize()) { + IntValue islandSize = this.islandSize.get(); + if (overrideCustom || islandSize.isSynced()) + setIslandSizeInternal(upgradeLevel.getBorderSizeUpgradeValue()); + } - bankLimit.set(bankLimit -> { - if ((overrideCustom || bankLimit.isSynced()) && bankLimit.get().compareTo(upgradeLevel.getBankLimit()) < 0) - return upgradeLevel.getBankLimitUpgradeValue(); - return bankLimit; - }); + if (upgradeLevel.hasBankLimit()) { + bankLimit.set(bankLimit -> { + if (overrideCustom || bankLimit.isSynced()) + return upgradeLevel.getBankLimitUpgradeValue(); + return bankLimit; + }); + } for (Map.Entry entry : upgradeLevel.getBlockLimitsUpgradeValue().entrySet()) { IntValue currentValue = blockLimits.getRaw(entry.getKey(), null); - if (currentValue == null || ((overrideCustom || currentValue.isSynced()) && currentValue.get() < entry.getValue().get())) - blockLimits.put(entry.getKey(), entry.getValue()); + if (currentValue == null || overrideCustom || currentValue.isSynced()) { + if (entry.getValue().get() < 0) { + blockLimits.remove(entry.getKey()); + } else { + blockLimits.put(entry.getKey(), entry.getValue()); + } + } } for (Map.Entry entry : upgradeLevel.getEntityLimitsUpgradeValue().entrySet()) { IntValue currentValue = entityLimits.getRaw(entry.getKey(), null); - if (currentValue == null || ((overrideCustom || currentValue.isSynced()) && currentValue.get() < entry.getValue().get())) - entityLimits.put(entry.getKey(), entry.getValue()); + if (currentValue == null || overrideCustom || currentValue.isSynced()) { + if (entry.getValue().get() < 0) { + entityLimits.remove(entry.getKey()); + } else { + entityLimits.put(entry.getKey(), entry.getValue()); + } + } } EnumerateMap> upgradeGeneratorRates = upgradeLevel.getGeneratorUpgradeValue(); @@ -5147,14 +5173,17 @@ private void syncUpgrade(SUpgradeLevel upgradeLevel, boolean overrideCustom) { IntValue rate = entry.getValue(); IntValue currentValue = worldGeneratorRates == null ? null : worldGeneratorRates.get(block); - if (currentValue == null || ((overrideCustom || currentValue.isSynced()) && - currentValue.get() < rate.get())) { - if (worldGeneratorRates == null) { - worldGeneratorRates = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL); - cobbleGeneratorValues.put(dimension, worldGeneratorRates); + if (currentValue == null || overrideCustom || currentValue.isSynced()) { + if (rate.get() < 0) { + worldGeneratorRates.remove(block); + } else { + if (worldGeneratorRates == null) { + worldGeneratorRates = KeyMaps.createConcurrentHashMap(KeyIndicator.MATERIAL); + cobbleGeneratorValues.put(dimension, worldGeneratorRates); + } + + worldGeneratorRates.put(block, rate); } - - worldGeneratorRates.put(block, rate); } } } @@ -5165,8 +5194,12 @@ private void syncUpgrade(SUpgradeLevel upgradeLevel, boolean overrideCustom) { for (Map.Entry entry : upgradeLevel.getPotionEffectsUpgradeValue().entrySet()) { IntValue currentValue = islandEffects.get(entry.getKey()); - if (currentValue == null || ((overrideCustom || currentValue.isSynced()) && currentValue.get() < entry.getValue().get())) { - islandEffects.put(entry.getKey(), entry.getValue()); + if (currentValue == null || overrideCustom || currentValue.isSynced()) { + if (entry.getValue().get() < 0) { + islandEffects.remove(entry.getKey()); + } else { + islandEffects.put(entry.getKey(), entry.getValue()); + } editedIslandEffects = true; } } @@ -5178,8 +5211,13 @@ private void syncUpgrade(SUpgradeLevel upgradeLevel, boolean overrideCustom) { roleLimits.write(roleLimits -> { for (Map.Entry entry : upgradeLevel.getRoleLimitsUpgradeValue().entrySet()) { IntValue currentValue = roleLimits.get(entry.getKey().getId()); - if (currentValue == null || ((overrideCustom || currentValue.isSynced()) && currentValue.get() < entry.getValue().get())) - roleLimits.put(entry.getKey().getId(), entry.getValue()); + if (currentValue == null || overrideCustom || currentValue.isSynced()) { + if (entry.getValue().get() < 0) { + roleLimits.remove(entry.getKey().getId()); + } else { + roleLimits.put(entry.getKey().getId(), entry.getValue()); + } + } } }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java index 0297591fc2..f52f6a1074 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/DefaultUpgradeLevel.java @@ -2,12 +2,13 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.key.KeyMap; -import com.bgsoftware.superiorskyblock.core.value.DoubleValue; -import com.bgsoftware.superiorskyblock.core.value.IntValue; import com.bgsoftware.superiorskyblock.core.value.Value; import com.bgsoftware.superiorskyblock.island.upgrade.cost.EmptyUpgradeCost; import java.util.Collections; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.OptionalInt; public class DefaultUpgradeLevel extends SUpgradeLevel { @@ -16,18 +17,18 @@ public class DefaultUpgradeLevel extends SUpgradeLevel { private DefaultUpgradeLevel() { super(-1, EmptyUpgradeCost.getInstance(), Collections.emptyList(), "", Collections.emptySet(), - DoubleValue.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getCropGrowth()), - DoubleValue.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getSpawnerRates()), - DoubleValue.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getMobDrops()), - IntValue.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getTeamLimit()), - IntValue.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getWarpsLimit()), - IntValue.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getCoopLimit()), - IntValue.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getIslandSize()), + Value.syncedSupplied(() -> OptionalDouble.of(plugin.getSettings().getDefaultValues().getCropGrowth())), + Value.syncedSupplied(() -> OptionalDouble.of(plugin.getSettings().getDefaultValues().getSpawnerRates())), + Value.syncedSupplied(() -> OptionalDouble.of(plugin.getSettings().getDefaultValues().getMobDrops())), + Value.syncedSupplied(() -> OptionalInt.of(plugin.getSettings().getDefaultValues().getTeamLimit())), + Value.syncedSupplied(() -> OptionalInt.of(plugin.getSettings().getDefaultValues().getWarpsLimit())), + Value.syncedSupplied(() -> OptionalInt.of(plugin.getSettings().getDefaultValues().getCoopLimit())), + Value.syncedSupplied(() -> OptionalInt.of(plugin.getSettings().getDefaultValues().getIslandSize())), Value.syncedSupplied(() -> (KeyMap) plugin.getSettings().getDefaultValues().getBlockLimits()), Value.syncedSupplied(() -> (KeyMap) plugin.getSettings().getDefaultValues().getEntityLimits()), Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getRealGeneratorsMap()), Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getIslandEffects()), - Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getBankLimit()), + Value.syncedSupplied(() -> Optional.of(plugin.getSettings().getDefaultValues().getBankLimit())), Value.syncedSupplied(() -> plugin.getSettings().getDefaultValues().getRoleLimitsAsView()) ); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java index 24eb5dc370..0f3b028794 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgrade.java @@ -5,18 +5,18 @@ import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.collections.view.EmptyInt2IntMapView; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; -import com.bgsoftware.superiorskyblock.core.value.DoubleValue; -import com.bgsoftware.superiorskyblock.core.value.IntValue; import com.bgsoftware.superiorskyblock.core.value.Value; import com.bgsoftware.superiorskyblock.island.upgrade.cost.EmptyUpgradeCost; -import java.math.BigDecimal; import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Objects; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.OptionalInt; import java.util.Set; public class SUpgrade implements Upgrade { @@ -26,18 +26,18 @@ public class SUpgrade implements Upgrade { Collections.emptyList(), "", Collections.emptySet(), - DoubleValue.syncedFixed(-1D), - DoubleValue.syncedFixed(-1D), - DoubleValue.syncedFixed(-1D), - IntValue.syncedFixed(-1), - IntValue.syncedFixed(-1), - IntValue.syncedFixed(-1), - IntValue.syncedFixed(-1), + Value.syncedFixed(OptionalDouble.empty()), + Value.syncedFixed(OptionalDouble.empty()), + Value.syncedFixed(OptionalDouble.empty()), + Value.syncedFixed(OptionalInt.empty()), + Value.syncedFixed(OptionalInt.empty()), + Value.syncedFixed(OptionalInt.empty()), + Value.syncedFixed(OptionalInt.empty()), Value.syncedFixed(KeyMaps.createEmptyMap()), Value.syncedFixed(KeyMaps.createEmptyMap()), Value.syncedFixed(new EnumerateMap<>(Collections.emptyList())), Value.syncedFixed(Collections.emptyMap()), - Value.syncedFixed(new BigDecimal(-2)), + Value.syncedFixed(Optional.empty()), Value.syncedFixed(EmptyInt2IntMapView.INSTANCE)); private final String name; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java index 68188e4ddb..ee758ba902 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java @@ -35,6 +35,9 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.OptionalInt; import java.util.Set; import java.util.stream.Collectors; @@ -53,29 +56,29 @@ protected PlaceholdersService create() { private final List commands; private final String permission; private final Set requirements; - private final DoubleValue cropGrowth; - private final DoubleValue spawnerRates; - private final DoubleValue mobDrops; - private final IntValue teamLimit; - private final IntValue warpsLimit; - private final IntValue coopLimit; - private final IntValue borderSize; + private final Value cropGrowth; + private final Value spawnerRates; + private final Value mobDrops; + private final Value teamLimit; + private final Value warpsLimit; + private final Value coopLimit; + private final Value borderSize; private final Value> blockLimits; private final Value> entityLimits; private final Value>> generatorRates; private final Value> islandEffects; - private final Value bankLimit; + private final Value> bankLimit; private final Value roleLimits; @Nullable private ItemData itemData; public SUpgradeLevel(int level, UpgradeCost cost, List commands, String permission, Set requirements, - DoubleValue cropGrowth, DoubleValue spawnerRates, DoubleValue mobDrops, - IntValue teamLimit, IntValue warpsLimit, IntValue coopLimit, - IntValue borderSize, Value> blockLimits, + Value cropGrowth, Value spawnerRates, Value mobDrops, + Value teamLimit, Value warpsLimit, Value coopLimit, + Value borderSize, Value> blockLimits, Value> entityLimits, Value>> generatorRates, - Value> islandEffects, Value bankLimit, + Value> islandEffects, Value> bankLimit, Value roleLimits) { this.level = level; this.cost = cost; @@ -143,19 +146,34 @@ public String checkRequirements(SuperiorPlayer superiorPlayer) { return ""; } + @Override + public boolean hasCropGrowth() { + return cropGrowth.get().isPresent(); + } + @Override public double getCropGrowth() { - return cropGrowth.get(); + return cropGrowth.get().orElse(-1D); + } + + @Override + public boolean hasSpawnerRates() { + return spawnerRates.get().isPresent(); } @Override public double getSpawnerRates() { - return spawnerRates.get(); + return spawnerRates.get().orElse(-1D); + } + + @Override + public boolean hasMobDrops() { + return mobDrops.get().isPresent(); } @Override public double getMobDrops() { - return mobDrops.get(); + return mobDrops.get().orElse(-1D); } @Override @@ -192,24 +210,44 @@ public Map getEntityLimitsAsKeys() { return Collections.unmodifiableMap(entityLimits.get()); } + @Override + public boolean hasTeamLimit() { + return teamLimit.get().isPresent(); + } + @Override public int getTeamLimit() { - return teamLimit.get(); + return teamLimit.get().orElse(-1); + } + + @Override + public boolean hasWarpsLimit() { + return warpsLimit.get().isPresent(); } @Override public int getWarpsLimit() { - return warpsLimit.get(); + return warpsLimit.get().orElse(-1); + } + + @Override + public boolean hasCoopLimit() { + return coopLimit.get().isPresent(); } @Override public int getCoopLimit() { - return coopLimit.get(); + return coopLimit.get().orElse(-1); + } + + @Override + public boolean hasBorderSize() { + return borderSize.get().isPresent(); } @Override public int getBorderSize() { - return borderSize.get(); + return borderSize.get().orElse(-1); } @Override @@ -252,9 +290,14 @@ public Map getPotionEffects() { return Collections.unmodifiableMap(islandEffects.get()); } + @Override + public boolean hasBankLimit() { + return bankLimit.get().isPresent(); + } + @Override public BigDecimal getBankLimit() { - return bankLimit.get(); + return bankLimit.get().orElseGet(() -> BigDecimal.valueOf(-1)); } @Override @@ -284,15 +327,15 @@ public Map getRoleLimits() { } public DoubleValue getCropGrowthUpgradeValue() { - return cropGrowth; + return DoubleValue.syncedSupplied(() -> cropGrowth.get().orElse(-1)); } public DoubleValue getSpawnerRatesUpgradeValue() { - return spawnerRates; + return DoubleValue.syncedSupplied(() -> spawnerRates.get().orElse(-1)); } public DoubleValue getMobDropsUpgradeValue() { - return mobDrops; + return DoubleValue.syncedSupplied(() -> mobDrops.get().orElse(-1)); } public Map getBlockLimitsUpgradeValue() { @@ -310,19 +353,19 @@ public Map getEntityLimitsUpgradeValue() { } public IntValue getTeamLimitUpgradeValue() { - return teamLimit; + return IntValue.syncedSupplied(() -> teamLimit.get().orElse(-1)); } public IntValue getWarpsLimitUpgradeValue() { - return warpsLimit; + return IntValue.syncedSupplied(() -> warpsLimit.get().orElse(-1)); } public IntValue getCoopLimitUpgradeValue() { - return coopLimit; + return IntValue.syncedSupplied(() -> coopLimit.get().orElse(-1)); } public IntValue getBorderSizeUpgradeValue() { - return borderSize; + return IntValue.syncedSupplied(() -> borderSize.get().orElse(-1)); } public EnumerateMap> getGeneratorUpgradeValue() { @@ -351,7 +394,7 @@ public Map getPotionEffectsUpgradeValue() { } public Value getBankLimitUpgradeValue() { - return bankLimit; + return Value.syncedSupplied(() -> bankLimit.get().orElseGet(() -> BigDecimal.valueOf(-1))); } public Map getRoleLimitsUpgradeValue() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java index d8e94536e8..4fd727dcd8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java @@ -18,8 +18,6 @@ import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; -import com.bgsoftware.superiorskyblock.core.value.DoubleValue; -import com.bgsoftware.superiorskyblock.core.value.IntValue; import com.bgsoftware.superiorskyblock.core.value.Value; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgrade; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; @@ -52,6 +50,9 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; +import java.util.OptionalDouble; +import java.util.OptionalInt; import java.util.Set; import java.util.stream.Collectors; @@ -257,20 +258,20 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade requirements.add(new UpgradeRequirement(sections[0], Formatters.COLOR_FORMATTER.format(sections[1]))); } - DoubleValue cropGrowth = DoubleValue.syncedFixed(levelSection.getDouble("crop-growth", -1D)); - DoubleValue spawnerRates = DoubleValue.syncedFixed(levelSection.getDouble("spawner-rates", -1D)); - DoubleValue mobDrops = DoubleValue.syncedFixed(levelSection.getDouble("mob-drops", -1D)); - IntValue teamLimit = IntValue.syncedFixed(levelSection.getInt("team-limit", -1)); - IntValue warpsLimit = IntValue.syncedFixed(levelSection.getInt("warps-limit", -1)); - IntValue coopLimit = IntValue.syncedFixed(levelSection.getInt("coop-limit", -1)); - IntValue borderSize = IntValue.syncedFixed(levelSection.getInt("border-size", -1)); + Value cropGrowth = Value.syncedFixed(readDouble(levelSection, "crop-growth")); + Value spawnerRates = Value.syncedFixed(readDouble(levelSection, "spawner-rates")); + Value mobDrops = Value.syncedFixed(readDouble(levelSection, "mob-drops")); + Value teamLimit = Value.syncedFixed(readInt(levelSection, "team-limit")); + Value warpsLimit = Value.syncedFixed(readInt(levelSection, "warps-limit")); + Value coopLimit = Value.syncedFixed(readInt(levelSection, "coop-limit")); + Value borderSize = Value.syncedFixed(readInt(levelSection, "border-size")); - if (borderSize.get() > plugin.getSettings().getMaxIslandSize()) { + if (borderSize.get().orElse(-1) > plugin.getSettings().getMaxIslandSize()) { this.logger().w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has illegal border-size, skipping..."); return; } - Value bankLimit = Value.syncedFixed(new BigDecimal(levelSection.getString("bank-limit", "-1"))); + Value> bankLimit = Value.syncedFixed(readString(levelSection, "bank-limit").map(BigDecimal::new)); KeyMap blockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); if (levelSection.isConfigurationSection("block-limits")) { for (String block : levelSection.getConfigurationSection("block-limits").getKeys(false)) { @@ -325,4 +326,25 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade upgrade.addUpgradeLevel(level, upgradeLevel); } + private static OptionalDouble readDouble(ConfigurationSection section, String key) { + if (section.contains(key)) + return OptionalDouble.of(section.getDouble(key)); + + return OptionalDouble.empty(); + } + + private static OptionalInt readInt(ConfigurationSection section, String key) { + if (section.contains(key)) + return OptionalInt.of(section.getInt(key)); + + return OptionalInt.empty(); + } + + private static Optional readString(ConfigurationSection section, String key) { + if (section.contains(key)) + return Optional.of(section.getString(key)); + + return Optional.empty(); + } + } From d6f06a39801614fe3a71cc06960a074608f1abe2 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 21 Feb 2026 16:53:24 +0100 Subject: [PATCH 507/600] Improve ClearActions (#2840) * Improve ClearActions * Fix updating island fly * Moved clear actions on join --- .../commands/admin/CmdAdminAdd.java | 6 -- .../commands/admin/CmdAdminJoin.java | 6 -- .../commands/player/CmdAccept.java | 6 -- .../superiorskyblock/island/SIsland.java | 100 ++++++++++-------- .../player/inventory/ClearActions.java | 23 ++-- 5 files changed, 66 insertions(+), 75 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java index 89673fa42e..357e97392f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminAdd.java @@ -12,7 +12,6 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; -import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import org.bukkit.command.CommandSender; import java.util.Collections; @@ -89,11 +88,6 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab Message.JOINED_ISLAND.send(targetPlayer, superiorPlayer.getName()); Message.ADMIN_ADD_PLAYER.send(sender, targetPlayer.getName(), superiorPlayer.getName()); } - - if (plugin.getSettings().isTeleportOnJoin() && targetPlayer.isOnline()) - targetPlayer.teleport(island); - - ClearActions.runClearActions(targetPlayer.asOfflinePlayer(), false, plugin.getSettings().getClearActionsOnJoin()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java index d8275d4f91..22e0e0c7c5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminJoin.java @@ -10,7 +10,6 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; -import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import org.bukkit.command.CommandSender; import java.util.Collections; @@ -80,11 +79,6 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab Message.JOINED_ISLAND_NAME.send(superiorPlayer, island.getName()); else Message.JOINED_ISLAND.send(superiorPlayer, targetPlayer.getName()); - - if (plugin.getSettings().isTeleportOnJoin()) - superiorPlayer.teleport(island); - - ClearActions.runClearActions(superiorPlayer.asOfflinePlayer(), false, plugin.getSettings().getClearActionsOnJoin()); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java index 56bd53567a..208189e733 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAccept.java @@ -10,7 +10,6 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; -import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import org.bukkit.command.CommandSender; import java.util.Arrays; @@ -100,11 +99,6 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, String[ Message.JOINED_ISLAND_NAME.send(superiorPlayer, island.getName()); else Message.JOINED_ISLAND.send(superiorPlayer, targetPlayer.getName()); - - if (plugin.getSettings().isTeleportOnJoin()) - superiorPlayer.teleport(island); - - ClearActions.runClearActions(superiorPlayer.asOfflinePlayer(), false, plugin.getSettings().getClearActionsOnJoin()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 52812aa9fa..c7ab1a8e2b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -577,6 +577,9 @@ public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) { updateLastTime(); + ClearActions.runClearActions(superiorPlayer, plugin.getSettings().getClearActionsOnJoin(), + plugin.getSettings().isTeleportOnJoin() ? this : null); + if (superiorPlayer.isOnline()) { updateIslandFly(superiorPlayer); setCurrentlyActive(); @@ -586,35 +589,53 @@ public void addMember(SuperiorPlayer superiorPlayer, PlayerRole playerRole) { } @Override - public void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason memberRemoveReason) { + public void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason reason) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer parameter cannot be null."); - Preconditions.checkNotNull(memberRemoveReason, "memberRemoveReason parameter cannot be null."); + Preconditions.checkNotNull(reason, "memberRemoveReason parameter cannot be null."); + Preconditions.checkArgument(!superiorPlayer.equals(owner), "superiorPlayer cannot be island owner."); + + removeMemberSafe(superiorPlayer, reason); + } - if (memberRemoveReason == MemberRemoveReason.KICK) { + private void removeMemberSafe(SuperiorPlayer superiorPlayer, MemberRemoveReason reason) { + if (reason == MemberRemoveReason.KICK) Log.debug(Debug.KICK_MEMBER, owner.getName(), superiorPlayer.getName()); - } else if (memberRemoveReason == MemberRemoveReason.LEAVE) { + else if (reason == MemberRemoveReason.LEAVE) Log.debug(Debug.LEAVE_ISLAND, owner.getName(), superiorPlayer.getName()); - } - boolean removedMember = members.writeAndGet(members -> members.remove(superiorPlayer)); + if (!superiorPlayer.equals(owner)) { + boolean removedMember = members.writeAndGet(members -> members.remove(superiorPlayer)); - if (!removedMember) { - // If the remove method failed, we iterate through all the members and remove the member manually. - // Should fix issues if members are not in the correct order. - // Reference: https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/734 - removedMember = members.writeAndGet(members -> members.removeIf(superiorPlayer::equals)); - } + if (!removedMember) { + // If the remove method failed, we iterate through all the members and remove the member manually. + // Should fix issues if members are not in the correct order. + // Reference: https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/734 + removedMember = members.writeAndGet(members -> members.removeIf(superiorPlayer::equals)); + } - // This player is not a member of the island. - if (!removedMember) - return; + // This player is not a member of the island. + if (!removedMember) + return; + } + boolean isInside = superiorPlayer.isInsideIsland(); superiorPlayer.setIsland(null); - if (memberRemoveReason == MemberRemoveReason.KICK) { - ClearActions.runClearActions(superiorPlayer.asOfflinePlayer(), false, plugin.getSettings().getClearActionsOnKick()); - } else if (memberRemoveReason == MemberRemoveReason.LEAVE) { - ClearActions.runClearActions(superiorPlayer.asOfflinePlayer(), false, plugin.getSettings().getClearActionsOnLeave()); + if (reason == MemberRemoveReason.DISBAND) { + ClearActions.runClearActions(superiorPlayer, plugin.getSettings().getClearActionsOnDisband(), + isInside ? plugin.getGrid().getSpawnIsland() : null); + } else if (reason == MemberRemoveReason.KICK) { + boolean shouldTeleport = plugin.getSettings().isTeleportOnKick() && isInside; + ClearActions.runClearActions(superiorPlayer, plugin.getSettings().getClearActionsOnKick(), + shouldTeleport ? plugin.getGrid().getSpawnIsland() : null); + if (!shouldTeleport) + updateIslandFly(superiorPlayer); + } else if (reason == MemberRemoveReason.LEAVE) { + boolean shouldTeleport = plugin.getSettings().isTeleportOnLeave() && isInside; + ClearActions.runClearActions(superiorPlayer, plugin.getSettings().getClearActionsOnLeave(), + shouldTeleport ? plugin.getGrid().getSpawnIsland() : null); + if (!shouldTeleport) + updateIslandFly(superiorPlayer); } superiorPlayer.runIfOnline(player -> { @@ -622,28 +643,26 @@ public void removeMember(SuperiorPlayer superiorPlayer, MemberRemoveReason membe if (openedView != null) openedView.closeView(); - - boolean shouldTeleport = (memberRemoveReason == MemberRemoveReason.KICK && plugin.getSettings().isTeleportOnKick()) || - (memberRemoveReason == MemberRemoveReason.LEAVE && plugin.getSettings().isTeleportOnLeave()); - - if (shouldTeleport && getAllPlayersInside().contains(superiorPlayer)) { - superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); - } else { - updateIslandFly(superiorPlayer); - } }); plugin.getMissions().getPlayerMissions().forEach(mission -> { MissionData missionData = plugin.getMissions().getMissionData(mission).orElse(null); - if (missionData != null && missionData.isLeaveReset()) + + if (missionData == null) + return; + + if ((reason == MemberRemoveReason.DISBAND && missionData.isDisbandReset()) || + ((reason == MemberRemoveReason.KICK || reason == MemberRemoveReason.LEAVE) && missionData.isLeaveReset())) superiorPlayer.resetMission(mission); }); - plugin.getMenus().destroyMemberManage(superiorPlayer); - plugin.getMenus().destroyMemberRole(superiorPlayer); - plugin.getMenus().refreshMembers(this); + if (reason == MemberRemoveReason.KICK || reason == MemberRemoveReason.LEAVE) { + plugin.getMenus().destroyMemberManage(superiorPlayer); + plugin.getMenus().destroyMemberRole(superiorPlayer); + plugin.getMenus().refreshMembers(this); - IslandsDatabaseBridge.removeMember(this, superiorPlayer); + IslandsDatabaseBridge.removeMember(this, superiorPlayer); + } } @Override @@ -1735,20 +1754,7 @@ public void disbandIsland() { long profilerId = Profiler.start(ProfileType.DISBAND_ISLAND, 2); forEachIslandMember(EMPTY_IGNORED_MEMBERS, false, islandMember -> { - if (islandMember.equals(owner)) { - owner.setIsland(null); - } else { - removeMember(islandMember, MemberRemoveReason.DISBAND); - } - - ClearActions.runClearActions(islandMember.asOfflinePlayer(), true, plugin.getSettings().getClearActionsOnDisband()); - - for (Mission mission : plugin.getMissions().getPlayerMissions()) { - MissionData missionData = plugin.getMissions().getMissionData(mission).orElse(null); - if (missionData != null && missionData.isDisbandReset()) { - islandMember.resetMission(mission); - } - } + removeMemberSafe(islandMember, MemberRemoveReason.DISBAND); }); this.activeTasks.write(activeTasks -> { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java b/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java index 2183da9eb5..6e60bff589 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java @@ -1,12 +1,11 @@ package com.bgsoftware.superiorskyblock.player.inventory; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; -import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; -import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.bgsoftware.superiorskyblock.world.EntityTeleports; -import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffect; @@ -82,7 +81,12 @@ public static void registerActions() { // Do nothing, only trigger all the register calls } - public static void runClearActions(OfflinePlayer offlinePlayer, boolean teleportToSpawn, Collection clearActions) { + public static void runClearActions(SuperiorPlayer superiorPlayer, Collection clearActions, + @Nullable Island islandToTeleport) { + if (clearActions.isEmpty() && islandToTeleport == null) + return; + + OfflinePlayer offlinePlayer = superiorPlayer.asOfflinePlayer(); OfflinePlayerData offlinePlayerData; Player onlinePlayer; @@ -97,13 +101,12 @@ public static void runClearActions(OfflinePlayer offlinePlayer, boolean teleport try { clearActions.forEach(clearAction -> clearAction.doClear(onlinePlayer)); - Location spawnLocation = plugin.getGrid().getSpawnIsland().getCenter(Dimensions.NORMAL); if (offlinePlayerData != null) { - if (teleportToSpawn) - offlinePlayerData.setLocation(spawnLocation); + if (islandToTeleport != null) + offlinePlayerData.setLocation(islandToTeleport.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension())); offlinePlayerData.applyChanges(); - } else if (teleportToSpawn) { - EntityTeleports.teleport(onlinePlayer, spawnLocation); + } else if (islandToTeleport != null) { + superiorPlayer.teleport(islandToTeleport); } } finally { if (offlinePlayerData != null) From c3318ebb3da326684356f286f018552b745bcf1f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Feb 2026 20:48:40 +0200 Subject: [PATCH 508/600] [CI SKIP] Configure claude --- .github/workflows/claude.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 .github/workflows/claude.yml diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml new file mode 100644 index 0000000000..7483698fcd --- /dev/null +++ b/.github/workflows/claude.yml @@ -0,0 +1,18 @@ +name: Claude Issue Fixer +on: + issues: + types: [opened, edited] + issue_comment: + types: [created] + +jobs: + claude-fix: + if: contains(github.event.issue.labels.*.name, 'bug') || contains(github.event.comment.body, '@claude') + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run Claude Fixer + uses: anthropics/claude-code-action-official@v1 + with: + anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} + command: "fix-issue ${{ github.event.issue.number }}" \ No newline at end of file From 296d1d837581648ceb08cd2e6acd8ed2ca254bd9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Feb 2026 21:01:16 +0200 Subject: [PATCH 509/600] [CI SKIP] Configure claude --- .github/workflows/claude.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 7483698fcd..3a0bf69e6c 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run Claude Fixer - uses: anthropics/claude-code-action-official@v1 + uses: anthropics/claude-code-action@v1 with: anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} command: "fix-issue ${{ github.event.issue.number }}" \ No newline at end of file From c1ee0be90211a543703373efed4636ecee0d88b8 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Feb 2026 21:15:34 +0200 Subject: [PATCH 510/600] [CI SKIP] Configure claude --- .github/workflows/claude.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 3a0bf69e6c..2505c6039c 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -9,6 +9,11 @@ jobs: claude-fix: if: contains(github.event.issue.labels.*.name, 'bug') || contains(github.event.comment.body, '@claude') runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + issues: write + id-token: write steps: - uses: actions/checkout@v4 - name: Run Claude Fixer From 80c232568ecd216e37d6391e535b15b8c547d0fa Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Feb 2026 21:22:42 +0200 Subject: [PATCH 511/600] [CI SKIP] Configure claude --- .github/workflows/claude.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 2505c6039c..dec1c770e7 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -19,5 +19,5 @@ jobs: - name: Run Claude Fixer uses: anthropics/claude-code-action@v1 with: - anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }} + anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} command: "fix-issue ${{ github.event.issue.number }}" \ No newline at end of file From ba9f81eb1a5049389349d76cc50e93848d3f905f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Feb 2026 21:27:32 +0200 Subject: [PATCH 512/600] [CI SKIP] Configure claude --- .github/workflows/claude.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index dec1c770e7..4e5424e52b 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run Claude Fixer - uses: anthropics/claude-code-action@v1 + uses: anthropics/claude-code-action@01e756b with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} command: "fix-issue ${{ github.event.issue.number }}" \ No newline at end of file From 01bf9c45348c6b71358bb6000e604cec9b72e2c9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Feb 2026 21:28:36 +0200 Subject: [PATCH 513/600] [CI SKIP] Configure claude --- .github/workflows/claude.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 4e5424e52b..021804c13f 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run Claude Fixer - uses: anthropics/claude-code-action@01e756b + uses: anthropics/claude-code-action@01e756b34ef7a1447e9508f674143b07d20c2631 with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} command: "fix-issue ${{ github.event.issue.number }}" \ No newline at end of file From 5bc98a637216d72bbe819927eec3f78a189a0eb9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Feb 2026 21:32:38 +0200 Subject: [PATCH 514/600] [CI SKIP] Configure claude --- .github/workflows/claude.yml | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 021804c13f..3e42e130de 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -16,8 +16,11 @@ jobs: id-token: write steps: - uses: actions/checkout@v4 - - name: Run Claude Fixer - uses: anthropics/claude-code-action@01e756b34ef7a1447e9508f674143b07d20c2631 - with: - anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - command: "fix-issue ${{ github.event.issue.number }}" \ No newline at end of file + - name: Install Claude CLI + run: npm install -g @anthropic-ai/claude-code + - name: Run Claude Fix + env: + ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + claude --non-interactive "Analyze the following issue comment and provide a fix in a new branch with a PR: ${{ github.event.comment.body }}" \ No newline at end of file From b5d4899f954bcaf3cc47c48d495a706af08cc819 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Feb 2026 21:34:59 +0200 Subject: [PATCH 515/600] [CI SKIP] Configure claude --- .github/workflows/claude.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 3e42e130de..b407e806d4 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -23,4 +23,4 @@ jobs: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - claude --non-interactive "Analyze the following issue comment and provide a fix in a new branch with a PR: ${{ github.event.comment.body }}" \ No newline at end of file + claude -p "Analyze the following issue comment and provide a fix in a new branch with a PR: ${{ github.event.comment.body }}" --dangerously-skip-permissions \ No newline at end of file From 1f0716fc8c6d5875a606de632db0b124dff1253a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 23 Feb 2026 21:47:44 +0200 Subject: [PATCH 516/600] Fix players without islands being treated as same team in PvP (#2878) When both players have no island, getIsland() returns null for both, causing null == null to evaluate to true and incorrectly blocking PvP between unrelated players. Add a null check so that players without islands are never considered teammates. Fixes #2873 Co-authored-by: Claude Co-authored-by: Claude Sonnet 4.6 --- .../bgsoftware/superiorskyblock/player/SSuperiorPlayer.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index dde361be99..b8cdc3f096 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -407,7 +407,8 @@ public HitActionResult canHit(SuperiorPlayer otherPlayer) { World world = getWorld(); // Checks for island teammates pvp - if (getIsland() == otherPlayer.getIsland() && (world == null || !isPvPWorldInternal(world.getName()))) + Island island = getIsland(); + if (island != null && island == otherPlayer.getIsland() && (world == null || !isPvPWorldInternal(world.getName()))) return HitActionResult.ISLAND_TEAM_PVP; // Checks if this player can bypass all pvp restrictions From 005cb039ba587af3c9648f2e05fbd0726b934861 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Feb 2026 21:51:38 +0200 Subject: [PATCH 517/600] [CI SKIP] Configure claude --- .claudeignore | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .claudeignore diff --git a/.claudeignore b/.claudeignore new file mode 100644 index 0000000000..c12cf215ee --- /dev/null +++ b/.claudeignore @@ -0,0 +1,5 @@ +gradle/ +.git/ +.github/ +*.jar +*.class From 4a06209e59cb053a31e3edd44cbbdf447d3a854a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Feb 2026 22:30:12 +0200 Subject: [PATCH 518/600] [CI SKIP] Configure claude --- .github/workflows/claude.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index b407e806d4..b799ee3d37 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -23,4 +23,4 @@ jobs: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - claude -p "Analyze the following issue comment and provide a fix in a new branch with a PR: ${{ github.event.comment.body }}" --dangerously-skip-permissions \ No newline at end of file + claude -p --dangerously-skip-permissions --max-turns 5 "Analyze the following issue comment and provide a fix in a new branch with a PR: ${{ github.event.comment.body }}" \ No newline at end of file From 12bbc96ed9b5471aac68b1f23d65709e10ca6997 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Feb 2026 23:48:59 +0200 Subject: [PATCH 519/600] [CI SKIP] Configure gemini --- .github/workflows/claude.yml | 26 -------------------------- .github/workflows/gemini.yml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 26 deletions(-) delete mode 100644 .github/workflows/claude.yml create mode 100644 .github/workflows/gemini.yml diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml deleted file mode 100644 index b799ee3d37..0000000000 --- a/.github/workflows/claude.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Claude Issue Fixer -on: - issues: - types: [opened, edited] - issue_comment: - types: [created] - -jobs: - claude-fix: - if: contains(github.event.issue.labels.*.name, 'bug') || contains(github.event.comment.body, '@claude') - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - issues: write - id-token: write - steps: - - uses: actions/checkout@v4 - - name: Install Claude CLI - run: npm install -g @anthropic-ai/claude-code - - name: Run Claude Fix - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - claude -p --dangerously-skip-permissions --max-turns 5 "Analyze the following issue comment and provide a fix in a new branch with a PR: ${{ github.event.comment.body }}" \ No newline at end of file diff --git a/.github/workflows/gemini.yml b/.github/workflows/gemini.yml new file mode 100644 index 0000000000..31560c25e8 --- /dev/null +++ b/.github/workflows/gemini.yml @@ -0,0 +1,32 @@ +name: Gemini Issue Fixer +on: + issues: + types: [opened, edited] + issue_comment: + types: [created] + +jobs: + gemini-fix: + if: contains(github.event.issue.labels.*.name, 'bug') || contains(github.event.comment.body, '@gemini') + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + issues: write + id-token: write + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Install Aider (The Agent Engine) + run: | + python -m pip install --upgrade pip + pip install aider-chat + - name: Run Gemini Fix + env: + GEMINI_API_KEY: ${{ secrets.GOOGLE_API_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + aider --model gemini/gemini-1.5-flash-latest --yes-create-pr --no-auto-commits --message "Analyze the following issue and provide a fix in a new branch with a PR. Title: ${{ github.event.issue.title }} Description: ${{ github.event.issue.body }}" \ No newline at end of file From c996480780b4da95e0b29cb64efd03f1d4d5cf80 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 23 Feb 2026 23:54:45 +0200 Subject: [PATCH 520/600] [CI SKIP] Configure gemini --- .github/workflows/gemini.yml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/gemini.yml b/.github/workflows/gemini.yml index 31560c25e8..2dfc1bbe76 100644 --- a/.github/workflows/gemini.yml +++ b/.github/workflows/gemini.yml @@ -29,4 +29,21 @@ jobs: GEMINI_API_KEY: ${{ secrets.GOOGLE_API_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - aider --model gemini/gemini-1.5-flash-latest --yes-create-pr --no-auto-commits --message "Analyze the following issue and provide a fix in a new branch with a PR. Title: ${{ github.event.issue.title }} Description: ${{ github.event.issue.body }}" \ No newline at end of file + git config --global user.name "Gemini AI" + git config --global user.email "gemini-ai@github.com" + + BRANCH_NAME="bugfix/issue-${{ github.event.issue.number }}" + git checkout -b "$BRANCH_NAME" + + aider --model gemini/gemini-1.5-flash-latest \ + --yes \ + --no-auto-commits \ + --message "Analyze the following issue and provide a fix in a new branch with a PR. Title: ${{ github.event.issue.title }} Description: ${{ github.event.issue.body }}" + + git push origin "$BRANCH_NAME" + + gh pr create \ + --title "Fix: ${{ github.event.issue.title }}" \ + --body "Automated fix for #${{ github.event.issue.number }} generated by Gemini." \ + --base dev \ + --head "$BRANCH_NAME" \ No newline at end of file From 699401820657f1a3cb0e78029dc574c907f666d7 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 24 Feb 2026 00:00:44 +0200 Subject: [PATCH 521/600] [CI SKIP] Configure gemini --- .github/workflows/gemini.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gemini.yml b/.github/workflows/gemini.yml index 2dfc1bbe76..2934ae6c33 100644 --- a/.github/workflows/gemini.yml +++ b/.github/workflows/gemini.yml @@ -35,7 +35,7 @@ jobs: BRANCH_NAME="bugfix/issue-${{ github.event.issue.number }}" git checkout -b "$BRANCH_NAME" - aider --model gemini/gemini-1.5-flash-latest \ + aider --model gemini/gemini-3-flash \ --yes \ --no-auto-commits \ --message "Analyze the following issue and provide a fix in a new branch with a PR. Title: ${{ github.event.issue.title }} Description: ${{ github.event.issue.body }}" From a62015e191ce4ff443cb21dd758a198fdd0c7fb2 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 24 Feb 2026 00:03:05 +0200 Subject: [PATCH 522/600] [CI SKIP] Configure gemini --- .github/workflows/gemini.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gemini.yml b/.github/workflows/gemini.yml index 2934ae6c33..4ce59ca4d6 100644 --- a/.github/workflows/gemini.yml +++ b/.github/workflows/gemini.yml @@ -35,7 +35,7 @@ jobs: BRANCH_NAME="bugfix/issue-${{ github.event.issue.number }}" git checkout -b "$BRANCH_NAME" - aider --model gemini/gemini-3-flash \ + aider --model gemini/gemini-3-flash-preview \ --yes \ --no-auto-commits \ --message "Analyze the following issue and provide a fix in a new branch with a PR. Title: ${{ github.event.issue.title }} Description: ${{ github.event.issue.body }}" From 7d9f656aa0c6079f3f304174f0cba645777b341e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 24 Feb 2026 00:11:40 +0200 Subject: [PATCH 523/600] [CI SKIP] Configure gemini --- .github/workflows/gemini.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gemini.yml b/.github/workflows/gemini.yml index 4ce59ca4d6..012d4ce1a8 100644 --- a/.github/workflows/gemini.yml +++ b/.github/workflows/gemini.yml @@ -37,8 +37,8 @@ jobs: aider --model gemini/gemini-3-flash-preview \ --yes \ - --no-auto-commits \ - --message "Analyze the following issue and provide a fix in a new branch with a PR. Title: ${{ github.event.issue.title }} Description: ${{ github.event.issue.body }}" + --commit \ + --message "Analyze the following issue and provide a fix in a new branch with a PR. Make changes to the source code and commit the changes to the branch $$BRANCH_NAME. Title: ${{ github.event.issue.title }} Description: ${{ github.event.issue.body }}" git push origin "$BRANCH_NAME" From 668174cce9d802e15cb5b5acba1d69689e369840 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 26 Feb 2026 20:45:09 +0200 Subject: [PATCH 524/600] Fixed typo in message warning about corrupted islands settings tables --- .../bgsoftware/superiorskyblock/core/database/DataManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java index e11958e309..4941b93eaf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java @@ -300,7 +300,7 @@ private void checkCorruptedIslandRecord(DatabaseCache.Record isl } if (!hasIslandsSettings) { - Log.warn("The island " + island.getUniqueId() + " does not have a islands_banks record - fixing it..."); + Log.warn("The island " + island.getUniqueId() + " does not have a islands_settings record - fixing it..."); IslandsDatabaseBridge.insertIslandSettings(island); } } From 071f615c00b68f73e4a287e722c614f7ad58e196 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 26 Feb 2026 20:57:27 +0200 Subject: [PATCH 525/600] Fixed loading of island visitors and ratings from database (#2880) --- .../serialization/IslandsDeserializer.java | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java index 1f3b1f2c1c..7f8cd91a0f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java @@ -112,21 +112,21 @@ public static void deserializeVisitors(DatabaseBridge databaseBridge, DatabaseCa databaseBridge.loadAllObjects("islands_visitors", visitorsRow -> { DatabaseResult visitors = new DatabaseResult(visitorsRow); - Optional islandUUID = visitors.getUUID("island"); - if (!islandUUID.isPresent()) { + Optional uuid = visitors.getUUID("island"); + if (!uuid.isPresent()) { Log.warn("Cannot load island visitors for null islands, skipping..."); return; } - Optional uuid = visitors.getUUID("player"); - if (!uuid.isPresent()) { - Log.warn("Cannot load island visitors with invalid uuids for ", islandUUID.get(), ", skipping..."); + Optional playerUUID = visitors.getUUID("player"); + if (!playerUUID.isPresent()) { + Log.warn("Cannot load island visitors with invalid uuids for ", uuid.get(), ", skipping..."); return; } - SuperiorPlayer visitorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid.get(), false); + SuperiorPlayer visitorPlayer = plugin.getPlayers().getSuperiorPlayer(playerUUID.get(), false); if (visitorPlayer == null) { - Log.warn("Cannot load island visitor with unrecognized uuid: " + uuid.get() + ", skipping..."); + Log.warn("Cannot load island visitor with unrecognized uuid: " + playerUUID.get() + ", skipping..."); return; } @@ -369,21 +369,21 @@ public static void deserializeRatings(DatabaseBridge databaseBridge, DatabaseCac databaseBridge.loadAllObjects("islands_ratings", ratingsRow -> { DatabaseResult ratings = new DatabaseResult(ratingsRow); - Optional islandUUID = ratings.getUUID("island"); - if (!islandUUID.isPresent()) { + Optional uuid = ratings.getUUID("island"); + if (!uuid.isPresent()) { Log.warn("Cannot load ratings for null islands, skipping..."); return; } - Optional uuid = ratings.getUUID("player"); - if (!uuid.isPresent()) { - Log.warn("Cannot load ratings with invalid players for ", islandUUID.get(), ", skipping..."); + Optional playerUUID = ratings.getUUID("player"); + if (!playerUUID.isPresent()) { + Log.warn("Cannot load ratings with invalid players for ", uuid.get(), ", skipping..."); return; } - SuperiorPlayer ratingPlayer = plugin.getPlayers().getSuperiorPlayer(uuid.get(), false); + SuperiorPlayer ratingPlayer = plugin.getPlayers().getSuperiorPlayer(playerUUID.get(), false); if (ratingPlayer == null) { - Log.warn("Cannot load island rating with unrecognized uuid: " + uuid.get() + ", skipping..."); + Log.warn("Cannot load island rating with unrecognized uuid: " + playerUUID.get() + ", skipping..."); return; } @@ -395,7 +395,7 @@ public static void deserializeRatings(DatabaseBridge databaseBridge, DatabaseCac } }); if (!rating.isPresent()) { - Log.warn("Cannot load ratings with invalid rating value for ", uuid.get(), ", skipping..."); + Log.warn("Cannot load ratings with invalid rating value for ", playerUUID.get(), ", skipping..."); return; } @@ -705,14 +705,13 @@ public static void deserializeIslandSettings(DatabaseBridge databaseBridge, Data databaseBridge.loadAllObjects("islands_settings", islandSettingsRow -> { DatabaseResult islandSettings = new DatabaseResult(islandSettingsRow); - Optional island = islandSettings.getString("island"); - if (!island.isPresent()) { + Optional uuid = islandSettings.getUUID("island"); + if (!uuid.isPresent()) { Log.warn("Cannot load island settings of null island, skipping "); return; } - UUID uuid = UUID.fromString(island.get()); - Island.Builder builder = lookupIsland(databaseCache, uuid, "islands_settings"); + Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_settings"); builder.setIslandSize(islandSettings.getInt("size").orElse(-1)); builder.setTeamLimit(islandSettings.getInt("members_limit").orElse(-1)); From 993630d954b14ebbb9d7363fcb8a44ac5fa42c32 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 10 Mar 2026 13:06:25 +0200 Subject: [PATCH 526/600] Fixed potential infinite recursive calls when trying to run tasks async when server shuts down (#2886) --- .../external/SkinsRestorerHook.java | 8 +++----- .../external/SkinsRestorer14Hook.java | 8 +++----- .../external/SkinsRestorer15Hook.java | 8 +++----- .../core/threads/BukkitExecutor.java | 20 ++++++++++++++++--- .../core/threads/SynchronizedTasks.java | 9 +++------ .../container/DefaultIslandsContainer.java | 6 +----- .../mission/MissionsManagerImpl.java | 8 ++------ .../impl/CachedSuperiorSchematic.java | 8 +++----- .../schematic/impl/SuperiorSchematic.java | 7 +++---- 9 files changed, 38 insertions(+), 44 deletions(-) diff --git a/Hooks/SkinsRestorer/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorerHook.java b/Hooks/SkinsRestorer/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorerHook.java index e1a4c9fd50..3fd1a1160c 100644 --- a/Hooks/SkinsRestorer/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorerHook.java +++ b/Hooks/SkinsRestorer/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorerHook.java @@ -4,7 +4,6 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.mojang.authlib.properties.Property; -import org.bukkit.Bukkit; import skinsrestorer.bukkit.SkinsRestorer; import skinsrestorer.shared.exception.SkinRequestException; import skinsrestorer.shared.storage.SkinStorage; @@ -20,11 +19,10 @@ public static void register(SuperiorSkyblockPlugin plugin) { } private static void setSkinTexture(SuperiorPlayer superiorPlayer) { - if (Bukkit.isPrimaryThread()) { - BukkitExecutor.async(() -> setSkinTexture(superiorPlayer)); - return; - } + BukkitExecutor.ensureAsync(() -> setSkinTextureInternal(superiorPlayer)); + } + private static void setSkinTextureInternal(SuperiorPlayer superiorPlayer) { Property property = getSkin(superiorPlayer); if (property != null) BukkitExecutor.sync(() -> plugin.getNMSPlayers().setSkinTexture(superiorPlayer, property)); diff --git a/Hooks/SkinsRestorer14/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorer14Hook.java b/Hooks/SkinsRestorer14/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorer14Hook.java index c2e502f9c7..81ae0ff6f0 100644 --- a/Hooks/SkinsRestorer14/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorer14Hook.java +++ b/Hooks/SkinsRestorer14/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorer14Hook.java @@ -10,7 +10,6 @@ import net.skinsrestorer.api.bukkit.events.SkinApplyBukkitEvent; import net.skinsrestorer.api.property.IProperty; import net.skinsrestorer.shared.storage.Config; -import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; @@ -55,11 +54,10 @@ public static void register(SuperiorSkyblockPlugin plugin) { } private static void setSkinTexture(SuperiorPlayer superiorPlayer) { - if (Bukkit.isPrimaryThread()) { - BukkitExecutor.async(() -> setSkinTexture(superiorPlayer)); - return; - } + BukkitExecutor.ensureAsync(() -> setSkinTextureInternal(superiorPlayer)); + } + private static void setSkinTextureInternal(SuperiorPlayer superiorPlayer) { Property property = getSkin(superiorPlayer); if (property != null) BukkitExecutor.sync(() -> plugin.getNMSPlayers().setSkinTexture(superiorPlayer, property)); diff --git a/Hooks/SkinsRestorer15/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorer15Hook.java b/Hooks/SkinsRestorer15/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorer15Hook.java index cb5273195c..3359d60103 100644 --- a/Hooks/SkinsRestorer15/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorer15Hook.java +++ b/Hooks/SkinsRestorer15/src/main/java/com/bgsoftware/superiorskyblock/external/SkinsRestorer15Hook.java @@ -9,7 +9,6 @@ import net.skinsrestorer.api.event.SkinApplyEvent; import net.skinsrestorer.api.exception.DataRequestException; import net.skinsrestorer.api.property.SkinProperty; -import org.bukkit.Bukkit; import org.bukkit.entity.Player; import java.util.function.Consumer; @@ -37,11 +36,10 @@ public static void register(SuperiorSkyblockPlugin plugin) { } private static void setSkinTexture(SuperiorPlayer superiorPlayer) { - if (Bukkit.isPrimaryThread()) { - BukkitExecutor.async(() -> setSkinTexture(superiorPlayer)); - return; - } + BukkitExecutor.ensureAsync(() -> setSkinTextureInternal(superiorPlayer)); + } + private static void setSkinTextureInternal(SuperiorPlayer superiorPlayer) { Property property = getSkin(superiorPlayer); if (property != null) BukkitExecutor.sync(() -> plugin.getNMSPlayers().setSkinTexture(superiorPlayer, property)); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java index 74fc16f1f8..7eb51700ec 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/BukkitExecutor.java @@ -43,6 +43,19 @@ public static BukkitTask ensureMain(Runnable runnable) { } } + @Nullable + public static BukkitTask ensureAsync(Runnable runnable) { + if (ensureNotShudown()) + return null; + + if (state != State.PREPARE_SHUTDOWN && Bukkit.isPrimaryThread()) { + return async(runnable); + } else { + runnable.run(); + return null; + } + } + public static BukkitTask sync(Runnable runnable) { return sync(runnable, 0); } @@ -59,14 +72,15 @@ public static BukkitTask sync(Runnable runnable, long delay) { } } - public static void async(Runnable runnable) { + public static BukkitTask async(Runnable runnable) { if (ensureNotShudown()) - return; + return null; if (state == State.PREPARE_SHUTDOWN) { runnable.run(); + return null; } else { - Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable); + return Bukkit.getScheduler().runTaskAsynchronously(plugin, runnable); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/SynchronizedTasks.java b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/SynchronizedTasks.java index 0674794bf1..22df1c54c8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/threads/SynchronizedTasks.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/threads/SynchronizedTasks.java @@ -1,7 +1,5 @@ package com.bgsoftware.superiorskyblock.core.threads; -import org.bukkit.Bukkit; - import javax.annotation.Nullable; import java.util.concurrent.CountDownLatch; @@ -23,11 +21,10 @@ public void notifyTaskComplete() { } public void waitAllAsync() { - if (Bukkit.isPrimaryThread()) { - BukkitExecutor.async(this::waitAllAsync); - return; - } + BukkitExecutor.ensureAsync(this::waitAllAsyncInternal); + } + private void waitAllAsyncInternal() { if (this.countDownLatch != null) { try { this.countDownLatch.await(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java index 0f6b97bdb8..9950f3547b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/container/DefaultIslandsContainer.java @@ -194,11 +194,7 @@ public void sortIslands(SortingType sortingType, boolean forceSort, @Nullable Ru return; } - if (Bukkit.isPrimaryThread()) { - BukkitExecutor.async(() -> sortIslandsInternal(sortingType, onFinish)); - } else { - sortIslandsInternal(sortingType, onFinish); - } + BukkitExecutor.ensureAsync(() -> sortIslandsInternal(sortingType, onFinish)); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java index 606a396a6a..f2a2868481 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/mission/MissionsManagerImpl.java @@ -267,12 +267,8 @@ public void rewardMission(Mission mission, SuperiorPlayer superiorPlayer, throw new IllegalStateException("Cannot reward island mission " + mission.getName() + " as the player " + superiorPlayer.getName() + " does not have island."); } - if (Bukkit.isPrimaryThread()) { - BukkitExecutor.async(() -> rewardMissionAsyncInternal(mission, missionData, superiorPlayer, - missionsHolder, checkAutoReward, forceReward, result)); - } else { - rewardMissionAsyncInternal(mission, missionData, superiorPlayer, missionsHolder, checkAutoReward, forceReward, result); - } + BukkitExecutor.ensureAsync(() -> rewardMissionAsyncInternal(mission, missionData, superiorPlayer, + missionsHolder, checkAutoReward, forceReward, result)); } private void rewardMissionAsyncInternal(Mission mission, MissionData missionData, SuperiorPlayer superiorPlayer, diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java index 92162c4b7a..25281d9fe0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/CachedSuperiorSchematic.java @@ -18,7 +18,6 @@ import com.bgsoftware.superiorskyblock.world.WorldGenerator; import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.bgsoftware.superiorskyblock.world.schematic.BaseSchematic; -import org.bukkit.Bukkit; import org.bukkit.Location; import java.util.Collections; @@ -60,11 +59,10 @@ public Runnable onTeleportCallback() { @Override public void pasteSchematic(Island island, Location location, Runnable callback, Consumer onFailure) { - if (Bukkit.isPrimaryThread()) { - BukkitExecutor.async(() -> pasteSchematic(island, location, callback, onFailure)); - return; - } + BukkitExecutor.ensureAsync(() -> pasteSchematicInternal(island, location, callback, onFailure)); + } + private void pasteSchematicInternal(Island island, Location location, Runnable callback, Consumer onFailure) { long profiler = Profiler.start(ProfileType.SCHEMATIC_PLACE, getName()); Log.debug(Debug.PASTE_SCHEMATIC, this.name, island.getOwner().getName(), location); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java index 29a9d0d01e..5b23e7596e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/schematic/impl/SuperiorSchematic.java @@ -185,11 +185,10 @@ private SuperiorSchematic(String name, Data data, KeyMap cachedCounts) @Override public void pasteSchematic(Island island, Location location, Runnable callback, Consumer onFailure) { - if (Bukkit.isPrimaryThread()) { - BukkitExecutor.async(() -> pasteSchematic(island, location, callback, onFailure)); - return; - } + BukkitExecutor.ensureAsync(() -> pasteSchematicInternal(island, location, callback, onFailure)); + } + private void pasteSchematicInternal(Island island, Location location, Runnable callback, Consumer onFailure) { long profiler = Profiler.start(ProfileType.SCHEMATIC_PLACE, getName()); Log.debug(Debug.PASTE_SCHEMATIC, this.name, island.getOwner().getName(), location); From a2c902ce55f3606709b8aa36530e171fb5e4ff42 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 10 Mar 2026 13:39:07 +0200 Subject: [PATCH 527/600] Fixed detection of harvesting rooted dirt blocks on other islands (#2885) --- .../com/bgsoftware/superiorskyblock/core/Materials.java | 9 ++++++++- .../service/region/RegionManagerServiceImpl.java | 9 ++++++--- src/main/resources/interactables.yml | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java index c5b8c756b0..4266c0fc50 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java @@ -119,6 +119,10 @@ public static boolean isBed(Material material) { return hasTag(material, Tag.BED); } + public static boolean isHoe(Material material) { + return hasTag(material, Tag.HOE); + } + public static Set getBlocksNonLegacy() { return Collections.unmodifiableSet(BLOCK_NON_LEGACY_MATERIALS); } @@ -177,6 +181,8 @@ private static EnumMap> setupMaterialTags() { materialTags.add(Tag.HARNESS); if (materialName.contains("BED")) materialTags.add(Tag.BED); + if (materialName.contains("_HOE")) + materialTags.add(Tag.HOE); if (!materialTags.isEmpty()) enumMap.put(material, materialTags); @@ -213,7 +219,8 @@ public enum Tag { SPAWN_EGG, CARPET, BED, - HARNESS + HARNESS, + HOE } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index feccbafaac..9522c510f1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -70,6 +70,8 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService private static final Material FARMLAND = EnumHelper.getEnum(Material.class, "FARMLAND", "SOIL"); @Nullable + private static final Material ROOTED_DIRT = EnumHelper.getEnum(Material.class, "ROOTED_DIRT"); + @Nullable private static final Material TURTLE_EGG = EnumHelper.getEnum(Material.class, "TURTLE_EGG"); @Nullable private static final Material SWEET_BERRY_BUSH = EnumHelper.getEnum(Material.class, "SWEET_BERRY_BUSH"); @@ -205,10 +207,11 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc BlockState blockState = block.getState(); EntityType spawnType = usedItem == null ? EntityType.UNKNOWN : BukkitItems.getEntityType(usedItem); Material blockType = block.getType(); + Material usedItemType = usedItem == null ? null : usedItem.getType(); IslandPrivilege islandPrivilege; - if (usedItem != null && Materials.isMinecart(usedItem.getType()) ? Materials.isRail(blockType) : Materials.isBoat(blockType)) { + if (usedItem != null && Materials.isMinecart(usedItemType) ? Materials.isRail(blockType) : Materials.isBoat(blockType)) { islandPrivilege = IslandPrivileges.MINECART_PLACE; } else if (Materials.isChest(blockType)) { islandPrivilege = IslandPrivileges.CHEST_ACCESS; @@ -216,13 +219,13 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc islandPrivilege = IslandPrivileges.PICKUP_LECTERN_BOOK; } else if (blockState instanceof InventoryHolder) { islandPrivilege = IslandPrivileges.USE; - } else if (usedItem != null && blockType == VAULT && (usedItem.getType() == TRIAL_KEY || usedItem.getType() == OMINOUS_TRIAL_KEY)) { + } else if (usedItem != null && blockType == VAULT && (usedItemType == TRIAL_KEY || usedItemType == OMINOUS_TRIAL_KEY)) { islandPrivilege = IslandPrivileges.USE; } else if (blockState instanceof Sign) { islandPrivilege = IslandPrivileges.SIGN_INTERACT; } else if (blockType == Materials.SPAWNER.toBukkitType()) { islandPrivilege = IslandPrivileges.SPAWNER_BREAK; - } else if (blockType == FARMLAND) { + } else if (blockType == FARMLAND || blockType == ROOTED_DIRT || (usedItem != null && Materials.isHoe(usedItemType))) { islandPrivilege = action == Action.PHYSICAL ? IslandPrivileges.FARM_TRAMPING : IslandPrivileges.BUILD; } else if (blockType == TURTLE_EGG) { islandPrivilege = action == Action.PHYSICAL ? IslandPrivileges.TURTLE_EGG_TRAMPING : IslandPrivileges.BUILD; diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index 00734a99a9..2ba655be71 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -282,6 +282,7 @@ interactables: - 'REPEATER' - 'REPEATING_COMMAND_BLOCK' - 'RESPAWN_ANCHOR' + - 'ROOTED_DIRT' - 'SHULKER_BOX' - 'SIGN_POST' - 'SMITHING_TABLE' From 5315d788405268468489dd7f6ecdae4a313ddeeb Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Tue, 10 Mar 2026 12:41:42 +0100 Subject: [PATCH 528/600] Added %superior_island_missions_completed% placeholder (#2883) --- .../service/placeholders/PlaceholdersServiceImpl.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index 7ebdc97e3c..a58c279df4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -253,6 +253,8 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { island.getIslandLevel().toString()) .put("locked", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island.isLocked(), superiorPlayer.getUserLocale())) + .put("missions_completed", (island, superiorPlayer) -> + island.getCompletedMissions().size() + "") .put("name", (island, superiorPlayer) -> island.getName()) .put("name_formatted", (island, superiorPlayer) -> island.getFormattedName()) .put("name_leader", (island, superiorPlayer) -> From df176cf5f9609b9d687a21b13705732c23f06f7b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 10 Mar 2026 16:49:32 +0200 Subject: [PATCH 529/600] Fixed errors with some schematics due to not considering IntArrayTag as a valid tag (#2872) --- src/main/java/com/bgsoftware/superiorskyblock/tag/NBTUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/tag/NBTUtils.java b/src/main/java/com/bgsoftware/superiorskyblock/tag/NBTUtils.java index 8c2cd34404..26804ae347 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/tag/NBTUtils.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/tag/NBTUtils.java @@ -159,6 +159,8 @@ public static Class getTypeClass(int type) { return ListTag.class; case NBTTags.TYPE_COMPOUND: return CompoundTag.class; + case NBTTags.TYPE_INT_ARRAY: + return IntArrayTag.class; case NBTTags.TYPE_BIG_DECIMAL: return BigDecimalTag.class; case NBTTags.TYPE_UUID: From fc774dceccf96f4f9ec11236e54367cab76833a2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 17:06:12 +0200 Subject: [PATCH 530/600] Fix RoseStacker stacked spawners not respecting block limits (#2877) (#2879) --- .../spawners/SpawnersProvider_RoseStacker.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker.java b/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker.java index fda745777b..97a2613874 100644 --- a/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker.java +++ b/Hooks/RoseStacker/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker.java @@ -3,6 +3,7 @@ import com.bgsoftware.common.reflection.ReflectMethod; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; @@ -64,7 +65,17 @@ public void onSpawnerStack(SpawnerStackEvent e) { Location location = e.getStack().getLocation(); Island island = plugin.getGrid().getIslandAt(location); if (island != null) { - island.handleBlockPlace(Keys.of(e.getStack().getBlock()), e.getIncreaseAmount()); + Key blockKey = Keys.of(e.getStack().getBlock()); + + int increaseAmount = e.getStack().getStackSize() + e.getIncreaseAmount() > e.getStack().getStackSettings().getMaxStackSize() ? + e.getStack().getStackSettings().getMaxStackSize() - e.getStack().getStackSize() : e.getIncreaseAmount(); + int newBlocksCount = e.isNew() ? Math.max(1, increaseAmount - 1) : increaseAmount; + + if (island.hasReachedBlockLimit(blockKey, newBlocksCount)) { + e.setCancelled(true); + } else { + island.handleBlockPlace(blockKey, newBlocksCount); + } } } From 142d92496aa9e032fcf753a158fdefa1ef40cbfb Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 10 Mar 2026 17:43:49 +0200 Subject: [PATCH 531/600] Fixed unlimited limit upgrades do not show as "synced" (#2856) --- .../commands/player/CmdDemote.java | 3 +- .../commands/player/CmdPromote.java | 3 +- .../config/SettingsContainer.java | 60 ++++++----- .../bridge/IslandsDatabaseBridge.java | 17 +-- .../sql/upgrade/v0/DatabaseConverter.java | 17 +-- .../serialization/IslandsDeserializer.java | 15 +-- .../superiorskyblock/island/SIsland.java | 100 +++++++++--------- .../superiorskyblock/island/SpawnIsland.java | 27 ++--- .../DefaultIslandBlocksTrackerAlgorithm.java | 5 +- ...DefaultIslandEntitiesTrackerAlgorithm.java | 3 +- .../island/bank/SIslandBank.java | 4 +- .../island/builder/IslandBuilderImpl.java | 16 +-- .../upgrade/IslandUpgradeConstants.java | 17 +++ .../island/upgrade/SUpgradeLevel.java | 40 +++---- .../module/upgrades/UpgradesModule.java | 3 +- 15 files changed, 186 insertions(+), 144 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/IslandUpgradeConstants.java diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDemote.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDemote.java index a2ea7c180f..4e65126064 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDemote.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdDemote.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import java.util.Collections; import java.util.List; @@ -84,7 +85,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer do { previousRole = previousRole.getPreviousRole(); - roleLimit = previousRole == null ? -1 : island.getRoleLimit(previousRole); + roleLimit = previousRole == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : island.getRoleLimit(previousRole); } while (previousRole != null && !previousRole.isFirstRole() && roleLimit >= 0 && roleLimit >= island.getIslandMembers(previousRole).size()); if (previousRole == null) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPromote.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPromote.java index 2deec8ce02..6288e0a652 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPromote.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdPromote.java @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import java.util.Collections; import java.util.List; @@ -91,7 +92,7 @@ public void execute(SuperiorSkyblockPlugin plugin, SuperiorPlayer superiorPlayer do { nextRole = nextRole.getNextRole(); - roleLimit = nextRole == null ? -1 : island.getRoleLimit(nextRole); + roleLimit = nextRole == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : island.getRoleLimit(nextRole); } while (nextRole != null && !nextRole.isLastRole() && !nextRole.isHigherThan(superiorPlayer.getPlayerRole()) && roleLimit >= 0 && island.getIslandMembers(nextRole).size() >= roleLimit); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 5a0981f1fe..baf52f3035 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -33,6 +33,7 @@ import com.bgsoftware.superiorskyblock.core.menu.TemplateItem; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.core.values.BlockValuesManagerImpl; +import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; import com.bgsoftware.superiorskyblock.world.Dimensions; @@ -259,41 +260,50 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config calcInterval = config.getLong("calc-interval", 6000); islandCommand = config.getString("island-command", "island,is,islands"); maxIslandSize = config.getInt("max-island-size", 200); - defaultIslandSize = config.getInt("default-values.island-size", 20); + defaultIslandSize = Math.max(config.getInt("default-values.island-size", 20), 1); KeyMap defaultBlockLimits = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); loadListOrSection(config, "default-values.block-limits", "block limit", (key, limit) -> { - Key blockKey = Keys.ofMaterialAndData(key); - defaultBlockLimits.put(blockKey, limit); - plugin.getBlockValues().addCustomBlockKey(blockKey); + if (limit >= 0) { + Key blockKey = Keys.ofMaterialAndData(key); + defaultBlockLimits.put(blockKey, limit); + plugin.getBlockValues().addCustomBlockKey(blockKey); + } }); this.defaultBlockLimits = KeyMaps.unmodifiableKeyMap(defaultBlockLimits); KeyMap defaultEntityLimits = KeyMaps.createArrayMap(KeyIndicator.ENTITY_TYPE); - loadListOrSection(config, "default-values.entity-limits", "entity limit", (entityType, limit) -> - defaultEntityLimits.put(Keys.ofEntityType(entityType), limit)); + loadListOrSection(config, "default-values.entity-limits", "entity limit", (entityType, limit) -> { + if (limit >= 0) { + defaultEntityLimits.put(Keys.ofEntityType(entityType), limit); + } + }); this.defaultEntityLimits = KeyMaps.unmodifiableKeyMap(defaultEntityLimits); Map defaultIslandEffects = new ArrayMap<>(); loadListOrSection(config, "default-values.island-effects", "island effect", (effectName, effectLevel) -> { - PotionEffectType potionEffectType = PotionEffectType.getByName(effectName); - if (potionEffectType == null) { - Log.errorFromFile("config.yml", "Invalid potion effect " + effectName + ", skipping..."); - } else { - defaultIslandEffects.put(potionEffectType, effectLevel - 1); + if (effectLevel >= 1) { + PotionEffectType potionEffectType = PotionEffectType.getByName(effectName); + if (potionEffectType == null) { + Log.errorFromFile("config.yml", "Invalid potion effect " + effectName + ", skipping..."); + } else { + defaultIslandEffects.put(potionEffectType, effectLevel - 1); + } } }); this.defaultIslandEffects = Collections.unmodifiableMap(defaultIslandEffects); - defaultTeamLimit = config.getInt("default-values.team-limit", 4); - defaultWarpsLimit = config.getInt("default-values.warps-limit", 3); - defaultCoopLimit = config.getInt("default-values.coop-limit", 8); - defaultCropGrowth = config.getInt("default-values.crop-growth", 1); - defaultSpawnerRates = config.getDouble("default-values.spawner-rates", 1D); - defaultMobDrops = config.getDouble("default-values.mob-drops", 1D); - defaultBankLimit = new BigDecimal(config.getString("default-values.bank-limit", "-1")); + defaultTeamLimit = Math.max(config.getInt("default-values.team-limit", 4), IslandUpgradeConstants.NO_LIMIT_VALUE); + defaultWarpsLimit = Math.max(config.getInt("default-values.warps-limit", 3), IslandUpgradeConstants.NO_LIMIT_VALUE); + defaultCoopLimit = Math.max(config.getInt("default-values.coop-limit", 8), IslandUpgradeConstants.NO_LIMIT_VALUE); + defaultCropGrowth = Math.max(config.getInt("default-values.crop-growth", 1), IslandUpgradeConstants.NO_LIMIT_VALUE); + defaultSpawnerRates = Math.max(config.getDouble("default-values.spawner-rates", 1D), IslandUpgradeConstants.NO_LIMIT_VALUE); + defaultMobDrops = Math.max(config.getDouble("default-values.mob-drops", 1D), IslandUpgradeConstants.NO_LIMIT_VALUE); + defaultBankLimit = new BigDecimal(config.getString("default-values.bank-limit", "-1")).max(IslandUpgradeConstants.NO_BANK_LIMIT_VALUE); defaultRoleLimits = CollectionsFactory.createInt2IntHashMap(); loadListOrSection(config, "default-values.role-limits", "role limit", (role, limit) -> { - try { - defaultRoleLimits.put(Integer.parseInt(role), limit); - } catch (NumberFormatException error) { - Log.warnFromFile("config.yml", "Invalid role id for limit: " + role); + if (limit >= 0) { + try { + defaultRoleLimits.put(Integer.parseInt(role), limit); + } catch (NumberFormatException error) { + Log.warnFromFile("config.yml", "Invalid role id for limit: " + role); + } } }); islandsHeight = config.getInt("islands-height", 100); @@ -693,8 +703,10 @@ private KeySet loadSafeBlocks(SuperiorSkyblockPlugin plugin) { private void loadGenerator(YamlConfiguration config, String path, Dimension dimension) { KeyMap defaultGenerator = KeyMaps.createArrayMap(KeyIndicator.MATERIAL); loadListOrSection(config, path, "generator-rates", (key, percentage) -> { - Key blockKey = Keys.ofMaterialAndData(key); - defaultGenerator.put(blockKey, percentage); + if (percentage >= 0) { + Key blockKey = Keys.ofMaterialAndData(key); + defaultGenerator.put(blockKey, percentage); + } }); this.defaultGenerator.put(dimension, KeyMaps.unmodifiableKeyMap(defaultGenerator)); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index 6afb7ec655..471ac664a7 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -32,6 +32,7 @@ import com.bgsoftware.superiorskyblock.core.serialization.Serializers; import com.bgsoftware.superiorskyblock.island.IslandNames; import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; +import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.bgsoftware.superiorskyblock.world.Dimensions; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; @@ -735,14 +736,14 @@ public static void clearIslandSettings(Island island) { try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.updateObject("islands_settings", createFilter("island", island), - pool.obtain().withNameAndValue("size", -1), - pool.obtain().withNameAndValue("bank_limit", "-2"), - pool.obtain().withNameAndValue("coops_limit", -1), - pool.obtain().withNameAndValue("members_limit", -1), - pool.obtain().withNameAndValue("warps_limit", -1), - pool.obtain().withNameAndValue("crop_growth_multiplier", -1D), - pool.obtain().withNameAndValue("spawner_rates_multiplier", -1D), - pool.obtain().withNameAndValue("mob_drops_multiplier", -1D) + pool.obtain().withNameAndValue("size", IslandUpgradeConstants.SYNCED_VALUE), + pool.obtain().withNameAndValue("bank_limit", IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE.toString()), + pool.obtain().withNameAndValue("coops_limit", IslandUpgradeConstants.SYNCED_VALUE), + pool.obtain().withNameAndValue("members_limit", IslandUpgradeConstants.SYNCED_VALUE), + pool.obtain().withNameAndValue("warps_limit", IslandUpgradeConstants.SYNCED_VALUE), + pool.obtain().withNameAndValue("crop_growth_multiplier", IslandUpgradeConstants.SYNCED_VALUE), + pool.obtain().withNameAndValue("spawner_rates_multiplier", IslandUpgradeConstants.SYNCED_VALUE), + pool.obtain().withNameAndValue("mob_drops_multiplier", IslandUpgradeConstants.SYNCED_VALUE) ); } }); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseConverter.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseConverter.java index d5dc5046de..d5f7dd7dd1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseConverter.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v0/DatabaseConverter.java @@ -31,6 +31,7 @@ import com.bgsoftware.superiorskyblock.core.mutable.MutableObject; import com.bgsoftware.superiorskyblock.island.privilege.PlayerPrivilegeNode; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; +import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import org.bukkit.World; import org.bukkit.potion.PotionEffectType; @@ -671,14 +672,14 @@ private static IslandAttributes loadIsland(ResultSetMapBridge resultSet) { .setValue(IslandAttributes.Field.BANK_BALANCE, resultSet.get("islandBank", "")) .setValue(IslandAttributes.Field.BANK_LAST_INTEREST, resultSet.get("lastInterest", currentTime / 1000)) .setValue(IslandAttributes.Field.VISITOR_HOMES, resultSet.get("visitorsLocation", "")) - .setValue(IslandAttributes.Field.ISLAND_SIZE, resultSet.get("islandSize", -1)) - .setValue(IslandAttributes.Field.TEAM_LIMIT, resultSet.get("teamLimit", -1)) - .setValue(IslandAttributes.Field.WARPS_LIMIT, resultSet.get("warpsLimit", -1)) - .setValue(IslandAttributes.Field.CROP_GROWTH_MULTIPLIER, resultSet.get("cropGrowth", -1D)) - .setValue(IslandAttributes.Field.SPAWNER_RATES_MULTIPLIER, resultSet.get("spawnerRates", -1D)) - .setValue(IslandAttributes.Field.MOB_DROPS_MULTIPLIER, resultSet.get("mobDrops", -1D)) - .setValue(IslandAttributes.Field.COOP_LIMIT, resultSet.get("coopLimit", -1)) - .setValue(IslandAttributes.Field.BANK_LIMIT, resultSet.get("bankLimit", "-2")); + .setValue(IslandAttributes.Field.ISLAND_SIZE, resultSet.get("islandSize", IslandUpgradeConstants.SYNCED_VALUE)) + .setValue(IslandAttributes.Field.TEAM_LIMIT, resultSet.get("teamLimit", IslandUpgradeConstants.SYNCED_VALUE)) + .setValue(IslandAttributes.Field.WARPS_LIMIT, resultSet.get("warpsLimit", IslandUpgradeConstants.SYNCED_VALUE)) + .setValue(IslandAttributes.Field.CROP_GROWTH_MULTIPLIER, resultSet.get("cropGrowth", IslandUpgradeConstants.SYNCED_VALUE)) + .setValue(IslandAttributes.Field.SPAWNER_RATES_MULTIPLIER, resultSet.get("spawnerRates", IslandUpgradeConstants.SYNCED_VALUE)) + .setValue(IslandAttributes.Field.MOB_DROPS_MULTIPLIER, resultSet.get("mobDrops", IslandUpgradeConstants.SYNCED_VALUE)) + .setValue(IslandAttributes.Field.COOP_LIMIT, resultSet.get("coopLimit", IslandUpgradeConstants.SYNCED_VALUE)) + .setValue(IslandAttributes.Field.BANK_LIMIT, resultSet.get("bankLimit", IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE.toString())); } private static StackedBlockAttributes loadStackedBlock(ResultSetMapBridge resultSet) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java index 7f8cd91a0f..2e947c4383 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java @@ -44,6 +44,7 @@ public class IslandsDeserializer { private static final Gson GSON = new GsonBuilder().create(); private static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2); + private static final int SYNCED_VALUE = -2; private IslandsDeserializer() { @@ -713,13 +714,13 @@ public static void deserializeIslandSettings(DatabaseBridge databaseBridge, Data Island.Builder builder = lookupIsland(databaseCache, uuid.get(), "islands_settings"); - builder.setIslandSize(islandSettings.getInt("size").orElse(-1)); - builder.setTeamLimit(islandSettings.getInt("members_limit").orElse(-1)); - builder.setWarpsLimit(islandSettings.getInt("warps_limit").orElse(-1)); - builder.setCropGrowth(islandSettings.getDouble("crop_growth_multiplier").orElse(-1D)); - builder.setSpawnerRates(islandSettings.getDouble("spawner_rates_multiplier").orElse(-1D)); - builder.setMobDrops(islandSettings.getDouble("mob_drops_multiplier").orElse(-1D)); - builder.setCoopLimit(islandSettings.getInt("coops_limit").orElse(-1)); + builder.setIslandSize(islandSettings.getInt("size").orElse(SYNCED_VALUE)); + builder.setTeamLimit(islandSettings.getInt("members_limit").orElse(SYNCED_VALUE)); + builder.setWarpsLimit(islandSettings.getInt("warps_limit").orElse(SYNCED_VALUE)); + builder.setCropGrowth(islandSettings.getDouble("crop_growth_multiplier").orElse((double) SYNCED_VALUE)); + builder.setSpawnerRates(islandSettings.getDouble("spawner_rates_multiplier").orElse((double) SYNCED_VALUE)); + builder.setMobDrops(islandSettings.getDouble("mob_drops_multiplier").orElse((double) SYNCED_VALUE)); + builder.setCoopLimit(islandSettings.getInt("coops_limit").orElse(SYNCED_VALUE)); builder.setBankLimit(islandSettings.getBigDecimal("bank_limit").orElse(SYNCED_BANK_LIMIT_VALUE)); }); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index c7ab1a8e2b..fa9ea48ad0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -92,6 +92,7 @@ import com.bgsoftware.superiorskyblock.island.top.SortingComparators; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.island.upgrade.DefaultUpgradeLevel; +import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; import com.bgsoftware.superiorskyblock.island.upgrade.container.IslandUpgrades; import com.bgsoftware.superiorskyblock.island.warp.SIslandWarp; @@ -161,10 +162,10 @@ public class SIsland implements Island { private static final UUID CONSOLE_UUID = new UUID(0, 0); - private static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2); private static final UUID[] EMPTY_IGNORED_MEMBERS = new UUID[0]; private static final Object[] EMPTY_MESSAGE_ARGS = new Object[0]; + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final LazyReference placeholdersService = new LazyReference() { @Override @@ -202,14 +203,14 @@ protected IslandCache create() { /* * Island Upgrade Values */ - private final Synchronized islandSize = Synchronized.of(IntValue.syncedFixed(-1)); - private final Synchronized warpsLimit = Synchronized.of(IntValue.syncedFixed(-1)); - private final Synchronized teamLimit = Synchronized.of(IntValue.syncedFixed(-1)); - private final Synchronized coopLimit = Synchronized.of(IntValue.syncedFixed(-1)); - private final Synchronized cropGrowth = Synchronized.of(DoubleValue.syncedFixed(-1D)); - private final Synchronized spawnerRates = Synchronized.of(DoubleValue.syncedFixed(-1D)); - private final Synchronized mobDrops = Synchronized.of(DoubleValue.syncedFixed(-1D)); - private final Synchronized> bankLimit = Synchronized.of(Value.syncedFixed(SYNCED_BANK_LIMIT_VALUE)); + private final Synchronized islandSize = Synchronized.of(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); + private final Synchronized warpsLimit = Synchronized.of(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); + private final Synchronized teamLimit = Synchronized.of(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); + private final Synchronized coopLimit = Synchronized.of(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); + private final Synchronized cropGrowth = Synchronized.of(DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); + private final Synchronized spawnerRates = Synchronized.of(DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); + private final Synchronized mobDrops = Synchronized.of(DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); + private final Synchronized> bankLimit = Synchronized.of(Value.syncedFixed(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE)); private final Synchronized> roleLimits = Synchronized.of(CollectionsFactory.createInt2ObjectArrayMap()); private final Synchronized>> cobbleGeneratorValues = Synchronized.of(new EnumerateMap<>(Dimension.values())); private final Map islandEffects = new ConcurrentHashMap<>(); @@ -794,7 +795,7 @@ public int getCoopLimit() { @Override public int getCoopLimitRaw() { - return this.coopLimit.readAndGet(coopLimit -> coopLimit.getNonSynced(-1)); + return this.coopLimit.readAndGet(coopLimit -> coopLimit.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override @@ -1941,7 +1942,7 @@ private void setIslandSizeInternal(IntValue islandSize) { @Override public int getIslandSizeRaw() { - return this.islandSize.readAndGet(islandSize -> islandSize.getNonSynced(-1)); + return this.islandSize.readAndGet(islandSize -> islandSize.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override @@ -2278,8 +2279,8 @@ public void setBankLimit(BigDecimal bankLimit) { if (Objects.equals(bankLimit, getBankLimitRaw())) return; - if (bankLimit.compareTo(SYNCED_BANK_LIMIT_VALUE) <= 0) { - this.bankLimit.set(Value.syncedFixed(SYNCED_BANK_LIMIT_VALUE)); + if (bankLimit.compareTo(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE) <= 0) { + this.bankLimit.set(Value.syncedFixed(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE)); getUpgrades().forEach((upgradeName, level) -> { Upgrade upgrade = plugin.getUpgrades().getUpgrade(upgradeName); @@ -2303,7 +2304,7 @@ public void setBankLimit(BigDecimal bankLimit) { @Override public BigDecimal getBankLimitRaw() { - return this.bankLimit.readAndGet(bankLimit -> bankLimit.getNonSynced(SYNCED_BANK_LIMIT_VALUE)); + return this.bankLimit.readAndGet(bankLimit -> bankLimit.getNonSynced(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE)); } @Override @@ -3052,7 +3053,7 @@ public void setCropGrowthMultiplier(double cropGrowth) { DoubleValue oldCropGrowth = this.cropGrowth.set(DoubleValue.fixed(cropGrowth)); - if (cropGrowth == DoubleValue.getNonSynced(oldCropGrowth, -1D)) + if (cropGrowth == DoubleValue.getNonSynced(oldCropGrowth, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveCropGrowth(this); @@ -3062,7 +3063,7 @@ public void setCropGrowthMultiplier(double cropGrowth) { @Override public double getCropGrowthRaw() { - return this.cropGrowth.readAndGet(cropGrowth -> cropGrowth.getNonSynced(-1D)); + return this.cropGrowth.readAndGet(cropGrowth -> cropGrowth.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override @@ -3078,7 +3079,7 @@ public void setSpawnerRatesMultiplier(double spawnerRates) { DoubleValue oldSpawnerRates = this.spawnerRates.set(DoubleValue.fixed(spawnerRates)); - if (spawnerRates == DoubleValue.getNonSynced(oldSpawnerRates, -1D)) + if (spawnerRates == DoubleValue.getNonSynced(oldSpawnerRates, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveSpawnerRates(this); @@ -3086,7 +3087,7 @@ public void setSpawnerRatesMultiplier(double spawnerRates) { @Override public double getSpawnerRatesRaw() { - return this.spawnerRates.readAndGet(spawnerRates -> spawnerRates.getNonSynced(-1D)); + return this.spawnerRates.readAndGet(spawnerRates -> spawnerRates.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override @@ -3102,7 +3103,7 @@ public void setMobDropsMultiplier(double mobDrops) { DoubleValue oldMobDrops = this.mobDrops.set(DoubleValue.fixed(mobDrops)); - if (mobDrops == DoubleValue.getNonSynced(oldMobDrops, -1D)) + if (mobDrops == DoubleValue.getNonSynced(oldMobDrops, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveMobDrops(this); @@ -3110,21 +3111,21 @@ public void setMobDropsMultiplier(double mobDrops) { @Override public double getMobDropsRaw() { - return this.mobDrops.readAndGet(mobDrops -> mobDrops.getNonSynced(-1D)); + return this.mobDrops.readAndGet(mobDrops -> mobDrops.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override public int getBlockLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); IntValue blockLimit = blockLimits.get(key); - return blockLimit == null ? -1 : blockLimit.get(); + return blockLimit == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : blockLimit.get(); } @Override public int getExactBlockLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); IntValue blockLimit = blockLimits.getRaw(key, null); - return blockLimit == null ? -1 : blockLimit.get(); + return blockLimit == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : blockLimit.get(); } @Override @@ -3168,7 +3169,7 @@ public void setBlockLimit(Key key, int limit) { IntValue oldLimit = blockLimits.put(key, IntValue.fixed(finalLimit)); - if (limit == IntValue.getNonSynced(oldLimit, -1)) + if (limit == IntValue.getNonSynced(oldLimit, IslandUpgradeConstants.SYNCED_VALUE)) return; plugin.getBlockValues().addCustomBlockKey(key); @@ -3226,7 +3227,7 @@ public int getEntityLimit(EntityType entityType) { public int getEntityLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); IntValue entityLimit = entityLimits.get(key); - return entityLimit == null ? -1 : entityLimit.get(); + return entityLimit == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : entityLimit.get(); } @Override @@ -3270,7 +3271,7 @@ public void setEntityLimit(Key key, int limit) { IntValue oldEntityLimit = entityLimits.put(key, IntValue.fixed(limit)); - if (limit == IntValue.getNonSynced(oldEntityLimit, -1)) + if (limit == IntValue.getNonSynced(oldEntityLimit, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveEntityLimit(this, key, limit); @@ -3339,7 +3340,7 @@ public void setTeamLimit(int teamLimit) { IntValue oldTeamLimit = this.teamLimit.set(IntValue.fixed(teamLimit)); - if (teamLimit == IntValue.getNonSynced(oldTeamLimit, -1)) + if (teamLimit == IntValue.getNonSynced(oldTeamLimit, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveTeamLimit(this); @@ -3347,7 +3348,7 @@ public void setTeamLimit(int teamLimit) { @Override public int getTeamLimitRaw() { - return this.teamLimit.readAndGet(teamLimit -> teamLimit.getNonSynced(-1)); + return this.teamLimit.readAndGet(teamLimit -> teamLimit.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override @@ -3363,7 +3364,7 @@ public void setWarpsLimit(int warpsLimit) { IntValue oldWarpsLimit = this.warpsLimit.set(IntValue.fixed(warpsLimit)); - if (warpsLimit == IntValue.getNonSynced(oldWarpsLimit, -1)) + if (warpsLimit == IntValue.getNonSynced(oldWarpsLimit, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveWarpsLimit(this); @@ -3371,7 +3372,7 @@ public void setWarpsLimit(int warpsLimit) { @Override public int getWarpsLimitRaw() { - return this.warpsLimit.readAndGet(warpsLimit -> warpsLimit.getNonSynced(-1)); + return this.warpsLimit.readAndGet(warpsLimit -> warpsLimit.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE)); } @Override @@ -3389,7 +3390,7 @@ public void setPotionEffect(PotionEffectType type, int level) { IntValue oldPotionLevel = islandEffects.put(type, IntValue.fixed(level)); - if (level == IntValue.getNonSynced(oldPotionLevel, -1)) + if (level == IntValue.getNonSynced(oldPotionLevel, IslandUpgradeConstants.SYNCED_VALUE)) return; registerTask(BukkitExecutor.ensureMain(() -> getAllPlayersInside().forEach(superiorPlayer -> { @@ -3450,7 +3451,7 @@ public Map getCustomPotionEffects() { Map islandEffects = new ArrayMap<>(); this.islandEffects.forEach((potionEffectType, levelValue) -> { - int level = levelValue.getNonSynced(-1); + int level = levelValue.getNonSynced(IslandUpgradeConstants.SYNCED_VALUE); if (level > 0) islandEffects.put(potionEffectType, level); }); @@ -3516,7 +3517,7 @@ public void setRoleLimit(PlayerRole playerRole, int limit) { IntValue oldRoleLimit = roleLimits.writeAndGet(roleLimits -> roleLimits.put(playerRole.getId(), IntValue.fixed(limit))); - if (limit == IntValue.getNonSynced(oldRoleLimit, -1)) + if (limit == IntValue.getNonSynced(oldRoleLimit, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveRoleLimit(this, playerRole, limit); @@ -3540,13 +3541,14 @@ public void removeRoleLimit(PlayerRole playerRole) { public int getRoleLimit(PlayerRole playerRole) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); IntValue roleLimit = roleLimits.readAndGet(roleLimits -> roleLimits.get(playerRole.getId())); - return roleLimit == null ? -1 : roleLimit.get(); + return roleLimit == null ? IslandUpgradeConstants.NO_LIMIT_VALUE : roleLimit.get(); } @Override public int getRoleLimitRaw(PlayerRole playerRole) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); - return IntValue.getNonSynced(roleLimits.readAndGet(roleLimits -> roleLimits.get(playerRole.getId())), -1); + return IntValue.getNonSynced(roleLimits.readAndGet(roleLimits -> + roleLimits.get(playerRole.getId())), IslandUpgradeConstants.SYNCED_VALUE); } @Override @@ -4208,7 +4210,7 @@ public void setGeneratorAmount(Key key, @Size int amount, Dimension dimension) { IntValue oldGeneratorRate = worldGeneratorRates.put(key, IntValue.fixed(amount)); - if (amount == IntValue.getNonSynced(oldGeneratorRate, -1)) + if (amount == IntValue.getNonSynced(oldGeneratorRate, IslandUpgradeConstants.SYNCED_VALUE)) return; IslandsDatabaseBridge.saveGeneratorRate(this, dimension, key, amount); @@ -4982,35 +4984,35 @@ private void updateOldUpgradeValues() { private void clearUpgrades(boolean overrideCustom) { if (overrideCustom || this.islandSize.get().isSynced()) { - setIslandSizeInternal(IntValue.syncedFixed(-1)); + setIslandSizeInternal(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); } warpsLimit.set(warpsLimit -> { if (overrideCustom || warpsLimit.isSynced()) { - return IntValue.syncedFixed(-1); + return IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE); } return warpsLimit; }); teamLimit.set(teamLimit -> { if (overrideCustom || teamLimit.isSynced()) { - return IntValue.syncedFixed(-1); + return IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE); } return teamLimit; }); coopLimit.set(coopLimit -> { if (overrideCustom || coopLimit.isSynced()) { - return IntValue.syncedFixed(-1); + return IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE); } return coopLimit; }); cropGrowth.set(cropGrowth -> { if (overrideCustom || cropGrowth.isSynced()) { - notifyCropGrowthChange(-1D); + notifyCropGrowthChange(IslandUpgradeConstants.SYNCED_VALUE); - return DoubleValue.syncedFixed(-1D); + return DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE); } return cropGrowth; @@ -5018,51 +5020,51 @@ private void clearUpgrades(boolean overrideCustom) { spawnerRates.set(spawnerRates -> { if (overrideCustom || spawnerRates.isSynced()) { - return DoubleValue.syncedFixed(-1D); + return DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE); } return spawnerRates; }); mobDrops.set(mobDrops -> { if (overrideCustom || mobDrops.isSynced()) { - return DoubleValue.syncedFixed(-1D); + return DoubleValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE); } return mobDrops; }); bankLimit.set(bankLimit -> { if (overrideCustom || bankLimit.isSynced()) { - return Value.syncedFixed(SYNCED_BANK_LIMIT_VALUE); + return Value.syncedFixed(IslandUpgradeConstants.SYNCED_BANK_LIMIT_VALUE); } return bankLimit; }); blockLimits.entrySet().stream() .filter(entry -> overrideCustom || entry.getValue().isSynced()) - .forEach(entry -> entry.setValue(IntValue.syncedFixed(-1))); + .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE))); entityLimits.entrySet().stream() .filter(entry -> overrideCustom || entry.getValue().isSynced()) - .forEach(entry -> entry.setValue(IntValue.syncedFixed(-1))); + .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE))); cobbleGeneratorValues.write(cobbleGeneratorValues -> { cobbleGeneratorValues.values().forEach(cobbleGeneratorValue -> { cobbleGeneratorValue.entrySet().stream() .filter(entry -> overrideCustom || entry.getValue().isSynced()) - .forEach(entry -> entry.setValue(IntValue.syncedFixed(-1))); + .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE))); }); }); islandEffects.entrySet().stream() .filter(entry -> overrideCustom || entry.getValue().isSynced()) - .forEach(entry -> entry.setValue(IntValue.syncedFixed(-1))); + .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE))); roleLimits.write(roleLimits -> { Iterator> iterator = roleLimits.entryIterator(); while (iterator.hasNext()) { Int2ObjectMapView.Entry entry = iterator.next(); if (overrideCustom || entry.getValue().isSynced()) - entry.setValue(IntValue.syncedFixed(-1)); + entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); } }); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 6409113faf..7f0cbc872e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -60,6 +60,7 @@ import com.bgsoftware.superiorskyblock.island.privilege.PrivilegeNodeAbstract; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.bgsoftware.superiorskyblock.island.top.SortingComparators; +import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.player.builder.SuperiorPlayerBuilderImpl; import com.bgsoftware.superiorskyblock.world.Dimensions; @@ -1166,7 +1167,7 @@ public IslandBank getIslandBank() { @Override public BigDecimal getBankLimit() { - return BigDecimal.valueOf(-1); + return IslandUpgradeConstants.NO_BANK_LIMIT_VALUE; } @Override @@ -1176,7 +1177,7 @@ public void setBankLimit(BigDecimal bankLimit) { @Override public BigDecimal getBankLimitRaw() { - return BigDecimal.valueOf(-1); + return IslandUpgradeConstants.NO_BANK_LIMIT_VALUE; } @Override @@ -1612,12 +1613,12 @@ public double getMobDropsRaw() { @Override public int getBlockLimit(Key key) { - return -1; + return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public int getExactBlockLimit(Key key) { - return -1; + return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override @@ -1662,12 +1663,12 @@ public boolean hasReachedBlockLimit(Key key, @Size int amount) { @Override public int getEntityLimit(EntityType entityType) { - return -1; + return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public int getEntityLimit(Key key) { - return -1; + return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override @@ -1727,7 +1728,7 @@ public IslandEntitiesTrackerAlgorithm getEntitiesTracker() { @Override public int getTeamLimit() { - return -1; + return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override @@ -1737,12 +1738,12 @@ public void setTeamLimit(int teamLimit) { @Override public int getTeamLimitRaw() { - return 0; + return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public int getWarpsLimit() { - return -1; + return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override @@ -1752,7 +1753,7 @@ public void setWarpsLimit(int warpsLimit) { @Override public int getWarpsLimitRaw() { - return -1; + return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override @@ -1817,12 +1818,12 @@ public void removeRoleLimit(PlayerRole playerRole) { @Override public int getRoleLimit(PlayerRole playerRole) { - return -1; + return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override public int getRoleLimitRaw(PlayerRole playerRole) { - return -1; + return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override @@ -2095,7 +2096,7 @@ public void setChestRows(int index, int rows) { @Override public int getCoopLimitRaw() { - return -1; + return IslandUpgradeConstants.NO_LIMIT_VALUE; } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java index f9a3e2c614..2178a1c08b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandBlocksTrackerAlgorithm.java @@ -14,6 +14,7 @@ import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.values.BlockValue; +import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.google.common.base.Preconditions; import java.math.BigInteger; @@ -48,7 +49,7 @@ public boolean trackBlock(Key key, BigInteger amount) { BlockValue blockValue = plugin.getBlockValues().getBlockValue(key); boolean increaseAmount = blockValue != BlockValue.ZERO; - boolean hasBlockLimit = island.getBlockLimit(key) != -1; + boolean hasBlockLimit = island.getBlockLimit(key) != IslandUpgradeConstants.NO_LIMIT_VALUE; boolean valuesMenu = plugin.getBlockValues().isValuesMenu(key); if (increaseAmount || hasBlockLimit || valuesMenu) { @@ -78,7 +79,7 @@ public boolean untrackBlock(Key key, BigInteger amount) { boolean decreaseAmount = blockValue != BlockValue.ZERO; - boolean hasBlockLimit = island.getBlockLimit(key) != -1; + boolean hasBlockLimit = island.getBlockLimit(key) != IslandUpgradeConstants.NO_LIMIT_VALUE; boolean valuesMenu = plugin.getBlockValues().isValuesMenu(key); if (decreaseAmount || hasBlockLimit || valuesMenu) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java index ade0247988..d5ccc2b1c5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/algorithm/DefaultIslandEntitiesTrackerAlgorithm.java @@ -17,6 +17,7 @@ import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.google.common.base.Preconditions; import org.bukkit.World; import org.bukkit.entity.EntityType; @@ -193,7 +194,7 @@ public boolean canRecalculateEntityCounts() { } private boolean canTrackEntity(Key key) { - if (island.getEntityLimit(key) != -1) + if (island.getEntityLimit(key) != IslandUpgradeConstants.NO_LIMIT_VALUE) return true; if (key instanceof EntityTypeKey) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java index d305745ece..49180bf313 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/SIslandBank.java @@ -22,6 +22,7 @@ import com.bgsoftware.superiorskyblock.island.bank.logs.DatabaseBankLogs; import com.bgsoftware.superiorskyblock.island.bank.logs.IBankLogs; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.bgsoftware.superiorskyblock.module.BuiltinModules; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; @@ -40,7 +41,6 @@ public class SIslandBank implements IslandBank { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); private static final BigDecimal MONEY_FAILURE = BigDecimal.valueOf(-1); - private static final BigDecimal NO_BANK_LIMIT = BigDecimal.valueOf(-1); private static final UUID CONSOLE_UUID = UUID.fromString("00000000-0000-0000-0000-000000000000"); private final AtomicReference balance = new AtomicReference<>(BigDecimal.ZERO); @@ -167,7 +167,7 @@ public boolean canDepositMoney(BigDecimal amount) { Preconditions.checkNotNull(amount, "amount parameter cannot be null."); BigDecimal bankLimit = this.island.getBankLimit(); - return bankLimit.compareTo(NO_BANK_LIMIT) <= 0 || + return bankLimit.compareTo(IslandUpgradeConstants.NO_BANK_LIMIT_VALUE) <= 0 || this.balance.get().add(amount).compareTo(bankLimit) <= 0; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java index 203385957c..96969a03f9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java @@ -62,6 +62,8 @@ public class IslandBuilderImpl implements Island.Builder { private static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2); + private static final int SYNCED_VALUE = -2; + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); @Nullable @@ -102,13 +104,13 @@ public class IslandBuilderImpl implements Island.Builder { public final List islandChests = new ArrayList<>(plugin.getSettings().getIslandChests().getDefaultPages()); public final Int2ObjectMapView roleLimits = CollectionsFactory.createInt2ObjectArrayMap(); public final EnumerateMap visitorHomes = new EnumerateMap<>(Dimension.values()); - public IntValue islandSize = IntValue.syncedFixed(-1); - public IntValue warpsLimit = IntValue.syncedFixed(-1); - public IntValue teamLimit = IntValue.syncedFixed(-1); - public IntValue coopLimit = IntValue.syncedFixed(-1); - public DoubleValue cropGrowth = DoubleValue.syncedFixed(-1D); - public DoubleValue spawnerRates = DoubleValue.syncedFixed(-1D); - public DoubleValue mobDrops = DoubleValue.syncedFixed(-1D); + public IntValue islandSize = IntValue.syncedFixed(SYNCED_VALUE); + public IntValue warpsLimit = IntValue.syncedFixed(SYNCED_VALUE); + public IntValue teamLimit = IntValue.syncedFixed(SYNCED_VALUE); + public IntValue coopLimit = IntValue.syncedFixed(SYNCED_VALUE); + public DoubleValue cropGrowth = DoubleValue.syncedFixed(SYNCED_VALUE); + public DoubleValue spawnerRates = DoubleValue.syncedFixed(SYNCED_VALUE); + public DoubleValue mobDrops = DoubleValue.syncedFixed(SYNCED_VALUE); public Value bankLimit = Value.syncedFixed(SYNCED_BANK_LIMIT_VALUE); public BigDecimal balance = BigDecimal.ZERO; public long lastInterestTime = System.currentTimeMillis() / 1000; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/IslandUpgradeConstants.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/IslandUpgradeConstants.java new file mode 100644 index 0000000000..c6d258ea95 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/IslandUpgradeConstants.java @@ -0,0 +1,17 @@ +package com.bgsoftware.superiorskyblock.island.upgrade; + +import java.math.BigDecimal; + +public class IslandUpgradeConstants { + + public static final BigDecimal SYNCED_BANK_LIMIT_VALUE = BigDecimal.valueOf(-2); + public static final BigDecimal NO_BANK_LIMIT_VALUE = BigDecimal.valueOf(-1); + + public static final int SYNCED_VALUE = -2; + public static final int NO_LIMIT_VALUE = -1; + + private IslandUpgradeConstants() { + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java index ee758ba902..6c087d470b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java @@ -153,7 +153,7 @@ public boolean hasCropGrowth() { @Override public double getCropGrowth() { - return cropGrowth.get().orElse(-1D); + return cropGrowth.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override @@ -163,7 +163,7 @@ public boolean hasSpawnerRates() { @Override public double getSpawnerRates() { - return spawnerRates.get().orElse(-1D); + return spawnerRates.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override @@ -173,19 +173,19 @@ public boolean hasMobDrops() { @Override public double getMobDrops() { - return mobDrops.get().orElse(-1D); + return mobDrops.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public int getBlockLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); - return blockLimits.get().getOrDefault(key, -1); + return blockLimits.get().getOrDefault(key, IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override public int getExactBlockLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); - return blockLimits.get().getRaw(key, -1); + return blockLimits.get().getRaw(key, IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override @@ -202,7 +202,7 @@ public int getEntityLimit(EntityType entityType) { @Override public int getEntityLimit(Key key) { Preconditions.checkNotNull(key, "key parameter cannot be null."); - return entityLimits.get().getOrDefault(key, -1); + return entityLimits.get().getOrDefault(key, IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override @@ -217,7 +217,7 @@ public boolean hasTeamLimit() { @Override public int getTeamLimit() { - return teamLimit.get().orElse(-1); + return teamLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override @@ -227,7 +227,7 @@ public boolean hasWarpsLimit() { @Override public int getWarpsLimit() { - return warpsLimit.get().orElse(-1); + return warpsLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override @@ -237,7 +237,7 @@ public boolean hasCoopLimit() { @Override public int getCoopLimit() { - return coopLimit.get().orElse(-1); + return coopLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override @@ -247,7 +247,7 @@ public boolean hasBorderSize() { @Override public int getBorderSize() { - return borderSize.get().orElse(-1); + return borderSize.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override @@ -297,13 +297,13 @@ public boolean hasBankLimit() { @Override public BigDecimal getBankLimit() { - return bankLimit.get().orElseGet(() -> BigDecimal.valueOf(-1)); + return bankLimit.get().orElse(IslandUpgradeConstants.NO_BANK_LIMIT_VALUE); } @Override public int getRoleLimit(PlayerRole playerRole) { Preconditions.checkNotNull(playerRole, "playerRole parameter cannot be null."); - return roleLimits.get().getOrDefault(playerRole.getId(), 0); + return roleLimits.get().getOrDefault(playerRole.getId(), IslandUpgradeConstants.NO_LIMIT_VALUE); } @Override @@ -327,15 +327,15 @@ public Map getRoleLimits() { } public DoubleValue getCropGrowthUpgradeValue() { - return DoubleValue.syncedSupplied(() -> cropGrowth.get().orElse(-1)); + return DoubleValue.syncedSupplied(() -> cropGrowth.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public DoubleValue getSpawnerRatesUpgradeValue() { - return DoubleValue.syncedSupplied(() -> spawnerRates.get().orElse(-1)); + return DoubleValue.syncedSupplied(() -> spawnerRates.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public DoubleValue getMobDropsUpgradeValue() { - return DoubleValue.syncedSupplied(() -> mobDrops.get().orElse(-1)); + return DoubleValue.syncedSupplied(() -> mobDrops.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public Map getBlockLimitsUpgradeValue() { @@ -353,19 +353,19 @@ public Map getEntityLimitsUpgradeValue() { } public IntValue getTeamLimitUpgradeValue() { - return IntValue.syncedSupplied(() -> teamLimit.get().orElse(-1)); + return IntValue.syncedSupplied(() -> teamLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public IntValue getWarpsLimitUpgradeValue() { - return IntValue.syncedSupplied(() -> warpsLimit.get().orElse(-1)); + return IntValue.syncedSupplied(() -> warpsLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public IntValue getCoopLimitUpgradeValue() { - return IntValue.syncedSupplied(() -> coopLimit.get().orElse(-1)); + return IntValue.syncedSupplied(() -> coopLimit.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public IntValue getBorderSizeUpgradeValue() { - return IntValue.syncedSupplied(() -> borderSize.get().orElse(-1)); + return IntValue.syncedSupplied(() -> borderSize.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE)); } public EnumerateMap> getGeneratorUpgradeValue() { @@ -394,7 +394,7 @@ public Map getPotionEffectsUpgradeValue() { } public Value getBankLimitUpgradeValue() { - return Value.syncedSupplied(() -> bankLimit.get().orElseGet(() -> BigDecimal.valueOf(-1))); + return Value.syncedSupplied(() -> bankLimit.get().orElseGet(() -> IslandUpgradeConstants.NO_BANK_LIMIT_VALUE)); } public Map getRoleLimitsUpgradeValue() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java index 4fd727dcd8..31c4b5f0cd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/UpgradesModule.java @@ -19,6 +19,7 @@ import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.value.Value; +import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgrade; import com.bgsoftware.superiorskyblock.island.upgrade.SUpgradeLevel; import com.bgsoftware.superiorskyblock.island.upgrade.UpgradeRequirement; @@ -266,7 +267,7 @@ private void loadUpgradeLevelFromSection(SuperiorSkyblockPlugin plugin, SUpgrade Value coopLimit = Value.syncedFixed(readInt(levelSection, "coop-limit")); Value borderSize = Value.syncedFixed(readInt(levelSection, "border-size")); - if (borderSize.get().orElse(-1) > plugin.getSettings().getMaxIslandSize()) { + if (borderSize.get().orElse(IslandUpgradeConstants.NO_LIMIT_VALUE) > plugin.getSettings().getMaxIslandSize()) { this.logger().w("Upgrade by name " + upgrade.getName() + " (level " + level + ") has illegal border-size, skipping..."); return; } From 7b2fc55bc32713186cc4dbcdcc9af3084f1e1f88 Mon Sep 17 00:00:00 2001 From: JorisvD01 <99077822+JorisvD01@users.noreply.github.com> Date: Wed, 18 Mar 2026 01:36:21 +0100 Subject: [PATCH 532/600] Fix bank logs breaking on missing position (#2890) * Fixed bank transactions capping at a fixed position and not recording new entries getLastTransactionPosition() used transaction count (size) instead of the maximum position value. When gaps existed in position numbers (caused by failed transactions consuming a position without being stored), new transactions would collide with existing positions. In CacheBankLogs, the TreeSet would silently reject duplicates, freezing the log. In DatabaseBankLogs, the counter would reset to the wrong value after restart. * Fix bank transaction player filter automatically returning to page 1 on new filtered player --------- Co-authored-by: Djoey --- .../superiorskyblock/core/menu/impl/MenuBankLogs.java | 1 + .../superiorskyblock/island/bank/logs/CacheBankLogs.java | 2 +- .../island/bank/logs/DatabaseBankLogs.java | 8 +++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java index 81603dfe95..2ddd69fd9a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBankLogs.java @@ -101,6 +101,7 @@ public void setSorting(Comparator sorting) { public void setFilteredPlayer(UUID filteredPlayer) { this.filteredPlayer = filteredPlayer == null ? CONSOLE_UUID : filteredPlayer; + this.setCurrentPage(1); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/CacheBankLogs.java b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/CacheBankLogs.java index edefbbd1f8..11516516e1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/CacheBankLogs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/CacheBankLogs.java @@ -21,7 +21,7 @@ public class CacheBankLogs implements IBankLogs { @Override public int getLastTransactionPosition() { - return this.transactions.readAndGet(SortedSet::size); + return this.transactions.readAndGet(set -> set.isEmpty() ? 0 : set.last().getPosition()); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/DatabaseBankLogs.java b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/DatabaseBankLogs.java index 1159d1de7d..b331860290 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/DatabaseBankLogs.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/bank/logs/DatabaseBankLogs.java @@ -49,7 +49,13 @@ public DatabaseBankLogs(Island island) { @Override public int getLastTransactionPosition() { if (lastTransactionPosition == -1) { - lastTransactionPosition = getTransactions().size(); + lastTransactionPosition = 0; + for (BankTransaction transaction : getTransactions()) { + int position = transaction.getPosition(); + if (position > lastTransactionPosition) { + lastTransactionPosition = position; + } + } } return lastTransactionPosition++; From 9b2e724df2f2e256b60058a1cae16f1ab5ee88ae Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Apr 2026 14:39:28 +0300 Subject: [PATCH 533/600] Adds support to 26.1 --- Hooks/AdvancedSlimePaper/build.gradle | 2 +- Hooks/AdvancedSpawners/build.gradle | 2 +- Hooks/CMI/build.gradle | 2 +- Hooks/CandcSilkSpawners/build.gradle | 2 +- Hooks/ChangeSkin/build.gradle | 2 +- Hooks/CoreProtect/build.gradle | 2 +- Hooks/CraftEngine/build.gradle | 2 +- Hooks/EpicSpawners6/build.gradle | 2 +- Hooks/EpicSpawners7/build.gradle | 2 +- Hooks/EpicSpawners8/build.gradle | 2 +- Hooks/EpicSpawners9/build.gradle | 2 +- Hooks/Essentials/build.gradle | 2 +- Hooks/FastAsyncWorldEdit/build.gradle | 2 +- Hooks/ItemsAdder/build.gradle | 2 +- Hooks/JetsMinions/build.gradle | 2 +- Hooks/LuckPerms/build.gradle | 2 +- Hooks/MVdWPlaceholderAPI/build.gradle | 2 +- Hooks/MergedSpawner/build.gradle | 2 +- Hooks/MiniMessage/build.gradle | 2 +- Hooks/Nexo/build.gradle | 2 +- Hooks/OpenJdkNashornEngine/build.gradle | 2 +- Hooks/Oraxen/build.gradle | 2 +- Hooks/PaperMC/build.gradle | 2 +- Hooks/PlaceholderAPI/build.gradle | 2 +- Hooks/ProtocolLib/build.gradle | 2 +- Hooks/PvpingSpawners/build.gradle | 2 +- Hooks/RoseStacker/build.gradle | 2 +- Hooks/SkinsRestorer/build.gradle | 2 +- Hooks/SkinsRestorer14/build.gradle | 2 +- Hooks/SkinsRestorer15/build.gradle | 2 +- Hooks/SlimeWorldManager/build.gradle | 2 +- .../ProtectionModule_Dev999/build.gradle | 2 +- .../ProtectionModule_RC13/build.gradle | 2 +- Hooks/Slimefun/build.gradle | 2 +- Hooks/SmoothTimber/build.gradle | 2 +- Hooks/SuperVanish/build.gradle | 2 +- Hooks/TimbruSilkSpawners/build.gradle | 2 +- Hooks/UltimateStacker/build.gradle | 2 +- Hooks/UltimateStacker3/build.gradle | 2 +- Hooks/UltimateStacker4/build.gradle | 2 +- Hooks/VanishNoPacket/build.gradle | 2 +- Hooks/Vault/build.gradle | 2 +- Hooks/WildStacker/build.gradle | 2 +- NMS/Paper-1_20_3/build.gradle | 4 +- NMS/Paper/build.gradle | 2 +- NMS/Spigot-1_20_3/build.gradle | 2 +- NMS/Spigot/build.gradle | 2 +- .../templates/AbstractNMSChunks.java.template | 9 +- .../templates/AbstractNMSWorld.java.template | 3 +- .../NMSDragonFightImpl.java.template | 28 +- NMS/src/main/templates/NMSUtils.java.template | 8 +- .../crops/CropsBlockEntity.java.template | 11 +- .../CropsTickingBlockEntity.java.template | 4 +- .../crops/CropsTickingMethod.java.template | 10 +- ...tractIslandEntityEnderDragon.java.template | 6 +- ...ndWorldEndDragonFightHandler.java.template | 11 +- .../dragon/IslandEndDragonFight.java.template | 32 +- .../dragon/SpikesCache.java.template | 36 +- .../AbstractEntityHologram.java.template | 6 - .../utils/SetBlockContext.java.template | 3 +- .../world/BlockEntityCache.java.template | 3 +- .../world/ChunkReaderImpl.java.template | 13 +- .../WorldEditSessionDataImpl.java.template | 10 +- .../world/WorldEditSessionImpl.java.template | 30 +- NMS/v1_12_R1/build.gradle | 2 +- NMS/v1_16_R3/build.gradle | 2 +- NMS/v1_17/build.gradle | 15 +- NMS/v1_17/properties | 4 +- .../v1_17/dragon/EndDragonFightWrapper.java | 31 ++ .../nms/v1_17/hologram/EntityHologram.java | 10 + .../nms/v1_17/utils/NMSUtilsVersioned.java | 24 +- NMS/v1_18/build.gradle | 15 +- NMS/v1_18/properties | 4 +- .../v1_18/dragon/EndDragonFightWrapper.java | 31 ++ .../nms/v1_18/hologram/EntityHologram.java | 10 + .../nms/v1_18/utils/NMSUtilsVersioned.java | 23 +- NMS/v1_19/build.gradle | 15 +- NMS/v1_19/properties | 4 +- .../v1_19/dragon/EndDragonFightWrapper.java | 31 ++ .../nms/v1_19/hologram/EntityHologram.java | 10 + .../nms/v1_19/utils/NMSUtilsVersioned.java | 23 +- NMS/v1_20_3/build.gradle | 15 +- NMS/v1_20_3/properties | 4 +- .../v1_20_3/dragon/EndDragonFightWrapper.java | 31 ++ .../nms/v1_20_3/hologram/EntityHologram.java | 10 + .../nms/v1_20_3/utils/NMSUtilsVersioned.java | 24 +- NMS/v1_20_4/build.gradle | 15 +- NMS/v1_20_4/properties | 4 +- .../v1_20_4/dragon/EndDragonFightWrapper.java | 31 ++ .../nms/v1_20_4/hologram/EntityHologram.java | 10 + .../nms/v1_20_4/utils/NMSUtilsVersioned.java | 24 +- NMS/v1_21/build.gradle | 15 +- NMS/v1_21/properties | 4 +- .../v1_21/dragon/EndDragonFightWrapper.java | 31 ++ .../nms/v1_21/hologram/EntityHologram.java | 10 + .../nms/v1_21/utils/NMSUtilsVersioned.java | 24 +- NMS/v1_21_10/build.gradle | 15 +- NMS/v1_21_10/properties | 4 +- .../dragon/EndDragonFightWrapper.java | 31 ++ .../nms/v1_21_10/hologram/EntityHologram.java | 10 + .../nms/v1_21_10/utils/NMSUtilsVersioned.java | 26 +- NMS/v1_21_3/build.gradle | 15 +- NMS/v1_21_3/properties | 4 +- .../v1_21_3/dragon/EndDragonFightWrapper.java | 31 ++ .../nms/v1_21_3/hologram/EntityHologram.java | 10 + .../nms/v1_21_3/utils/NMSUtilsVersioned.java | 24 +- NMS/v1_21_4/build.gradle | 15 +- NMS/v1_21_4/properties | 4 +- .../v1_21_4/dragon/EndDragonFightWrapper.java | 31 ++ .../nms/v1_21_4/hologram/EntityHologram.java | 10 + .../nms/v1_21_4/utils/NMSUtilsVersioned.java | 24 +- NMS/v1_21_5/build.gradle | 15 +- NMS/v1_21_5/properties | 4 +- .../v1_21_5/dragon/EndDragonFightWrapper.java | 31 ++ .../nms/v1_21_5/hologram/EntityHologram.java | 10 + .../nms/v1_21_5/utils/NMSUtilsVersioned.java | 24 +- NMS/v1_21_7/build.gradle | 15 +- NMS/v1_21_7/properties | 4 +- .../v1_21_7/dragon/EndDragonFightWrapper.java | 31 ++ .../nms/v1_21_7/hologram/EntityHologram.java | 10 + .../nms/v1_21_7/utils/NMSUtilsVersioned.java | 24 +- NMS/v1_21_9/build.gradle | 15 +- NMS/v1_21_9/properties | 4 +- .../v1_21_9/dragon/EndDragonFightWrapper.java | 31 ++ .../nms/v1_21_9/hologram/EntityHologram.java | 10 + .../nms/v1_21_9/utils/NMSUtilsVersioned.java | 24 +- NMS/v1_8_R3/build.gradle | 2 +- NMS/v26_1/build.gradle | 25 + NMS/v26_1/properties | 12 + .../nms/v26_1/NMSAlgorithmsImpl.java | 87 ++++ .../nms/v26_1/NMSChunksImpl.java | 360 ++++++++++++++ .../nms/v26_1/NMSEntitiesImpl.java | 24 + .../nms/v26_1/NMSTagsImpl.java | 146 ++++++ .../nms/v26_1/NMSWorldImpl.java | 145 ++++++ .../v26_1/dragon/EndDragonFightWrapper.java | 34 ++ .../v26_1/dragon/IslandEntityEnderDragon.java | 40 ++ .../nms/v26_1/hologram/EntityHologram.java | 64 +++ .../nms/v26_1/trial/IslandPlayerDetector.java | 53 ++ .../nms/v26_1/utils/NMSUtilsVersioned.java | 451 ++++++++++++++++++ .../v26_1/vibration/IslandVibrationUser.java | 90 ++++ .../v26_1/world/BlockLevelTicksTracker.java | 59 +++ .../CollectingNeighborUpdaterTracker.java | 44 ++ .../world/PropertiesMapperVersioned.java | 18 + build.gradle | 109 +++-- gradle/wrapper/gradle-wrapper.properties | 2 +- settings.gradle | 3 +- .../superiorskyblock/core/ServerVersion.java | 1 + 147 files changed, 2695 insertions(+), 405 deletions(-) create mode 100644 NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v26_1/build.gradle create mode 100644 NMS/v26_1/properties create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSChunksImpl.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSEntitiesImpl.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSTagsImpl.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSWorldImpl.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/IslandEntityEnderDragon.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/hologram/EntityHologram.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/utils/NMSUtilsVersioned.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/vibration/IslandVibrationUser.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/BlockLevelTicksTracker.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/CollectingNeighborUpdaterTracker.java create mode 100644 NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/PropertiesMapperVersioned.java diff --git a/Hooks/AdvancedSlimePaper/build.gradle b/Hooks/AdvancedSlimePaper/build.gradle index 6c21724d39..88c73b7a04 100644 --- a/Hooks/AdvancedSlimePaper/build.gradle +++ b/Hooks/AdvancedSlimePaper/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'com.infernalsuite:AdvancedSlimePaper:1.19.4-R0.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_slimeworldmanager') && diff --git a/Hooks/AdvancedSpawners/build.gradle b/Hooks/AdvancedSpawners/build.gradle index 4df9011d64..710170daaf 100644 --- a/Hooks/AdvancedSpawners/build.gradle +++ b/Hooks/AdvancedSpawners/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'gcspawners:AdvancedSpawners:2.2.14' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_advancedspawners') && diff --git a/Hooks/CMI/build.gradle b/Hooks/CMI/build.gradle index 0452ad5436..bcecf14e6b 100644 --- a/Hooks/CMI/build.gradle +++ b/Hooks/CMI/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'com.Zrips:CMI:8.5.1.4' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_cmi') && !Boolean.valueOf(project.findProperty("hook.compile_cmi").toString())) { diff --git a/Hooks/CandcSilkSpawners/build.gradle b/Hooks/CandcSilkSpawners/build.gradle index 7c62a8218b..4d8761ded0 100644 --- a/Hooks/CandcSilkSpawners/build.gradle +++ b/Hooks/CandcSilkSpawners/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'de.candc:SilkSpawners:1.6' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_candcsilkspawners') && diff --git a/Hooks/ChangeSkin/build.gradle b/Hooks/ChangeSkin/build.gradle index 30211a299e..05256c36c3 100644 --- a/Hooks/ChangeSkin/build.gradle +++ b/Hooks/ChangeSkin/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'com.github.games647:ChangeSkin:3.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_changeskin') && diff --git a/Hooks/CoreProtect/build.gradle b/Hooks/CoreProtect/build.gradle index 209a3af22a..8059780794 100644 --- a/Hooks/CoreProtect/build.gradle +++ b/Hooks/CoreProtect/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'net.coreprotect:CoreProtect:19.0' compileOnly "org.spigotmc:v1_16_R3:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_coreprotect') && diff --git a/Hooks/CraftEngine/build.gradle b/Hooks/CraftEngine/build.gradle index 7d665809a3..4947e7bbf9 100644 --- a/Hooks/CraftEngine/build.gradle +++ b/Hooks/CraftEngine/build.gradle @@ -15,7 +15,7 @@ dependencies { compileOnly "net.momirealms:craft-engine-bukkit:0.0.56" compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_craftengine') && diff --git a/Hooks/EpicSpawners6/build.gradle b/Hooks/EpicSpawners6/build.gradle index 49441fd75d..82813bf9f7 100644 --- a/Hooks/EpicSpawners6/build.gradle +++ b/Hooks/EpicSpawners6/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'com.songoda:EpicSpawners:6.0.6' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_epicspawners6') && diff --git a/Hooks/EpicSpawners7/build.gradle b/Hooks/EpicSpawners7/build.gradle index 8328833a22..545e3f3d1f 100644 --- a/Hooks/EpicSpawners7/build.gradle +++ b/Hooks/EpicSpawners7/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'com.songoda:EpicSpawners:7.0.2' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_epicspawners7') && diff --git a/Hooks/EpicSpawners8/build.gradle b/Hooks/EpicSpawners8/build.gradle index 76e8b8c9d2..f8f6ef98e9 100644 --- a/Hooks/EpicSpawners8/build.gradle +++ b/Hooks/EpicSpawners8/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly "com.songoda:EpicSpawners:8.1.0" compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_epicspawners8') && diff --git a/Hooks/EpicSpawners9/build.gradle b/Hooks/EpicSpawners9/build.gradle index 6fbe56ab49..ea29015339 100644 --- a/Hooks/EpicSpawners9/build.gradle +++ b/Hooks/EpicSpawners9/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly "com.songoda:EpicSpawners:9.1.1" compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_epicspawners9') && diff --git a/Hooks/Essentials/build.gradle b/Hooks/Essentials/build.gradle index 44b68ed64d..d20aec60e3 100644 --- a/Hooks/Essentials/build.gradle +++ b/Hooks/Essentials/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'com.earth2me:Essentials:2.16.0.3' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_essentials') && diff --git a/Hooks/FastAsyncWorldEdit/build.gradle b/Hooks/FastAsyncWorldEdit/build.gradle index 78e621d9f7..f5f40f3525 100644 --- a/Hooks/FastAsyncWorldEdit/build.gradle +++ b/Hooks/FastAsyncWorldEdit/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'com.boydti:FastAsyncWorldEdit:1.13.135' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_fastasyncworldedit') && diff --git a/Hooks/ItemsAdder/build.gradle b/Hooks/ItemsAdder/build.gradle index 9ac845e4c1..0aa91c173f 100644 --- a/Hooks/ItemsAdder/build.gradle +++ b/Hooks/ItemsAdder/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'dev.lone:ItemsAdder:3.5.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_itemsadder') && diff --git a/Hooks/JetsMinions/build.gradle b/Hooks/JetsMinions/build.gradle index 1458b3c27e..8f89b7e341 100644 --- a/Hooks/JetsMinions/build.gradle +++ b/Hooks/JetsMinions/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'me.jet315:JetsMinions:6.9.2' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_jetsminions') && diff --git a/Hooks/LuckPerms/build.gradle b/Hooks/LuckPerms/build.gradle index f6e7c505c1..61f40c07fe 100644 --- a/Hooks/LuckPerms/build.gradle +++ b/Hooks/LuckPerms/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'net.luckperms:LuckPerms:5.1.15' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_luckperms') && diff --git a/Hooks/MVdWPlaceholderAPI/build.gradle b/Hooks/MVdWPlaceholderAPI/build.gradle index bd4c40158e..aca8b41bfc 100644 --- a/Hooks/MVdWPlaceholderAPI/build.gradle +++ b/Hooks/MVdWPlaceholderAPI/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'be.maximvdw:MVdWPlaceholderAPI:3.0.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_mvdwplaceholderapi') && diff --git a/Hooks/MergedSpawner/build.gradle b/Hooks/MergedSpawner/build.gradle index 9dd1af5398..aa3984ef37 100644 --- a/Hooks/MergedSpawner/build.gradle +++ b/Hooks/MergedSpawner/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'com.vk2gpz:MergedSpawner:13.0.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_mergedspawner') && diff --git a/Hooks/MiniMessage/build.gradle b/Hooks/MiniMessage/build.gradle index 5b9e117a99..fc7852ac68 100644 --- a/Hooks/MiniMessage/build.gradle +++ b/Hooks/MiniMessage/build.gradle @@ -15,7 +15,7 @@ dependencies { compileOnly("net.kyori:adventure-text-serializer-plain:4.19.0") compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_minimessage') && diff --git a/Hooks/Nexo/build.gradle b/Hooks/Nexo/build.gradle index dd3e4db83d..0eb20fa019 100644 --- a/Hooks/Nexo/build.gradle +++ b/Hooks/Nexo/build.gradle @@ -15,7 +15,7 @@ dependencies { compileOnly "com.nexomc:Nexo:0.9" compileOnly "org.spigotmc:spigot-api:1.21.1-R0.1-SNAPSHOT" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_nexo') && diff --git a/Hooks/OpenJdkNashornEngine/build.gradle b/Hooks/OpenJdkNashornEngine/build.gradle index 449e6233cd..5927bc3c52 100644 --- a/Hooks/OpenJdkNashornEngine/build.gradle +++ b/Hooks/OpenJdkNashornEngine/build.gradle @@ -13,5 +13,5 @@ repositories { dependencies { compileOnly 'org.openjdk.nashorn:nashorn-core:15.4' compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } diff --git a/Hooks/Oraxen/build.gradle b/Hooks/Oraxen/build.gradle index 593f01754f..ec0c8bcc70 100644 --- a/Hooks/Oraxen/build.gradle +++ b/Hooks/Oraxen/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'io.th0rgal:Oraxen:1.187.0' compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_oraxen') && diff --git a/Hooks/PaperMC/build.gradle b/Hooks/PaperMC/build.gradle index bcccbf6e35..b1cfc40a10 100644 --- a/Hooks/PaperMC/build.gradle +++ b/Hooks/PaperMC/build.gradle @@ -3,7 +3,7 @@ group 'Hooks:PaperMC' dependencies { compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_papermc') && diff --git a/Hooks/PlaceholderAPI/build.gradle b/Hooks/PlaceholderAPI/build.gradle index 2c69756e13..c63546f628 100644 --- a/Hooks/PlaceholderAPI/build.gradle +++ b/Hooks/PlaceholderAPI/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'me.clip:PlaceholderAPI:2.10.3' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_placeholderapi') && diff --git a/Hooks/ProtocolLib/build.gradle b/Hooks/ProtocolLib/build.gradle index 5cb140dbcc..9f091f613f 100644 --- a/Hooks/ProtocolLib/build.gradle +++ b/Hooks/ProtocolLib/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly "com.comphenix.protocol:ProtocolLib:4.8.0" compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_protocollib') && diff --git a/Hooks/PvpingSpawners/build.gradle b/Hooks/PvpingSpawners/build.gradle index 94e76920d2..e80f4b8c06 100644 --- a/Hooks/PvpingSpawners/build.gradle +++ b/Hooks/PvpingSpawners/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'skyblock.hassan:PvpingSpawners:1.3' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_pvpingspawners') && diff --git a/Hooks/RoseStacker/build.gradle b/Hooks/RoseStacker/build.gradle index 46f5377f40..3bef11cb0d 100644 --- a/Hooks/RoseStacker/build.gradle +++ b/Hooks/RoseStacker/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'dev.rosewood:RoseStacker:1.4.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_rosestacker') && diff --git a/Hooks/SkinsRestorer/build.gradle b/Hooks/SkinsRestorer/build.gradle index d945fbc1d3..d40eb6f9eb 100644 --- a/Hooks/SkinsRestorer/build.gradle +++ b/Hooks/SkinsRestorer/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'net.skinsrestorer:SkinsRestorer:13.7.5' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_skinsrestorer') && diff --git a/Hooks/SkinsRestorer14/build.gradle b/Hooks/SkinsRestorer14/build.gradle index 61c17de2ce..ed1b5cf6c3 100644 --- a/Hooks/SkinsRestorer14/build.gradle +++ b/Hooks/SkinsRestorer14/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'net.skinsrestorer:SkinsRestorer:14.1.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_skinsrestorer') && diff --git a/Hooks/SkinsRestorer15/build.gradle b/Hooks/SkinsRestorer15/build.gradle index 12c59f2d53..b18fa877b6 100644 --- a/Hooks/SkinsRestorer15/build.gradle +++ b/Hooks/SkinsRestorer15/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'net.skinsrestorer:SkinsRestorer:15.0.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_skinsrestorer') && diff --git a/Hooks/SlimeWorldManager/build.gradle b/Hooks/SlimeWorldManager/build.gradle index 2fff79ab52..95ed83f910 100644 --- a/Hooks/SlimeWorldManager/build.gradle +++ b/Hooks/SlimeWorldManager/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'com.grinderwolf:SlimeWorldManager:2.2.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_slimeworldmanager') && diff --git a/Hooks/Slimefun/ProtectionModule_Dev999/build.gradle b/Hooks/Slimefun/ProtectionModule_Dev999/build.gradle index d28bacd33a..348a0d7566 100644 --- a/Hooks/Slimefun/ProtectionModule_Dev999/build.gradle +++ b/Hooks/Slimefun/ProtectionModule_Dev999/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'me.mrcookieslime:Slimefun:4.Dev999' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_slimefun') && diff --git a/Hooks/Slimefun/ProtectionModule_RC13/build.gradle b/Hooks/Slimefun/ProtectionModule_RC13/build.gradle index 92c3a492e9..09c457788c 100644 --- a/Hooks/Slimefun/ProtectionModule_RC13/build.gradle +++ b/Hooks/Slimefun/ProtectionModule_RC13/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'me.mrcookieslime:Slimefun:4.RC13' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_slimefun') && diff --git a/Hooks/Slimefun/build.gradle b/Hooks/Slimefun/build.gradle index 0b0919c247..c7fb97690e 100644 --- a/Hooks/Slimefun/build.gradle +++ b/Hooks/Slimefun/build.gradle @@ -6,7 +6,7 @@ dependencies { compileOnly project(":API") compileOnly project(":Hooks:Slimefun:ProtectionModule_RC13") compileOnly project(":Hooks:Slimefun:ProtectionModule_Dev999") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_slimefun') && diff --git a/Hooks/SmoothTimber/build.gradle b/Hooks/SmoothTimber/build.gradle index 33031051b6..7d95a580fe 100644 --- a/Hooks/SmoothTimber/build.gradle +++ b/Hooks/SmoothTimber/build.gradle @@ -10,7 +10,7 @@ dependencies { compileOnly 'com.syntaxphoenix:SmoothTimber:1.27.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_smoothtimber') && diff --git a/Hooks/SuperVanish/build.gradle b/Hooks/SuperVanish/build.gradle index 552d43a462..e4cd737c05 100644 --- a/Hooks/SuperVanish/build.gradle +++ b/Hooks/SuperVanish/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'de.myzelyam:SuperVanish:6.1.6' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_supervanish') && diff --git a/Hooks/TimbruSilkSpawners/build.gradle b/Hooks/TimbruSilkSpawners/build.gradle index ae5f9bb25e..7ef0f9934b 100644 --- a/Hooks/TimbruSilkSpawners/build.gradle +++ b/Hooks/TimbruSilkSpawners/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'de.dustplanet:SilkSpawners:6.0.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_timbrusilkspawners') && diff --git a/Hooks/UltimateStacker/build.gradle b/Hooks/UltimateStacker/build.gradle index 8d52cc8dcc..04347cca8a 100644 --- a/Hooks/UltimateStacker/build.gradle +++ b/Hooks/UltimateStacker/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'com.songoda:UltimateStacker:2.1.7' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_ultimatestacker') && diff --git a/Hooks/UltimateStacker3/build.gradle b/Hooks/UltimateStacker3/build.gradle index 3b5f6b836f..87508225fb 100644 --- a/Hooks/UltimateStacker3/build.gradle +++ b/Hooks/UltimateStacker3/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'com.craftaro:UltimateStacker:3.0.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_ultimatestacker') && diff --git a/Hooks/UltimateStacker4/build.gradle b/Hooks/UltimateStacker4/build.gradle index 5702335b36..a7ae7e8beb 100644 --- a/Hooks/UltimateStacker4/build.gradle +++ b/Hooks/UltimateStacker4/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'com.songoda:UltimateStacker:4.3.0' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_ultimatestacker') && diff --git a/Hooks/VanishNoPacket/build.gradle b/Hooks/VanishNoPacket/build.gradle index eafc57268e..ab8ac7a739 100644 --- a/Hooks/VanishNoPacket/build.gradle +++ b/Hooks/VanishNoPacket/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'org.kitteh:VanishNoPacket:3.20.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_vanishnopacket') && diff --git a/Hooks/Vault/build.gradle b/Hooks/Vault/build.gradle index 9b118c72a4..a245c897d4 100644 --- a/Hooks/Vault/build.gradle +++ b/Hooks/Vault/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'net.milkbowl:Vault:1.6.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_vault') && diff --git a/Hooks/WildStacker/build.gradle b/Hooks/WildStacker/build.gradle index d437608bda..a72704ae6b 100644 --- a/Hooks/WildStacker/build.gradle +++ b/Hooks/WildStacker/build.gradle @@ -4,7 +4,7 @@ dependencies { compileOnly 'com.bgsoftware:WildStackerAPI:3.6.1' compileOnly "org.spigotmc:v1_8_R3-Taco:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('hook.compile_wildstacker') && diff --git a/NMS/Paper-1_20_3/build.gradle b/NMS/Paper-1_20_3/build.gradle index 7446737715..0455bf5241 100644 --- a/NMS/Paper-1_20_3/build.gradle +++ b/NMS/Paper-1_20_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } group 'NMS:Paper-1_20_3' @@ -14,5 +14,5 @@ dependencies { paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT") compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } \ No newline at end of file diff --git a/NMS/Paper/build.gradle b/NMS/Paper/build.gradle index 61916eea3a..6fd5e93d50 100644 --- a/NMS/Paper/build.gradle +++ b/NMS/Paper/build.gradle @@ -4,5 +4,5 @@ dependencies { compileOnly "org.spigotmc:v1_16_R3-Tuinity:latest" compileOnly project(":NMS:Spigot") compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } \ No newline at end of file diff --git a/NMS/Spigot-1_20_3/build.gradle b/NMS/Spigot-1_20_3/build.gradle index d8f4368ff0..326d0198d7 100644 --- a/NMS/Spigot-1_20_3/build.gradle +++ b/NMS/Spigot-1_20_3/build.gradle @@ -3,5 +3,5 @@ group 'NMS:Spigot-1_20_R3' dependencies { compileOnly "org.spigotmc:v1_20_R3:b3973-3" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } \ No newline at end of file diff --git a/NMS/Spigot/build.gradle b/NMS/Spigot/build.gradle index 4560abb73a..56f59eaf45 100644 --- a/NMS/Spigot/build.gradle +++ b/NMS/Spigot/build.gradle @@ -3,5 +3,5 @@ group 'NMS:Spigot' dependencies { compileOnly "org.spigotmc:v1_16_R3:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } \ No newline at end of file diff --git a/NMS/src/main/templates/AbstractNMSChunks.java.template b/NMS/src/main/templates/AbstractNMSChunks.java.template index 440d35b15f..5524ad86e5 100644 --- a/NMS/src/main/templates/AbstractNMSChunks.java.template +++ b/NMS/src/main/templates/AbstractNMSChunks.java.template @@ -169,7 +169,8 @@ public abstract class AbstractNMSChunks implements NMSChunks { return; if (stop) { - CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(ChunkPos.asLong(chunk.getX(), chunk.getZ())); + long packedPos = NMSUtils.getChunkPackedPos(chunk.getX(), chunk.getZ()); + CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(packedPos); if (cropsBlockEntity != null) cropsBlockEntity.remove(); } else { @@ -291,12 +292,10 @@ public abstract class AbstractNMSChunks implements NMSChunks { } protected void removeEntities(LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); ServerLevel serverLevel = levelChunk.level; - int chunkWorldCoordX = chunkPos.x << 4; - int chunkWorldCoordZ = chunkPos.z << 4; - + int chunkWorldCoordX = levelChunk.locX << 4; + int chunkWorldCoordZ = levelChunk.locZ << 4; AABB chunkBounds = new AABB(chunkWorldCoordX, NMSUtilsVersioned.getMinBuildHeight(serverLevel), chunkWorldCoordZ, chunkWorldCoordX + 15, NMSUtilsVersioned.getMaxBuildHeight(serverLevel), chunkWorldCoordZ + 15); diff --git a/NMS/src/main/templates/AbstractNMSWorld.java.template b/NMS/src/main/templates/AbstractNMSWorld.java.template index 3df41b15f4..bc9cdf6ca4 100644 --- a/NMS/src/main/templates/AbstractNMSWorld.java.template +++ b/NMS/src/main/templates/AbstractNMSWorld.java.template @@ -17,6 +17,7 @@ import com.bgsoftware.superiorskyblock.nms.bridge.PistonPushReaction; import ${COMMON_NMS_PACKAGE}.algorithms.NMSCachedBlock; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.generator.IslandsGeneratorImpl; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.spawners.TickingSpawnerBlockEntityNotifier; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.ChunkReaderImpl; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.KeyBlocksCache; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.WorldEditSessionImpl; @@ -236,7 +237,7 @@ public abstract class AbstractNMSWorld implements NMSWorld { @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { - BlockState blockState = ((CraftBlock) block).getNMS(); + BlockState blockState = NMSUtilsVersioned.getBlockState(block); return PistonPushReaction.values()[blockState.getPistonPushReaction().ordinal()]; } diff --git a/NMS/src/main/templates/NMSDragonFightImpl.java.template b/NMS/src/main/templates/NMSDragonFightImpl.java.template index 854ceb2241..0ef7b2c597 100644 --- a/NMS/src/main/templates/NMSDragonFightImpl.java.template +++ b/NMS/src/main/templates/NMSDragonFightImpl.java.template @@ -5,7 +5,7 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.nms.NMSDragonFight; -import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.EndWorldEndDragonFightHandler; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.EndDragonFightWrapper; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEndDragonFight; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEntityEnderDragon; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.SpikesCache; @@ -14,8 +14,8 @@ import com.google.common.cache.LoadingCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; -import net.minecraft.world.level.dimension.end.EndDragonFight; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; +import net.minecraft.world.level.dimension.end.${END_DRAGON_FIGHT_CLASS}; +import net.minecraft.world.level.levelgen.feature.${SPIKE_FEATURE_CLASS}; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.NamespacedKey; @@ -33,11 +33,11 @@ public class NMSDragonFightImpl implements NMSDragonFight { EntityType.class, EntityType.EntityFactory.class, Modifier.PRIVATE | Modifier.FINAL, 1) .removeFinal(); - private static final ReflectField WORLD_DRAGON_BATTLE = new ReflectField<>( - ServerLevel.class, EndDragonFight.class, Modifier.PRIVATE, 1); + private static final ReflectField<${END_DRAGON_FIGHT_CLASS}> WORLD_DRAGON_BATTLE = new ReflectField<>( + ServerLevel.class, ${END_DRAGON_FIGHT_CLASS}.class, Modifier.PRIVATE, 1); - private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( - SpikeFeature.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) + private static final ReflectField>> SPIKE_CACHE = new ReflectField>>( + ${SPIKE_FEATURE_CLASS}.class, LoadingCache.class, Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL, 1) .removeFinal(); private static boolean firstWorldPreparation = true; @@ -49,7 +49,7 @@ public class NMSDragonFightImpl implements NMSDragonFight { @Override public void prepareEndWorld(World bukkitWorld) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - WORLD_DRAGON_BATTLE.set(serverLevel, new EndWorldEndDragonFightHandler(serverLevel)); + WORLD_DRAGON_BATTLE.set(serverLevel, new EndDragonFightWrapper(serverLevel)); if (firstWorldPreparation) { firstWorldPreparation = false; @@ -67,10 +67,10 @@ public class NMSDragonFightImpl implements NMSDragonFight { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndDragonFightWrapper dragonFight)) return null; - IslandEndDragonFight enderDragonBattle = dragonFightHandler.getDragonFight(island.getCache()); + IslandEndDragonFight enderDragonBattle = dragonFight.HANDLER.getDragonFight(island.getCache()); return enderDragonBattle == null ? null : enderDragonBattle.getEnderDragon().getBukkitEntity(); } @@ -83,10 +83,10 @@ public class NMSDragonFightImpl implements NMSDragonFight { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndDragonFightWrapper dragonFight)) return; - dragonFightHandler.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); + dragonFight.HANDLER.addDragonFight(island.getCache(), new IslandEndDragonFight(island, serverLevel, location)); } @Override @@ -98,10 +98,10 @@ public class NMSDragonFightImpl implements NMSDragonFight { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndWorldEndDragonFightHandler dragonFightHandler)) + if (!(NMSUtilsVersioned.getEndDragonFight(serverLevel) instanceof EndDragonFightWrapper dragonFight)) return; - EndDragonFight endDragonFight = dragonFightHandler.removeDragonFight(island.getCache()); + ${END_DRAGON_FIGHT_CLASS} endDragonFight = dragonFight.HANDLER.removeDragonFight(island.getCache()); if (endDragonFight instanceof IslandEndDragonFight islandEndDragonFight) { islandEndDragonFight.removeBattlePlayers(); diff --git a/NMS/src/main/templates/NMSUtils.java.template b/NMS/src/main/templates/NMSUtils.java.template index f118592508..31997006e5 100644 --- a/NMS/src/main/templates/NMSUtils.java.template +++ b/NMS/src/main/templates/NMSUtils.java.template @@ -267,7 +267,7 @@ public class NMSUtils { } @Override - public void prepareChunkAccess(ChunkPos chunkPos) { + public void prepareChunkAccess(int chunkX, int chunkZ) { // Do nothing } @@ -353,7 +353,7 @@ public class NMSUtils { return blockState; } - setBlockContext.prepareChunkAccess(new ChunkPos(blockPos)); + setBlockContext.prepareChunkAccess(blockPos.getX() >> 4, blockPos.getZ() >> 4); int indexY = setBlockContext.levelHeightAccessor().getSectionIndex(blockPos.getY()); @@ -391,6 +391,10 @@ public class NMSUtils { blockState.getValue(SlabBlock.TYPE) == SlabType.DOUBLE; } + public static long getChunkPackedPos(int chunkX, int chunkZ) { + return (long) chunkX & 4294967295L | ((long) chunkZ & 4294967295L) << 32; + } + public record UnloadedChunkCompound(ChunkPosition chunkPosition, net.minecraft.nbt.CompoundTag chunkCompound) { diff --git a/NMS/src/main/templates/crops/CropsBlockEntity.java.template b/NMS/src/main/templates/crops/CropsBlockEntity.java.template index ddf7f54db3..24c9b953e1 100644 --- a/NMS/src/main/templates/crops/CropsBlockEntity.java.template +++ b/NMS/src/main/templates/crops/CropsBlockEntity.java.template @@ -5,11 +5,11 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsTickingBlockEntity; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsTickingMethod; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; @@ -42,10 +42,11 @@ public class CropsBlockEntity extends BlockEntity { } public static void create(Island island, LevelChunk levelChunk) { - ChunkPos chunkPos = levelChunk.getPos(); - long chunkPair = chunkPos.toLong(); - tickingChunks.computeIfAbsent(chunkPair, p -> { - BlockPos blockPos = new BlockPos(chunkPos.x << 4, 1, chunkPos.z << 4); + int chunkX = levelChunk.locX; + int chunkZ = levelChunk.locZ; + long packedPos = NMSUtils.getChunkPackedPos(chunkX, chunkZ); + tickingChunks.computeIfAbsent(packedPos, p -> { + BlockPos blockPos = new BlockPos(chunkX << 4, 1, chunkZ << 4); return new CropsBlockEntity(island, levelChunk, blockPos); }); } diff --git a/NMS/src/main/templates/crops/CropsTickingBlockEntity.java.template b/NMS/src/main/templates/crops/CropsTickingBlockEntity.java.template index d6214befd5..24055e4bb6 100644 --- a/NMS/src/main/templates/crops/CropsTickingBlockEntity.java.template +++ b/NMS/src/main/templates/crops/CropsTickingBlockEntity.java.template @@ -1,7 +1,7 @@ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import net.minecraft.core.BlockPos; -import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.TickingBlockEntity; public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) implements TickingBlockEntity { @@ -24,7 +24,7 @@ public record CropsTickingBlockEntity(CropsBlockEntity cropsBlockEntity) impleme @Override public String getType() { - return BlockEntityType.getKey(cropsBlockEntity.getType()) + ""; + return NMSUtilsVersioned.getBlockEntityTypeKey(cropsBlockEntity.getType()) + ""; } } diff --git a/NMS/src/main/templates/crops/CropsTickingMethod.java.template b/NMS/src/main/templates/crops/CropsTickingMethod.java.template index a2e024c795..552673b70c 100644 --- a/NMS/src/main/templates/crops/CropsTickingMethod.java.template +++ b/NMS/src/main/templates/crops/CropsTickingMethod.java.template @@ -72,9 +72,8 @@ public abstract class CropsTickingMethod { LevelChunkSection[] sections = levelChunk.getSections(); int minSection = NMSUtilsVersioned.getMinSection(serverLevel); - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; + int chunkOffsetX = levelChunk.locX << 4; + int chunkOffsetZ = levelChunk.locZ << 4; ${SERVER_LEVEL_RANDOM_TYPE} simpleRandom = SERVER_LEVEL_SIMPLE_RANDOM.get(serverLevel); @@ -129,9 +128,8 @@ public abstract class CropsTickingMethod { LevelChunkSection[] sections = levelChunk.getSections(); ServerLevel serverLevel = levelChunk.level; - ChunkPos chunkPos = levelChunk.getPos(); - int chunkOffsetX = chunkPos.x << 4; - int chunkOffsetZ = chunkPos.z << 4; + int chunkOffsetX = levelChunk.locX << 4; + int chunkOffsetZ = levelChunk.locZ << 4; for (int sectionIndex = 0; sectionIndex < sections.length; ++sectionIndex) { LevelChunkSection levelChunkSection = sections[sectionIndex]; diff --git a/NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template b/NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template index 2253858535..8fd4b14219 100644 --- a/NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template +++ b/NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template @@ -8,7 +8,7 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEntityEnderDragon; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.DragonUtils; -import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.EndWorldEndDragonFightHandler; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.EndDragonFightWrapper; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEndDragonFight; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import net.minecraft.core.BlockPos; @@ -56,7 +56,7 @@ public class AbstractIslandEntityEnderDragon extends EnderDragon { } protected void finalizeIslandEnderDragon() { - if (!(NMSUtilsVersioned.getEndDragonFight(this.serverLevel) instanceof EndWorldEndDragonFightHandler dragonBattleHandler)) + if (!(NMSUtilsVersioned.getEndDragonFight(this.serverLevel) instanceof EndDragonFightWrapper dragonFight)) return; Island island; @@ -78,7 +78,7 @@ public class AbstractIslandEntityEnderDragon extends EnderDragon { IslandEndDragonFight dragonBattle = new IslandEndDragonFight(island, this.serverLevel, this.islandBlockPos, (IslandEntityEnderDragon) this); - dragonBattleHandler.addDragonFight(island.getCache(), dragonBattle); + dragonFight.HANDLER.addDragonFight(island.getCache(), dragonBattle); } } diff --git a/NMS/src/main/templates/dragon/EndWorldEndDragonFightHandler.java.template b/NMS/src/main/templates/dragon/EndWorldEndDragonFightHandler.java.template index 88cbee6092..d61330505d 100644 --- a/NMS/src/main/templates/dragon/EndWorldEndDragonFightHandler.java.template +++ b/NMS/src/main/templates/dragon/EndWorldEndDragonFightHandler.java.template @@ -4,25 +4,24 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.island.cache.IslandCacheKey; import com.bgsoftware.superiorskyblock.island.cache.IslandCacheKeys; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEndDragonFight; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.dimension.end.${END_DRAGON_FIGHT_CLASS}; import java.util.LinkedList; import java.util.List; -public class EndWorldEndDragonFightHandler extends EndDragonFight { +public class EndWorldEndDragonFightHandler { private static final IslandCacheKey CACHE_KEY = IslandCacheKeys.register("DRAGON_FIGHT", IslandEndDragonFight.class); private final List worldDragonFightsList = new LinkedList<>(); - public EndWorldEndDragonFightHandler(ServerLevel serverLevel) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + EndWorldEndDragonFightHandler() { } - @Override public void tick() { - this.worldDragonFightsList.forEach(EndDragonFight::tick); + this.worldDragonFightsList.forEach(IslandEndDragonFight::tick); } public void addDragonFight(IslandCache islandCache, IslandEndDragonFight endDragonFight) { diff --git a/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template b/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template index c512f7a5b1..a487d0a109 100644 --- a/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template +++ b/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template @@ -24,7 +24,7 @@ import net.minecraft.world.level.block.state.pattern.BlockPattern; import net.minecraft.world.level.block.state.pattern.BlockPatternBuilder; import net.minecraft.world.level.block.state.predicate.BlockPredicate; import net.minecraft.world.level.chunk.LevelChunk; -import net.minecraft.world.level.dimension.end.EndDragonFight; +import net.minecraft.world.level.dimension.end.${END_DRAGON_FIGHT_CLASS}; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.phys.Vec3; import org.bukkit.Location; @@ -39,16 +39,16 @@ import java.util.List; import java.util.Set; import java.util.UUID; -public class IslandEndDragonFight extends EndDragonFight { +public class IslandEndDragonFight extends EndDragonFightWrapper { - private static final ReflectField DRAGON_BATTLE = initializeDragonBattleField(); + private static final ReflectField<${END_DRAGON_FIGHT_CLASS}> DRAGON_BATTLE = initializeDragonBattleField(); private static final ReflectField SCAN_FOR_LEGACY_PORTALS = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 3); + ${END_DRAGON_FIGHT_CLASS}.class, boolean.class, Modifier.PRIVATE, 3); private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( - EndDragonFight.class, boolean.class, Modifier.PRIVATE, 1); + ${END_DRAGON_FIGHT_CLASS}.class, boolean.class, Modifier.PRIVATE, 1); private static final ReflectField TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>( - EndDragonFight.class, int.class, Modifier.PRIVATE, 4); + ${END_DRAGON_FIGHT_CLASS}.class, int.class, Modifier.PRIVATE, 4); private static final ReflectField LANDING_TARGET_POSITION = new ReflectField<>( DragonLandingPhase.class, Vec3.class, Modifier.PRIVATE, 1); @@ -75,7 +75,7 @@ public class IslandEndDragonFight extends EndDragonFight { public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { - super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + super(serverLevel); this.island = island; this.islandBlockPos = islandBlockPos; @@ -124,8 +124,8 @@ public class IslandEndDragonFight extends EndDragonFight { this.serverLevel, blockEntity.getBlockPos()); if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + if(getPortalPos() == null) + setPortalPos(blockPatternMatch.getBlock(3, 3, 3).getPos()); return blockPatternMatch; } @@ -145,8 +145,8 @@ public class IslandEndDragonFight extends EndDragonFight { BlockPattern.BlockPatternMatch blockPatternMatch = EXIT_PORTAL_PATTERN.find(this.serverLevel, currentPosition); if (blockPatternMatch != null) { - if (this.portalLocation == null) - this.portalLocation = blockPatternMatch.getBlock(3, 3, 3).getPos(); + if(getPortalPos() == null) + setPortalPos(blockPatternMatch.getBlock(3, 3, 3).getPos()); return blockPatternMatch; } @@ -210,15 +210,15 @@ public class IslandEndDragonFight extends EndDragonFight { return entityEnderDragon; } - private static ReflectField initializeDragonBattleField() { - ReflectField dragonBattleField = new ReflectField( - EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE | Modifier.FINAL, 1); + private static ReflectField<${END_DRAGON_FIGHT_CLASS}> initializeDragonBattleField() { + ReflectField<${END_DRAGON_FIGHT_CLASS}> dragonBattleField = new ReflectField<${END_DRAGON_FIGHT_CLASS}>( + EnderDragon.class, ${END_DRAGON_FIGHT_CLASS}.class, Modifier.PRIVATE | Modifier.FINAL, 1); if(dragonBattleField.isValid()) { dragonBattleField = dragonBattleField.removeFinal(); } else { - dragonBattleField = new ReflectField( - EnderDragon.class, EndDragonFight.class, Modifier.PRIVATE, 1); + dragonBattleField = new ReflectField<${END_DRAGON_FIGHT_CLASS}>( + EnderDragon.class, ${END_DRAGON_FIGHT_CLASS}.class, Modifier.PRIVATE, 1); } return dragonBattleField; diff --git a/NMS/src/main/templates/dragon/SpikesCache.java.template b/NMS/src/main/templates/dragon/SpikesCache.java.template index 034ec9fbb5..8395d57844 100644 --- a/NMS/src/main/templates/dragon/SpikesCache.java.template +++ b/NMS/src/main/templates/dragon/SpikesCache.java.template @@ -11,7 +11,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; -import net.minecraft.world.level.levelgen.feature.SpikeFeature; +import net.minecraft.world.level.levelgen.feature.${SPIKE_FEATURE_CLASS}; import java.util.Collections; import java.util.List; @@ -24,11 +24,11 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.IntStream; -public class SpikesCache implements LoadingCache> { +public class SpikesCache implements LoadingCache> { private static final SpikesCache INSTANCE = new SpikesCache(); - private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() + private final LoadingCache> cachedSpikes = CacheBuilder.newBuilder() .expireAfterWrite(5L, TimeUnit.MINUTES).build(new InternalCacheLoader()); private long worldSeed; @@ -43,7 +43,7 @@ public class SpikesCache implements LoadingCache get(@NotNull Long worldSeed) throws ExecutionException { + List<${SPIKE_FEATURE_CLASS}.EndSpike> get(@NotNull Long worldSeed) throws ExecutionException { try { this.worldSeed = worldSeed; return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition()); @@ -54,7 +54,7 @@ public class SpikesCache implements LoadingCache getUnchecked(@NotNull Long worldSeed) { + List<${SPIKE_FEATURE_CLASS}.EndSpike> getUnchecked(@NotNull Long worldSeed) { try { this.worldSeed = worldSeed; return cachedSpikes.getUnchecked(DragonUtils.getCurrentPodiumPosition()); @@ -65,12 +65,12 @@ public class SpikesCache implements LoadingCache> getAll(@NotNull Iterable keys) { + ImmutableMap> getAll(@NotNull Iterable keys) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override - public List apply(@NotNull Long worldSeed) { + public List<${SPIKE_FEATURE_CLASS}.EndSpike> apply(@NotNull Long worldSeed) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @@ -86,20 +86,20 @@ public class SpikesCache implements LoadingCache> asMap() { + ConcurrentMap> asMap() { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Nullable @Override - public List getIfPresent(@NotNull Object worldSeed) { + public List<${SPIKE_FEATURE_CLASS}.EndSpike> getIfPresent(@NotNull Object worldSeed) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override public @NotNull - List get(@NotNull Long worldSeed, - @NotNull Callable> loader) throws ExecutionException { + List<${SPIKE_FEATURE_CLASS}.EndSpike> get(@NotNull Long worldSeed, + @NotNull Callable> loader) throws ExecutionException { try { this.worldSeed = worldSeed; return cachedSpikes.get(DragonUtils.getCurrentPodiumPosition(), loader); @@ -110,12 +110,12 @@ public class SpikesCache implements LoadingCache> getAllPresent(@NotNull Iterable keys) { + ImmutableMap> getAllPresent(@NotNull Iterable keys) { throw new UnsupportedOperationException("This operation is not supported in SpikesCache."); } @Override - public void put(@NotNull Long worldSeed, @NotNull List spikes) { + public void put(@NotNull Long worldSeed, @NotNull List<${SPIKE_FEATURE_CLASS}.EndSpike> spikes) { try { this.worldSeed = worldSeed; cachedSpikes.put(DragonUtils.getCurrentPodiumPosition(), spikes); @@ -125,7 +125,7 @@ public class SpikesCache implements LoadingCache> spikesMap) { + public void putAll(Map> spikesMap) { spikesMap.forEach(this::put); } @@ -160,15 +160,15 @@ public class SpikesCache implements LoadingCache> { + private class InternalCacheLoader extends CacheLoader> { @Override public @NotNull - List load(@NotNull BlockPos blockPos) { + List<${SPIKE_FEATURE_CLASS}.EndSpike> load(@NotNull BlockPos blockPos) { List list = IntStream.range(0, 10).boxed().collect(Collectors.toList()); Collections.shuffle(list, new Random(worldSeed)); - List spikesList = Lists.newArrayList(); + List<${SPIKE_FEATURE_CLASS}.EndSpike> spikesList = Lists.newArrayList(); for (int i = 0; i < 10; ++i) { int spikeX = Mth.floor(42.0D * Math.cos(2.0D * (-3.141592653589793D + 0.3141592653589793D * (double) i))); @@ -178,7 +178,7 @@ public class SpikesCache implements LoadingCache { for (BlockEntityType blockEntityType : ${REGISTRY_CLASS}.BLOCK_ENTITY_TYPE) { if (blockEntityType.isValid(blockState)) { - Object resourceLocation = BlockEntityType.getKey(blockEntityType); + Object resourceLocation = NMSUtilsVersioned.getBlockEntityTypeKey(blockEntityType); if (resourceLocation != null) return resourceLocation.toString(); } diff --git a/NMS/src/main/templates/world/ChunkReaderImpl.java.template b/NMS/src/main/templates/world/ChunkReaderImpl.java.template index 678036b644..e0a1c3faef 100644 --- a/NMS/src/main/templates/world/ChunkReaderImpl.java.template +++ b/NMS/src/main/templates/world/ChunkReaderImpl.java.template @@ -11,7 +11,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.SectionPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BooleanProperty; @@ -61,9 +60,8 @@ public class ChunkReaderImpl implements ChunkReader { this.serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle(); LevelChunk levelChunk = this.serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); - ChunkPos chunkPos = levelChunk.getPos(); - this.x = chunkPos.x; - this.z = chunkPos.z; + this.x = levelChunk.locX; + this.z = levelChunk.locZ; LevelChunkSection[] levelChunkSections = levelChunk.getSections(); this.blockids = new PalettedContainer[levelChunkSections.length]; @@ -150,12 +148,9 @@ public class ChunkReaderImpl implements ChunkReader { public CompoundTag readBlockStates(int x, int y, int z) { BlockState blockState = getBlockState(x, y, z); - if (blockState.getValues().isEmpty()) - return null; - CompoundTag compoundTag = CompoundTag.of(); - blockState.getValues().forEach((property, value) -> { + boolean processedAny = NMSUtilsVersioned.forEachProperty(blockState, (property, value) -> { String name = PropertiesMapper.getPropertyName(property); if (property instanceof BooleanProperty) { @@ -167,7 +162,7 @@ public class ChunkReaderImpl implements ChunkReader { } }); - return compoundTag; + return processedAny ? compoundTag : null; } @Override diff --git a/NMS/src/main/templates/world/WorldEditSessionDataImpl.java.template b/NMS/src/main/templates/world/WorldEditSessionDataImpl.java.template index 5b74c899f4..8b3ab5577a 100644 --- a/NMS/src/main/templates/world/WorldEditSessionDataImpl.java.template +++ b/NMS/src/main/templates/world/WorldEditSessionDataImpl.java.template @@ -3,6 +3,7 @@ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world; import com.bgsoftware.superiorskyblock.api.objects.Pair; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.nms.world.WorldEditSession; +import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.world.WorldEditSessionImpl; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import net.minecraft.core.BlockPos; @@ -10,6 +11,7 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.phys.Vec2; import org.bukkit.Location; import java.util.Collections; @@ -39,7 +41,7 @@ public class WorldEditSessionDataImpl implements WorldEditSession.Data { public WorldEditSessionDataImpl(Location baseLocation, Long2ObjectMapView chunks, List> blocksToUpdate, List> blockEntities, - Set lightenChunks) { + Set lightenChunks) { int baseBlockPosXAxis = baseLocation.getBlockX(); int baseBlockPosYAxis = baseLocation.getBlockY(); int baseBlockPosZAxis = baseLocation.getBlockZ(); @@ -91,8 +93,8 @@ public class WorldEditSessionDataImpl implements WorldEditSession.Data { // Convert lights lightenChunks.forEach(lightPosition -> { - this.lightenChunks.add(new PositionedObject<>(lightPosition.x - baseChunkPosXAxis, - lightPosition.z - baseChunkPosZAxis, null)); + this.lightenChunks.add(new PositionedObject<>((int)lightPosition.x - baseChunkPosXAxis, + (int)lightPosition.y - baseChunkPosZAxis, null)); }); } @@ -100,7 +102,7 @@ public class WorldEditSessionDataImpl implements WorldEditSession.Data { int baseBlockPosZAxis, WorldEditSessionImpl worldEditSession, Long2ObjectMapView chunks) { this.chunks.forEach(chunkDataPositioned -> { - long newPos = ChunkPos.asLong(baseChunkPosXAxis + chunkDataPositioned.xOffset, + long newPos = NMSUtils.getChunkPackedPos(baseChunkPosXAxis + chunkDataPositioned.xOffset, baseChunkPosZAxis + chunkDataPositioned.zOffset); List lights = chunkDataPositioned.object.lights.isEmpty() ? Collections.emptyList() : new LinkedList<>(); diff --git a/NMS/src/main/templates/world/WorldEditSessionImpl.java.template b/NMS/src/main/templates/world/WorldEditSessionImpl.java.template index 42e2658c34..e2330a98c9 100644 --- a/NMS/src/main/templates/world/WorldEditSessionImpl.java.template +++ b/NMS/src/main/templates/world/WorldEditSessionImpl.java.template @@ -29,6 +29,7 @@ import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.ProtoChunk; import net.minecraft.world.level.dimension.DimensionType; import net.minecraft.world.level.levelgen.Heightmap; +import net.minecraft.world.phys.Vec2; import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; @@ -61,7 +62,8 @@ public class WorldEditSessionImpl implements WorldEditSession { private final Long2ObjectMapView chunks = CollectionsFactory.createLong2ObjectArrayMap(); private final List> blocksToUpdate = new LinkedList<>(); private final List> blockEntities = new LinkedList<>(); - private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); + private final Set lightenChunks = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); + private final Set lightenChunksPositions = isStarLightInterface ? new HashSet<>() : Collections.emptySet(); private Dimension dimension; private LevelHeightAccessor levelHeightAccessor; @@ -79,8 +81,9 @@ public class WorldEditSessionImpl implements WorldEditSession { } @Override - public void prepareChunkAccess(ChunkPos chunkPos) { - chunkData = chunks.computeIfAbsent(chunkPos.toLong(), ChunkData::new); + public void prepareChunkAccess(int chunkX, int chunkZ) { + long packedPos = NMSUtils.getChunkPackedPos(chunkX, chunkZ); + chunkData = chunks.computeIfAbsent(packedPos, pos -> new ChunkData(new ChunkPos(chunkX, chunkZ))); } @Override @@ -172,11 +175,13 @@ public class WorldEditSessionImpl implements WorldEditSession { public void applyBlocks(Chunk bukkitChunk) { Preconditions.checkState(this.serverLevel != null, "Cannot call WorldEditSession#applyBlocks on partial initialized session"); + int chunkX = bukkitChunk.getX(); + int chunkZ = bukkitChunk.getZ(); + ServerLevel serverLevel = ((CraftWorld) bukkitChunk.getWorld()).getHandle(); - LevelChunk levelChunk = serverLevel.getChunk(bukkitChunk.getX(), bukkitChunk.getZ()); - ChunkPos chunkPos = levelChunk.getPos(); + LevelChunk levelChunk = serverLevel.getChunk(chunkX, chunkZ); - long chunkKey = chunkPos.toLong(); + long chunkKey = NMSUtils.getChunkPackedPos(chunkX, chunkZ); ChunkData chunkData = this.chunks.remove(chunkKey); if (chunkData == null) @@ -193,7 +198,8 @@ public class WorldEditSessionImpl implements WorldEditSession { if (plugin.getSettings().isLightsUpdate()) { if (isStarLightInterface) { - this.lightenChunks.add(chunkPos); + this.lightenChunks.add(new Vec2(chunkX, chunkZ)); + this.lightenChunksPositions.add(levelChunk.getPos()); } else { ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); chunkData.lights.forEach(threadedLevelLightEngine::checkBlock); @@ -232,8 +238,9 @@ public class WorldEditSessionImpl implements WorldEditSession { if (plugin.getSettings().isLightsUpdate() && isStarLightInterface && !lightenChunks.isEmpty()) { ThreadedLevelLightEngine threadedLevelLightEngine = serverLevel.getChunkSource().getLightEngine(); - NMSUtilsVersioned.relightChunks(threadedLevelLightEngine, lightenChunks); + NMSUtilsVersioned.relightChunks(threadedLevelLightEngine, lightenChunksPositions); this.lightenChunks.clear(); + this.lightenChunksPositions.clear(); } release(); @@ -260,7 +267,7 @@ public class WorldEditSessionImpl implements WorldEditSession { baseBlockPosZAxis, this, this.chunks); dataImpl.readBlocksToUpdate(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blocksToUpdate); dataImpl.readBlockEntities(baseBlockPosXAxis, baseBlockPosYAxis, baseBlockPosZAxis, this.blockEntities); - dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunks); + dataImpl.readLights(baseChunkPosXAxis, baseChunkPosZAxis, this.lightenChunksPositions); } @Override @@ -269,6 +276,7 @@ public class WorldEditSessionImpl implements WorldEditSession { this.blocksToUpdate.clear(); this.blockEntities.clear(); this.lightenChunks.clear(); + this.lightenChunksPositions.clear(); this.serverLevel = null; this.dimension = null; this.levelHeightAccessor = null; @@ -308,12 +316,10 @@ public class WorldEditSessionImpl implements WorldEditSession { private final Map heightmaps; private final List lights; - private ChunkData(long chunkKey) { + private ChunkData(ChunkPos chunkPos) { this(new LevelChunkSection[levelHeightAccessor.getSectionsCount()], new EnumMap<>(Heightmap.Types.class), isStarLightInterface ? Collections.emptyList() : new LinkedList<>()); - ChunkPos chunkPos = new ChunkPos(chunkKey); - NMSUtilsVersioned.createChunkSections(serverLevel, levelHeightAccessor, this.chunkSections, dimension); ProtoChunk tempChunk = NMSUtilsVersioned.createProtoChunk( diff --git a/NMS/v1_12_R1/build.gradle b/NMS/v1_12_R1/build.gradle index 92a29175d3..1d46803b37 100644 --- a/NMS/v1_12_R1/build.gradle +++ b/NMS/v1_12_R1/build.gradle @@ -3,7 +3,7 @@ group 'NMS:v1_12_R1' dependencies { compileOnly "org.spigotmc:v1_12_R1-Paper:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('nms.compile_v1_12') && !Boolean.valueOf(project.findProperty("nms.compile_v1_12").toString())) { diff --git a/NMS/v1_16_R3/build.gradle b/NMS/v1_16_R3/build.gradle index 2b0ae259e0..1770ccde45 100644 --- a/NMS/v1_16_R3/build.gradle +++ b/NMS/v1_16_R3/build.gradle @@ -5,7 +5,7 @@ dependencies { compileOnly project(":NMS:Spigot") compileOnly project(":NMS:Paper") compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('nms.compile_v1_16') && !Boolean.valueOf(project.findProperty("nms.compile_v1_16").toString())) { diff --git a/NMS/v1_17/build.gradle b/NMS/v1_17/build.gradle index bf5f5d8352..485e69e3d3 100644 --- a/NMS/v1_17/build.gradle +++ b/NMS/v1_17/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { @@ -15,24 +15,13 @@ dependencies { compileOnly project(":NMS:Spigot") compileOnly project(":NMS:Paper") compileOnly project(":API") - compileOnly rootProject -} - -shadowJar { - archiveFileName = "${project.name}-exclude.jar" + compileOnly project(":") } assemble { dependsOn(reobfJar) } -tasks { - reobfJar { - File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") - outputJar.set(layout.buildDirectory.file(outputFile.getPath())) - } -} - if (project.hasProperty('nms.compile_v1_17') && !Boolean.valueOf(project.findProperty("nms.compile_v1_17").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_17/properties b/NMS/v1_17/properties index cb208334a4..0a3a9fdabb 100644 --- a/NMS/v1_17/properties +++ b/NMS/v1_17/properties @@ -7,4 +7,6 @@ CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=java.util.Random STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle -GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) +END_DRAGON_FIGHT_CLASS=EndDragonFight +SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndDragonFightWrapper.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..9a6a0d60f1 --- /dev/null +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndDragonFightWrapper.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_17.dragon; + +import com.bgsoftware.superiorskyblock.nms.v1_17.dragon.EndWorldEndDragonFightHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +public class EndDragonFightWrapper extends EndDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.portalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.portalLocation = blockPos; + } + + + +} diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/hologram/EntityHologram.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/hologram/EntityHologram.java index f6edd2e5d6..a53d882bf8 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/hologram/EntityHologram.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/hologram/EntityHologram.java @@ -2,6 +2,10 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_17.hologram.AbstractEntityHologram { @@ -36,4 +40,10 @@ public void load(CompoundTag compoundTag) { // Do not load NBT. } + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java index 111d3fbbfe..be8c7c6f11 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/utils/NMSUtilsVersioned.java @@ -13,13 +13,13 @@ import com.bgsoftware.superiorskyblock.nms.v1_17.world.WorldEditSessionImpl; import com.google.common.base.Suppliers; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; @@ -33,7 +33,9 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -49,6 +51,7 @@ import net.minecraft.world.level.material.Fluids; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_17_R1.block.CraftBlock; import org.bukkit.craftbukkit.v1_17_R1.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage; import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; @@ -63,6 +66,7 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; public class NMSUtilsVersioned { @@ -259,7 +263,7 @@ public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } - public static String getPropertyValue(Property property) { + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.getValue(); } @@ -295,6 +299,22 @@ public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, return compoundTag.getLong(key); } + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getNMS(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + if (blockState.getValues().isEmpty()) + return false; + + blockState.getValues().forEach(consumer); + return true; + } + + public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { + return BlockEntityType.getKey(type); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_18/build.gradle b/NMS/v1_18/build.gradle index bdcf38c1ca..f82af39f1e 100644 --- a/NMS/v1_18/build.gradle +++ b/NMS/v1_18/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { @@ -15,24 +15,13 @@ dependencies { compileOnly project(":NMS:Spigot") compileOnly project(":NMS:Paper") compileOnly project(":API") - compileOnly rootProject -} - -shadowJar { - archiveFileName = "${project.name}-exclude.jar" + compileOnly project(":") } assemble { dependsOn(reobfJar) } -tasks { - reobfJar { - File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") - outputJar.set(layout.buildDirectory.file(outputFile.getPath())) - } -} - if (project.hasProperty('nms.compile_v1_18') && !Boolean.valueOf(project.findProperty("nms.compile_v1_18").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_18/properties b/NMS/v1_18/properties index 47b4067ae2..b32acd70c2 100644 --- a/NMS/v1_18/properties +++ b/NMS/v1_18/properties @@ -7,4 +7,6 @@ CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=java.util.Random STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle -GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) +END_DRAGON_FIGHT_CLASS=EndDragonFight +SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndDragonFightWrapper.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..59afbcbe30 --- /dev/null +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndDragonFightWrapper.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_18.dragon; + +import com.bgsoftware.superiorskyblock.nms.v1_18.dragon.EndWorldEndDragonFightHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +public class EndDragonFightWrapper extends EndDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.portalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.portalLocation = blockPos; + } + + + +} diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/hologram/EntityHologram.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/hologram/EntityHologram.java index ea0460f312..deb97441f1 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/hologram/EntityHologram.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/hologram/EntityHologram.java @@ -2,6 +2,10 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_18.hologram.AbstractEntityHologram { @@ -36,4 +40,10 @@ public void load(CompoundTag compoundTag) { // Do not load NBT. } + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java index 6caef06a74..d567f3a31e 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/utils/NMSUtilsVersioned.java @@ -12,13 +12,13 @@ import com.bgsoftware.superiorskyblock.nms.v1_18.utils.TickingBlockList; import com.google.common.base.Suppliers; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; @@ -32,7 +32,9 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; @@ -62,6 +64,7 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; public class NMSUtilsVersioned { @@ -249,7 +252,7 @@ public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } - public static String getPropertyValue(Property property) { + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.getValue(); } @@ -285,6 +288,22 @@ public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, return compoundTag.getLong(key); } + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getNMS(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + if (blockState.getValues().isEmpty()) + return false; + + blockState.getValues().forEach(consumer); + return true; + } + + public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { + return BlockEntityType.getKey(type); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_19/build.gradle b/NMS/v1_19/build.gradle index 39cf25b853..c67751da8b 100644 --- a/NMS/v1_19/build.gradle +++ b/NMS/v1_19/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { @@ -15,24 +15,13 @@ dependencies { compileOnly project(":NMS:Spigot") compileOnly project(":NMS:Paper") compileOnly project(":API") - compileOnly rootProject -} - -shadowJar { - archiveFileName = "${project.name}-exclude.jar" + compileOnly project(":") } assemble { dependsOn(reobfJar) } -tasks { - reobfJar { - File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") - outputJar.set(layout.buildDirectory.file(outputFile.getPath())) - } -} - if (project.hasProperty('nms.compile_v1_19') && !Boolean.valueOf(project.findProperty("nms.compile_v1_19").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_19/properties b/NMS/v1_19/properties index 4e09ae1316..d240d1c6c7 100644 --- a/NMS/v1_19/properties +++ b/NMS/v1_19/properties @@ -7,4 +7,6 @@ CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle -GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) +END_DRAGON_FIGHT_CLASS=EndDragonFight +SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndDragonFightWrapper.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..1ffe3aa974 --- /dev/null +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndDragonFightWrapper.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_19.dragon; + +import com.bgsoftware.superiorskyblock.nms.v1_19.dragon.EndWorldEndDragonFightHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +public class EndDragonFightWrapper extends EndDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.portalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.portalLocation = blockPos; + } + + + +} diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/hologram/EntityHologram.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/hologram/EntityHologram.java index cad2f29de6..ac3eb9075d 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/hologram/EntityHologram.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/hologram/EntityHologram.java @@ -2,6 +2,10 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_19.hologram.AbstractEntityHologram { @@ -36,4 +40,10 @@ public void load(CompoundTag compoundTag) { // Do not load NBT. } + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java index b429123007..1caf28e1de 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/utils/NMSUtilsVersioned.java @@ -13,7 +13,6 @@ import com.bgsoftware.superiorskyblock.nms.v1_19.utils.TickingBlockList; import com.google.common.base.Suppliers; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; @@ -22,6 +21,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; @@ -35,7 +35,9 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; @@ -67,6 +69,7 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; public class NMSUtilsVersioned { @@ -280,7 +283,7 @@ public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } - public static String getPropertyValue(Property property) { + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.getValue(); } @@ -316,6 +319,22 @@ public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, return compoundTag.getLong(key); } + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getNMS(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + if (blockState.getValues().isEmpty()) + return false; + + blockState.getValues().forEach(consumer); + return true; + } + + public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { + return BlockEntityType.getKey(type); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_20_3/build.gradle b/NMS/v1_20_3/build.gradle index 94cd254e76..c8c13d693f 100644 --- a/NMS/v1_20_3/build.gradle +++ b/NMS/v1_20_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { @@ -15,24 +15,13 @@ dependencies { compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") - compileOnly rootProject -} - -shadowJar { - archiveFileName = "${project.name}-exclude.jar" + compileOnly project(":") } assemble { dependsOn(reobfJar) } -tasks { - reobfJar { - File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") - outputJar.set(layout.buildDirectory.file(outputFile.getPath())) - } -} - if (project.hasProperty('nms.compile_v1_20') && !Boolean.valueOf(project.findProperty("nms.compile_v1_20").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_20_3/properties b/NMS/v1_20_3/properties index 3a073245fb..e601ac463d 100644 --- a/NMS/v1_20_3/properties +++ b/NMS/v1_20_3/properties @@ -7,4 +7,6 @@ CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle -GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) +END_DRAGON_FIGHT_CLASS=EndDragonFight +SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndDragonFightWrapper.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..73cce416fa --- /dev/null +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndDragonFightWrapper.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon; + +import com.bgsoftware.superiorskyblock.nms.v1_20_3.dragon.EndWorldEndDragonFightHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +public class EndDragonFightWrapper extends EndDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.portalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.portalLocation = blockPos; + } + + + +} diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/hologram/EntityHologram.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/hologram/EntityHologram.java index 566c8cb5d2..70c352f6c6 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/hologram/EntityHologram.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/hologram/EntityHologram.java @@ -2,6 +2,10 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_20_3.hologram.AbstractEntityHologram { @@ -36,4 +40,10 @@ public void load(CompoundTag compoundTag) { // Do not load NBT. } + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java index 0e8da41819..29a4d2a198 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/utils/NMSUtilsVersioned.java @@ -13,7 +13,6 @@ import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; @@ -24,6 +23,7 @@ import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; @@ -39,8 +39,10 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.LevelChunk; @@ -58,6 +60,7 @@ import org.bukkit.Material; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.block.CraftBiome; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock; import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; @@ -74,6 +77,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; public class NMSUtilsVersioned { @@ -279,7 +283,7 @@ public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } - public static String getPropertyValue(Property property) { + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } @@ -367,6 +371,22 @@ private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) } } + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getNMS(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + if (blockState.getValues().isEmpty()) + return false; + + blockState.getValues().forEach(consumer); + return true; + } + + public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { + return BlockEntityType.getKey(type); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_20_4/build.gradle b/NMS/v1_20_4/build.gradle index 808202fdbe..335c44597b 100644 --- a/NMS/v1_20_4/build.gradle +++ b/NMS/v1_20_4/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { @@ -15,24 +15,13 @@ dependencies { compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") - compileOnly rootProject -} - -shadowJar { - archiveFileName = "${project.name}-exclude.jar" + compileOnly project(":") } assemble { dependsOn(reobfJar) } -tasks { - reobfJar { - File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") - outputJar.set(layout.buildDirectory.file(outputFile.getPath())) - } -} - if (project.hasProperty('nms.compile_v1_20') && !Boolean.valueOf(project.findProperty("nms.compile_v1_20").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_20_4/properties b/NMS/v1_20_4/properties index ecc89fb050..bfc67e1151 100644 --- a/NMS/v1_20_4/properties +++ b/NMS/v1_20_4/properties @@ -7,4 +7,6 @@ CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle -GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) +END_DRAGON_FIGHT_CLASS=EndDragonFight +SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndDragonFightWrapper.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..eb66afb754 --- /dev/null +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndDragonFightWrapper.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon; + +import com.bgsoftware.superiorskyblock.nms.v1_20_4.dragon.EndWorldEndDragonFightHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +public class EndDragonFightWrapper extends EndDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.portalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.portalLocation = blockPos; + } + + + +} diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/hologram/EntityHologram.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/hologram/EntityHologram.java index 99fe663b4d..991c9998f1 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/hologram/EntityHologram.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/hologram/EntityHologram.java @@ -2,6 +2,10 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_20_4.hologram.AbstractEntityHologram { @@ -36,4 +40,10 @@ public void load(CompoundTag compoundTag) { // Do not load NBT. } + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java index b05151d123..eff43ab53a 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/utils/NMSUtilsVersioned.java @@ -13,7 +13,6 @@ import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; @@ -24,6 +23,7 @@ import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; @@ -39,8 +39,10 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -58,6 +60,7 @@ import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; @@ -74,6 +77,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; public class NMSUtilsVersioned { @@ -331,7 +335,7 @@ public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } - public static String getPropertyValue(Property property) { + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } @@ -367,6 +371,22 @@ public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, return compoundTag.getLong(key); } + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getNMS(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + if (blockState.getValues().isEmpty()) + return false; + + blockState.getValues().forEach(consumer); + return true; + } + + public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { + return BlockEntityType.getKey(type); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_21/build.gradle b/NMS/v1_21/build.gradle index fcc7b15fe0..3197418f99 100644 --- a/NMS/v1_21/build.gradle +++ b/NMS/v1_21/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { @@ -15,24 +15,13 @@ dependencies { compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") - compileOnly rootProject -} - -shadowJar { - archiveFileName = "${project.name}-exclude.jar" + compileOnly project(":") } assemble { dependsOn(reobfJar) } -tasks { - reobfJar { - File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") - outputJar.set(layout.buildDirectory.file(outputFile.getPath())) - } -} - if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_21/properties b/NMS/v1_21/properties index ba78f8cb8d..3f84e339d7 100644 --- a/NMS/v1_21/properties +++ b/NMS/v1_21/properties @@ -7,4 +7,6 @@ CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle -GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) +END_DRAGON_FIGHT_CLASS=EndDragonFight +SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndDragonFightWrapper.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..d2d2316ba8 --- /dev/null +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndDragonFightWrapper.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21.dragon; + +import com.bgsoftware.superiorskyblock.nms.v1_21.dragon.EndWorldEndDragonFightHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +public class EndDragonFightWrapper extends EndDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.portalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.portalLocation = blockPos; + } + + + +} diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/hologram/EntityHologram.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/hologram/EntityHologram.java index 3d4c5ea3eb..5018b2b134 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/hologram/EntityHologram.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/hologram/EntityHologram.java @@ -2,6 +2,10 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21.hologram.AbstractEntityHologram { @@ -36,4 +40,10 @@ public void load(CompoundTag compoundTag) { // Do not load NBT. } + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java index 5b474a2d93..c909c68738 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/utils/NMSUtilsVersioned.java @@ -13,7 +13,6 @@ import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; @@ -24,6 +23,7 @@ import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; @@ -39,8 +39,10 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -61,6 +63,7 @@ import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; @@ -77,6 +80,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; public class NMSUtilsVersioned { @@ -288,7 +292,7 @@ public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } - public static String getPropertyValue(Property property) { + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } @@ -376,6 +380,22 @@ private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) } } + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getNMS(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + if (blockState.getValues().isEmpty()) + return false; + + blockState.getValues().forEach(consumer); + return true; + } + + public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { + return BlockEntityType.getKey(type); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_21_10/build.gradle b/NMS/v1_21_10/build.gradle index 404cd93a9a..4858da32b7 100644 --- a/NMS/v1_21_10/build.gradle +++ b/NMS/v1_21_10/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { @@ -15,24 +15,13 @@ dependencies { compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") - compileOnly rootProject -} - -shadowJar { - archiveFileName = "${project.name}-exclude.jar" + compileOnly project(":") } assemble { dependsOn(reobfJar) } -tasks { - reobfJar { - File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") - outputJar.set(layout.buildDirectory.file(outputFile.getPath())) - } -} - if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_21_10/properties b/NMS/v1_21_10/properties index dfc0b992a7..5f03a6f719 100644 --- a/NMS/v1_21_10/properties +++ b/NMS/v1_21_10/properties @@ -7,4 +7,6 @@ CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle.minecart -GET_RANDOM_TICK_SPEED_METHOD=get(net.minecraft.world.level.gamerules.GameRules.RANDOM_TICK_SPEED) \ No newline at end of file +GET_RANDOM_TICK_SPEED_METHOD=get(net.minecraft.world.level.gamerules.GameRules.RANDOM_TICK_SPEED) +END_DRAGON_FIGHT_CLASS=EndDragonFight +SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/EndDragonFightWrapper.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..8e18d50e0a --- /dev/null +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/EndDragonFightWrapper.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_10.dragon; + +import com.bgsoftware.superiorskyblock.nms.v1_21_10.dragon.EndWorldEndDragonFightHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +public class EndDragonFightWrapper extends EndDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.portalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.portalLocation = blockPos; + } + + + +} diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/hologram/EntityHologram.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/hologram/EntityHologram.java index 9c18f54de0..5ae827b8f5 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/hologram/EntityHologram.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/hologram/EntityHologram.java @@ -1,8 +1,12 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_10.hologram; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; +import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_10.hologram.AbstractEntityHologram { @@ -52,4 +56,10 @@ public void load(ValueInput input) { // Do not load NBT. } + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + } diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java index 328628ee17..c4d886170c 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/utils/NMSUtilsVersioned.java @@ -10,11 +10,8 @@ import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; import com.bgsoftware.superiorskyblock.nms.v1_21_10.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.v1_21_10.utils.TickingBlockList; -import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import net.minecraft.core.Holder; @@ -25,6 +22,7 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; @@ -41,8 +39,10 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -67,6 +67,7 @@ import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; @@ -83,6 +84,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; public class NMSUtilsVersioned { @@ -308,7 +310,7 @@ public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.properties(); } - public static String getPropertyValue(Property property) { + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } @@ -418,6 +420,22 @@ private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) } } + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getNMS(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + if (blockState.getValues().isEmpty()) + return false; + + blockState.getValues().forEach(consumer); + return true; + } + + public static Identifier getBlockEntityTypeKey(BlockEntityType type) { + return BlockEntityType.getKey(type); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_21_3/build.gradle b/NMS/v1_21_3/build.gradle index 4c164d66eb..89e3ceab83 100644 --- a/NMS/v1_21_3/build.gradle +++ b/NMS/v1_21_3/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { @@ -15,24 +15,13 @@ dependencies { compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") - compileOnly rootProject -} - -shadowJar { - archiveFileName = "${project.name}-exclude.jar" + compileOnly project(":") } assemble { dependsOn(reobfJar) } -tasks { - reobfJar { - File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") - outputJar.set(layout.buildDirectory.file(outputFile.getPath())) - } -} - if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_21_3/properties b/NMS/v1_21_3/properties index 5fc11e7a2a..3e4b00f9d9 100644 --- a/NMS/v1_21_3/properties +++ b/NMS/v1_21_3/properties @@ -7,4 +7,6 @@ CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle -GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) +END_DRAGON_FIGHT_CLASS=EndDragonFight +SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndDragonFightWrapper.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..594004c520 --- /dev/null +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndDragonFightWrapper.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon; + +import com.bgsoftware.superiorskyblock.nms.v1_21_3.dragon.EndWorldEndDragonFightHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +public class EndDragonFightWrapper extends EndDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.portalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.portalLocation = blockPos; + } + + + +} diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/hologram/EntityHologram.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/hologram/EntityHologram.java index c17b157278..c8a340268a 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/hologram/EntityHologram.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/hologram/EntityHologram.java @@ -2,6 +2,10 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_3.hologram.AbstractEntityHologram { @@ -36,4 +40,10 @@ public void load(CompoundTag compoundTag) { // Do not load NBT. } + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java index 334bae5862..a422d940b8 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/utils/NMSUtilsVersioned.java @@ -14,7 +14,6 @@ import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; @@ -25,6 +24,7 @@ import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; @@ -40,8 +40,10 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -61,6 +63,7 @@ import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; @@ -76,6 +79,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; public class NMSUtilsVersioned { @@ -297,7 +301,7 @@ public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } - public static String getPropertyValue(Property property) { + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } @@ -385,6 +389,22 @@ private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) } } + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getNMS(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + if (blockState.getValues().isEmpty()) + return false; + + blockState.getValues().forEach(consumer); + return true; + } + + public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { + return BlockEntityType.getKey(type); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_21_4/build.gradle b/NMS/v1_21_4/build.gradle index b868b25a2d..5fd2d8a61c 100644 --- a/NMS/v1_21_4/build.gradle +++ b/NMS/v1_21_4/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { @@ -15,24 +15,13 @@ dependencies { compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") - compileOnly rootProject -} - -shadowJar { - archiveFileName = "${project.name}-exclude.jar" + compileOnly project(":") } assemble { dependsOn(reobfJar) } -tasks { - reobfJar { - File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") - outputJar.set(layout.buildDirectory.file(outputFile.getPath())) - } -} - if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_21_4/properties b/NMS/v1_21_4/properties index 15bec624c2..8dbb058db2 100644 --- a/NMS/v1_21_4/properties +++ b/NMS/v1_21_4/properties @@ -7,4 +7,6 @@ CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle -GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) +END_DRAGON_FIGHT_CLASS=EndDragonFight +SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndDragonFightWrapper.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..5704cc6170 --- /dev/null +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndDragonFightWrapper.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon; + +import com.bgsoftware.superiorskyblock.nms.v1_21_4.dragon.EndWorldEndDragonFightHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +public class EndDragonFightWrapper extends EndDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.portalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.portalLocation = blockPos; + } + + + +} diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/hologram/EntityHologram.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/hologram/EntityHologram.java index aac6edff5d..ba937c96f5 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/hologram/EntityHologram.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/hologram/EntityHologram.java @@ -2,6 +2,10 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_4.hologram.AbstractEntityHologram { @@ -36,4 +40,10 @@ public void load(CompoundTag compoundTag) { // Do not load NBT. } + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java index 0e0a16c29c..4351d49104 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/utils/NMSUtilsVersioned.java @@ -14,7 +14,6 @@ import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; @@ -25,6 +24,7 @@ import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; @@ -40,8 +40,10 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -61,6 +63,7 @@ import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; @@ -76,6 +79,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; public class NMSUtilsVersioned { @@ -297,7 +301,7 @@ public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } - public static String getPropertyValue(Property property) { + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } @@ -385,6 +389,22 @@ private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) } } + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getNMS(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + if (blockState.getValues().isEmpty()) + return false; + + blockState.getValues().forEach(consumer); + return true; + } + + public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { + return BlockEntityType.getKey(type); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_21_5/build.gradle b/NMS/v1_21_5/build.gradle index 00638de249..4c24bc47f0 100644 --- a/NMS/v1_21_5/build.gradle +++ b/NMS/v1_21_5/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { @@ -15,24 +15,13 @@ dependencies { compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") - compileOnly rootProject -} - -shadowJar { - archiveFileName = "${project.name}-exclude.jar" + compileOnly project(":") } assemble { dependsOn(reobfJar) } -tasks { - reobfJar { - File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") - outputJar.set(layout.buildDirectory.file(outputFile.getPath())) - } -} - if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_21_5/properties b/NMS/v1_21_5/properties index c2c62d87f0..ed9c7d9895 100644 --- a/NMS/v1_21_5/properties +++ b/NMS/v1_21_5/properties @@ -7,4 +7,6 @@ CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle -GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) +END_DRAGON_FIGHT_CLASS=EndDragonFight +SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndDragonFightWrapper.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..5c5a5fdcb9 --- /dev/null +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndDragonFightWrapper.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon; + +import com.bgsoftware.superiorskyblock.nms.v1_21_5.dragon.EndWorldEndDragonFightHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +public class EndDragonFightWrapper extends EndDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.portalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.portalLocation = blockPos; + } + + + +} diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/hologram/EntityHologram.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/hologram/EntityHologram.java index 9ed5be439c..bdb682755d 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/hologram/EntityHologram.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/hologram/EntityHologram.java @@ -2,6 +2,10 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_5.hologram.AbstractEntityHologram { @@ -36,4 +40,10 @@ public void load(CompoundTag compoundTag) { // Do not load NBT. } + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java index e43c0078d9..ccc7d616f8 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/utils/NMSUtilsVersioned.java @@ -13,7 +13,6 @@ import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; @@ -24,6 +23,7 @@ import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; @@ -39,8 +39,10 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -60,6 +62,7 @@ import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; @@ -75,6 +78,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; public class NMSUtilsVersioned { @@ -296,7 +300,7 @@ public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } - public static String getPropertyValue(Property property) { + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } @@ -383,6 +387,22 @@ private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) } } + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getNMS(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + if (blockState.getValues().isEmpty()) + return false; + + blockState.getValues().forEach(consumer); + return true; + } + + public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { + return BlockEntityType.getKey(type); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_21_7/build.gradle b/NMS/v1_21_7/build.gradle index 2f64d3bca5..3494d79d1e 100644 --- a/NMS/v1_21_7/build.gradle +++ b/NMS/v1_21_7/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { @@ -15,24 +15,13 @@ dependencies { compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") - compileOnly rootProject -} - -shadowJar { - archiveFileName = "${project.name}-exclude.jar" + compileOnly project(":") } assemble { dependsOn(reobfJar) } -tasks { - reobfJar { - File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") - outputJar.set(layout.buildDirectory.file(outputFile.getPath())) - } -} - if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_21_7/properties b/NMS/v1_21_7/properties index db87c5e455..9bcdf8c242 100644 --- a/NMS/v1_21_7/properties +++ b/NMS/v1_21_7/properties @@ -7,4 +7,6 @@ CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle -GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) +END_DRAGON_FIGHT_CLASS=EndDragonFight +SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndDragonFightWrapper.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..1bd33b4a61 --- /dev/null +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndDragonFightWrapper.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon; + +import com.bgsoftware.superiorskyblock.nms.v1_21_7.dragon.EndWorldEndDragonFightHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +public class EndDragonFightWrapper extends EndDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.portalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.portalLocation = blockPos; + } + + + +} diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/hologram/EntityHologram.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/hologram/EntityHologram.java index 06bbd73f8c..9713e94d95 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/hologram/EntityHologram.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/hologram/EntityHologram.java @@ -2,8 +2,12 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; +import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_7.hologram.AbstractEntityHologram { @@ -53,4 +57,10 @@ public void load(ValueInput input) { // Do not load NBT. } + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java index 82f51b65ba..c4d246afc3 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/utils/NMSUtilsVersioned.java @@ -14,7 +14,6 @@ import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import net.minecraft.core.Holder; @@ -26,6 +25,7 @@ import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; @@ -42,8 +42,10 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -66,6 +68,7 @@ import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; @@ -82,6 +85,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; public class NMSUtilsVersioned { @@ -312,7 +316,7 @@ public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.getProperties(); } - public static String getPropertyValue(Property property) { + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } @@ -409,6 +413,22 @@ private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) } } + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getNMS(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + if (blockState.getValues().isEmpty()) + return false; + + blockState.getValues().forEach(consumer); + return true; + } + + public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { + return BlockEntityType.getKey(type); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_21_9/build.gradle b/NMS/v1_21_9/build.gradle index 9f4c3882a7..fc60682dda 100644 --- a/NMS/v1_21_9/build.gradle +++ b/NMS/v1_21_9/build.gradle @@ -1,5 +1,5 @@ plugins { - id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" } java { @@ -15,24 +15,13 @@ dependencies { compileOnly project(":NMS:Spigot-1_20_3") compileOnly project(":NMS:Paper-1_20_3") compileOnly project(":API") - compileOnly rootProject -} - -shadowJar { - archiveFileName = "${project.name}-exclude.jar" + compileOnly project(":") } assemble { dependsOn(reobfJar) } -tasks { - reobfJar { - File outputFile = new File(rootProject.archiveFolder, "reobf/${project.name}.jar") - outputJar.set(layout.buildDirectory.file(outputFile.getPath())) - } -} - if (project.hasProperty('nms.compile_v1_21') && !Boolean.valueOf(project.findProperty("nms.compile_v1_21").toString())) { project.tasks.all { task -> task.enabled = false } } \ No newline at end of file diff --git a/NMS/v1_21_9/properties b/NMS/v1_21_9/properties index 9f4a5728ed..431e8a567f 100644 --- a/NMS/v1_21_9/properties +++ b/NMS/v1_21_9/properties @@ -7,4 +7,6 @@ CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle -GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) \ No newline at end of file +GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) +END_DRAGON_FIGHT_CLASS=EndDragonFight +SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/EndDragonFightWrapper.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..e661634d40 --- /dev/null +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/EndDragonFightWrapper.java @@ -0,0 +1,31 @@ +package com.bgsoftware.superiorskyblock.nms.v1_21_9.dragon; + +import com.bgsoftware.superiorskyblock.nms.v1_21_9.dragon.EndWorldEndDragonFightHandler; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EndDragonFight; + +public class EndDragonFightWrapper extends EndDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.portalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.portalLocation = blockPos; + } + + + +} diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/hologram/EntityHologram.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/hologram/EntityHologram.java index d6f9034d08..bd1b204958 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/hologram/EntityHologram.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/hologram/EntityHologram.java @@ -1,8 +1,12 @@ package com.bgsoftware.superiorskyblock.nms.v1_21_9.hologram; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; +import net.minecraft.world.phys.Vec3; public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v1_21_9.hologram.AbstractEntityHologram { @@ -52,4 +56,10 @@ public void load(ValueInput input) { // Do not load NBT. } + @Override + public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand hand) { + // Prevent stand being equipped + return InteractionResult.PASS; + } + } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java index 1f490d7b28..af12654f61 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/utils/NMSUtilsVersioned.java @@ -14,7 +14,6 @@ import com.google.common.base.Suppliers; import com.google.gson.JsonParseException; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.properties.Property; import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import net.minecraft.core.Holder; @@ -26,6 +25,7 @@ import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ClientInformation; @@ -42,8 +42,10 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.entity.SignText; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunkSection; @@ -68,6 +70,7 @@ import org.bukkit.Material; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.generator.CustomChunkGenerator; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftMagicNumbers; @@ -84,6 +87,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; public class NMSUtilsVersioned { @@ -310,7 +314,7 @@ public static PropertyMap getProfileProperties(GameProfile gameProfile) { return gameProfile.properties(); } - public static String getPropertyValue(Property property) { + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { return property.value(); } @@ -420,6 +424,22 @@ private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) } } + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getNMS(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + if (blockState.getValues().isEmpty()) + return false; + + blockState.getValues().forEach(consumer); + return true; + } + + public static ResourceLocation getBlockEntityTypeKey(BlockEntityType type) { + return BlockEntityType.getKey(type); + } + private NMSUtilsVersioned() { } diff --git a/NMS/v1_8_R3/build.gradle b/NMS/v1_8_R3/build.gradle index 913093dba8..0b12a50dbd 100644 --- a/NMS/v1_8_R3/build.gradle +++ b/NMS/v1_8_R3/build.gradle @@ -3,7 +3,7 @@ group 'NMS:v1_8_R3' dependencies { compileOnly "org.spigotmc:v1_8_R3:latest" compileOnly project(":API") - compileOnly rootProject + compileOnly project(":") } if (project.hasProperty('nms.compile_v1_8') && !Boolean.valueOf(project.findProperty("nms.compile_v1_8").toString())) { diff --git a/NMS/v26_1/build.gradle b/NMS/v26_1/build.gradle new file mode 100644 index 0000000000..c5f5357f2e --- /dev/null +++ b/NMS/v26_1/build.gradle @@ -0,0 +1,25 @@ +plugins { + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(25)) + } +} + +paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.getMOJANG_PRODUCTION() + +group 'NMS:v26_1' + +dependencies { + paperweight.paperDevBundle("26.1.1.build.+") + compileOnly project(":NMS:Spigot-1_20_3") + compileOnly project(":NMS:Paper-1_20_3") + compileOnly project(":API") + compileOnly project(":") +} + +if (project.hasProperty('nms.compile_v26_1') && !Boolean.valueOf(project.findProperty("nms.compile_v26_1").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/NMS/v26_1/properties b/NMS/v26_1/properties new file mode 100644 index 0000000000..cfd4a71e95 --- /dev/null +++ b/NMS/v26_1/properties @@ -0,0 +1,12 @@ +NMS_VERSION=v26_1 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle.minecart +GET_RANDOM_TICK_SPEED_METHOD=get(net.minecraft.world.level.gamerules.GameRules.RANDOM_TICK_SPEED) +END_DRAGON_FIGHT_CLASS=EnderDragonFight +SPIKE_FEATURE_CLASS=EndSpikeFeature \ No newline at end of file diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java new file mode 100644 index 0000000000..99887f9ada --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java @@ -0,0 +1,87 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1; + +import com.bgsoftware.common.reflection.ReflectField; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.mojang.serialization.JsonOps; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.ComponentSerialization; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.inventory.ItemRarity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; + +import java.lang.reflect.Modifier; +import java.util.Locale; +import java.util.Objects; + +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms { + + public static final ReflectField SERVER_RECENT_TPS = new ReflectField<>(MinecraftServer.class, + double[].class, Modifier.PUBLIC | Modifier.FINAL, 1); + + private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create(); + + @Override + public String parseSignLine(String original) { + RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE); + JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0]) + .getOrThrow(JsonParseException::new); + return COMPONENT_GSON.toJson(jsonElement); + } + + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + itemMeta.setRarity(ItemRarity.valueOf(rarity)); + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + + @Override + public String getMinecraftKey(ItemStack itemStack) { + return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); + } + + @Override + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.setEnchantmentGlintOverride(true); + } + + @Override + public double getCurrentTps() { + return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0]; + } + +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSChunksImpl.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSChunksImpl.java new file mode 100644 index 0000000000..d4a2c79b45 --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSChunksImpl.java @@ -0,0 +1,360 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1; + +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.core.CalculatedChunk; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.bgsoftware.superiorskyblock.nms.v26_1.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v26_1.utils.NMSUtilsVersioned; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.mojang.logging.LogUtils; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; +import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.ProblemReporter; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerFactory; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.ValueInput; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.generator.ChunkGenerator; +import org.slf4j.Logger; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import static com.bgsoftware.superiorskyblock.nms.v26_1.utils.NMSUtilsVersioned.DEFAULT_PALETTED_CONTAINER_FACTORY; + +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSChunks { + + private static final ReflectMethod>>> CONTAINER_FACTORY_BIOME_RW_CODEC = + new ReflectMethod<>(PalettedContainerFactory.class, "biomeContainerCodecRW"); + + private static final Logger LOGGER = LogUtils.getLogger(); + + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { + super(plugin); + } + + @Override + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); + + ChunkPos chunkPos = levelChunk.getPos(); + + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + LevelChunkSection currentSection = chunkSections[i]; + if (currentSection != null) { + PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); + chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); + } + } + + levelChunk.markUnsaved(); + + ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); + ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( + levelChunk, levelChunk.level.getLightEngine(), null, null); + + playersToUpdate.forEach(player -> { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + serverPlayer.connection.send(forgetLevelChunkPacket); + serverPlayer.connection.send(mapChunkPacket); + }); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); + + PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); + DataResult dataResult = getBiomeContainerRWCodec() + .encodeStart(NbtOps.INSTANCE, biomesContainer); + Tag biomesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); + + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); + } + + @Override + public void onFinish() { + // Do nothing. + } + }; + } + + @Override + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + chunkSections[i] = new LevelChunkSection(DEFAULT_PALETTED_CONTAINER_FACTORY); + } + + removeEntities(levelChunk); + removeBlockEntities(levelChunk); + removeBlocks(levelChunk); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + ListTag tileEntities = new ListTag(); + + chunkCompound.put("Entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); + + if (serverLevel.generator instanceof IslandsGenerator) { + PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() + .encodeStart(NbtOps.INSTANCE, statesContainer); + Tag blockStatesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); + } else { + ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); + + try { + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); + } catch (Exception ignored) { + } + + LevelLightEngine lightEngine = serverLevel.getLightEngine(); + LevelChunkSection[] chunkSections = protoChunk.getSections(); + + ListTag sectionsList = new ListTag(); + + // Save blocks + for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { + int chunkSectionIndex = serverLevel.getSectionIndex(i); + + CompoundTag sectionCompound = new CompoundTag(); + + if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { + LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; + + { + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() + .encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); + sectionCompound.put("block_states", dataResult.getOrThrow()); + } + + { + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerCodec() + .encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); + sectionCompound.put("biomes", dataResult.getOrThrow()); + } + } + + if (!sectionCompound.isEmpty()) { + sectionCompound.putByte("Y", (byte) i); + sectionsList.add(sectionCompound); + } + } + + for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { + CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, + MinecraftServer.getServer().registryAccess()); + if (blockEntityCompound != null) + tileEntities.add(blockEntityCompound); + } + + chunkCompound.put("sections", sectionsList); + } + } + + @Override + public void onFinish() { + if (onFinish != null) + onFinish.run(); + } + }; + } + + @Override + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), levelChunk.locX, levelChunk.locZ, false); + allCalculatedChunks.add(calculateChunk(chunkPosition, levelChunk.level, levelChunk.getSections())); + + latchCountDown(); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + + LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; + + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); + for (int i = 0; i < sectionsList.size(); ++i) { + CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); + byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); + int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); + + if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { + PalettedContainer blocksPalettedContainer; + Optional blockStatesCompound = sectionCompound.getCompound("block_states"); + if (blockStatesCompound.isPresent()) { + DataResult> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY + .blockStatesContainerCodec().parse(NbtOps.INSTANCE, blockStatesCompound.get()) + .promotePartial((sx) -> { + }); + blocksPalettedContainer = dataResult.getOrThrow(); + } else { + blocksPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + } + + PalettedContainer> biomesPalettedContainer; + Optional biomesCompound = sectionCompound.getCompound("biomes"); + if (biomesCompound.isPresent()) { + DataResult>> dataResult = getBiomeContainerRWCodec() + .parse(NbtOps.INSTANCE, biomesCompound.get()) + .promotePartial((sx) -> { + }); + biomesPalettedContainer = dataResult.getOrThrow(); + } else { + biomesPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBiomes(); + } + + chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); + } + + } + + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + allCalculatedChunks.add(calculatedChunk); + unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + latchCountDown(); + } + + @Override + public void onFinish() { + completableFuture.complete(allCalculatedChunks); + } + }; + } + + @Override + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.level.getWorld(), levelChunk.locX, levelChunk.locZ, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); + + latchCountDown(); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + unloadedChunkCompounds.add(unloadedChunkCompound); + + latchCountDown(); + } + + @Override + public void onFinish() { + BukkitExecutor.ensureMain(() -> { + for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("Entities"); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); + } + + completableFuture.complete(allCalculatedChunks); + }); + } + }; + } + + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getIntOr("DataVersion", 0); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag); + return EntityType.create(valueInput, serverLevel, EntitySpawnReason.NATURAL); + } + } + + private static void removeBlocks(ChunkAccess chunk) { + ServerLevel serverLevel = ((LevelChunk) chunk).level; + ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); + + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; + + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); + } + + private static Codec>> getBiomeContainerRWCodec() { + if (CONTAINER_FACTORY_BIOME_RW_CODEC.isValid()) { + return CONTAINER_FACTORY_BIOME_RW_CODEC.invoke(DEFAULT_PALETTED_CONTAINER_FACTORY); + } else { + return DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerRWCodec(); + } + } + +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSEntitiesImpl.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSEntitiesImpl.java new file mode 100644 index 0000000000..61928e8126 --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSEntitiesImpl.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1; + +import net.minecraft.tags.ItemTags; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PortalProcessor; +import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.minecart.PoweredMinecart; + +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSEntities { + + @Override + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); + } + + @Override + protected int getPortalTicks(Entity entity) { + PortalProcessor portalProcessor = entity.portalProcess; + return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); + } + +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSTagsImpl.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSTagsImpl.java new file mode 100644 index 0000000000..54bd4037a1 --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSTagsImpl.java @@ -0,0 +1,146 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1; + +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.logging.LogUtils; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.ByteArrayTag; +import net.minecraft.nbt.IntArrayTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.NumericTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Util; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ResolvableProfile; +import org.bukkit.Location; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.slf4j.Logger; + +import java.util.Set; + +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSTags { + + private static final Logger LOGGER = LogUtils.getLogger(); + + @Override + public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + Multimap properties = HashMultimap.create(); + properties.put("textures", new Property("textures", texture)); + + GameProfile gameProfile = new GameProfile(Util.NIL_UUID, "", new PropertyMap(properties)); + + ResolvableProfile resolvableProfile = ResolvableProfile.createResolved(gameProfile); + + itemStack.set(DataComponents.PROFILE, resolvableProfile); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { + RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); + + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) + ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow(); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms.DATA_VERSION); + + return CompoundTag.fromNBT(tagCompound); + } + + @Override + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.getIntOr(key, def); + } + + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + RegistryOps context = + MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); + + return ItemStack.CODEC.parse(context, compoundTag) + .resultOrPartial((itemId) -> LOGGER.error("Tried to load invalid item: '{}'", itemId)) + .orElseThrow(); + } + + @Override + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); + } + + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { + EntityType.loadEntityRecursive(compoundTag, serverLevel, EntitySpawnReason.NATURAL, entity -> { + entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); + return !serverLevel.addWithUUID(entity) ? null : entity; + }); + } + + @Override + public byte[] getNBTByteArrayValue(Object object) { + return ((ByteArrayTag) object).getAsByteArray(); + } + + @Override + public byte getNBTByteValue(Object object) { + return ((NumericTag) object).byteValue(); + } + + @Override + public Set getNBTCompoundValue(Object object) { + return ((net.minecraft.nbt.CompoundTag) object).keySet(); + } + + @Override + public double getNBTDoubleValue(Object object) { + return ((NumericTag) object).doubleValue(); + } + + @Override + public float getNBTFloatValue(Object object) { + return ((NumericTag) object).floatValue(); + } + + @Override + public int[] getNBTIntArrayValue(Object object) { + return ((IntArrayTag) object).getAsIntArray(); + } + + @Override + public int getNBTIntValue(Object object) { + return ((NumericTag) object).intValue(); + } + + @Override + public Object getNBTListIndexValue(Object object, int index) { + return ((net.minecraft.nbt.ListTag) object).get(index); + } + + @Override + public long getNBTLongValue(Object object) { + return ((NumericTag) object).longValue(); + } + + @Override + public short getNBTShortValue(Object object) { + return ((NumericTag) object).shortValue(); + } + + @Override + public String getNBTStringValue(Object object) { + return ((StringTag) object).value(); + } + +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSWorldImpl.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSWorldImpl.java new file mode 100644 index 0000000000..cdd1ee1c3b --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSWorldImpl.java @@ -0,0 +1,145 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.nms.v26_1.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v26_1.trial.IslandPlayerDetector; +import com.bgsoftware.superiorskyblock.nms.v26_1.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v26_1.world.BlockLevelTicksTracker; +import com.bgsoftware.superiorskyblock.nms.v26_1.world.CollectingNeighborUpdaterTracker; +import com.bgsoftware.superiorskyblock.world.SignType; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; +import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; +import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; + +import java.lang.reflect.Modifier; + +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSWorld { + + private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( + SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( + Level.class, CollectingNeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + + public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { + super(plugin); + } + + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE, worldBorder.world.getGameTime()); + } + + @Override + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); + } + + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.getDelegate(); + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.settings.value(); + } + + @Override + public void replaceTrialBlockPlayerDetector(Island island, Location location) { + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); + if (blockEntity == null) + return; + + if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { + VaultConfig vaultConfig = vaultBlockEntity.getConfig(); + + PlayerDetector playerDetector = vaultConfig.playerDetector(); + if (playerDetector instanceof IslandPlayerDetector) + return; + + VaultConfig newConfig = new VaultConfig( + vaultConfig.lootTable(), + vaultConfig.activationRange(), + vaultConfig.deactivationRange(), + vaultConfig.keyItem(), + vaultConfig.overrideLootTableToDisplay(), + IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), + vaultConfig.entitySelector() + ); + + vaultBlockEntity.setConfig(newConfig); + } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { + TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); + PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); + + if (playerDetector instanceof IslandPlayerDetector) + return; + + trialSpawnerBlockEntity.trialSpawner.setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector)); + } + } + + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) + return; + + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } + + @Override + public SignType getSignType(Object sign) { + if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return super.getSignType(sign); + } + + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + } + +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/EndDragonFightWrapper.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..3708ef0d5f --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/EndDragonFightWrapper.java @@ -0,0 +1,34 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1.dragon; + +import com.bgsoftware.superiorskyblock.nms.v26_1.dragon.EndWorldEndDragonFightHandler; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EnderDragonFight; + +import java.util.List; +import java.util.Optional; + +public class EndDragonFightWrapper extends EnderDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel) { + super(true, false, false, Optional.empty(), 0, Optional.empty(), Optional.empty(), new ObjectArrayList(), List.of()); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.exitPortalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.exitPortalLocation = blockPos; + } + + +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/IslandEntityEnderDragon.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/IslandEntityEnderDragon.java new file mode 100644 index 0000000000..f69f7b9a26 --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/IslandEntityEnderDragon.java @@ -0,0 +1,40 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1.dragon; + +import com.bgsoftware.common.annotations.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.SpawnGroupData; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; +import net.minecraft.world.level.storage.ValueInput; + +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v26_1.dragon.AbstractIslandEntityEnderDragon { + + public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { + super(level, islandBlockPos); + } + + public IslandEntityEnderDragon(Level level) { + super(level); + } + + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, + DifficultyInstance difficulty, + EntitySpawnReason spawnReason, + @Nullable SpawnGroupData entityData) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(world, difficulty, spawnReason, entityData); + } + + @Override + protected void readAdditionalSaveData(ValueInput input) { + super.readAdditionalSaveData(input); + finalizeIslandEnderDragon(); + } + +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/hologram/EntityHologram.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/hologram/EntityHologram.java new file mode 100644 index 0000000000..50e7438f95 --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/hologram/EntityHologram.java @@ -0,0 +1,64 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1.hologram; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.level.storage.ValueOutput; +import net.minecraft.world.phys.Vec3; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v26_1.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + protected void addAdditionalSaveData(ValueOutput output) { + // Do not save NBT. + } + + @Override + protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) { + // Do not save NBT. + } + + @Override + protected void readAdditionalSaveData(ValueInput input) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { + // Do not save NBT. + return false; + } + + @Override + public boolean saveAsPassenger(ValueOutput output) { + // Do not save NBT. + return false; + } + + @Override + public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { + // Do not save NBT. + } + + @Override + public void saveWithoutId(ValueOutput output) { + // Do not save NBT. + } + + @Override + public void load(ValueInput input) { + // Do not load NBT. + } + + @Override + public InteractionResult interact(Player player, InteractionHand hand, Vec3 location) { + // Prevent stand being equipped + return InteractionResult.PASS; + } +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java new file mode 100644 index 0000000000..4ca3ba0929 --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java @@ -0,0 +1,53 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1.trial; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +public class IslandPlayerDetector implements PlayerDetector { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final PlayerDetector original; + private final IslandPrivilege requiredPrivilege; + + public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + } + + public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + } + + private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + this.island = island; + this.original = original; + this.requiredPrivilege = requiredPrivilege; + } + + @Override + public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { + List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); + if (!players.isEmpty()) { + players = new LinkedList<>(players); + players.removeIf(uuid -> { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); + return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + }); + players = Collections.unmodifiableList(players); + } + return players; + } + +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/utils/NMSUtilsVersioned.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..487f35750e --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/utils/NMSUtilsVersioned.java @@ -0,0 +1,451 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1.utils; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.mutable.MutableInt; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v26_1.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v26_1.utils.TickingBlockList; +import com.google.gson.JsonParseException; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.logging.LogUtils; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.util.ProblemReporter; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerFactory; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.Strategy; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.dimension.end.EnderDragonFight; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.TagValueOutput; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; +import org.slf4j.Logger; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; +import java.util.stream.Stream; + +public class NMSUtilsVersioned { + + private static final Logger LOGGER = LogUtils.getLogger(); + + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( + EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + public static final PalettedContainerFactory DEFAULT_PALETTED_CONTAINER_FACTORY = PalettedContainerFactory.create( + MinecraftServer.getServer().registryAccess()); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { + return chunkMap.read(chunkPos).join().orElse(null); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { + return chunkMap.upgradeChunkTag(chunkCompoundTag); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { + chunkMap.write(chunkPos, () -> chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } else { + return BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + MoonriseRegionFileIO.RegionDataController regionDataController = + serverLevel.moonrise$getEntityChunkDataController(); + int chunkX = chunkPosition.getX(); + int chunkZ = chunkPosition.getZ(); + MoonriseRegionFileIO.RegionDataController.ReadData readData = + regionDataController.readData(chunkX, chunkZ); + if (readData != null) { + CompoundTag entityData = switch (readData.result()) { + case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); + case SYNC_READ -> readData.syncRead(); + default -> null; + }; + if (entityData != null) { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + return; + } + } + + chunkCallback.onChunkNotExist(chunkPosition); + } catch (IOException error) { + countDownLatch.countDown(); + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + DEFAULT_PALETTED_CONTAINER_FACTORY, + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), + new ProtoChunkTicks<>(), levelHeightAccessor, DEFAULT_PALETTED_CONTAINER_FACTORY, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.liquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "block_entity@" + blockEntity.getBlockPos(), LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag); + blockEntity.loadWithComponents(valueInput); + } + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + applySignTextLines(compoundTag, "front_text"); + applySignTextLines(compoundTag, "back_text"); + convertLegacySignTextLines(compoundTag); + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + PalettedContainer> biomesContainer = createBiomesContainer(biome); + PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); + + // Unsafe: we do not provide chunks cache, even tho it is required. + // Should be fine in normal flow, as the only method that access the chunks cache + // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 + WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); + + customChunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + } + + public static CompoundTag saveEntity(Entity entity) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "cached_entity@" + entity.getUUID(), LOGGER)) { + TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess()); + entity.save(valueOutput); + return valueOutput.buildResult(); + } + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.moonrise$getTickingBlockList().size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.properties(); + } + + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { + return property.value(); + } + + public static EnderDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.getDragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absSnapTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSectionY(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinY(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxY(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.markUnsaved(); + } + + public static PalettedContainer> createBiomesContainer(Holder biome) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + Strategy> biomesStrategy = Strategy.createForBiomes(biomesRegistry.asHolderIdMap()); + return new PalettedContainerFactory( + null, + null, + null, + biomesStrategy, + biome, + null, + null + ).createForBiomes(); + } + + public static Optional loadPlayerData(ServerPlayer serverPlayer) { + try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) { + return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId()) + .map(playerData -> { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData); + serverPlayer.load(valueInput); + return playerData; + }); + } + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLongOr(key, def); + } + + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { + blockEntityCompound.getCompound(key).ifPresent(textCompound -> { + ListTag messages = textCompound.getListOrEmpty("messages"); + List textLines = new ArrayList<>(); + for (net.minecraft.nbt.Tag lineTag : messages) { + try { + textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); + } catch (JsonParseException error) { + textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); + } + } + + for (int i = 0; i < 4; i++) { + if (textLines.get(i) == null) + textLines.set(i, Component.empty()); + } + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); + }); + } + + private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getBlockState(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + int[] count = new int[]{0}; + + blockState.getValues().forEach(value -> { + ++count[0]; + consumer.accept(value.property(), value.value()); + }); + + return count[0] > 0; + } + + public static Identifier getBlockEntityTypeKey(BlockEntityType type) { + return BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(type); + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/vibration/IslandVibrationUser.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/vibration/IslandVibrationUser.java new file mode 100644 index 0000000000..5db0b9ac9c --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/vibration/IslandVibrationUser.java @@ -0,0 +1,90 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.PositionSource; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; + +import javax.annotation.Nullable; + +public class IslandVibrationUser implements VibrationSystem.User { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final VibrationSystem.User original; + + public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + this.island = island; + this.original = sculkSensorBlockEntity.getVibrationUser(); + } + + @Override + public int getListenerRadius() { + return this.original.getListenerRadius(); + } + + @Override + public PositionSource getPositionSource() { + return this.original.getPositionSource(); + } + + @Override + public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { + if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) + return false; + + if (context.sourceEntity() instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + + @Override + public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { + this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); + } + + @Override + public TagKey getListenableEvents() { + return this.original.getListenableEvents(); + } + + @Override + public boolean canTriggerAvoidVibration() { + return this.original.canTriggerAvoidVibration(); + } + + @Override + public boolean requiresAdjacentChunksToBeTicking() { + return this.original.requiresAdjacentChunksToBeTicking(); + } + + @Override + public int calculateTravelTimeInTicks(float distance) { + return this.original.calculateTravelTimeInTicks(distance); + } + + @Override + public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { + return this.original.isValidVibration(gameEvent, context); + } + + @Override + public void onDataChanged() { + this.original.onDataChanged(); + } + +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/BlockLevelTicksTracker.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..91a773b6ba --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/BlockLevelTicksTracker.java @@ -0,0 +1,59 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +import java.util.List; +import java.util.function.BiConsumer; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(serverLevel::isPositionTickingWithEntitiesLoaded); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/CollectingNeighborUpdaterTracker.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/CollectingNeighborUpdaterTracker.java new file mode 100644 index 0000000000..26784bf4d3 --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/CollectingNeighborUpdaterTracker.java @@ -0,0 +1,44 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Level level; + + public CollectingNeighborUpdaterTracker(Level level) { + super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); + this.level = level; + } + + @Override + public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, @Block.UpdateFlags int flags, int recursionLeft) { + BlockState oldState = this.level.getBlockState(pos); + super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); + BlockState newState = this.level.getBlockState(pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + +} diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/PropertiesMapperVersioned.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..4eb45ba2e3 --- /dev/null +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/world/PropertiesMapperVersioned.java @@ -0,0 +1,18 @@ +package com.bgsoftware.superiorskyblock.nms.v26_1.world; + +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/build.gradle b/build.gradle index 907134d8e3..29c7ef47e3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'io.github.goooler.shadow' version '8.1.8' + id 'com.gradleup.shadow' version '9.4.1' id 'maven-publish' } @@ -8,7 +8,6 @@ group 'SuperiorSkyblock' version = "2025.2.1" project.ext { - archiveFolder = file("archive/") targetFolder = file("target/") buildVersion = System.getenv("BUILD_NUMBER") == null || Boolean.parseBoolean(System.getenv("STABLE_BUILD")) ? version : version + "-b" + System.getenv("BUILD_NUMBER") @@ -16,7 +15,7 @@ project.ext { allprojects { apply plugin: 'java' - apply plugin: 'io.github.goooler.shadow' + apply plugin: 'com.gradleup.shadow' java { toolchain { @@ -36,7 +35,7 @@ allprojects { compileOnly 'com.bgsoftware.common.annotations:Annotations:b2' } - task checkDebug() { + tasks.register('checkDebug') { Set filesWithDebug = fileTree('src/main/java').filter { file -> file.text.contains('Bukkit.broadcastMessage') }.getFiles() @@ -51,19 +50,11 @@ allprojects { } } -subprojects { - shadowJar { - archiveFileName = "${project.name}.jar" - destinationDirectory = rootProject.archiveFolder - } -} - repositories { mavenCentral() } dependencies { - implementation fileTree(rootProject.archiveFolder.getAbsolutePath()) implementation project(":API") implementation 'com.bgsoftware.common.config:CommentedConfiguration:b1' @@ -72,7 +63,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b17' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b18' implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b2' implementation 'org.bstats:bstats-bukkit:3.0.0' @@ -82,14 +73,6 @@ dependencies { compileOnly 'org.spigotmc:v1_16_R3-Tuinity:latest' } -jar { - from { - for (File file : rootProject.archiveFolder.listFiles()) { - zipTree(file) - } - } -} - processResources { outputs.upToDateWhen { false } eachFile { details -> @@ -102,42 +85,76 @@ processResources { } shadowJar { - dependsOn(jar) - relocate 'org.bstats', 'com.bgsoftware.superiorskyblock.libs.org.bstats' relocate 'com.bgsoftware.common', 'com.bgsoftware.superiorskyblock.libs.com.bgsoftware.common' - archiveFileName = rootProject.name + "-" + rootProject.buildVersion + ".jar" + archiveClassifier.set('') - delete fileTree(rootProject.targetFolder.getAbsolutePath()) + from sourceSets.main.output - exclude '*exclude.jar' + from(project.configurations.runtimeClasspath.filter { it.name.endsWith('.jar') }.collect { zipTree(it) }) { + exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' + } - destinationDirectory = rootProject.targetFolder - from sourceSets.getByName("main").output - configurations = [project.configurations.getByName("runtimeClasspath")] -} + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + + subprojects.each { sub -> + if (sub.path.startsWith(':NMS:v1')) { + try { + def reobfTask = sub.tasks.named('reobfJar') + dependsOn(reobfTask) + from(zipTree(reobfTask.outputJar)) { + // Exclude metadata that might cause duplicates + exclude 'META-INF/MANIFEST.MF' + exclude 'META-INF/*.SF' + exclude 'META-INF/*.DSA' + exclude 'META-INF/*.RSA' + } + } catch (Exception ignored) { + from sub.sourceSets.main.output + } + } else { + from sub.sourceSets.main.output + } + } + + dependencies { + // This includes the API and all sub-modules in the final JAR + include project(':API') -task copyAPI(type: Copy, dependsOn: ':API:build') { - from rootProject.archiveFolder.getAbsolutePath() + '/API.jar' - into rootProject.targetFolder.getAbsolutePath() - rename('API.jar', rootProject.name + 'API.jar') + // Use a loop to include all NMS and Hook subprojects automatically + subprojects.findAll { it.path.startsWith(':NMS:') || it.path.startsWith(':Hooks:') }.each { sub -> + include project(sub.path) + } + } } -clean { - delete rootProject.archiveFolder +tasks.register('cleanTarget', Delete) { + delete rootProject.targetFolder } -build { - dependsOn shadowJar - dependsOn copyAPI - dependsOn clean +tasks.register('collectArtifacts', Copy) { + group = 'build' + + dependsOn('cleanTarget') + dependsOn(tasks.named('shadowJar')) + dependsOn(project(':API').tasks.named('shadowJar')) + + from(tasks.named('shadowJar').map { it.archiveFile }) { + rename { rootProject.name + "-" + rootProject.buildVersion + ".jar" } + } + + from(project(':API').tasks.named('shadowJar').map { it.archiveFile }) { + rename { rootProject.name + "-API.jar" } + } + + into(rootProject.targetFolder) } -publish.shouldRunAfter shadowJar -shadowJar.shouldRunAfter build -build.shouldRunAfter subprojects.build -clean.shouldRunAfter copyAPI +tasks.named('build') { + dependsOn(tasks.named('shadowJar')) +} -shadowJar.dependsOn subprojects.build -compileJava.dependsOn childProjects.values().shadowJar \ No newline at end of file +tasks.named('shadowJar') { + finalizedBy('collectArtifacts') +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 260504c0cb..221c4f9822 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/settings.gradle b/settings.gradle index 7bf55744bd..f801f82b6b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -71,4 +71,5 @@ include 'NMS:v1_21_4' include 'NMS:v1_21_5' include 'NMS:v1_21_7' include 'NMS:v1_21_9' -include 'NMS:v1_21_10' \ No newline at end of file +include 'NMS:v1_21_10' +include 'NMS:v26_1' \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ServerVersion.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ServerVersion.java index 78436c1135..71481c7349 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/ServerVersion.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ServerVersion.java @@ -21,6 +21,7 @@ public enum ServerVersion { v1_19(119), v1_20(120), v1_21(121), + v26_1(261), UNKONWN(-1); From 403972757650af37c0b95ed8f4de5616ace44325 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Apr 2026 14:41:29 +0300 Subject: [PATCH 534/600] [CI SKIP] Add "compile_v26_1" to gradle properties --- gradle.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/gradle.properties b/gradle.properties index 50845a498e..665fb9b2c1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,6 +8,7 @@ nms.compile_v1_18=true nms.compile_v1_19=true nms.compile_v1_20=true nms.compile_v1_21=true +nms.compile_v26_1=true hook.compile_advancedspawners=true hook.compile_candcsilkspawners=true hook.compile_changeskin=true From 84e5e94823e1e6612eeff5cb6c92407b3ec65985 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Apr 2026 17:34:50 +0300 Subject: [PATCH 535/600] Fixed lava is considered a safe block (#2900) --- .../com/bgsoftware/superiorskyblock/world/WorldBlocks.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java b/src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java index 3fc3587f64..1fc8ead85f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java @@ -30,11 +30,14 @@ private static boolean isSafeBlockInternal(Block block) { // This means that the block below it is considered "safe", and the two blocks above the safe blocks // cannot suffocate the player. - return !plugin.getNMSWorld().canPlayerSuffocate(block) && - !plugin.getNMSWorld().canPlayerSuffocate(block.getRelative(BlockFace.UP)) && + return !canPlayerSuffocateFromBlock(block) && !canPlayerSuffocateFromBlock(block.getRelative(BlockFace.UP)) && plugin.getSettings().getSafeBlocks().contains(Keys.of(block.getRelative(BlockFace.DOWN))); } + private static boolean canPlayerSuffocateFromBlock(Block block) { + return block.getType() == Material.LAVA || plugin.getNMSWorld().canPlayerSuffocate(block); + } + public static boolean isSafeBlock(ChunkSnapshot chunkSnapshot, int x, int y, int z) { Key feetBlockKey = plugin.getNMSWorld().getBlockKey(chunkSnapshot, x, y + 1, z); Key headBlockKey = plugin.getNMSWorld().getBlockKey(chunkSnapshot, x, y + 2, z); From 6b18fc5b24152e1094f2d356eda1345be1b98742 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 11 Apr 2026 18:14:07 +0300 Subject: [PATCH 536/600] Fixed players being kicked out when chaging biomes in some cases (#2897) --- .../dragon/IslandEndDragonFight.java.template | 21 ++-- .../dragon/IslandEnderDragonBattle.java | 12 +- .../dragon/IslandEnderDragonBattle.java | 14 +-- .../commands/admin/CmdAdminResetWorld.java | 18 ++- .../core/IslandWorldsPlayersStrategy.java | 119 ++++++++++++++++++ .../superiorskyblock/island/SIsland.java | 17 ++- .../listener/ChunksListener.java | 11 +- 7 files changed, 169 insertions(+), 43 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorldsPlayersStrategy.java diff --git a/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template b/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template index a487d0a109..d1499d015a 100644 --- a/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template +++ b/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template @@ -3,7 +3,8 @@ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; @@ -175,16 +176,14 @@ public class IslandEndDragonFight extends EndDragonFightWrapper { private void updateBattlePlayers() { Set nearbyPlayers = new HashSet<>(); - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - Player bukkitPlayer = superiorPlayer.asPlayer(); - if (bukkitPlayer != null) { - ServerLevel serverLevel = ((CraftWorld) bukkitPlayer.getWorld()).getHandle(); - if (serverLevel.equals(this.serverLevel)) { - ServerPlayer serverPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); - this.dragonEvent.addPlayer(serverPlayer); - nearbyPlayers.add(serverPlayer.getUUID()); - } - } + WorldInfo worldInfo = WorldInfo.of(this.serverLevel.getWorld()); + + try(IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) { + strategy.getPlayers(worldInfo).forEach(player -> { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + this.dragonEvent.addPlayer(serverPlayer); + nearbyPlayers.add(serverPlayer.getUUID()); + }); } List dragonEventPlayers = new SequentialListBuilder() diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEnderDragonBattle.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEnderDragonBattle.java index 7ec201e0bb..6b3dc8ae7b 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEnderDragonBattle.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/dragon/IslandEnderDragonBattle.java @@ -4,7 +4,9 @@ import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.google.common.collect.Sets; import net.minecraft.server.v1_12_R1.AxisAlignedBB; import net.minecraft.server.v1_12_R1.BlockPosition; @@ -307,14 +309,14 @@ private void generateExitPortal(boolean flag) { private void updateBattlePlayers() { Set nearbyPlayers = Sets.newHashSet(); - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - Player player = superiorPlayer.asPlayer(); - assert player != null; - if (((CraftWorld) player.getWorld()).getHandle() == this.worldServer) { + WorldInfo worldInfo = WorldInfo.of(this.worldServer.getWorld()); + + try(IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) { + strategy.getPlayers(worldInfo).forEach(player -> { EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); this.bossBattleServer.addPlayer(entityPlayer); nearbyPlayers.add(entityPlayer); - } + }); } new HashSet<>(this.bossBattleServer.getPlayers()).stream() diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java index cd0f9be5b0..b2286f98cd 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/dragon/IslandEnderDragonBattle.java @@ -3,7 +3,9 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.common.reflection.ReflectField; import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.nms.v1_16_R3.NMSUtils; import net.minecraft.server.v1_16_R3.BlockPosition; @@ -167,16 +169,14 @@ public IslandEntityEnderDragon getEnderDragon() { private void updateBattlePlayers() { Set nearbyPlayers = new HashSet<>(); - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - Player bukkitPlayer = superiorPlayer.asPlayer(); - assert bukkitPlayer != null; + WorldInfo worldInfo = WorldInfo.of(this.world.getWorld()); - EntityPlayer entityPlayer = ((CraftPlayer) bukkitPlayer).getHandle(); - - if (entityPlayer.getWorld().equals(this.world)) { + try(IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) { + strategy.getPlayers(worldInfo).forEach(player -> { + EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle(); this.bossBattle.addPlayer(entityPlayer); nearbyPlayers.add(entityPlayer.getUniqueID()); - } + }); } this.bossBattle.getPlayers().stream() diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java index 3bbe5bac81..46c76dd58a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminResetWorld.java @@ -7,11 +7,13 @@ import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.service.dragon.DragonBattleService; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.commands.CommandTabCompletes; import com.bgsoftware.superiorskyblock.commands.IAdminIslandCommand; import com.bgsoftware.superiorskyblock.commands.arguments.CommandArguments; import com.bgsoftware.superiorskyblock.core.IslandWorlds; +import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; @@ -116,16 +118,12 @@ else if (targetPlayer == null) private static void resetChunksInternal(Island island, World world, Dimension dimension) { boolean isDefaultDimension = dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension(); - // Sending the players that are in that world to the main island. - // If the world that will be reset is the normal world, they will be teleported to spawn. - for (SuperiorPlayer superiorPlayer : island.getAllPlayersInside()) { - assert superiorPlayer.getWorld() != null; - if (superiorPlayer.getWorld().equals(world)) { - if (isDefaultDimension) { - superiorPlayer.teleport(plugin.getGrid().getSpawnIsland()); - } else { - superiorPlayer.teleport(island); - } + try(IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) { + // Sending the players that are in that world to the main island. + // If the world that will be reset is the normal world, they will be teleported to spawn. + Island teleportIsland = isDefaultDimension ? plugin.getGrid().getSpawnIsland() : island; + for (SuperiorPlayer superiorPlayer : strategy.getSuperiorPlayers(WorldInfo.of(world))) { + superiorPlayer.teleport(teleportIsland); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorldsPlayersStrategy.java b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorldsPlayersStrategy.java new file mode 100644 index 0000000000..c4a4cc4854 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/IslandWorldsPlayersStrategy.java @@ -0,0 +1,119 @@ +package com.bgsoftware.superiorskyblock.core; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.Player; + +import java.util.List; + +public abstract class IslandWorldsPlayersStrategy implements ObjectsPool.Releasable, AutoCloseable { + + private static final LazyReference> POOL = new LazyReference>() { + @Override + protected ObjectsPool create() { + return plugin.getProviders().hasCustomWorldsSupport() ? new ObjectsPool<>(IslandWorldsPlayersStrategyMultiWorld::new) : + new ObjectsPool<>(IslandWorldsPlayersStrategySingleWorld::new); + } + }; + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + public static IslandWorldsPlayersStrategy create(Island island) { + return POOL.get().obtain().initialize(island); + } + + private IslandWorldsPlayersStrategy() { + + } + + protected abstract IslandWorldsPlayersStrategy initialize(Island island); + + @Override + public void close() { + release(); + } + + public abstract List getPlayers(WorldInfo worldInfo); + + public abstract List getSuperiorPlayers(WorldInfo worldInfo); + + private static class IslandWorldsPlayersStrategySingleWorld extends IslandWorldsPlayersStrategy { + + private List playersInIsland = null; + + private IslandWorldsPlayersStrategySingleWorld() { + } + + protected IslandWorldsPlayersStrategySingleWorld initialize(Island island) { + this.playersInIsland = island.getAllPlayersInside(); + return this; + } + + @Override + public void release() { + this.playersInIsland = null; + } + + @Override + public List getPlayers(WorldInfo worldInfo) { + return new SequentialListBuilder() + .filter(player -> player.getWorld().getName().equals(worldInfo.getName())) + .build(this.playersInIsland, SuperiorPlayer::asPlayer); + } + + @Override + public List getSuperiorPlayers(WorldInfo worldInfo) { + return new SequentialListBuilder() + .filter(player -> player.getWorld().getName().equals(worldInfo.getName())) + .build(this.playersInIsland); + } + + } + + + private static class IslandWorldsPlayersStrategyMultiWorld extends IslandWorldsPlayersStrategy { + + private Island island = null; + + private IslandWorldsPlayersStrategyMultiWorld() { + + } + + protected IslandWorldsPlayersStrategyMultiWorld initialize(Island island) { + this.island = island; + return this; + } + + @Override + public void release() { + this.island = null; + } + + @Override + public List getPlayers(WorldInfo worldInfo) { + World bukkitWorld = Bukkit.getWorld(worldInfo.getName()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return new SequentialListBuilder() + .filter(player -> island.isInside(player.getLocation(wrapper.getHandle()))) + .build(bukkitWorld.getPlayers()); + } + } + + @Override + public List getSuperiorPlayers(WorldInfo worldInfo) { + World bukkitWorld = Bukkit.getWorld(worldInfo.getName()); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + return new SequentialListBuilder() + .filter(player -> island.isInside(player.getLocation(wrapper.getHandle()))) + .build(bukkitWorld.getPlayers(), plugin.getPlayers()::getSuperiorPlayer); + } + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index fa9ea48ad0..72ba40f023 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -43,6 +43,7 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.IslandArea; import com.bgsoftware.superiorskyblock.core.IslandWorlds; +import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.LegacyMasks; @@ -2044,8 +2045,6 @@ public void setBiome(Biome biome, boolean updateBlocks) { if (!updateBlocks) return; - List playersToUpdate = new SequentialListBuilder() - .build(getAllPlayersInside(), SuperiorPlayer::asPlayer); IslandWorlds.accessIslandWorldsAsync(this, false, result -> { result.ifLeft(world -> { @@ -2053,13 +2052,21 @@ public void setBiome(Biome biome, boolean updateBlocks) { Biome worldBiome = plugin.getSettings().getWorlds().getDefaultWorldDimension() == worldInfo.getDimension() ? biome : IslandUtils.getDefaultWorldBiome(worldInfo.getDimension()); List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, 0); + List playersToUpdate; + try (IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(this)) { + playersToUpdate = strategy.getPlayers(worldInfo); + } plugin.getNMSChunks().setBiome(chunkPositions, worldBiome, playersToUpdate); }); }); - for (World registeredWorld : plugin.getGrid().getRegisteredWorlds()) { - List chunkPositions = IslandUtils.getChunkCoords(this, WorldInfo.of(registeredWorld), 0); - plugin.getNMSChunks().setBiome(chunkPositions, biome, playersToUpdate); + try (IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(this)) { + for (World registeredWorld : plugin.getGrid().getRegisteredWorlds()) { + WorldInfo worldInfo = WorldInfo.of(registeredWorld); + List chunkPositions = IslandUtils.getChunkCoords(this, worldInfo, 0); + List playersToUpdate = strategy.getPlayers(worldInfo); + plugin.getNMSChunks().setBiome(chunkPositions, biome, playersToUpdate); + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java index ca118f3837..fb9d7b5de5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java @@ -5,12 +5,12 @@ import com.bgsoftware.superiorskyblock.api.island.cache.IslandCache; import com.bgsoftware.superiorskyblock.api.service.world.WorldRecordService; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; -import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.IslandUtils; @@ -121,9 +121,10 @@ private void handleIslandChunkLoad(Island island, Chunk chunk, ChunkPosition chu Biome defaultWorldBiome = IslandUtils.getDefaultWorldBiome(dimension); // We want to update the biome for new island chunks. if (island.getBiome() != defaultWorldBiome) { - List playersToUpdate = new SequentialListBuilder() - .filter(player -> player.getWorld().equals(world)) - .build(island.getAllPlayersInside(), SuperiorPlayer::asPlayer); + List playersToUpdate; + try (IslandWorldsPlayersStrategy strategy = IslandWorldsPlayersStrategy.create(island)) { + playersToUpdate = strategy.getPlayers(WorldInfo.of(world)); + } plugin.getNMSChunks().setBiome(Collections.singletonList(chunkPosition), island.getBiome(), playersToUpdate); } } From 5641f77d193b58f9e16419bb50da03f097966d77 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 14 Apr 2026 00:52:10 +0300 Subject: [PATCH 537/600] Adds the ability to configure the interaction privileges required for players --- .../api/config/SettingsManager.java | 30 +++ .../external/SlimefunHook.java | 5 +- .../nms/v1_21/trial/IslandPlayerDetector.java | 18 +- .../v1_21_10/trial/IslandPlayerDetector.java | 15 +- .../v1_21_3/trial/IslandPlayerDetector.java | 15 +- .../v1_21_4/trial/IslandPlayerDetector.java | 15 +- .../v1_21_5/trial/IslandPlayerDetector.java | 15 +- .../v1_21_7/trial/IslandPlayerDetector.java | 15 +- .../v1_21_9/trial/IslandPlayerDetector.java | 15 +- .../nms/v26_1/trial/IslandPlayerDetector.java | 15 +- .../commands/player/CmdAdmin.java | 2 +- .../config/SettingsContainer.java | 31 ++- .../config/SettingsManagerImpl.java | 13 +- .../config/section/GlobalSection.java | 3 +- .../config/section/InteractablesSection.java | 221 ++++++++++++++++++ .../superiorskyblock/core/Materials.java | 13 +- .../events/plugin/PluginEventsDispatcher.java | 7 +- .../core/key/ConstantKeys.java | 3 + .../island/privilege/IslandPrivileges.java | 7 +- .../listener/ProtectionListener.java | 13 +- .../IslandPlayerDetectorHelper.java | 37 +++ .../region/RegionManagerServiceImpl.java | 64 ++--- src/main/resources/interactables.yml | 9 +- 23 files changed, 456 insertions(+), 125 deletions(-) create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/config/section/InteractablesSection.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/nms/player_detector/IslandPlayerDetectorHelper.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 542645076a..92cc5ea875 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -3,6 +3,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; @@ -175,9 +176,17 @@ public interface SettingsManager { /** * Get all the interactable blocks. + * + * @deprecated See {@link #getInteractablesMap} */ + @Deprecated List getInteractables(); + /** + * Get all the interactable blocks and their interact privilege. + */ + Interactables getInteractablesMap(); + /** * Get all the safe blocks. */ @@ -1382,4 +1391,25 @@ interface IslandPreviews { } + interface Interactables { + + /** + * Get all the interactables from the interactables file. + */ + Set getInteractables(); + + /** + * Get all the interactables for a specific {@link IslandPrivilege} + */ + @Nullable + Set getInteractables(IslandPrivilege islandPrivilege); + + /** + * Get the required {@link IslandPrivilege} for a specific key. + */ + @Nullable + IslandPrivilege getRequiredPrivilege(Key key); + + } + } diff --git a/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java b/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java index cd685c0853..2b20700ac3 100644 --- a/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java +++ b/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; @@ -108,14 +109,14 @@ private static boolean checkPermission(OfflinePlayer offlinePlayer, Location loc break; case "ACCESS_INVENTORIES": case "INTERACT_BLOCK": - islandPrivilege = IslandPrivileges.CHEST_ACCESS; + islandPrivilege = plugin.getSettings().getInteractablesMap().getRequiredPrivilege(ConstantKeys.CHEST); break; default: islandPrivilege = IslandPrivileges.INTERACT; break; } - return island != null && island.hasPermission(superiorPlayer, islandPrivilege); + return island != null && islandPrivilege != null && island.hasPermission(superiorPlayer, islandPrivilege); } private static class AndroidMineListener implements Listener { diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java index a8634c37c1..57392d9252 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java @@ -1,10 +1,14 @@ package com.bgsoftware.superiorskyblock.nms.v1_21.trial; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -13,6 +17,7 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; +import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { @@ -20,17 +25,17 @@ public class IslandPlayerDetector implements PlayerDetector { private final Island island; private final PlayerDetector original; - private final IslandPrivilege requiredPrivilege; + private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); } - private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; @@ -39,11 +44,12 @@ private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivi @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); - if (!players.isEmpty()) { + IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); + if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); - return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java index d11bc37f28..3f57852c90 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -13,6 +14,7 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; +import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { @@ -20,17 +22,17 @@ public class IslandPlayerDetector implements PlayerDetector { private final Island island; private final PlayerDetector original; - private final IslandPrivilege requiredPrivilege; + private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); } - private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; @@ -39,11 +41,12 @@ private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivi @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); - if (!players.isEmpty()) { + IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); + if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); - return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java index 0b7f8e1264..5b8ca04a60 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -13,6 +14,7 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; +import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { @@ -20,17 +22,17 @@ public class IslandPlayerDetector implements PlayerDetector { private final Island island; private final PlayerDetector original; - private final IslandPrivilege requiredPrivilege; + private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); } - private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; @@ -39,11 +41,12 @@ private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivi @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); - if (!players.isEmpty()) { + IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); + if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); - return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java index 665907d4a3..237044292d 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -13,6 +14,7 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; +import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { @@ -20,17 +22,17 @@ public class IslandPlayerDetector implements PlayerDetector { private final Island island; private final PlayerDetector original; - private final IslandPrivilege requiredPrivilege; + private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); } - private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; @@ -39,11 +41,12 @@ private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivi @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); - if (!players.isEmpty()) { + IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); + if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); - return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java index 455c4f3a7a..aef668efbd 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -13,6 +14,7 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; +import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { @@ -20,17 +22,17 @@ public class IslandPlayerDetector implements PlayerDetector { private final Island island; private final PlayerDetector original; - private final IslandPrivilege requiredPrivilege; + private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); } - private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; @@ -39,11 +41,12 @@ private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivi @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); - if (!players.isEmpty()) { + IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); + if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); - return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java index c3e36b40fe..43787f1fed 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -13,6 +14,7 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; +import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { @@ -20,17 +22,17 @@ public class IslandPlayerDetector implements PlayerDetector { private final Island island; private final PlayerDetector original; - private final IslandPrivilege requiredPrivilege; + private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); } - private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; @@ -39,11 +41,12 @@ private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivi @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); - if (!players.isEmpty()) { + IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); + if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); - return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java index 8b84361071..bf78ea8ede 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -13,6 +14,7 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; +import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { @@ -20,17 +22,17 @@ public class IslandPlayerDetector implements PlayerDetector { private final Island island; private final PlayerDetector original; - private final IslandPrivilege requiredPrivilege; + private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); } - private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; @@ -39,11 +41,12 @@ private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivi @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); - if (!players.isEmpty()) { + IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); + if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); - return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java index 4ca3ba0929..ee0f58415a 100644 --- a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -13,6 +14,7 @@ import java.util.LinkedList; import java.util.List; import java.util.UUID; +import java.util.function.Supplier; public class IslandPlayerDetector implements PlayerDetector { @@ -20,17 +22,17 @@ public class IslandPlayerDetector implements PlayerDetector { private final Island island; private final PlayerDetector original; - private final IslandPrivilege requiredPrivilege; + private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.USE); + return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); } - private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivilege requiredPrivilege) { + private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { this.island = island; this.original = original; this.requiredPrivilege = requiredPrivilege; @@ -39,11 +41,12 @@ private IslandPlayerDetector(Island island, PlayerDetector original, IslandPrivi @Override public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); - if (!players.isEmpty()) { + IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); + if (requiredPrivilege != null && !players.isEmpty()) { players = new LinkedList<>(players); players.removeIf(uuid -> { SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); - return !island.hasPermission(superiorPlayer, this.requiredPrivilege); + return !island.hasPermission(superiorPlayer, requiredPrivilege); }); players = Collections.unmodifiableList(players); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java index 9e34034eef..04fe2ae1a9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/player/CmdAdmin.java @@ -25,7 +25,7 @@ public class CmdAdmin implements ISuperiorCommand { private static final Int2ObjectMapView> commandsPerPageCache = CollectionsFactory.createInt2ObjectArrayMap(); - public static void registerCallbacks(PluginEventsDispatcher dispatcher) { + public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CmdAdmin::onCommandsRefresh); dispatcher.registerCallback(PluginEventType.COMMANDS_UPDATE_EVENT, CmdAdmin::onCommandsRefresh); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index baf52f3035..7d35dd280f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.config.section.InteractablesSection; import com.bgsoftware.superiorskyblock.config.section.WorldsSection; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.SBlockOffset; @@ -55,6 +56,7 @@ import java.util.Collections; import java.util.EnumMap; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; @@ -137,7 +139,7 @@ public class SettingsContainer { public final Set worldPermissions; public final boolean voidTeleportMembers; public final boolean voidTeleportVisitors; - public final List interactables; + public final SettingsManager.Interactables interactables; public final KeySet safeBlocks; public final boolean visitorsDamage; public final boolean coopDamage; @@ -647,7 +649,7 @@ private List loadClearActions(List clearActionsNames) { return Collections.unmodifiableList(clearActions); } - private List loadInteractables(SuperiorSkyblockPlugin plugin) { + private SettingsManager.Interactables loadInteractables(SuperiorSkyblockPlugin plugin) { File file = new File(plugin.getDataFolder(), "interactables.yml"); if (!file.exists()) @@ -655,20 +657,31 @@ private List loadInteractables(SuperiorSkyblockPlugin plugin) { YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file); - List interactablesList = cfg.getStringList("interactables"); + InteractablesSection interactables = new InteractablesSection(plugin, cfg); // Warn about interactables that the default file contains but the current // file does not. + Set localInteractables = new HashSet<>(); + for (Key key : interactables.getInteractables()) { + localInteractables.add(key.toString()); + } + YamlConfiguration defaultInteractablesConfig = CommentedConfiguration.loadConfiguration(plugin.getResource("interactables.yml")); - List defaultInteractables = defaultInteractablesConfig.getStringList("interactables"); - if (defaultInteractables != null) { - for (String interactableBlock : defaultInteractables) { - if (!interactablesList.contains(interactableBlock)) - Log.warn("Potentially missing interactable block ", interactableBlock); + for (String block : defaultInteractablesConfig.getStringList("interactables")) { + if (!localInteractables.contains(block)) { + Log.warn("Potentially missing interactable block ", block); + } + } + + if (interactables.isLegacy()) { + try { + interactables.saveToFile(file); + } catch (IOException error) { + Log.errorFromFile(error, "interactables.yml", "Failed to save interactables:"); } } - return Collections.unmodifiableList(interactablesList); + return interactables; } private KeySet loadSafeBlocks(SuperiorSkyblockPlugin plugin) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index c6c6e0a535..4672ccd28e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; @@ -39,6 +40,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -215,7 +217,16 @@ public VoidTeleport getVoidTeleport() { @Override public List getInteractables() { - return this.global.getInteractables(); + List interactables = new LinkedList<>(); + for (Key key : getInteractablesMap().getInteractables()) { + interactables.add(key.toString()); + } + return interactables.isEmpty() ? Collections.emptyList() : interactables; + } + + @Override + public Interactables getInteractablesMap() { + return this.global.getInteractablesMap(); } @Override diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index 7ebf7d0abc..4b7975b76a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.config.section; +import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.island.SortingType; @@ -83,7 +84,7 @@ public List getSignWarp() { return getContainer().signWarp; } - public List getInteractables() { + public SettingsManager.Interactables getInteractablesMap() { return getContainer().interactables; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/InteractablesSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/InteractablesSection.java new file mode 100644 index 0000000000..0f9f865ea3 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/InteractablesSection.java @@ -0,0 +1,221 @@ +package com.bgsoftware.superiorskyblock.config.section; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.config.CommentedConfiguration; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.config.SettingsManager; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.core.EnumHelper; +import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.Materials; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.set.KeySets; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import org.bukkit.Material; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.util.Collections; +import java.util.Comparator; +import java.util.IdentityHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +public class InteractablesSection implements SettingsManager.Interactables { + + private static final LazyReference PRIVILEGE_CHEST_ACCESS = lazyIslandPrivilege("CHEST_ACCESS"); + private static final LazyReference PRIVILEGE_FARM_TRAMPING = lazyIslandPrivilege("FARM_TRAMPING"); + private static final LazyReference PRIVILEGE_INTERACT = lazyIslandPrivilege("INTERACT"); + private static final LazyReference PRIVILEGE_PICKUP_LECTERN_BOOK = lazyIslandPrivilege("PICKUP_LECTERN_BOOK"); + private static final LazyReference PRIVILEGE_SIGN_INTERACT = lazyIslandPrivilege("SIGN_INTERACT"); + private static final LazyReference PRIVILEGE_SPAWNER_BREAK = lazyIslandPrivilege("SPAWNER_BREAK"); + private static final LazyReference PRIVILEGE_TURTLE_EGG_TRAMPING = lazyIslandPrivilege("TURTLE_EGG_TRAMPING"); + private static final LazyReference PRIVILEGE_USE = lazyIslandPrivilege("USE"); + + private static final Material FARMLAND = EnumHelper.getEnum(Material.class, "FARMLAND", "SOIL"); + @Nullable + private static final Material ROOTED_DIRT = EnumHelper.getEnum(Material.class, "ROOTED_DIRT"); + @Nullable + private static final Material TURTLE_EGG = EnumHelper.getEnum(Material.class, "TURTLE_EGG"); + @Nullable + private static final Material SWEET_BERRY_BUSH = EnumHelper.getEnum(Material.class, "SWEET_BERRY_BUSH"); + @Nullable + private static final Material LECTERN = EnumHelper.getEnum(Material.class, "LECTERN"); + @Nullable + private static final Material VAULT = EnumHelper.getEnum(Material.class, "VAULT"); + @Nullable + private static final Material BLAST_FURNACE = EnumHelper.getEnum(Material.class, "BLAST_FURNACE"); + @Nullable + private static final Material BURNING_FURNACE = EnumHelper.getEnum(Material.class, "BURNING_FURNACE"); + @Nullable + private static final Material CHISELED_BOOKSHELF = EnumHelper.getEnum(Material.class, "CHISELED_BOOKSHELF"); + @Nullable + private static final Material CRAFTER = EnumHelper.getEnum(Material.class, "CRAFTER"); + @Nullable + private static final Material DECORATED_POT = EnumHelper.getEnum(Material.class, "DECORATED_POT"); + @Nullable + private static final Material SMOKER = EnumHelper.getEnum(Material.class, "SMOKER"); + + private final Map privilegeToInteractables; + private final KeyMap interactableToPrivilege; + private final SuperiorSkyblockPlugin plugin; + private final boolean legacy; + + public InteractablesSection(SuperiorSkyblockPlugin plugin, YamlConfiguration cfg) { + this.plugin = plugin; + this.legacy = cfg.getKeys(false).size() == 1 && cfg.isList("interactables"); + + Map privilegeToInteractables = new IdentityHashMap<>(); + if (this.legacy) { + loadLegacyInternal(cfg, privilegeToInteractables); + } else { + loadInternal(cfg, privilegeToInteractables); + } + this.privilegeToInteractables = privilegeToInteractables.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(privilegeToInteractables); + this.interactableToPrivilege = convertView(privilegeToInteractables); + } + + private static KeyMap convertView(Map base) { + KeyMap converted = KeyMaps.createHashMap(KeyIndicator.MATERIAL); + base.forEach((islandPrivilege, keySet) -> { + for (Key key : keySet) { + IslandPrivilege oldPrivilege = converted.put(key, islandPrivilege); + if (oldPrivilege != null) { + Log.warnFromFile("interactables.yml", "The interactable block ", key, " had two privileges: ", oldPrivilege, ", ", islandPrivilege); + } + } + }); + return KeyMaps.unmodifiableKeyMap(converted); + } + + public boolean isLegacy() { + return legacy; + } + + @Override + public Set getInteractables() { + return Collections.unmodifiableSet(this.interactableToPrivilege.keySet()); + } + + @Override + @Nullable + public Set getInteractables(IslandPrivilege islandPrivilege) { + Set interactables = this.privilegeToInteractables.get(islandPrivilege); + return interactables == null || interactables.isEmpty() ? null : Collections.unmodifiableSet(interactables); + } + + @Override + @Nullable + public IslandPrivilege getRequiredPrivilege(Key key) { + return this.interactableToPrivilege.get(key); + } + + public void saveToFile(File file) throws IOException { + CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(plugin.getResource("interactables.yml")); + + Set islandPrivileges = new TreeSet<>(Comparator.comparing(IslandPrivilege::getName)); + islandPrivileges.addAll(this.privilegeToInteractables.keySet()); + + boolean copyHeaderComment = true; + for(IslandPrivilege islandPrivilege : islandPrivileges) { + Set keys = new TreeSet<>(String::compareTo); + this.privilegeToInteractables.get(islandPrivilege).forEach(key -> keys.add(key.toString())); + cfg.set(islandPrivilege.getName(), new LinkedList<>(keys)); + + if (copyHeaderComment) { + copyHeaderComment = false; + cfg.setComment(islandPrivilege.getName(), cfg.getComment("interactables")); + } else { + cfg.setComment(islandPrivilege.getName(), ""); + } + } + + // Remove the default interactables + cfg.set("interactables", null); + + cfg.save(file); + } + + private static void loadLegacyInternal(YamlConfiguration cfg, Map interactablesMap) { + List interactables = cfg.getStringList("interactables"); + + for (String blockType : interactables) { + Key blockKey = Key.ofMaterialAndData(blockType); + + IslandPrivilege islandPrivilege; + try { + Material material = ((MaterialKey) blockKey).getMaterial(); + + if (Materials.isChest(material)) { + islandPrivilege = PRIVILEGE_CHEST_ACCESS.get(); + } else if (material == LECTERN) { + islandPrivilege = PRIVILEGE_PICKUP_LECTERN_BOOK.get(); + } else if (isInventoryHolder(material)) { + islandPrivilege = PRIVILEGE_USE.get(); + } else if (Materials.isSign(material)) { + islandPrivilege = PRIVILEGE_SIGN_INTERACT.get(); + } else if (material == Materials.SPAWNER.toBukkitType()) { + islandPrivilege = PRIVILEGE_SPAWNER_BREAK.get(); + } else if (material == FARMLAND || material == ROOTED_DIRT || material == SWEET_BERRY_BUSH) { + islandPrivilege = PRIVILEGE_FARM_TRAMPING.get(); + } else if (material == TURTLE_EGG) { + islandPrivilege = PRIVILEGE_TURTLE_EGG_TRAMPING.get(); + } else { + islandPrivilege = PRIVILEGE_INTERACT.get(); + } + + } catch (Throwable ignored) { + // In the case this is a custom block or something, default to INTERACT privilege. + islandPrivilege = PRIVILEGE_INTERACT.get(); + } + + interactablesMap.computeIfAbsent(islandPrivilege, p -> KeySets.createHashSet(KeyIndicator.MATERIAL)) + .add(blockKey); + } + } + + private static boolean isInventoryHolder(Material material) { + return Materials.isShelf(material) || material == BLAST_FURNACE || material == Material.BREWING_STAND || + material == BURNING_FURNACE || material == CHISELED_BOOKSHELF || material == CRAFTER || + material == DECORATED_POT || material == Material.DISPENSER || material == Material.DROPPER || + material == Material.FURNACE || material == Material.HOPPER || material == Material.JUKEBOX || + material == SMOKER || material == VAULT; + } + + private static void loadInternal(YamlConfiguration cfg, Map interactablesMap) { + for (String islandPrivilegeName : cfg.getKeys(false)) { + try { + IslandPrivilege.register(islandPrivilegeName); + } catch (IllegalStateException ignored) { + } + + IslandPrivilege islandPrivilege = IslandPrivilege.getByName(islandPrivilegeName); + KeySet keys = KeySets.createHashSet(KeyIndicator.MATERIAL, cfg.getStringList(islandPrivilegeName)); + interactablesMap.put(islandPrivilege, keys); + } + } + + private static LazyReference lazyIslandPrivilege(String name) { + return new LazyReference() { + @Override + protected IslandPrivilege create() { + try { + IslandPrivilege.register(name); + } catch (IllegalStateException ignored) { + } + + return IslandPrivilege.getByName(name); + } + }; + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java index 4266c0fc50..a23630c5b3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/Materials.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.core; +import com.bgsoftware.superiorskyblock.core.logging.Log; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -123,6 +124,10 @@ public static boolean isHoe(Material material) { return hasTag(material, Tag.HOE); } + public static boolean isShelf(Material material) { + return hasTag(material, Tag.SHELF); + } + public static Set getBlocksNonLegacy() { return Collections.unmodifiableSet(BLOCK_NON_LEGACY_MATERIALS); } @@ -183,14 +188,13 @@ private static EnumMap> setupMaterialTags() { materialTags.add(Tag.BED); if (materialName.contains("_HOE")) materialTags.add(Tag.HOE); + if (materialName.contains("_SHELF")) + materialTags.add(Tag.SHELF); if (!materialTags.isEmpty()) enumMap.put(material, materialTags); } - Arrays.stream(Material.values()).forEach(material -> { - - }); return enumMap; } @@ -220,7 +224,8 @@ public enum Tag { CARPET, BED, HARNESS, - HOE + HOE, + SHELF } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java index a25f7802b9..ad86e870b2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java @@ -14,6 +14,7 @@ import com.bgsoftware.superiorskyblock.external.worlds.WorldsProvider_Default; import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.SpawnIsland; +import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; import com.bgsoftware.superiorskyblock.world.entity.EntityCategories; @@ -38,13 +39,15 @@ public void registerDefaultListeners() { SIsland.registerListeners(this); CommandsMap.registerListeners(this); SpawnIsland.registerListeners(this); - RegionManagerServiceImpl.registerCallbacks(this); + RegionManagerServiceImpl.registerListeners(this); CmdHelp.registerListeners(this); - CmdAdmin.registerCallbacks(this); + CmdAdmin.registerListeners(this); Message.registerListeners(this); SSuperiorPlayer.registerListeners(this); EntityCategories.registerListeners(this); WorldsProvider_Default.registerListeners(this); + IslandPlayerDetectorHelper.registerListeners(this); + } public void registerCallback(PluginEventType type, Runnable callback) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java index 60c57a6226..7889fec278 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/ConstantKeys.java @@ -41,6 +41,9 @@ public class ConstantKeys { .map(Keys::of).orElse(null); public static final Key SNOW_BLOCK = Keys.of(Material.SNOW_BLOCK); public static final Key SOUL_SAND = Keys.of(Material.SOUL_SAND); + @Nullable + public static final Key TARGET = Optional.ofNullable(EnumHelper.getEnum(Material.class, "TARGET")) + .map(Keys::of).orElse(null); public static final Key TNT = Keys.of(Material.TNT); public static final Key WATER = Keys.of(Material.WATER); public static final Key WET_SPONGE = Keys.of(EnumHelper.getEnum(Material.class, "WET_SPONGE", "SPONGE")); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index 11c578321a..bfcc09b235 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -25,7 +25,6 @@ public class IslandPrivileges { public static final IslandPrivilege BRUSH = register("BRUSH", ServerVersion.isAtLeast(ServerVersion.v1_20)); public static final IslandPrivilege BUILD = register("BUILD"); public static final IslandPrivilege CHANGE_NAME = register("CHANGE_NAME", IslandPrivilege.Type.COMMAND); - public static final IslandPrivilege CHEST_ACCESS = register("CHEST_ACCESS"); public static final IslandPrivilege CHORUS_FRUIT = register("CHORUS_FRUIT", ServerVersion.isAtLeast(ServerVersion.v1_9)); public static final IslandPrivilege CLOSE_BYPASS = register("CLOSE_BYPASS"); public static final IslandPrivilege CLOSE_ISLAND = register("CLOSE_ISLAND", IslandPrivilege.Type.COMMAND); @@ -42,12 +41,12 @@ public class IslandPrivileges { public static final IslandPrivilege ENTITY_RIDE = register("ENTITY_RIDE"); public static final IslandPrivilege EXPEL_BYPASS = register("EXPEL_BYPASS"); public static final IslandPrivilege EXPEL_PLAYERS = register("EXPEL_PLAYERS", IslandPrivilege.Type.COMMAND); - public static final IslandPrivilege FARM_TRAMPING = register("FARM_TRAMPING"); public static final IslandPrivilege FERTILIZE = register("FERTILIZE"); public static final IslandPrivilege FISH = register("FISH"); public static final IslandPrivilege FLY = register("FLY"); public static final IslandPrivilege HORSE_INTERACT = register("HORSE_INTERACT"); public static final IslandPrivilege IGNITE_CREEPER = register("IGNITE_CREEPER"); + // TODO - get rid of INTERACT public static final IslandPrivilege INTERACT = register("INTERACT"); public static final IslandPrivilege INVITE_MEMBER = register("INVITE_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege ISLAND_CHEST = register("ISLAND_CHEST", IslandPrivilege.Type.COMMAND); @@ -71,7 +70,6 @@ public class IslandPrivileges { @Nullable public static final IslandPrivilege PICKUP_FISH = register("PICKUP_FISH", !ServerVersion.isLegacy()); @Nullable - public static final IslandPrivilege PICKUP_LECTERN_BOOK = register("PICKUP_LECTERN_BOOK", ServerVersion.isAtLeast(ServerVersion.v1_14)); public static final IslandPrivilege PROMOTE_MEMBERS = register("PROMOTE_MEMBERS", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege RANKUP = register("RANKUP", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege RATINGS_SHOW = register("RATINGS_SHOW", IslandPrivilege.Type.COMMAND); @@ -86,13 +84,10 @@ public class IslandPrivileges { public static final IslandPrivilege SET_ROLE = register("SET_ROLE", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SET_SETTINGS = register("SET_SETTINGS", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SET_WARP = register("SET_WARP", IslandPrivilege.Type.COMMAND); - public static final IslandPrivilege SIGN_INTERACT = register("SIGN_INTERACT"); public static final IslandPrivilege SPAWNER_BREAK = register("SPAWNER_BREAK"); public static final IslandPrivilege TAMED_ANIMAL_DAMAGE = register("TAMED_ANIMAL_DAMAGE"); @Nullable - public static final IslandPrivilege TURTLE_EGG_TRAMPING = register("TURTLE_EGG_TRAMPING", !ServerVersion.isLegacy()); public static final IslandPrivilege UNCOOP_MEMBER = register("UNCOOP_MEMBER", IslandPrivilege.Type.COMMAND); - public static final IslandPrivilege USE = register("USE"); public static final IslandPrivilege VALUABLE_BREAK = register("VALUABLE_BREAK"); public static final IslandPrivilege VILLAGER_TRADING = register("VILLAGER_TRADING"); public static final IslandPrivilege WIND_CHARGE = register("WIND_CHARGE", ServerVersion.isAtLeast(ServerVersion.v1_21)); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 9028eb5532..c4c28579e0 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; +import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; @@ -431,7 +432,7 @@ private void onVehicleOpen(GameEvent e) { IslandPrivilege islandPrivilege = BukkitEntities.isHorse((Vehicle) inventoryHolder) ? IslandPrivileges.HORSE_INTERACT : BukkitEntities.isNautilus(((Vehicle) inventoryHolder).getType()) ? IslandPrivileges.NAUTILUS_INTERACT : - inventoryHolder instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_OPEN; + inventoryHolder instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_OPEN; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().bukkitEvent.getPlayer()); InteractionResult interactionResult; @@ -543,8 +544,11 @@ private void onProjectileHit(GameEvent e) { if (hitBlockType != CHORUS_FLOWER && hitBlockType != DECORATED_POT && hitBlockType != TARGET) return; + IslandPrivilege requiredPrivilege = plugin.getSettings().getInteractablesMap() + .getRequiredPrivilege(ConstantKeys.TARGET); + location = hitBlock.getLocation(wrapper.getHandle()); - islandPrivilege = hitBlockType == TARGET ? IslandPrivileges.INTERACT : IslandPrivileges.BREAK; + islandPrivilege = hitBlockType == TARGET ? requiredPrivilege : IslandPrivileges.BREAK; } if (islandPrivilege == null) @@ -581,7 +585,10 @@ private void onSoftExplodeEvent(GameEvent e) { Material blockType = block.getType(); IslandPrivilege islandPrivilege = blockType == CHORUS_FLOWER || blockType == POINTED_DRIPSTONE ? - IslandPrivileges.BREAK : IslandPrivileges.INTERACT; + IslandPrivileges.BREAK : plugin.getSettings().getInteractablesMap().getRequiredPrivilege(Keys.of(block)); + + if (islandPrivilege == null) + continue; InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/player_detector/IslandPlayerDetectorHelper.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/player_detector/IslandPlayerDetectorHelper.java new file mode 100644 index 0000000000..c8aa3c39d3 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/player_detector/IslandPlayerDetectorHelper.java @@ -0,0 +1,37 @@ +package com.bgsoftware.superiorskyblock.nms.player_detector; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; +import com.bgsoftware.superiorskyblock.core.key.Keys; + +import java.util.function.Supplier; + +public class IslandPlayerDetectorHelper { + + @Nullable + private static IslandPrivilege CACHED_TRIAL_VAULT_PRIVILEGE; + + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, IslandPlayerDetectorHelper::onSettingsUpdate); + } + + private static void onSettingsUpdate() { + SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + // Do not call in static-initializator, otherwise will cause errors + Key vaultKey = Keys.ofMaterialAndData("VAULT"); + CACHED_TRIAL_VAULT_PRIVILEGE = plugin.getSettings().getInteractablesMap().getRequiredPrivilege(vaultKey); + } + + public static Supplier getTrialVaultIslandPrivilege() { + return () -> CACHED_TRIAL_VAULT_PRIVILEGE; + } + + private IslandPlayerDetectorHelper() { + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 9522c510f1..463dc970c9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -9,7 +9,6 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPreview; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; import com.bgsoftware.superiorskyblock.api.service.region.MoveResult; @@ -23,9 +22,7 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.messages.Message; @@ -41,8 +38,6 @@ import org.bukkit.Material; import org.bukkit.WeatherType; import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.block.Sign; import org.bukkit.entity.Animals; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Arrow; @@ -60,7 +55,6 @@ import org.bukkit.event.block.Action; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitTask; @@ -76,8 +70,6 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService @Nullable private static final Material SWEET_BERRY_BUSH = EnumHelper.getEnum(Material.class, "SWEET_BERRY_BUSH"); @Nullable - private static final Material LECTERN = EnumHelper.getEnum(Material.class, "LECTERN"); - @Nullable private static final Material VAULT = EnumHelper.getEnum(Material.class, "VAULT"); @Nullable private static final Material TRIAL_KEY = EnumHelper.getEnum(Material.class, "TRIAL_KEY"); @@ -98,7 +90,6 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService private static final int MAX_PICKUP_DISTANCE = 1; private static EnumerateSet WORLD_PERMISSIONS_CACHE; - private static KeySet INTERACTABLES_CACHE; private final SuperiorSkyblockPlugin plugin; @@ -106,7 +97,7 @@ public RegionManagerServiceImpl(SuperiorSkyblockPlugin plugin) { this.plugin = plugin; } - public static void registerCallbacks(PluginEventsDispatcher dispatcher) { + public static void registerListeners(PluginEventsDispatcher dispatcher) { dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, RegionManagerServiceImpl::onSettingsUpdate); } @@ -119,12 +110,6 @@ private static void onSettingsUpdate() { } catch (Throwable ignored) { } }); - - INTERACTABLES_CACHE = KeySets.createHashSet(KeyIndicator.MATERIAL); - plugin.getSettings().getInteractables().forEach(interactableName -> { - INTERACTABLES_CACHE.add(Keys.ofMaterialAndData(interactableName)); - }); - } @Override @@ -201,49 +186,34 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc int stackedBlockAmount = plugin.getStackedBlocks().getStackedBlockAmount(blockLocation); - if (!isInteractableItem && stackedBlockAmount <= 1 && !INTERACTABLES_CACHE.contains(blockKey)) + IslandPrivilege islandPrivilege = plugin.getSettings().getInteractablesMap().getRequiredPrivilege(blockKey); + + if (!isInteractableItem && stackedBlockAmount <= 1 && islandPrivilege == null) return InteractionResult.SUCCESS; - BlockState blockState = block.getState(); EntityType spawnType = usedItem == null ? EntityType.UNKNOWN : BukkitItems.getEntityType(usedItem); Material blockType = block.getType(); Material usedItemType = usedItem == null ? null : usedItem.getType(); - IslandPrivilege islandPrivilege; - if (usedItem != null && Materials.isMinecart(usedItemType) ? Materials.isRail(blockType) : Materials.isBoat(blockType)) { islandPrivilege = IslandPrivileges.MINECART_PLACE; - } else if (Materials.isChest(blockType)) { - islandPrivilege = IslandPrivileges.CHEST_ACCESS; - } else if (blockType == LECTERN) { - islandPrivilege = IslandPrivileges.PICKUP_LECTERN_BOOK; - } else if (blockState instanceof InventoryHolder) { - islandPrivilege = IslandPrivileges.USE; - } else if (usedItem != null && blockType == VAULT && (usedItemType == TRIAL_KEY || usedItemType == OMINOUS_TRIAL_KEY)) { - islandPrivilege = IslandPrivileges.USE; - } else if (blockState instanceof Sign) { - islandPrivilege = IslandPrivileges.SIGN_INTERACT; - } else if (blockType == Materials.SPAWNER.toBukkitType()) { - islandPrivilege = IslandPrivileges.SPAWNER_BREAK; - } else if (blockType == FARMLAND || blockType == ROOTED_DIRT || (usedItem != null && Materials.isHoe(usedItemType))) { - islandPrivilege = action == Action.PHYSICAL ? IslandPrivileges.FARM_TRAMPING : IslandPrivileges.BUILD; - } else if (blockType == TURTLE_EGG) { - islandPrivilege = action == Action.PHYSICAL ? IslandPrivileges.TURTLE_EGG_TRAMPING : IslandPrivileges.BUILD; - } else if (blockType == SWEET_BERRY_BUSH && action == Action.RIGHT_CLICK_BLOCK) { - islandPrivilege = Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem) ? IslandPrivileges.FERTILIZE : IslandPrivileges.FARM_TRAMPING; + } else if (usedItem != null && blockType == VAULT && usedItemType != TRIAL_KEY && usedItemType != OMINOUS_TRIAL_KEY) { + return InteractionResult.SUCCESS; + } else if (action == Action.PHYSICAL && blockType == FARMLAND || blockType == ROOTED_DIRT || + (usedItem != null && Materials.isHoe(usedItemType))) { + islandPrivilege = IslandPrivileges.BUILD; + } else if (action == Action.PHYSICAL && blockType == TURTLE_EGG) { + islandPrivilege = IslandPrivileges.BUILD; + } else if (blockType == SWEET_BERRY_BUSH && action == Action.RIGHT_CLICK_BLOCK && + Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem)) { + islandPrivilege = IslandPrivileges.FERTILIZE; } else if (stackedBlockAmount > 1) { islandPrivilege = IslandPrivileges.BREAK; - } else if (blockType == Material.PUMPKIN) { - islandPrivilege = IslandPrivileges.BREAK; } else if (spawnType != EntityType.UNKNOWN) { EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(spawnType)); - if (entityCategory == null) { - islandPrivilege = IslandPrivileges.INTERACT; - } else { - islandPrivilege = Optional.ofNullable(entityCategory.getSpawnPrivilege()).orElse(IslandPrivileges.INTERACT); + if (entityCategory != null && entityCategory.getSpawnPrivilege() != null) { + islandPrivilege = entityCategory.getSpawnPrivilege(); } - } else { - islandPrivilege = IslandPrivileges.INTERACT; } return handleInteractionInternal(superiorPlayer, blockLocation, islandPrivilege, @@ -406,7 +376,7 @@ public InteractionResult handleEntityRide(SuperiorPlayer superiorPlayer, Entity IslandPrivilege islandPrivilege = BukkitEntities.isHorse(vehicle) ? IslandPrivileges.HORSE_INTERACT : BukkitEntities.isNautilus(vehicle.getType()) ? IslandPrivileges.NAUTILUS_INTERACT : - vehicle instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_ENTER; + vehicle instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_ENTER; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = vehicle.getLocation(wrapper.getHandle()); diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index 2ba655be71..536d39bcfd 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -7,7 +7,14 @@ # A list of interactable blocks. # Only interactable blocks & stacked blocks will be blocked from being interacted. +# The format of the file is as so: +# : +# - BLOCK_TYPE +# - ... +# You can create as many custom privileges as you want. + interactables: + - 'TEST' - 'ACACIA_BUTTON' - 'ACACIA_DOOR' - 'ACACIA_FENCE' @@ -354,4 +361,4 @@ interactables: - 'WORKBENCH' - 'YELLOW_BED' - 'YELLOW_CANDLE' - - 'YELLOW_SHULKER_BOX' \ No newline at end of file + - 'YELLOW_SHULKER_BOX' From f8ce91d753027d627e59ab2458e9510b964b4236 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 15 Apr 2026 01:39:55 +0300 Subject: [PATCH 538/600] Fix the plugin not working on 1.17-1.21.11 --- build.gradle | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 29c7ef47e3..3fe0df86ae 100644 --- a/build.gradle +++ b/build.gradle @@ -84,6 +84,8 @@ processResources { } } +subprojects.each { evaluationDependsOn(it.path) } + shadowJar { relocate 'org.bstats', 'com.bgsoftware.superiorskyblock.libs.org.bstats' relocate 'com.bgsoftware.common', 'com.bgsoftware.superiorskyblock.libs.com.bgsoftware.common' @@ -103,12 +105,8 @@ shadowJar { try { def reobfTask = sub.tasks.named('reobfJar') dependsOn(reobfTask) - from(zipTree(reobfTask.outputJar)) { - // Exclude metadata that might cause duplicates - exclude 'META-INF/MANIFEST.MF' - exclude 'META-INF/*.SF' - exclude 'META-INF/*.DSA' - exclude 'META-INF/*.RSA' + from(reobfTask.flatMap { it.outputJar }.map { zipTree(it) }) { + exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' } } catch (Exception ignored) { from sub.sourceSets.main.output From fd9cdf5643b8cc4e0a5f4ed06fc9f68094e03aeb Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 17 Apr 2026 18:21:12 +0300 Subject: [PATCH 539/600] Move all mission code into the main source code --- Missions/BlocksMissions/build.gradle | 12 + .../missions/BlocksMissions.java | 430 ++++++++++++++++++ .../missions/blocks/BlocksTracker.java | 154 +++++++ .../blocks/BlocksTrackingComponent.java | 73 +++ .../missions/blocks/ChunkBitSet.java | 83 ++++ .../missions/blocks/TrackedBlocksData.java | 53 +++ Missions/BrewingMissions/build.gradle | 9 + .../missions/BrewingMissions.java | 411 +++++++++++++++++ Missions/CraftingMissions/build.gradle | 9 + .../missions/CraftingMissions.java | 254 +++++++++++ Missions/EnchantingMissions/build.gradle | 9 + .../missions/EnchantingMissions.java | 358 +++++++++++++++ Missions/FarmingMissions/build.gradle | 9 + .../missions/FarmingMissions.java | 402 ++++++++++++++++ .../missions/farming/PlantType.java | 103 +++++ .../missions/farming/PlantsTracker.java | 160 +++++++ .../farming/PlantsTrackingComponent.java | 69 +++ .../missions/farming/TrackedPlantsData.java | 30 ++ Missions/FishingMissions/build.gradle | 9 + .../missions/FishingMissions.java | 204 +++++++++ Missions/IslandMissions/build.gradle | 9 + .../missions/IslandMissions.java | 176 +++++++ .../island/DynamicRegisteredListener.java | 18 + .../missions/island/EventsHelper.java | 38 ++ .../missions/island/timings/DummyTimings.java | 21 + .../missions/island/timings/ITimings.java | 23 + .../island/timings/LegacyTimingsWrapper.java | 27 ++ .../island/timings/TimingsWrapper.java | 62 +++ Missions/ItemsMissions/build.gradle | 9 + .../missions/ItemsMissions.java | 280 ++++++++++++ Missions/KillsMissions/build.gradle | 10 + .../missions/KillsMissions.java | 218 +++++++++ Missions/StatisticsMissions/build.gradle | 9 + .../missions/StatisticsMissions.java | 248 ++++++++++ Missions/build.gradle | 15 + .../missions/common/BuiltinMission.java | 58 +++ .../missions/common/Placeholders.java | 140 ++++++ .../requirements/CustomRequirements.java | 22 + .../common/requirements/IRequirements.java | 9 + .../common/requirements/KeyRequirements.java | 25 + .../common/requirements/Requirements.java | 17 + .../requirements/RequirementsAbstract.java | 45 ++ .../missions/common/tracker/DataTracker.java | 54 +++ .../common/tracker/KeyDataTracker.java | 13 + .../common/tracker/RawDataTracker.java | 13 + build.gradle | 13 + settings.gradle | 11 + .../resources/modules/missions/BlocksMissions | Bin 41443 -> 0 bytes .../modules/missions/BrewingMissions | Bin 30011 -> 0 bytes .../modules/missions/CraftingMissions | Bin 26028 -> 0 bytes .../modules/missions/EnchantingMissions | Bin 30075 -> 0 bytes .../modules/missions/FarmingMissions | Bin 38717 -> 0 bytes .../modules/missions/FishingMissions | Bin 23055 -> 0 bytes .../resources/modules/missions/IslandMissions | Bin 28661 -> 0 bytes .../resources/modules/missions/ItemsMissions | Bin 24510 -> 0 bytes .../resources/modules/missions/KillsMissions | Bin 23231 -> 0 bytes .../modules/missions/StatisticsMissions | Bin 24470 -> 0 bytes 57 files changed, 4424 insertions(+) create mode 100644 Missions/BlocksMissions/build.gradle create mode 100644 Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/BlocksMissions.java create mode 100644 Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/BlocksTracker.java create mode 100644 Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/BlocksTrackingComponent.java create mode 100644 Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/ChunkBitSet.java create mode 100644 Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/TrackedBlocksData.java create mode 100644 Missions/BrewingMissions/build.gradle create mode 100644 Missions/BrewingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/BrewingMissions.java create mode 100644 Missions/CraftingMissions/build.gradle create mode 100644 Missions/CraftingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/CraftingMissions.java create mode 100644 Missions/EnchantingMissions/build.gradle create mode 100644 Missions/EnchantingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/EnchantingMissions.java create mode 100644 Missions/FarmingMissions/build.gradle create mode 100644 Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/FarmingMissions.java create mode 100644 Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantType.java create mode 100644 Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantsTracker.java create mode 100644 Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantsTrackingComponent.java create mode 100644 Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/TrackedPlantsData.java create mode 100644 Missions/FishingMissions/build.gradle create mode 100644 Missions/FishingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/FishingMissions.java create mode 100644 Missions/IslandMissions/build.gradle create mode 100644 Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/IslandMissions.java create mode 100644 Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/DynamicRegisteredListener.java create mode 100644 Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/EventsHelper.java create mode 100644 Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/DummyTimings.java create mode 100644 Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/ITimings.java create mode 100644 Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/LegacyTimingsWrapper.java create mode 100644 Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/TimingsWrapper.java create mode 100644 Missions/ItemsMissions/build.gradle create mode 100644 Missions/ItemsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/ItemsMissions.java create mode 100644 Missions/KillsMissions/build.gradle create mode 100644 Missions/KillsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/KillsMissions.java create mode 100644 Missions/StatisticsMissions/build.gradle create mode 100644 Missions/StatisticsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/StatisticsMissions.java create mode 100644 Missions/build.gradle create mode 100644 Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/BuiltinMission.java create mode 100644 Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/Placeholders.java create mode 100644 Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/CustomRequirements.java create mode 100644 Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/IRequirements.java create mode 100644 Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/KeyRequirements.java create mode 100644 Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/Requirements.java create mode 100644 Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/RequirementsAbstract.java create mode 100644 Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/DataTracker.java create mode 100644 Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/KeyDataTracker.java create mode 100644 Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/RawDataTracker.java delete mode 100644 src/main/resources/modules/missions/BlocksMissions delete mode 100644 src/main/resources/modules/missions/BrewingMissions delete mode 100644 src/main/resources/modules/missions/CraftingMissions delete mode 100644 src/main/resources/modules/missions/EnchantingMissions delete mode 100644 src/main/resources/modules/missions/FarmingMissions delete mode 100644 src/main/resources/modules/missions/FishingMissions delete mode 100644 src/main/resources/modules/missions/IslandMissions delete mode 100644 src/main/resources/modules/missions/ItemsMissions delete mode 100644 src/main/resources/modules/missions/KillsMissions delete mode 100644 src/main/resources/modules/missions/StatisticsMissions diff --git a/Missions/BlocksMissions/build.gradle b/Missions/BlocksMissions/build.gradle new file mode 100644 index 0000000000..e5de0b9635 --- /dev/null +++ b/Missions/BlocksMissions/build.gradle @@ -0,0 +1,12 @@ +group 'Missions:BlocksMissions' + +dependencies { + compileOnly "org.spigotmc:v1_8_R3-Taco:latest" + + compileOnly "com.bgsoftware:WildStackerAPI:3.6.3" + compileOnly "com.bgsoftware:WildToolsAPI:2.11.4" +} + +shadowJar { + relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.blocks' +} \ No newline at end of file diff --git a/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/BlocksMissions.java b/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/BlocksMissions.java new file mode 100644 index 0000000000..583c968076 --- /dev/null +++ b/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/BlocksMissions.java @@ -0,0 +1,430 @@ +package com.bgsoftware.superiorskyblock.missions; + +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.Counter; +import com.bgsoftware.superiorskyblock.missions.blocks.BlocksTracker; +import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; +import com.bgsoftware.superiorskyblock.missions.common.Placeholders; +import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; +import com.bgsoftware.superiorskyblock.missions.common.tracker.KeyDataTracker; +import com.bgsoftware.wildstacker.api.WildStackerAPI; +import com.bgsoftware.wildstacker.api.events.BarrelUnstackEvent; +import com.bgsoftware.wildtools.api.events.CuboidWandUseEvent; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPistonExtendEvent; +import org.bukkit.event.block.BlockPistonRetractEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +public class BlocksMissions extends BuiltinMission implements Listener { + + private final Map requiredBlocks = new LinkedHashMap<>(); + + private boolean onlyNatural; + private ProgressAction progressAction; + + private Predicate isBarrelCheck = block -> false; + + @Override + protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { + if (!section.contains("required-blocks")) + throw new MissionLoadException("You must have the \"required-blocks\" section in the config."); + + for (String key : section.getConfigurationSection("required-blocks").getKeys(false)) { + KeySet blocks = KeySet.createKeySet(); + section.getStringList("required-blocks." + key + ".types").forEach(requiredBlock -> + blocks.add(Key.ofMaterialAndData(requiredBlock.toUpperCase(Locale.ENGLISH)))); + int requiredAmount = section.getInt("required-blocks." + key + ".amount"); + this.requiredBlocks.put(new KeyRequirements(blocks), requiredAmount); + } + + this.onlyNatural = section.getBoolean("only-natural-blocks", false); + this.progressAction = section.getBoolean("blocks-placement", false) ? + ProgressAction.PLACE : ProgressAction.BREAK; + } + + @Override + protected void registerListeners() { + registerListener(this); + + Bukkit.getScheduler().runTaskLater(plugin, () -> { + if (Bukkit.getPluginManager().isPluginEnabled("WildStacker")) { + registerListener(new WildStackerListener()); + this.isBarrelCheck = block -> WildStackerAPI.getWildStacker().getSystemManager().isStackedBarrel(block); + } + + if (Bukkit.getPluginManager().isPluginEnabled("WildTools")) { + registerListener(new WildToolsListener()); + } + }, 1L); + } + + @Override + protected void clearModuleData(KeyDataTracker data) { + data.clear(); + } + + @Override + public double getProgress(SuperiorPlayer superiorPlayer) { + KeyDataTracker blocksCounter = get(superiorPlayer); + + if (blocksCounter == null) + return 0.0; + + int requiredBlocks = 0; + int interactions = 0; + + for (Map.Entry requiredBlock : this.requiredBlocks.entrySet()) { + requiredBlocks += requiredBlock.getValue(); + interactions += Math.min(blocksCounter.getCounts(requiredBlock.getKey()), requiredBlock.getValue()); + } + + return (double) interactions / requiredBlocks; + } + + @Override + public int getProgressValue(SuperiorPlayer superiorPlayer) { + KeyDataTracker blocksCounter = get(superiorPlayer); + + if (blocksCounter == null) + return 0; + + int interactions = 0; + + for (Map.Entry requiredBlock : this.requiredBlocks.entrySet()) + interactions += Math.min(blocksCounter.getCounts(requiredBlock.getKey()), requiredBlock.getValue()); + + return interactions; + } + + @Override + public void saveProgress(ConfigurationSection section) { + for (Map.Entry entry : entrySet()) { + String uuid = entry.getKey().getUniqueId().toString(); + for (Map.Entry blockCountEntry : entry.getValue().getCounts().entrySet()) { + section.set(uuid + ".counts." + blockCountEntry.getKey(), blockCountEntry.getValue().get()); + } + } + + BlocksTracker.INSTANCE.save(section); + } + + @Override + public void loadProgress(ConfigurationSection section) { + for (String uuid : section.getKeys(false)) { + KeyDataTracker blocksCounter = new KeyDataTracker(); + UUID playerUUID; + + try { + playerUUID = UUID.fromString(uuid); + } catch (Exception error) { + // tracked section probably, skipping. + continue; + } + + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); + + insertData(superiorPlayer, blocksCounter); + + if (section.contains(uuid + ".counts")) { + ConfigurationSection countsSection = section.getConfigurationSection(uuid + ".counts"); + if (countsSection != null) { + for (String key : countsSection.getKeys(false)) { + Key typeKey = getMissionBlockKey(Key.ofMaterialAndData(key)); + blocksCounter.load(typeKey, countsSection.getInt(key)); + } + } + } else { + ConfigurationSection countsSection = section.getConfigurationSection(uuid); + if (countsSection != null) { + for (String key : countsSection.getKeys(false)) { + Key typeKey = getMissionBlockKey(Key.ofMaterialAndData(key)); + blocksCounter.load(typeKey, section.getInt(uuid + "." + key)); + } + } + } + + loadTrackedBlocks(section.getConfigurationSection(uuid + ".tracked.placed"), section.getConfigurationSection(uuid + ".tracked.broken")); + } + + loadTrackedBlocks(section.getConfigurationSection("tracked.placed"), section.getConfigurationSection("tracked.broken")); + } + + private static void loadTrackedBlocks(@Nullable ConfigurationSection trackedPlacedSection, + @Nullable ConfigurationSection trackedBrokenSection) { + if (trackedPlacedSection != null) { + for (String worldName : trackedPlacedSection.getKeys(false)) { + ConfigurationSection worldSection = trackedPlacedSection.getConfigurationSection(worldName); + BlocksTracker.INSTANCE.loadTrackedBlocks(BlocksTracker.TrackingType.PLACED_BLOCKS, worldName, worldSection); + } + } + + if (trackedBrokenSection != null) { + for (String worldName : trackedBrokenSection.getKeys(false)) { + ConfigurationSection worldSection = trackedBrokenSection.getConfigurationSection(worldName); + BlocksTracker.INSTANCE.loadTrackedBlocks(BlocksTracker.TrackingType.BROKEN_BLOCKS, worldName, worldSection); + } + } + } + + @Override + public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { + KeyDataTracker blocksCounter = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); + + if (blocksCounter == null) + return; + + ItemMeta itemMeta = itemStack.getItemMeta(); + + if (itemMeta == null) + return; + + if (itemMeta.hasDisplayName()) + itemMeta.setDisplayName(Placeholders.parseKeyPlaceholders(this.requiredBlocks, blocksCounter, itemMeta.getDisplayName(), true)); + + if (itemMeta.hasLore()) { + List lore = new ArrayList<>(); + for (String line : Objects.requireNonNull(itemMeta.getLore())) + lore.add(Placeholders.parseKeyPlaceholders(this.requiredBlocks, blocksCounter, line, true)); + itemMeta.setLore(lore); + } + + itemStack.setItemMeta(itemMeta); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent e) { + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + + if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) + return; + + Key blockKey = getMissionBlockKey(Key.of(e.getBlock())); + if (blockKey == null) + return; + + if (this.progressAction == ProgressAction.PLACE) { + // We want to handle block place only if players gain progress by placing blocks. + handleBlockAction(e.getPlayer(), e.getBlock().getLocation(), blockKey, superiorPlayer, false); + } + + if (this.onlyNatural) { + // We want to track block broken & placed only if this mission only progresses for natural blocks + // We do that in a delayed tick so all other missions will check for their progress as well. + Bukkit.getScheduler().runTaskLater(this.plugin, () -> { + BlocksTracker.INSTANCE.untrackBlock(BlocksTracker.TrackingType.BROKEN_BLOCKS, e.getBlock()); + BlocksTracker.INSTANCE.trackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, e.getBlock()); + }, 1L); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockBreak(BlockBreakEvent e) { + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + + if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) + return; + + Key blockKey = getMissionBlockKey(Key.of(e.getBlock())); + if (blockKey == null) + return; + + if (this.progressAction == ProgressAction.BREAK) { + // We want to handle block break only if players gain progress by breaking blocks. + handleBlockAction(e.getPlayer(), e.getBlock().getLocation(), blockKey, superiorPlayer, true); + } + + if (this.onlyNatural) { + // We want to track block broken & placed only if this mission only progresses for natural blocks + // We do that in a delayed tick so all other missions will check for their progress as well. + Bukkit.getScheduler().runTaskLater(this.plugin, () -> { + BlocksTracker.INSTANCE.untrackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, e.getBlock()); + BlocksTracker.INSTANCE.trackBlock(BlocksTracker.TrackingType.BROKEN_BLOCKS, e.getBlock()); + }, 1L); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPistonRetract(BlockPistonRetractEvent e) { + if (!e.getBlocks().isEmpty()) + handleBlockPistonMove(new LinkedList<>(e.getBlocks()), e.getDirection()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPistonExtend(BlockPistonExtendEvent e) { + if (!e.getBlocks().isEmpty()) + handleBlockPistonMove(new LinkedList<>(e.getBlocks()), e.getDirection()); + } + + private class WildStackerListener implements Listener { + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBarrelUnstack(BarrelUnstackEvent e) { + if (onlyNatural || progressAction != ProgressAction.BREAK || !(e.getUnstackSource() instanceof Player)) + return; + + Player player = (Player) e.getUnstackSource(); + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); + + if (!BlocksMissions.this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, BlocksMissions.this)) + return; + + Key blockKey = getMissionBlockKey(Key.of(e.getBarrel().getType(), e.getBarrel().getData())); + if (blockKey == null) + return; + + handleBlockAction(player, e.getBarrel().getLocation(), blockKey, superiorPlayer, false); + } + + } + + private class WildToolsListener implements Listener { + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onCuboidUse(CuboidWandUseEvent e) { + if (progressAction != ProgressAction.BREAK) + return; + + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + + if (!BlocksMissions.this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, BlocksMissions.this)) + return; + + for (Location location : e.getBlocks()) { + Block block = location.getBlock(); + + Key blockKey = getMissionBlockKey(Key.of(block)); + if (blockKey == null) + return; + + handleBlockAction(e.getPlayer(), location, blockKey, superiorPlayer, true); + + if (onlyNatural) { + // We want to track block broken & placed only if this mission only progresses for natural blocks + // We do that in a delayed tick so all other missions will check for their progress as well. + Bukkit.getScheduler().runTaskLater(plugin, () -> { + BlocksTracker.INSTANCE.untrackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, block); + BlocksTracker.INSTANCE.trackBlock(BlocksTracker.TrackingType.BROKEN_BLOCKS, block); + }, 1L); + } + } + } + + } + + private void handleBlockPistonMove(LinkedList blockList, BlockFace direction) { + blockList.removeIf(block -> getMissionBlockKey(Key.of(block)) == null || + !BlocksTracker.INSTANCE.isTracked(BlocksTracker.TrackingType.PLACED_BLOCKS, block)); + + if (blockList.isEmpty()) + return; + + List movedBlocks = blockList.stream() + .map(block -> block.getRelative(direction)) + .collect(Collectors.toList()); + + List addedBlocks = new LinkedList<>(movedBlocks); + addedBlocks.removeAll(blockList); + + List removedBlocks = new LinkedList<>(blockList); + removedBlocks.removeAll(movedBlocks); + + removedBlocks.forEach(block -> BlocksTracker.INSTANCE.untrackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, block)); + addedBlocks.forEach(block -> BlocksTracker.INSTANCE.trackBlock(BlocksTracker.TrackingType.PLACED_BLOCKS, block)); + } + + /** + * Handle placing or breaking of a block and add count to mission progress. + * + * @param player The player. + * @param blockLocation The location of the block. + * @param blockKey The {@link Key} of the block in @param blockLocation. + * @param superiorPlayer The {@link SuperiorPlayer} wrapper of @param player. + */ + private void handleBlockAction(Player player, Location blockLocation, Key blockKey, + @Nullable SuperiorPlayer superiorPlayer, boolean checkForBarrels) { + int blockAmount = getBlockAmount(player, blockLocation); + + if (superiorPlayer == null) + superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); + + if (checkForBarrels && this.isBarrelCheck.test(blockLocation)) + return; + + // In case we progress for breaking blocks, we want to ensure the block is not tracked in case + // the mission only progresses for natural blocks. + if (this.onlyNatural && this.progressAction == ProgressAction.BREAK && + BlocksTracker.INSTANCE.isTracked(BlocksTracker.TrackingType.PLACED_BLOCKS, blockLocation)) { + return; + } + + handleBlockTrack(superiorPlayer, blockKey, blockAmount); + } + + private void handleBlockTrack(SuperiorPlayer superiorPlayer, Key blockKey, int amount) { + KeyDataTracker blocksCounter = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); + + blocksCounter.track(blockKey, amount); + + Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> superiorPlayer.runIfOnline(_player -> { + if (canComplete(superiorPlayer)) + this.plugin.getMissions().rewardMission(this, superiorPlayer, true); + }), 2L); + } + + private int getBlockAmount(Player player, Location blockLocation) { + int blockAmount = this.plugin.getStackedBlocks().getStackedBlockAmount(blockLocation); + + // When sneaking, you'll break 64 from the stack. Otherwise, 1. + int amount = !player.isSneaking() ? 1 : 64; + + // Fix amount so it won't be more than the stack's amount + amount = Math.min(amount, blockAmount); + + return amount; + } + + @Nullable + private Key getMissionBlockKey(Key blockKey) { + for (KeyRequirements requirementsList : requiredBlocks.keySet()) { + if (requirementsList.contains(blockKey)) + return requirementsList.getKey(blockKey); + } + + return null; + } + + private enum ProgressAction { + + BREAK, + PLACE + + } + +} diff --git a/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/BlocksTracker.java b/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/BlocksTracker.java new file mode 100644 index 0000000000..7f244e1c6a --- /dev/null +++ b/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/BlocksTracker.java @@ -0,0 +1,154 @@ +package com.bgsoftware.superiorskyblock.missions.blocks; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.configuration.ConfigurationSection; + +import java.util.EnumMap; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +public class BlocksTracker { + + public static final BlocksTracker INSTANCE = new BlocksTracker(); + + private final EnumMap> trackingComponentMap = new EnumMap<>(TrackingType.class); + private EnumMap> rawData = null; + + private boolean saved = false; + + private BlocksTracker() { + + } + + public void trackBlock(TrackingType trackingType, Block block) { + getComponent(trackingType, block.getWorld()).add(block.getX(), block.getY(), block.getZ()); + } + + public boolean untrackBlock(TrackingType trackingType, Block block) { + return ifComponentExists(trackingType, block.getWorld(), false, + component -> component.remove(block.getX(), block.getY(), block.getZ())); + } + + public boolean isTracked(TrackingType trackingType, Block block) { + return ifComponentExists(trackingType, block.getWorld(), false, + component -> component.contains(block.getX(), block.getY(), block.getZ())); + } + + public boolean isTracked(TrackingType trackingType, Location blockLocation) { + return ifComponentExists(trackingType, blockLocation.getWorld(), false, component -> + component.contains(blockLocation.getBlockX(), blockLocation.getBlockY(), blockLocation.getBlockZ())); + } + + public void loadTrackedBlocks(TrackingType trackingType, String worldName, ConfigurationSection section) { + if (this.rawData == null) + this.rawData = new EnumMap<>(TrackingType.class); + + this.rawData.computeIfAbsent(trackingType, t -> new HashMap<>()).put(worldName, new TrackedBlocksData(section)); + } + + public void save(ConfigurationSection section) { + if (!this.saved) { + saveInternal(section, TrackingType.PLACED_BLOCKS); + saveInternal(section, TrackingType.BROKEN_BLOCKS); + this.saved = true; + } + } + + private void saveInternal(ConfigurationSection section, TrackingType trackingType) { + Map trackingComponentMap = this.trackingComponentMap.get(trackingType); + + if (trackingComponentMap == null) + return; + + trackingComponentMap.forEach((worldName, component) -> { + component.getBlocks().forEach((chunkKey, blocksBitSet) -> { + List blocks = new LinkedList<>(); + blocksBitSet.forEach(blocks::add); + if (!blocks.isEmpty()) + section.set("tracked." + trackingType.path + "." + worldName + "." + chunkKey, blocks); + }); + }); + + if (this.rawData != null) { + Map rawData = this.rawData.get(trackingType); + if (rawData != null) { + rawData.forEach((worldName, trackedBlocksData) -> { + trackedBlocksData.getBlocks().forEach((chunkKey, blocksBitSet) -> { + List blocks = new LinkedList<>(); + blocksBitSet.forEach(blocks::add); + if (!blocks.isEmpty()) + section.set("tracked." + trackingType.path + "." + worldName + "." + chunkKey, blocks); + }); + }); + } + } + } + + private BlocksTrackingComponent getComponent(TrackingType trackingType, World world) { + BlocksTrackingComponent trackingComponent = loadRawData(trackingType, world); + return trackingComponent != null ? trackingComponent : + trackingComponentMap.computeIfAbsent(trackingType, t -> new HashMap<>()) + .computeIfAbsent(world.getName(), uuid -> new BlocksTrackingComponent(world)); + } + + private R ifComponentExists(TrackingType trackingType, World world, R def, Function function) { + String worldName = world.getName(); + + BlocksTrackingComponent trackingComponent = loadRawData(trackingType, world); + if (trackingComponent != null) + return function.apply(trackingComponent); + + Map trackingTypeComponents = trackingComponentMap.get(trackingType); + if (trackingTypeComponents != null) { + trackingComponent = trackingTypeComponents.get(worldName); + if (trackingComponent != null) + return function.apply(trackingComponent); + } + + return def; + } + + private BlocksTrackingComponent loadRawData(TrackingType trackingType, World world) { + String worldName = world.getName(); + + if (this.rawData != null) { + Map rawData = this.rawData.get(trackingType); + if (rawData != null) { + TrackedBlocksData trackedBlocksData = rawData.remove(worldName); + if (trackedBlocksData != null) { + BlocksTrackingComponent trackingComponent = new BlocksTrackingComponent(world); + trackingComponent.loadBlocks(trackedBlocksData); + this.trackingComponentMap.computeIfAbsent(trackingType, i -> new HashMap<>()) + .put(worldName, trackingComponent); + if (rawData.isEmpty()) { + this.rawData.remove(trackingType); + if(this.rawData.isEmpty()) + this.rawData = null; + } + return trackingComponent; + } + } + } + + return null; + } + + public enum TrackingType { + + PLACED_BLOCKS("placed"), + BROKEN_BLOCKS("broken"); + + private final String path; + + TrackingType(String path) { + this.path = path; + } + + } + +} diff --git a/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/BlocksTrackingComponent.java b/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/BlocksTrackingComponent.java new file mode 100644 index 0000000000..4f64af1659 --- /dev/null +++ b/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/BlocksTrackingComponent.java @@ -0,0 +1,73 @@ +package com.bgsoftware.superiorskyblock.missions.blocks; + +import com.bgsoftware.common.reflection.ClassInfo; +import com.bgsoftware.common.reflection.ReflectMethod; +import org.bukkit.World; + +import java.util.Map; + +public class BlocksTrackingComponent { + + private static final ReflectMethod WORLD_GET_MIN_HEIGHT = new ReflectMethod<>( + new ClassInfo("CraftWorld", ClassInfo.PackageType.CRAFTBUKKIT), + "getMinHeight", + new ClassInfo[0]); + + // Key represents chunk's coords + // Value represents all blocks broken in that chunk + private TrackedBlocksData trackedBlocksData = new TrackedBlocksData(); + + private final int worldMinHeight; + + public BlocksTrackingComponent(World world) { + this(!WORLD_GET_MIN_HEIGHT.isValid() ? 0 : WORLD_GET_MIN_HEIGHT.invoke(world)); + } + + public BlocksTrackingComponent(int worldMinHeight) { + this.worldMinHeight = worldMinHeight; + } + + public int getWorldMinHeight() { + return worldMinHeight; + } + + public void add(int blockX, int blockY, int blockZ) { + long chunkKey = serializeChunk(blockX >> 4, blockZ >> 4); + this.trackedBlocksData.track(chunkKey, serializeLocation(blockX, blockY, blockZ)); + } + + public boolean remove(int blockX, int blockY, int blockZ) { + long chunkKey = serializeChunk(blockX >> 4, blockZ >> 4); + return this.trackedBlocksData.untrack(chunkKey, () -> serializeLocation(blockX, blockY, blockZ)); + } + + public boolean contains(int blockX, int blockY, int blockZ) { + long chunkKey = serializeChunk(blockX >> 4, blockZ >> 4); + return this.trackedBlocksData.contains(chunkKey, () -> serializeLocation(blockX, blockY, blockZ)); + } + + public void loadBlocks(TrackedBlocksData trackedBlocksData) { + this.trackedBlocksData = trackedBlocksData; + } + + public Map getBlocks() { + return this.trackedBlocksData.getBlocks(); + } + + private int serializeLocation(int blockX, int blockY, int blockZ) { + int chunkMinX = blockX >> 4 << 4; + int chunkMinZ = blockZ >> 4 << 4; + + + byte relativeX = (byte) (blockX - chunkMinX); + short relativeY = (short) (blockY - this.worldMinHeight); + byte relativeZ = (byte) (blockZ - chunkMinZ); + + return (relativeY << 8) | (relativeX << 4) | relativeZ; + } + + private static long serializeChunk(int chunkX, int chunkZ) { + return (long) chunkX << 32 | chunkZ; + } + +} diff --git a/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/ChunkBitSet.java b/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/ChunkBitSet.java new file mode 100644 index 0000000000..581a646fec --- /dev/null +++ b/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/ChunkBitSet.java @@ -0,0 +1,83 @@ +package com.bgsoftware.superiorskyblock.missions.blocks; + +import java.util.Arrays; +import java.util.BitSet; +import java.util.function.IntConsumer; + +public class ChunkBitSet { + + private static final BitSet[] EMPTY_BIT_SET_ARRAY = new BitSet[0]; + + private BitSet[] bitSets = EMPTY_BIT_SET_ARRAY; + + public ChunkBitSet() { + + } + + public void set(int index) { + BitSet bitSet = getBitSetForBlock(index, true); + if (bitSet == null) + throw new IllegalStateException(); + int blockIdx = index & 0xFFF; + bitSet.set(blockIdx); + } + + public boolean clear(int index) { + BitSet bitSet = getBitSetForBlock(index, false); + if (bitSet == null) + return false; + int blockIdx = index & 0xFFF; + boolean old = bitSet.get(blockIdx); + bitSet.clear(blockIdx); + return old; + } + + public boolean get(int index) { + BitSet bitSet = getBitSetForBlock(index, false); + if (bitSet == null) + return false; + int blockIdx = index & 0xFFF; + return bitSet.get(blockIdx); + } + + public void forEach(IntConsumer consumer) { + for (int i = 0; i < this.bitSets.length; ++i) { + BitSet bitSet = this.bitSets[i]; + if (bitSet != null) { + for (int j = bitSet.nextSetBit(0); j != -1; j = bitSet.nextSetBit(j + 1)) { + consumer.accept(((i << 4) << 8) | j); + } + } + } + } + + private void ensureCapacity(int capacity) { + if (bitSets.length >= capacity) + return; + + bitSets = Arrays.copyOf(bitSets, capacity); + } + + private BitSet getBitSetForBlock(int block, boolean createNew) { + int sectionIdx = (block >> 8) >> 4; + + if (bitSets.length <= sectionIdx) { + if (!createNew) + return null; + + ensureCapacity(sectionIdx + 1); + } + + BitSet bitSet = bitSets[sectionIdx]; + + if (bitSet == null) { + if (!createNew) + return null; + + bitSet = bitSets[sectionIdx] = new BitSet(); + } + + return bitSet; + } + +} diff --git a/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/TrackedBlocksData.java b/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/TrackedBlocksData.java new file mode 100644 index 0000000000..d2f20958ee --- /dev/null +++ b/Missions/BlocksMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/blocks/TrackedBlocksData.java @@ -0,0 +1,53 @@ +package com.bgsoftware.superiorskyblock.missions.blocks; + +import org.bukkit.configuration.ConfigurationSection; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.IntSupplier; + +public class TrackedBlocksData { + + private final Map TRACKED_BLOCKS = new HashMap<>(); + private final Map TRACKED_BLOCKS_VIEW = Collections.unmodifiableMap(TRACKED_BLOCKS); + + public TrackedBlocksData(ConfigurationSection section) { + for (String chunkKey : section.getKeys(false)) { + List trackedBlocks = section.getIntegerList(chunkKey); + ChunkBitSet bitSet = new ChunkBitSet(); + trackedBlocks.forEach(bitSet::set); + try { + TRACKED_BLOCKS.put(Long.parseLong(chunkKey), bitSet); + } catch (NumberFormatException ignored) { + } + } + } + + public TrackedBlocksData() { + + } + + public void track(long chunkKey, int block) { + TRACKED_BLOCKS.computeIfAbsent(chunkKey, key -> new ChunkBitSet()).set(block); + } + + public boolean untrack(long chunkKey, IntSupplier block) { + return Optional.ofNullable(TRACKED_BLOCKS.get(chunkKey)) + .map(bitSet -> bitSet.clear(block.getAsInt())) + .orElse(false); + } + + public boolean contains(long chunkKey, IntSupplier block) { + return Optional.ofNullable(TRACKED_BLOCKS.get(chunkKey)) + .map(bitSet -> bitSet.get(block.getAsInt())) + .orElse(false); + } + + public Map getBlocks() { + return TRACKED_BLOCKS_VIEW; + } + +} diff --git a/Missions/BrewingMissions/build.gradle b/Missions/BrewingMissions/build.gradle new file mode 100644 index 0000000000..be7a63649f --- /dev/null +++ b/Missions/BrewingMissions/build.gradle @@ -0,0 +1,9 @@ +group 'Missions:BrewingMissions' + +dependencies { + compileOnly "org.spigotmc:v1_16_R3:latest" +} + +shadowJar { + relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.brewing' +} \ No newline at end of file diff --git a/Missions/BrewingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/BrewingMissions.java b/Missions/BrewingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/BrewingMissions.java new file mode 100644 index 0000000000..aac2f30051 --- /dev/null +++ b/Missions/BrewingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/BrewingMissions.java @@ -0,0 +1,411 @@ +package com.bgsoftware.superiorskyblock.missions; + +import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; +import com.bgsoftware.superiorskyblock.missions.common.Placeholders; +import com.bgsoftware.superiorskyblock.missions.common.requirements.CustomRequirements; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.BrewingStand; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.inventory.BrewEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.BrewerInventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.Potion; +import org.bukkit.potion.PotionType; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.function.Predicate; + +public final class BrewingMissions extends BuiltinMission implements Listener { + + private static final boolean isUsing18 = Bukkit.getServer().getClass().getPackage().getName().contains("1_8"); + + private final Map, Integer> requiredPotions = new LinkedHashMap<>(); + private final Map trackedBrewItems = new HashMap<>(); + + @Override + protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { + ConfigurationSection requiredPotionsSection = section.getConfigurationSection("required-potions"); + + if (requiredPotionsSection == null) + throw new MissionLoadException("You must have the \"required-potions\" section in the config."); + + for (String key : requiredPotionsSection.getKeys(false)) { + CustomRequirements requiredPotions = new CustomRequirements<>(); + + ConfigurationSection potionsSection = section.getConfigurationSection("required-potions." + key + ".potions"); + + for (String potionSectionName : potionsSection.getKeys(false)) { + ConfigurationSection potionSection = potionsSection.getConfigurationSection(potionSectionName); + + if (potionSection == null) { + plugin.getLogger().info(ChatColor.RED + "Potion section " + potionSectionName + " is invalid, skipping..."); + continue; + } + + PotionType potionType; + + try { + potionType = PotionType.valueOf(potionSection.getString("type")); + } catch (Exception ex) { + plugin.getLogger().info(ChatColor.RED + "Potion type in section " + + potionsSection.getCurrentPath() + "." + potionSectionName + " is invalid, skipping..."); + continue; + } + + boolean upgraded = potionSection.getBoolean("upgraded", false); + boolean extended = potionSection.getBoolean("extended", false); + boolean splash = potionSection.getBoolean("splash", false); + + requiredPotions.add(new PotionData(potionType, upgraded, extended, splash)); + } + + if (!requiredPotions.isEmpty()) { + int requiredAmount = section.getInt("required-potions." + key + ".amount"); + this.requiredPotions.put(requiredPotions, requiredAmount); + } + } + + if (requiredPotions.isEmpty()) { + throw new MissionLoadException("There are no valid required potions for this mission."); + } + } + + @Override + protected void registerListeners() { + registerListener(this); + } + + @Override + protected void clearModuleData(BrewingTracker data) { + data.brewingTracker.clear(); + } + + @Override + public double getProgress(SuperiorPlayer superiorPlayer) { + BrewingTracker brewingTracker = get(superiorPlayer); + + if (brewingTracker == null) + return 0.0; + + int requiredPotions = 0; + int kills = 0; + + for (Map.Entry, Integer> requiredPotion : this.requiredPotions.entrySet()) { + requiredPotions += requiredPotion.getValue(); + kills += Math.min(brewingTracker.getBrews(requiredPotion.getKey()), requiredPotion.getValue()); + } + + return (double) kills / requiredPotions; + } + + @Override + public int getProgressValue(SuperiorPlayer superiorPlayer) { + BrewingTracker brewingTracker = get(superiorPlayer); + + if (brewingTracker == null) + return 0; + + int kills = 0; + + for (Map.Entry, Integer> requiredEntity : this.requiredPotions.entrySet()) + kills += Math.min(brewingTracker.getBrews(requiredEntity.getKey()), requiredEntity.getValue()); + + return kills; + } + + @Override + public void saveProgress(ConfigurationSection section) { + for (Map.Entry entry : entrySet()) { + String uuid = entry.getKey().getUniqueId().toString(); + for (Map.Entry brokenEntry : entry.getValue().brewingTracker.entrySet()) { + section.set(uuid + "." + brokenEntry.getKey(), brokenEntry.getValue()); + } + } + } + + @Override + public void loadProgress(ConfigurationSection section) { + for (String uuid : section.getKeys(false)) { + BrewingTracker brewingTracker = new BrewingTracker(); + UUID playerUUID = UUID.fromString(uuid); + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); + + insertData(superiorPlayer, brewingTracker); + + for (String key : section.getConfigurationSection(uuid).getKeys(false)) { + brewingTracker.brewingTracker.put(PotionData.fromString(key), section.getInt(uuid + "." + key)); + } + } + } + + @Override + public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { + BrewingTracker brewingTracker = getOrCreate(superiorPlayer, s -> new BrewingTracker()); + + if (brewingTracker == null) + return; + + ItemMeta itemMeta = itemStack.getItemMeta(); + + if (itemMeta == null) + return; + + Placeholders.PlaceholdersFunctions> placeholdersFunctions = new Placeholders.PlaceholdersFunctions>() { + @Override + public CustomRequirements getRequirementFromKey(String key) { + PotionData potionData = PotionData.fromString(key); + + for (CustomRequirements requirements : requiredPotions.keySet()) { + if (requirements.contains(potionData)) + return requirements; + } + + return null; + } + + @Override + public Optional lookupRequirement(CustomRequirements requirement) { + return Optional.ofNullable(requiredPotions.get(requirement)); + } + + @Override + public int getCountForRequirement(CustomRequirements requirement) { + return brewingTracker.getBrews(requirement); + } + }; + + if (itemMeta.hasDisplayName()) + itemMeta.setDisplayName(Placeholders.parsePlaceholders(itemMeta.getDisplayName(), placeholdersFunctions)); + + if (itemMeta.hasLore()) { + List lore = new LinkedList<>(); + for (String line : Objects.requireNonNull(itemMeta.getLore())) + lore.add(Placeholders.parsePlaceholders(line, placeholdersFunctions)); + itemMeta.setLore(lore); + } + + itemStack.setItemMeta(itemMeta); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBrew(BrewEvent e) { + ItemStack[] originalResultItems = new ItemStack[3]; + for (int i = 0; i < 3; ++i) { + ItemStack resultItem = e.getContents().getItem(i); + if (resultItem != null) { + originalResultItems[i] = resultItem.clone(); + } + } + + Bukkit.getScheduler().runTaskLater(plugin, () -> { + for (int i = 0; i < 3; ++i) { + ItemStack resultItem = e.getContents().getItem(i); + if (resultItem != null && !resultItem.isSimilar(originalResultItems[i]) && isMissionBrewing(resultItem)) { + trackedBrewItems.computeIfAbsent(e.getBlock().getLocation(), block -> new boolean[3])[i] = true; + } + } + }, 1L); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBrew(InventoryClickEvent e) { + if (!(e.getClickedInventory() instanceof BrewerInventory) || e.getRawSlot() > 2) + return; + + BrewerInventory inventory = (BrewerInventory) e.getClickedInventory(); + + handleBrewing((Player) e.getWhoClicked(), inventory, slot -> slot == e.getRawSlot()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockBreak(BlockBreakEvent e) { + BlockState blockState = e.getBlock().getState(); + + if (!(blockState instanceof BrewingStand)) + return; + + BrewingStand brewingStand = (BrewingStand) blockState; + + handleBrewing(e.getPlayer(), brewingStand.getInventory(), slot -> true); + } + + private void handleBrewing(Player player, BrewerInventory inventory, Predicate checkSlot) { + Block block = inventory.getHolder().getBlock(); + + boolean[] brewItems = this.trackedBrewItems.get(block.getLocation()); + + if (brewItems == null) { + return; + } + + try { + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(player); + + if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) + return; + + BrewingTracker brewingTracker = getOrCreate(superiorPlayer, s -> new BrewingTracker()); + + if (brewingTracker == null) + return; + + for (int i = 0; i < 3; ++i) { + if (checkSlot.test(i) && brewItems[i]) { + brewItems[i] = false; + + ItemStack brewItem = inventory.getItem(i); + + brewingTracker.track(brewItem, brewItem.getAmount()); + } + } + + this.plugin.getServer().getScheduler().runTaskLaterAsynchronously(this.plugin, () -> superiorPlayer.runIfOnline(unused -> { + if (canComplete(superiorPlayer)) + this.plugin.getMissions().rewardMission(this, superiorPlayer, true); + }), 2L); + } finally { + if (!brewItems[0] && !brewItems[1] && !brewItems[2]) + this.trackedBrewItems.remove(block.getLocation()); + } + } + + private boolean isMissionBrewing(ItemStack itemStack) { + PotionData potionData = PotionData.fromItemStack(itemStack); + + if (potionData == null) + return false; + + for (Collection requiredPotion : requiredPotions.keySet()) { + if (requiredPotion.contains(potionData)) + return true; + } + + return false; + } + + + public static class BrewingTracker { + + private final Map brewingTracker = new HashMap<>(); + + void track(ItemStack brewing, int amount) { + PotionData potionData = PotionData.fromItemStack(brewing); + int newAmount = amount + brewingTracker.getOrDefault(potionData, 0); + brewingTracker.put(potionData, newAmount); + } + + int getBrews(Collection potions) { + int amount = 0; + + for (Map.Entry potionData : brewingTracker.entrySet()) { + if (potions.contains(potionData.getKey())) + amount += potionData.getValue(); + } + + return amount; + } + + } + + private static class PotionData { + + private final PotionType potionType; + private final boolean upgraded; + private final boolean extended; + private final boolean splash; + + public PotionData(PotionType potionType, boolean upgraded, boolean extended, boolean splash) { + this.potionType = potionType; + this.upgraded = upgraded; + this.extended = extended; + this.splash = splash; + } + + @Nullable + public static PotionData fromItemStack(ItemStack itemStack) { + return isUsing18 ? fromItemStack18(itemStack) : fromItemStack19(itemStack); + } + + public static PotionData fromString(String line) { + String[] sections = line.split(";"); + + PotionType potionType; + + try { + potionType = PotionType.valueOf(sections[0]); + } catch (IllegalArgumentException ex) { + throw new IllegalArgumentException("Potion type '" + sections[0] + "' is invalid."); + } + + boolean upgraded = sections.length >= 2 && Boolean.parseBoolean(sections[1]); + boolean extended = sections.length >= 3 && Boolean.parseBoolean(sections[2]); + boolean splash = sections.length >= 4 && Boolean.parseBoolean(sections[3]); + + return new PotionData(potionType, upgraded, extended, splash); + } + + private static PotionData fromItemStack19(ItemStack itemStack) { + ItemMeta itemMeta = itemStack.getItemMeta(); + + if (!(itemMeta instanceof PotionMeta)) { + return null; + } + + PotionMeta potionMeta = (PotionMeta) itemMeta; + org.bukkit.potion.PotionData potionData = potionMeta.getBasePotionData(); + + return new PotionData(potionData.getType(), potionData.isUpgraded(), potionData.isExtended(), + itemStack.getType() == Material.SPLASH_POTION); + } + + @SuppressWarnings("deprecation") + private static PotionData fromItemStack18(ItemStack itemStack) { + Potion potion = Potion.fromItemStack(itemStack); + return new PotionData(potion.getType(), potion.getLevel() > 1, potion.hasExtendedDuration(), potion.isSplash()); + } + + @Override + public String toString() { + return potionType.name() + ";" + upgraded + ";" + extended + ";" + splash; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PotionData that = (PotionData) o; + return upgraded == that.upgraded && extended == that.extended && splash == that.splash && potionType == that.potionType; + } + + @Override + public int hashCode() { + return Objects.hash(potionType, upgraded, extended, splash); + } + + } + +} diff --git a/Missions/CraftingMissions/build.gradle b/Missions/CraftingMissions/build.gradle new file mode 100644 index 0000000000..ece771d3c1 --- /dev/null +++ b/Missions/CraftingMissions/build.gradle @@ -0,0 +1,9 @@ +group 'Missions:EnchantingMissions' + +dependencies { + compileOnly "org.spigotmc:v1_8_R3-Taco:latest" +} + +shadowJar { + relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.crafting' +} \ No newline at end of file diff --git a/Missions/CraftingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/CraftingMissions.java b/Missions/CraftingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/CraftingMissions.java new file mode 100644 index 0000000000..36429b4290 --- /dev/null +++ b/Missions/CraftingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/CraftingMissions.java @@ -0,0 +1,254 @@ +package com.bgsoftware.superiorskyblock.missions; + +import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; +import com.bgsoftware.superiorskyblock.missions.common.Placeholders; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +public final class CraftingMissions extends BuiltinMission implements Listener { + + private final Map itemsToCraft = new LinkedHashMap<>(); + + @Override + protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { + ConfigurationSection craftingsSection = section.getConfigurationSection("craftings"); + + if (craftingsSection == null) + throw new MissionLoadException("You must have the \"craftings\" section in the config."); + + for (String key : craftingsSection.getKeys(false)) { + String type = section.getString("craftings." + key + ".type"); + short data = (short) section.getInt("craftings." + key + ".data", 0); + int amount = section.getInt("craftings." + key + ".amount", 1); + Material material; + + try { + material = Material.valueOf(type); + } catch (IllegalArgumentException ex) { + throw new MissionLoadException("Invalid crafting result " + type + "."); + } + + this.itemsToCraft.put(new ItemStack(material, 1, data), amount); + } + } + + @Override + protected void registerListeners() { + registerListener(this); + } + + @Override + protected void clearModuleData(CraftingsTracker data) { + data.craftedItems.clear(); + } + + @Override + public double getProgress(SuperiorPlayer superiorPlayer) { + CraftingsTracker craftingsTracker = get(superiorPlayer); + + if (craftingsTracker == null) + return 0.0; + + int requiredItems = 0; + int interactions = 0; + + for (Map.Entry entry : this.itemsToCraft.entrySet()) { + requiredItems += entry.getValue(); + interactions += Math.min(craftingsTracker.getCrafts(entry.getKey()), entry.getValue()); + } + + return (double) interactions / requiredItems; + } + + @Override + public int getProgressValue(SuperiorPlayer superiorPlayer) { + CraftingsTracker craftingsTracker = get(superiorPlayer); + + if (craftingsTracker == null) + return 0; + + int interactions = 0; + + for (Map.Entry entry : this.itemsToCraft.entrySet()) + interactions += Math.min(craftingsTracker.getCrafts(entry.getKey()), entry.getValue()); + + return interactions; + } + + @Override + public void saveProgress(ConfigurationSection section) { + for (Map.Entry entry : entrySet()) { + String uuid = entry.getKey().getUniqueId().toString(); + int index = 0; + for (Map.Entry craftedEntry : entry.getValue().craftedItems.entrySet()) { + section.set(uuid + "." + index + ".item", craftedEntry.getKey()); + section.set(uuid + "." + index + ".amount", craftedEntry.getValue()); + index++; + } + } + } + + @Override + public void loadProgress(ConfigurationSection section) { + for (String uuid : section.getKeys(false)) { + if (uuid.equals("players")) + continue; + + CraftingsTracker craftingsTracker = new CraftingsTracker(); + UUID playerUUID = UUID.fromString(uuid); + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); + + insertData(superiorPlayer, craftingsTracker); + + for (String key : section.getConfigurationSection(uuid).getKeys(false)) { + ItemStack itemStack = section.getItemStack(uuid + "." + key + ".item"); + int amount = section.getInt(uuid + "." + key + ".amount"); + craftingsTracker.craftedItems.put(itemStack, amount); + } + } + } + + @Override + public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { + CraftingsTracker craftingsTracker = getOrCreate(superiorPlayer, s -> new CraftingsTracker()); + + if (craftingsTracker == null) + return; + + ItemMeta itemMeta = itemStack.getItemMeta(); + + if (itemMeta == null) + return; + + Placeholders.PlaceholdersFunctions placeholdersFunctions = new Placeholders.PlaceholdersFunctions() { + @Override + public ItemStack getRequirementFromKey(String key) { + return new ItemStack(Material.valueOf(key)); + } + + @Override + public Optional lookupRequirement(ItemStack requirement) { + return itemsToCraft.entrySet().stream() + .filter(e -> e.getKey().isSimilar(requirement)) + .findFirst() + .map(Map.Entry::getValue); + } + + @Override + public int getCountForRequirement(ItemStack requirement) { + return craftingsTracker.getCrafts(requirement); + } + }; + + if (itemMeta.hasDisplayName()) + itemMeta.setDisplayName(Placeholders.parsePlaceholders(itemMeta.getDisplayName(), placeholdersFunctions)); + + if (itemMeta.hasLore()) { + List lore = new ArrayList<>(); + for (String line : Objects.requireNonNull(itemMeta.getLore())) + lore.add(Placeholders.parsePlaceholders(line, placeholdersFunctions)); + itemMeta.setLore(lore); + } + + itemStack.setItemMeta(itemMeta); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryClick(InventoryClickEvent e) { + if (e.getClickedInventory() == null || (e.getClickedInventory().getType() != InventoryType.WORKBENCH && + e.getClickedInventory().getType() != InventoryType.CRAFTING && e.getClickedInventory().getType() != InventoryType.FURNACE)) + return; + + int requiredSlot = e.getClickedInventory().getType() == InventoryType.FURNACE ? 2 : 0; + + ItemStack resultItem = e.getCurrentItem().clone(); + resultItem.setAmount(1); + + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer((Player) e.getWhoClicked()); + + if (e.getRawSlot() == requiredSlot && itemsToCraft.containsKey(resultItem) && + this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) { + int amountOfResult = countItems(e.getWhoClicked(), resultItem); + Bukkit.getScheduler().runTaskLater(this.plugin, () -> { + int afterTickAmountOfResult = countItems(e.getWhoClicked(), resultItem); + resultItem.setAmount(afterTickAmountOfResult - amountOfResult); + trackItem(superiorPlayer, resultItem); + }, 1L); + } + + } + + private void trackItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { + CraftingsTracker blocksTracker = getOrCreate(superiorPlayer, s -> new CraftingsTracker()); + + if (blocksTracker == null) + return; + + blocksTracker.trackItem(itemStack); + + Bukkit.getScheduler().runTaskLaterAsynchronously(this.plugin, () -> superiorPlayer.runIfOnline(player -> { + if (canComplete(superiorPlayer)) + this.plugin.getMissions().rewardMission(this, superiorPlayer, true); + }), 2L); + } + + private static int countItems(HumanEntity humanEntity, ItemStack itemStack) { + int amount = 0; + + if (itemStack == null) + return amount; + + PlayerInventory playerInventory = humanEntity.getInventory(); + + for (ItemStack invItem : playerInventory.getContents()) { + if (invItem != null && itemStack.isSimilar(invItem)) + amount += invItem.getAmount(); + } + + if (humanEntity.getItemOnCursor() != null && itemStack.isSimilar(humanEntity.getItemOnCursor())) + amount += humanEntity.getItemOnCursor().getAmount(); + + return amount; + } + + public static class CraftingsTracker { + + private final Map craftedItems = new HashMap<>(); + + void trackItem(ItemStack itemStack) { + ItemStack keyItem = itemStack.clone(); + keyItem.setAmount(1); + craftedItems.put(keyItem, craftedItems.getOrDefault(keyItem, 0) + itemStack.getAmount()); + } + + int getCrafts(ItemStack itemStack) { + ItemStack keyItem = itemStack.clone(); + keyItem.setAmount(1); + return craftedItems.getOrDefault(keyItem, 0); + } + + } + +} diff --git a/Missions/EnchantingMissions/build.gradle b/Missions/EnchantingMissions/build.gradle new file mode 100644 index 0000000000..e743fd9b70 --- /dev/null +++ b/Missions/EnchantingMissions/build.gradle @@ -0,0 +1,9 @@ +group 'Missions:EnchantingMissions' + +dependencies { + compileOnly "org.spigotmc:v1_9_R1:latest" +} + +shadowJar { + relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.enchanting' +} \ No newline at end of file diff --git a/Missions/EnchantingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/EnchantingMissions.java b/Missions/EnchantingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/EnchantingMissions.java new file mode 100644 index 0000000000..91c6558d35 --- /dev/null +++ b/Missions/EnchantingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/EnchantingMissions.java @@ -0,0 +1,358 @@ +package com.bgsoftware.superiorskyblock.missions; + +import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; +import com.bgsoftware.superiorskyblock.missions.common.Placeholders; +import com.bgsoftware.superiorskyblock.missions.common.requirements.Requirements; +import com.bgsoftware.superiorskyblock.missions.common.tracker.RawDataTracker; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.enchantment.EnchantItemEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.EnchantmentStorageMeta; +import org.bukkit.inventory.meta.ItemMeta; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class EnchantingMissions extends BuiltinMission implements Listener { + + private static final Pattern ENCHANTED_PATTERN = Pattern.compile("\\{enchanted_(.+?)}"); + + private final Map requiredEnchantments = new LinkedHashMap<>(); + + private String enchantedPlaceholder, notEnchantedPlaceholder; + + @Override + protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { + ConfigurationSection requiredEnchantsSection = section.getConfigurationSection("required-enchants"); + + if (requiredEnchantsSection == null) + throw new MissionLoadException("You must have the \"required-enchants\" section in the config."); + + for (String key : requiredEnchantsSection.getKeys(false)) { + List itemTypes = section.getStringList("required-enchants." + key + ".types"); + Map enchantments = new HashMap<>(); + + ConfigurationSection enchantsSection = section.getConfigurationSection("required-enchants." + key + ".enchants"); + + if (enchantsSection == null) + throw new MissionLoadException("You must have the \"required-enchants." + key + ".enchants\" section in the config."); + + for (String enchantment : enchantsSection.getKeys(false)) { + Enchantment _enchantment = Enchantment.getByName(enchantment.toUpperCase(Locale.ENGLISH)); + + if (_enchantment == null) + throw new MissionLoadException("Enchantment " + enchantment + " is not valid."); + + enchantments.put(_enchantment, section.getInt("required-enchants." + key + ".enchants." + enchantment)); + } + + if (!enchantments.isEmpty()) { + this.requiredEnchantments.put(new Requirements(itemTypes), new RequiredEnchantment(key, enchantments, + section.getInt("required-enchants." + key + ".amount", 1))); + } + } + + this.enchantedPlaceholder = section.getString("enchanted-placeholder", "Yes"); + this.notEnchantedPlaceholder = section.getString("not-enchanted-placeholder", "No"); + } + + @Override + protected void registerListeners() { + registerListener(this); + + try { + Class.forName("org.bukkit.event.inventory.PrepareAnvilEvent"); + registerListener(new PrepareAnvilListener()); + } catch (Exception ignored) { + } + } + + @Override + protected void clearModuleData(RawDataTracker data) { + data.clear(); + } + + @Override + public double getProgress(SuperiorPlayer superiorPlayer) { + RawDataTracker enchantsTracker = get(superiorPlayer); + + if (enchantsTracker == null) + return 0.0; + + int requiredItems = 0; + int enchants = 0; + + for (RequiredEnchantment requiredEnchantment : this.requiredEnchantments.values()) { + requiredItems += requiredEnchantment.amount; + enchants += Math.min(enchantsTracker.getCount(requiredEnchantment.key), requiredEnchantment.amount); + } + + return (double) enchants / requiredItems; + } + + @Override + public int getProgressValue(SuperiorPlayer superiorPlayer) { + RawDataTracker enchantsTracker = get(superiorPlayer); + + if (enchantsTracker == null) + return 0; + + int enchants = 0; + + for (RequiredEnchantment requiredEnchantment : this.requiredEnchantments.values()) { + enchants += Math.min(enchantsTracker.getCount(requiredEnchantment.key), requiredEnchantment.amount); + } + + return enchants; + } + + @Override + public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { + RawDataTracker enchantsTracker = getOrCreate(superiorPlayer, s -> new RawDataTracker()); + + if (enchantsTracker == null) + return; + + ItemMeta itemMeta = itemStack.getItemMeta(); + + if (itemMeta == null) + return; + + Placeholders.PlaceholdersFunctions placeholdersFunctions = new Placeholders.PlaceholdersFunctions() { + @Override + public Requirements getRequirementFromKey(String key) { + for (Requirements requirements : requiredEnchantments.keySet()) { + if (requirements.contains(key)) + return requirements; + } + + return null; + } + + @Override + public Optional lookupRequirement(Requirements requirement) { + return Optional.ofNullable(requiredEnchantments.get(requirement)) + .map(requiredEnchantment -> requiredEnchantment.amount); + } + + @Override + public int getCountForRequirement(Requirements requirement) { + return Optional.ofNullable(requiredEnchantments.get(requirement)) + .map(requiredEnchantment -> enchantsTracker.getCount(requiredEnchantment.key)) + .orElse(0); + } + }; + + if (itemMeta.hasDisplayName()) + itemMeta.setDisplayName(parsePlaceholders(placeholdersFunctions, enchantsTracker, itemMeta.getDisplayName())); + + if (itemMeta.hasLore()) { + List lore = new ArrayList<>(); + for (String line : Objects.requireNonNull(itemMeta.getLore())) + lore.add(parsePlaceholders(placeholdersFunctions, enchantsTracker, line)); + itemMeta.setLore(lore); + } + + itemStack.setItemMeta(itemMeta); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onItemEnchant(EnchantItemEvent e) { + ItemStack simulateEnchanted = e.getItem().clone(); + ItemMeta itemMeta = simulateEnchanted.getItemMeta(); + + for (Map.Entry entry : e.getEnchantsToAdd().entrySet()) { + if (simulateEnchanted.getType() == Material.BOOK) { + simulateEnchanted = new ItemStack(Material.ENCHANTED_BOOK); + itemMeta = simulateEnchanted.getItemMeta(); + } + + if (itemMeta == null) + continue; + + if (simulateEnchanted.getType() == Material.ENCHANTED_BOOK) { + ((EnchantmentStorageMeta) itemMeta).addStoredEnchant(entry.getKey(), entry.getValue(), true); + } else if (entry.getKey().canEnchantItem(simulateEnchanted)) { + itemMeta.addEnchant(entry.getKey(), entry.getValue(), true); + } + } + + simulateEnchanted.setItemMeta(itemMeta); + + getMissionRequirement(simulateEnchanted).ifPresent(requirement -> handleEnchanting(e.getEnchanter(), requirement)); + } + + @Override + public void saveProgress(ConfigurationSection section) { + for (Map.Entry entry : entrySet()) { + String uuid = entry.getKey().getUniqueId().toString(); + List data = new ArrayList<>(); + entry.getValue().getCounts().forEach((enchant, amount) -> data.add(enchant + ";" + amount.get())); + section.set(uuid, data); + } + } + + @Override + public void loadProgress(ConfigurationSection section) { + for (String uuid : section.getKeys(false)) { + RawDataTracker enchantsTracker = new RawDataTracker(); + UUID playerUUID = UUID.fromString(uuid); + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); + + insertData(superiorPlayer, enchantsTracker); + + section.getStringList(uuid).forEach(line -> { + String[] sections = line.split(";"); + int amount = sections.length == 2 ? Integer.parseInt(sections[1]) : 1; + String enchantment = sections[0]; + enchantsTracker.load(enchantment, amount); + }); + } + } + + private Optional getMissionRequirement(ItemStack itemStack) { + outerLoop: + for (Map.Entry requirement : this.requiredEnchantments.entrySet()) { + if (!requirement.getKey().contains(itemStack.getType().name())) + continue; + + for (Map.Entry requiredEnchantment : requirement.getValue().enchantments.entrySet()) { + Enchantment enchantment = requiredEnchantment.getKey(); + int requiredLevel = requiredEnchantment.getValue(); + + if (itemStack.getType() == Material.ENCHANTED_BOOK) { + EnchantmentStorageMeta storageMeta = (EnchantmentStorageMeta) itemStack.getItemMeta(); + if (storageMeta == null || storageMeta.getStoredEnchantLevel(enchantment) < requiredLevel) + continue outerLoop; + } else if (itemStack.getEnchantmentLevel(enchantment) < requiredLevel) { + continue outerLoop; + } + } + + return Optional.of(requirement.getValue()); + } + + return Optional.empty(); + } + + private void handleEnchanting(Player player, RequiredEnchantment requirement) { + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(player); + + if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) + return; + + RawDataTracker enchantsTracker = getOrCreate(superiorPlayer, s -> new RawDataTracker()); + + if (enchantsTracker == null) + return; + + enchantsTracker.track(requirement.key, 1); + + Bukkit.getScheduler().runTaskLaterAsynchronously(this.plugin, () -> superiorPlayer.runIfOnline(_player -> { + if (canComplete(superiorPlayer)) + this.plugin.getMissions().rewardMission(this, superiorPlayer, true); + }), 2L); + } + + private String parsePlaceholders(Placeholders.PlaceholdersFunctions placeholdersFunctions, + RawDataTracker enchantsTracker, String line) { + Matcher matcher = ENCHANTED_PATTERN.matcher(line); + + if (matcher.find()) { + String requiredBlock = matcher.group(1).toUpperCase(Locale.ENGLISH); + + Optional> entry = requiredEnchantments.entrySet().stream() + .filter(e -> e.getKey().contains(requiredBlock)).findAny(); + + if (entry.isPresent()) { + RequiredEnchantment requiredEnchantment = entry.get().getValue(); + line = matcher.replaceAll(enchantsTracker.getCount(requiredEnchantment.key) > 0 ? enchantedPlaceholder : notEnchantedPlaceholder); + } + } + + return Placeholders.parsePlaceholders(line, placeholdersFunctions); + } + + private static class RequiredEnchantment { + + private final String key; + private final Map enchantments; + private final Integer amount; + + RequiredEnchantment(String key, Map enchantments, Integer amount) { + this.key = key; + this.enchantments = enchantments; + this.amount = amount; + } + + } + + private class PrepareAnvilListener implements Listener { + + private final Map addingEnchantments = new HashMap<>(); + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onItemAnvil(org.bukkit.event.inventory.PrepareAnvilEvent e) { + if (e.getResult() == null || !isAddingEnchantment(e)) + return; + + getMissionRequirement(e.getResult()).ifPresent(requirement -> + addingEnchantments.put(e.getView().getPlayer().getUniqueId(), requirement)); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onItemAnvil(InventoryClickEvent e) { + if (e.getRawSlot() != 2) + return; + + RequiredEnchantment requiredEnchantment = addingEnchantments.remove(e.getWhoClicked().getUniqueId()); + if (requiredEnchantment == null) + return; + + handleEnchanting((Player) e.getWhoClicked(), requiredEnchantment); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryClose(InventoryCloseEvent e) { + addingEnchantments.remove(e.getPlayer().getUniqueId()); + } + + private boolean isAddingEnchantment(org.bukkit.event.inventory.PrepareAnvilEvent e) { + ItemStack result = e.getResult(); + if (result == null) + return false; + + ItemStack firstSlot = e.getInventory().getItem(0); + if (firstSlot == null) + return false; + + ItemStack secondSlot = e.getInventory().getItem(1); + if (secondSlot == null) + return false; + + return firstSlot.getType() == secondSlot.getType() || secondSlot.getType().name().contains("BOOK"); + } + + } + +} diff --git a/Missions/FarmingMissions/build.gradle b/Missions/FarmingMissions/build.gradle new file mode 100644 index 0000000000..806fcc0b1e --- /dev/null +++ b/Missions/FarmingMissions/build.gradle @@ -0,0 +1,9 @@ +group 'Missions:FarmingMissions' + +dependencies { + compileOnly "org.spigotmc:v1_16_R3:latest" +} + +shadowJar { + relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.farming' +} \ No newline at end of file diff --git a/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/FarmingMissions.java b/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/FarmingMissions.java new file mode 100644 index 0000000000..db4dc139bc --- /dev/null +++ b/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/FarmingMissions.java @@ -0,0 +1,402 @@ +package com.bgsoftware.superiorskyblock.missions; + +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.SBlockPosition; +import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; +import com.bgsoftware.superiorskyblock.missions.common.Placeholders; +import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; +import com.bgsoftware.superiorskyblock.missions.common.tracker.KeyDataTracker; +import com.bgsoftware.superiorskyblock.missions.farming.PlantType; +import com.bgsoftware.superiorskyblock.missions.farming.PlantsTracker; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.Ageable; +import org.bukkit.block.data.BlockData; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockGrowEvent; +import org.bukkit.event.block.BlockPistonExtendEvent; +import org.bukkit.event.block.BlockPistonRetractEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.block.BlockSpreadEvent; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.event.world.StructureGrowEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +public final class FarmingMissions extends BuiltinMission implements Listener { + + private static final BlockFace[] STEM_NEARBY_BLOCKS = new BlockFace[]{ + BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH + }; + private static final BlockFace[] CHORUS_NEARBY_BLOCKS = new BlockFace[]{ + BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH, BlockFace.DOWN + }; + + private final Map requiredPlants = new LinkedHashMap<>(); + + @Override + protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { + ConfigurationSection requiredPlantsSection = section.getConfigurationSection("required-plants"); + + if (requiredPlantsSection == null) + throw new MissionLoadException("You must have the \"required-plants\" section in the config."); + + for (String key : requiredPlantsSection.getKeys(false)) { + KeySet requiredPlants = KeySet.createKeySet(); + section.getStringList("required-plants." + key + ".types").forEach(requiredPlant -> + requiredPlants.add(Key.ofMaterialAndData(requiredPlant.toUpperCase(Locale.ENGLISH)))); + int requiredAmount = section.getInt("required-plants." + key + ".amount"); + this.requiredPlants.put(new KeyRequirements(requiredPlants), requiredAmount); + } + } + + @Override + protected void registerListeners() { + registerListener(this); + } + + @Override + protected void clearModuleData(KeyDataTracker data) { + data.clear(); + } + + @Override + public double getProgress(SuperiorPlayer superiorPlayer) { + KeyDataTracker farmingTracker = get(superiorPlayer); + + if (farmingTracker == null) + return 0.0; + + int requiredPlants = 0; + int grewPlants = 0; + + for (Map.Entry requiredPlant : this.requiredPlants.entrySet()) { + requiredPlants += requiredPlant.getValue(); + grewPlants += Math.min(farmingTracker.getCounts(requiredPlant.getKey()), requiredPlant.getValue()); + } + + return (double) grewPlants / requiredPlants; + } + + @Override + public int getProgressValue(SuperiorPlayer superiorPlayer) { + KeyDataTracker farmingTracker = get(superiorPlayer); + + if (farmingTracker == null) + return 0; + + int kills = 0; + + for (Map.Entry requiredPlant : this.requiredPlants.entrySet()) + kills += Math.min(farmingTracker.getCounts(requiredPlant.getKey()), requiredPlant.getValue()); + + return kills; + } + + @Override + public void saveProgress(ConfigurationSection section) { + for (Map.Entry entry : entrySet()) { + String uuid = entry.getKey().getUniqueId().toString(); + entry.getValue().getCounts().forEach((plant, count) -> + section.set("grown-plants." + uuid + "." + plant, count.get())); + } + + PlantsTracker.INSTANCE.save(section); + } + + @Override + public void loadProgress(ConfigurationSection section) { + ConfigurationSection grownPlants = section.getConfigurationSection("grown-plants"); + if (grownPlants != null) { + for (String uuid : grownPlants.getKeys(false)) { + KeyDataTracker farmingTracker = new KeyDataTracker(); + UUID playerUUID = UUID.fromString(uuid); + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); + + insertData(superiorPlayer, farmingTracker); + + for (String key : grownPlants.getConfigurationSection(uuid).getKeys(false)) { + Key typeKey = getMissionPlantKey(Key.ofMaterialAndData(key)); + farmingTracker.load(typeKey, grownPlants.getInt(uuid + "." + key)); + } + } + } + + ConfigurationSection placedPlants = section.getConfigurationSection("placed-plants"); + if (placedPlants != null) { + int dataVersion = section.getInt("data-version", 0); + + if (dataVersion == 0) { + loadLegacyData(placedPlants); + } else { + for (String placerUUID : placedPlants.getKeys(false)) { + UUID placer = UUID.fromString(placerUUID); + ConfigurationSection placerSection = placedPlants.getConfigurationSection(placerUUID); + if (placerSection == null) + continue; + + for (String worldName : placerSection.getKeys(false)) { + ConfigurationSection worldSection = placerSection.getConfigurationSection(worldName); + if (worldSection == null) + continue; + + for (String chunkKey : worldSection.getKeys(false)) { + PlantsTracker.INSTANCE.load(worldName, Long.parseLong(chunkKey), + worldSection.getIntegerList(chunkKey), placer); + } + } + } + + ConfigurationSection legacyPlacedPlants = section.getConfigurationSection("placed-plants-legacy"); + if (legacyPlacedPlants != null) + loadLegacyData(legacyPlacedPlants); + } + } + } + + private void loadLegacyData(ConfigurationSection section) { + for (String locationKey : section.getKeys(false)) { + UUID placer = UUID.fromString(section.getString(locationKey)); + String[] sections = locationKey.split(";"); + if (sections.length == 4) { + BlockPosition plantPosition = plugin.getFactory().createBlockPosition(Integer.parseInt(sections[1]), + Integer.parseInt(sections[2]), Integer.parseInt(sections[3])); + PlantsTracker.INSTANCE.loadLegacy(sections[0], plantPosition, placer); + } + } + } + + @Override + public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { + KeyDataTracker farmingTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); + + if (farmingTracker == null) + return; + + ItemMeta itemMeta = itemStack.getItemMeta(); + + if (itemMeta == null) + return; + + if (itemMeta.hasDisplayName()) + itemMeta.setDisplayName(Placeholders.parseKeyPlaceholders(this.requiredPlants, farmingTracker, itemMeta.getDisplayName(), true)); + + if (itemMeta.hasLore()) { + List lore = new ArrayList<>(); + for (String line : Objects.requireNonNull(itemMeta.getLore())) + lore.add(Placeholders.parseKeyPlaceholders(this.requiredPlants, farmingTracker, line, true)); + itemMeta.setLore(lore); + } + + itemStack.setItemMeta(itemMeta); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent e) { + PlantType plantType = PlantType.getBySaplingType(e.getBlock().getType()); + Key plantKey = plantType == PlantType.UNKNOWN ? Key.of(e.getBlock()) : plantType.getCachedKey(); + + if (getMissionPlantKey(plantKey) == null) + return; + + PlantsTracker.INSTANCE.track(e.getBlock(), e.getPlayer().getUniqueId()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockBreak(BlockBreakEvent e) { + PlantsTracker.INSTANCE.untrack(e.getBlock()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockExplode(EntityExplodeEvent e) { + for (Block block : e.blockList()) + PlantsTracker.INSTANCE.untrack(block); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPistonRetract(BlockPistonRetractEvent e) { + for (Block block : e.getBlocks()) + PlantsTracker.INSTANCE.untrack(block); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPistonRetract(BlockPistonExtendEvent e) { + for (Block block : e.getBlocks()) + PlantsTracker.INSTANCE.untrack(block); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBambooGrow(BlockSpreadEvent e) { + handlePlantGrow(e.getBlock(), e.getNewState()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlantGrow(StructureGrowEvent e) { + Block block = e.getLocation().getBlock(); + handlePlantGrow(block, block.getState()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlantGrow(BlockGrowEvent e) { + handlePlantGrow(e.getBlock(), e.getNewState()); + } + + private void handlePlantGrow(Block plantBlock, BlockState newState) { + PlantType plantType = PlantType.getByType(newState.getType()); + Key plantKey = plantType == PlantType.UNKNOWN ? Key.of(newState) : plantType.getCachedKey(); + plantKey = getMissionPlantKey(plantKey); + + if (plantKey == null) + return; + + int maxAge = plantType.getMaxAge(); + if (maxAge > 0 && getBlockAge(newState) < maxAge) + return; + + Location placedBlockLocation = plantBlock.getLocation(); + + switch (plantType) { + case CACTUS: + case SUGAR_CANE: + case BAMBOO: + placedBlockLocation = getRoot(plantBlock); + break; + case MELON: + case PUMPKIN: + placedBlockLocation = getStemRoot(plantType, plantBlock); + break; + case CHORUS_PLANT: + placedBlockLocation = getChorusRoot(plantBlock); + break; + } + + UUID placerUUID = PlantsTracker.INSTANCE.getPlacer(placedBlockLocation); + + if (placerUUID == null) + return; + + SuperiorPlayer playerTracked; + + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(placerUUID); + if (getIslandMission()) { + // In case this is an island mission, we want to get the uuid of the owner. + Island island = superiorPlayer.getIsland(); + if (island == null) + return; + playerTracked = island.getOwner(); + } else { + playerTracked = superiorPlayer; + } + + if (!this.plugin.getMissions().canCompleteNoProgress(playerTracked, this)) + return; + + KeyDataTracker farmingTracker = getOrCreate(playerTracked, s -> new KeyDataTracker()); + + if (farmingTracker == null) + return; + + farmingTracker.track(plantKey, 1); + + Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> playerTracked.runIfOnline(player -> { + if (canComplete(playerTracked)) + this.plugin.getMissions().rewardMission(this, playerTracked, true); + }), 2L); + } + + private int getBlockAge(BlockState newState) { + try { + BlockData blockData = newState.getBlockData(); + return blockData instanceof Ageable ? ((Ageable) blockData).getAge() : 0; + } catch (Throwable error) { + // noinspection deprecation + return newState.getRawData(); + } + } + + private static Location getRoot(Block original) { + Block lastSimilarBlock = original.getRelative(BlockFace.DOWN); + + Material originalType = lastSimilarBlock.getType(); + + while (lastSimilarBlock.getType() == originalType) { + lastSimilarBlock = lastSimilarBlock.getRelative(BlockFace.DOWN); + } + + return lastSimilarBlock.getLocation().add(0, 1, 0); + } + + private static Location getStemRoot(PlantType plantType, Block plantBlock) { + Material stemType = plantType == PlantType.PUMPKIN ? Material.PUMPKIN_STEM : Material.MELON_STEM; + + for (BlockFace blockFace : STEM_NEARBY_BLOCKS) { + Block nearbyBlock = plantBlock.getRelative(blockFace); + if (nearbyBlock.getType() == stemType) { + return nearbyBlock.getLocation(); + } + } + + return plantBlock.getLocation(); + } + + private static Location getChorusRoot(Block plantBlock) { + return findChorusRoot(plantBlock, BlockFace.SELF).orElseGet(plantBlock::getLocation); + } + + private static Optional findChorusRoot(Block plantBlock, BlockFace ignoredFace) { + Block downBlock = plantBlock.getRelative(BlockFace.DOWN); + + if (downBlock.getType() == Material.END_STONE) + return Optional.of(plantBlock.getLocation()); + + for (BlockFace blockFace : CHORUS_NEARBY_BLOCKS) { + if (blockFace != ignoredFace) { + Block nearbyBlock = plantBlock.getRelative(blockFace); + if (PlantType.getByType(nearbyBlock.getType()) == PlantType.CHORUS_PLANT) { + Optional nearbyResult = findChorusRoot(nearbyBlock, blockFace.getOppositeFace()); + if (nearbyResult.isPresent()) + return nearbyResult; + } + } + } + + return Optional.empty(); + } + + @Nullable + private Key getMissionPlantKey(@Nullable Key blockKey) { + if (blockKey == null) + return null; + + for (KeyRequirements requirement : requiredPlants.keySet()) { + if (requirement.contains(blockKey)) + return requirement.getKey(blockKey); + } + + return null; + } + +} diff --git a/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantType.java b/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantType.java new file mode 100644 index 0000000000..10cc7d0637 --- /dev/null +++ b/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantType.java @@ -0,0 +1,103 @@ +package com.bgsoftware.superiorskyblock.missions.farming; + +import com.bgsoftware.superiorskyblock.api.key.Key; +import org.bukkit.Material; + +import java.util.EnumMap; + +public enum PlantType { + + BAMBOO(0, Plants.of("BAMBOO"), Plants.of("BAMBOO_SAPLING")), + BEETROOT(3, Plants.of("BEETROOT", "BEETROOTS", "BEETROOT_SEEDS")), + CACTUS(0, Plants.of("CACTUS")), + CARROT(7, Plants.of("CARROT", "CARROTS")), + CHORUS_PLANT(0, Plants.of("CHORUS_PLANT", "CHORUS_FLOWER")), + COCOA(2, Plants.of("COCOA", "COCOA_BEANS")), + MELON(-1, Plants.of("MELON", "MELON_BLOCK"), Plants.of("MELON_STEM")), + NETHER_WART(3, Plants.of("NETHER_WART", "NETHER_STALK")), + POTATO(7, Plants.of("POTATO", "POTATOES")), + PUMPKIN(-1, Plants.of("PUMPKIN"), Plants.of("PUMPKIN_STEM")), + SUGAR_CANE(0, Plants.of("SUGAR_CANE", "SUGAR_CANE_BLOCK")), + SWEET_BERRY_BUSH(3, Plants.of("SWEET_BERRY_BUSH")), + WHEAT(7, Plants.of("WHEAT", "CROPS", "WHEAT_SEEDS")), + + UNKNOWN(-1, Plants.EMPTY); + + private static final EnumMap MATERIALS_TO_PLANT_TYPE = new EnumMap<>(Material.class); + private static final EnumMap SAPLING_MATERIALS_TO_PLANT_TYPE = new EnumMap<>(Material.class); + private static boolean hasRegisteredPlantTypes = false; + + private final String[] plantTypes; + private final String[] saplingTypes; + private final int maxAge; + private final Key cachedKey; + + PlantType(int maxAge, Plants plantTypes) { + this(maxAge, plantTypes, plantTypes); + } + + PlantType(int maxAge, Plants plantTypes, Plants saplingTypes) { + this.maxAge = maxAge; + this.plantTypes = plantTypes.arr; + this.saplingTypes = saplingTypes.arr; + this.cachedKey = Key.ofMaterialAndData(name()); + } + + public int getMaxAge() { + return maxAge; + } + + public Key getCachedKey() { + return cachedKey; + } + + public static PlantType getByType(Material material) { + registerPlantTypes(); + return MATERIALS_TO_PLANT_TYPE.getOrDefault(material, UNKNOWN); + } + + public static PlantType getBySaplingType(Material material) { + registerPlantTypes(); + return SAPLING_MATERIALS_TO_PLANT_TYPE.getOrDefault(material, UNKNOWN); + } + + private static void registerPlantType(PlantType plantType) { + for (String material : plantType.plantTypes) { + try { + MATERIALS_TO_PLANT_TYPE.put(Material.valueOf(material), plantType); + } catch (IllegalArgumentException ignored) { + } + } + for (String material : plantType.saplingTypes) { + try { + SAPLING_MATERIALS_TO_PLANT_TYPE.put(Material.valueOf(material), plantType); + } catch (IllegalArgumentException ignored) { + } + } + } + + private static void registerPlantTypes() { + if (!hasRegisteredPlantTypes) { + for (PlantType plantType : PlantType.values()) + registerPlantType(plantType); + hasRegisteredPlantTypes = true; + } + } + + private static class Plants { + + static Plants EMPTY = of(); + + private final String[] arr; + + static Plants of(String... arr) { + return new Plants(arr); + } + + Plants(String[] arr) { + this.arr = arr; + } + + } + +} diff --git a/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantsTracker.java b/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantsTracker.java new file mode 100644 index 0000000000..df8895b0d4 --- /dev/null +++ b/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantsTracker.java @@ -0,0 +1,160 @@ +package com.bgsoftware.superiorskyblock.missions.farming; + +import com.bgsoftware.superiorskyblock.api.wrappers.BlockPosition; +import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.configuration.ConfigurationSection; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class PlantsTracker { + + public static final PlantsTracker INSTANCE = new PlantsTracker(); + + private final Map plantsTracker = new HashMap<>(); + private Map rawData = null; + private Map>> legacyRawData = null; + private boolean saved = false; + + private PlantsTracker() { + + } + + public void track(Block block, UUID placer) { + track(block.getWorld(), block.getX(), block.getY(), block.getZ(), placer); + } + + public void track(World world, int x, int y, int z, UUID placer) { + loadRawData(world); + plantsTracker.computeIfAbsent(world.getName(), s -> new PlantsTrackingComponent(world)) + .track(x, y, z, placer); + } + + public void untrack(Block block) { + untrack(block.getWorld(), block.getX(), block.getY(), block.getZ()); + } + + public void untrack(World world, int x, int y, int z) { + loadRawData(world); + PlantsTrackingComponent trackingComponent = this.plantsTracker.get(world.getName()); + if (trackingComponent != null) + trackingComponent.untrack(x, y, z); + } + + @Nullable + public UUID getPlacer(Location location) { + World world = location.getWorld(); + return world == null ? null : getPlacer(world, location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + @Nullable + public UUID getPlacer(World world, int x, int y, int z) { + loadRawData(world); + PlantsTrackingComponent trackingComponent = this.plantsTracker.get(world.getName()); + return trackingComponent == null ? null : trackingComponent.getPlacer(x, y, z); + } + + public void load(String worldName, long chunkKey, List blocks, UUID placer) { + if (this.rawData == null) + this.rawData = new HashMap<>(); + TrackedPlantsData trackedPlantsData = this.rawData.computeIfAbsent(worldName, w -> new TrackedPlantsData()); + blocks.forEach(block -> trackedPlantsData.track(chunkKey, block, placer)); + } + + public void loadLegacy(String worldName, BlockPosition plant, UUID placer) { + if (this.legacyRawData == null) + this.legacyRawData = new HashMap<>(); + this.legacyRawData.computeIfAbsent(worldName, w -> new LinkedHashMap<>()) + .computeIfAbsent(placer, i -> new LinkedList<>()).add(plant); + } + + public void save(ConfigurationSection section) { + if (!this.saved) { + saveInternal(section); + this.saved = true; + } + } + + private void saveInternal(ConfigurationSection section) { + MutableBoolean savedData = new MutableBoolean(false); + + this.plantsTracker.forEach((worldName, component) -> { + component.getPlants().forEach((chunkKey, blocks) -> { + blocks.forEach((block, placer) -> { + String path = "placed-plants." + placer + "." + worldName + "." + chunkKey; + List blocksList = section.getIntegerList(path); + blocksList.add(block); + section.set(path, blocksList); + savedData.set(true); + }); + }); + }); + + if (this.rawData != null) { + this.rawData.forEach((worldName, worldData) -> { + worldData.getPlants().forEach((chunkKey, blocks) -> { + blocks.forEach((block, placer) -> { + String path = "placed-plants." + placer + "." + worldName + "." + chunkKey; + List blocksList = section.getIntegerList(path); + blocksList.add(block); + section.set(path, blocksList); + savedData.set(true); + }); + }); + }); + } + + if (this.legacyRawData != null) { + this.legacyRawData.forEach((worldName, worldData) -> { + worldData.forEach((placer, plants) -> { + plants.forEach(plant -> { + String plantKey = worldName + ";" + plant.getX() + ";" + plant.getY() + ";" + plant.getZ(); + section.set("placed-plants-legacy." + plantKey, placer.toString()); + savedData.set(true); + }); + }); + }); + } + + if (savedData.get()) { + section.set("data-version", 1); + } + } + + private void loadRawData(World world) { + String worldName = world.getName(); + + if (this.rawData != null) { + TrackedPlantsData rawDataForWorld = this.rawData.remove(worldName); + if (rawDataForWorld != null) { + plantsTracker.put(worldName, new PlantsTrackingComponent(world, rawDataForWorld)); + + if (this.rawData.isEmpty()) + this.rawData = null; + } + } + + if (this.legacyRawData != null) { + Map> legacyRawDataForWorld = this.legacyRawData.remove(worldName); + if (legacyRawDataForWorld != null) { + PlantsTrackingComponent plantsTrackingComponent = new PlantsTrackingComponent(world); + legacyRawDataForWorld.forEach((placer, plants) -> { + plants.forEach(plant -> plantsTrackingComponent.track(plant.getX(), plant.getY(), plant.getZ(), placer)); + }); + this.plantsTracker.put(worldName, plantsTrackingComponent); + + if (this.legacyRawData.isEmpty()) + this.legacyRawData = null; + } + } + } + +} diff --git a/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantsTrackingComponent.java b/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantsTrackingComponent.java new file mode 100644 index 0000000000..6b062d55b2 --- /dev/null +++ b/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/PlantsTrackingComponent.java @@ -0,0 +1,69 @@ +package com.bgsoftware.superiorskyblock.missions.farming; + +import com.bgsoftware.common.reflection.ClassInfo; +import com.bgsoftware.common.reflection.ReflectMethod; +import org.bukkit.World; + +import javax.annotation.Nullable; +import java.util.Map; +import java.util.UUID; + +public class PlantsTrackingComponent { + + private static final ReflectMethod WORLD_GET_MIN_HEIGHT = new ReflectMethod<>( + new ClassInfo("CraftWorld", ClassInfo.PackageType.CRAFTBUKKIT), + "getMinHeight", + new ClassInfo[0]); + + private final TrackedPlantsData trackedPlantsData; + + private final int worldMinHeight; + + public PlantsTrackingComponent(World world) { + this(world, new TrackedPlantsData()); + } + + public PlantsTrackingComponent(World world, TrackedPlantsData trackedPlantsData) { + this.worldMinHeight = WORLD_GET_MIN_HEIGHT.isValid() ? WORLD_GET_MIN_HEIGHT.invoke(world) : 0; + this.trackedPlantsData = trackedPlantsData; + } + + public void track(int x, int y, int z, UUID placer) { + int block = getBlockIndex(x, y, z); + trackedPlantsData.track(getChunkKey(x, z), block, placer); + } + + public void untrack(int x, int y, int z) { + int block = getBlockIndex(x, y, z); + trackedPlantsData.untrack(getChunkKey(x, z), block); + } + + @Nullable + public UUID getPlacer(int x, int y, int z) { + int block = getBlockIndex(x, y, z); + return trackedPlantsData.getPlacer(getChunkKey(x, z), block); + } + + public Map> getPlants() { + return this.trackedPlantsData.getPlants(); + } + + private int getBlockIndex(int blockX, int blockY, int blockZ) { + int chunkMinX = blockX >> 4 << 4; + int chunkMinZ = blockZ >> 4 << 4; + + + byte relativeX = (byte) (blockX - chunkMinX); + short relativeY = (short) (blockY - this.worldMinHeight); + byte relativeZ = (byte) (blockZ - chunkMinZ); + + return (relativeY << 8) | (relativeX << 4) | relativeZ; + } + + private static long getChunkKey(int blockX, int blockZ) { + int chunkX = blockX >> 4; + int chunkZ = blockZ >> 4; + return (long) chunkX << 32 | chunkZ; + } + +} diff --git a/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/TrackedPlantsData.java b/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/TrackedPlantsData.java new file mode 100644 index 0000000000..547153befe --- /dev/null +++ b/Missions/FarmingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/farming/TrackedPlantsData.java @@ -0,0 +1,30 @@ +package com.bgsoftware.superiorskyblock.missions.farming; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class TrackedPlantsData { + + private final Map> trackedData = new HashMap<>(); + + public void track(long chunkKey, int block, UUID placer) { + trackedData.computeIfAbsent(chunkKey, i -> new HashMap<>()).put(block, placer); + } + + public void untrack(long chunkKey, int block) { + Map chunkTrackedData = this.trackedData.get(chunkKey); + if (chunkTrackedData != null) + chunkTrackedData.remove(block); + } + + public UUID getPlacer(long chunkKey, int block) { + Map chunkTrackedData = this.trackedData.get(chunkKey); + return chunkTrackedData == null ? null : chunkTrackedData.get(block); + } + + public Map> getPlants() { + return trackedData; + } + +} diff --git a/Missions/FishingMissions/build.gradle b/Missions/FishingMissions/build.gradle new file mode 100644 index 0000000000..168e0e597c --- /dev/null +++ b/Missions/FishingMissions/build.gradle @@ -0,0 +1,9 @@ +group 'Missions:FishingMissions' + +dependencies { + compileOnly "org.spigotmc:v1_16_R3:latest" +} + +shadowJar { + relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.fishing' +} \ No newline at end of file diff --git a/Missions/FishingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/FishingMissions.java b/Missions/FishingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/FishingMissions.java new file mode 100644 index 0000000000..e2da4d0331 --- /dev/null +++ b/Missions/FishingMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/FishingMissions.java @@ -0,0 +1,204 @@ +package com.bgsoftware.superiorskyblock.missions; + +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.Counter; +import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; +import com.bgsoftware.superiorskyblock.missions.common.Placeholders; +import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; +import com.bgsoftware.superiorskyblock.missions.common.tracker.KeyDataTracker; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Item; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerFishEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +public final class FishingMissions extends BuiltinMission implements Listener { + + private final Map itemsToCatch = new LinkedHashMap<>(); + + @Override + protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { + ConfigurationSection requiredCaughtsSection = section.getConfigurationSection("required-caughts"); + if (requiredCaughtsSection == null) + throw new MissionLoadException("You must have the \"required-caughts\" section in the config."); + + for (String key : requiredCaughtsSection.getKeys(false)) { + KeySet blocks = KeySet.createKeySet(); + section.getStringList("required-caughts." + key + ".types").forEach(requiredBlock -> + blocks.add(Key.ofMaterialAndData(requiredBlock.toUpperCase(Locale.ENGLISH)))); + int amount = section.getInt("required-caughts." + key + ".amount", 1); + this.itemsToCatch.put(new KeyRequirements(blocks), amount); + } + } + + @Override + protected void registerListeners() { + registerListener(this); + } + + @Override + protected void clearModuleData(KeyDataTracker data) { + data.clear(); + } + + @Override + public double getProgress(SuperiorPlayer superiorPlayer) { + KeyDataTracker fishingTracker = get(superiorPlayer); + + if (fishingTracker == null) + return 0.0; + + int requiredItems = 0; + int interactions = 0; + + for (Map.Entry entry : this.itemsToCatch.entrySet()) { + requiredItems += entry.getValue(); + interactions += Math.min(fishingTracker.getCounts(entry.getKey()), entry.getValue()); + } + + return (double) interactions / requiredItems; + } + + @Override + public int getProgressValue(SuperiorPlayer superiorPlayer) { + KeyDataTracker fishingTracker = get(superiorPlayer); + + if (fishingTracker == null) + return 0; + + int interactions = 0; + + for (Map.Entry entry : this.itemsToCatch.entrySet()) + interactions += Math.min(fishingTracker.getCounts(entry.getKey()), entry.getValue()); + + return interactions; + } + + @Override + public void saveProgress(ConfigurationSection section) { + for (Map.Entry entry : entrySet()) { + String uuid = entry.getKey().getUniqueId().toString(); + int index = 0; + for (Map.Entry craftedEntry : entry.getValue().getCounts().entrySet()) { + section.set(uuid + "." + index + ".item", craftedEntry.getKey().toString()); + section.set(uuid + "." + index + ".amount", craftedEntry.getValue().get()); + index++; + } + } + } + + @Override + public void loadProgress(ConfigurationSection section) { + for (String uuid : section.getKeys(false)) { + if (uuid.equals("players")) + continue; + + KeyDataTracker fishingTracker = new KeyDataTracker(); + UUID playerUUID = UUID.fromString(uuid); + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); + + insertData(superiorPlayer, fishingTracker); + + for (String key : section.getConfigurationSection(uuid).getKeys(false)) { + Key typeKey; + if (section.isItemStack(uuid + "." + key + ".item")) { + ItemStack itemStack = section.getItemStack(uuid + "." + key + ".item"); + typeKey = itemStack == null ? null : Key.of(itemStack); + } else { + typeKey = Key.ofMaterialAndData(section.getString(uuid + "." + key + ".item")); + } + if (typeKey != null) { + typeKey = getMissionItemKey(typeKey); + int amount = section.getInt(uuid + "." + key + ".amount"); + fishingTracker.load(typeKey, amount); + } + } + } + } + + @Override + public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { + KeyDataTracker fishingTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); + + if (fishingTracker == null) + return; + + ItemMeta itemMeta = itemStack.getItemMeta(); + + if (itemMeta == null) + return; + + if (itemMeta.hasDisplayName()) + itemMeta.setDisplayName(Placeholders.parseKeyPlaceholders(this.itemsToCatch, fishingTracker, itemMeta.getDisplayName(), true)); + + if (itemMeta.hasLore()) { + List lore = new ArrayList<>(); + for (String line : Objects.requireNonNull(itemMeta.getLore())) + lore.add(Placeholders.parseKeyPlaceholders(this.itemsToCatch, fishingTracker, line, true)); + itemMeta.setLore(lore); + } + + itemStack.setItemMeta(itemMeta); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerFish(PlayerFishEvent e) { + if (!(e.getCaught() instanceof Item) || e.getState() != PlayerFishEvent.State.CAUGHT_FISH) + return; + + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + + if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) + return; + + Item caughtItem = (Item) e.getCaught(); + ItemStack caughtItemStack = caughtItem.getItemStack(); + + Key itemKey = getMissionItemKey(Key.of(caughtItemStack)); + if (itemKey == null) + return; + + trackItem(superiorPlayer, itemKey, caughtItemStack.getAmount()); + } + + private void trackItem(SuperiorPlayer superiorPlayer, Key itemKey, int count) { + KeyDataTracker blocksTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); + + if (blocksTracker == null) + return; + + blocksTracker.track(itemKey, count); + + Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> superiorPlayer.runIfOnline(player -> { + if (canComplete(superiorPlayer)) + this.plugin.getMissions().rewardMission(this, superiorPlayer, true); + }), 2L); + } + + @Nullable + private Key getMissionItemKey(Key blockKey) { + for (KeyRequirements requirementsList : itemsToCatch.keySet()) { + if (requirementsList.contains(blockKey)) + return requirementsList.getKey(blockKey); + } + + return null; + } + +} diff --git a/Missions/IslandMissions/build.gradle b/Missions/IslandMissions/build.gradle new file mode 100644 index 0000000000..dea05a0cb4 --- /dev/null +++ b/Missions/IslandMissions/build.gradle @@ -0,0 +1,9 @@ +group 'Missions:IslandMissions' + +dependencies { + compileOnly "org.spigotmc:v1_8_R3-Taco:latest" +} + +shadowJar { + relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.island' +} \ No newline at end of file diff --git a/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/IslandMissions.java b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/IslandMissions.java new file mode 100644 index 0000000000..aa53ae4c42 --- /dev/null +++ b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/IslandMissions.java @@ -0,0 +1,176 @@ +package com.bgsoftware.superiorskyblock.missions; + +import com.bgsoftware.superiorskyblock.api.events.IslandEvent; +import com.bgsoftware.superiorskyblock.api.events.IslandTransferEvent; +import com.bgsoftware.superiorskyblock.api.events.MissionCompleteEvent; +import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; +import com.bgsoftware.superiorskyblock.api.scripts.IScriptEngine; +import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; +import com.bgsoftware.superiorskyblock.missions.island.DynamicRegisteredListener; +import com.bgsoftware.superiorskyblock.missions.island.EventsHelper; +import com.bgsoftware.superiorskyblock.missions.island.timings.ITimings; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.event.Event; +import org.bukkit.event.EventException; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.RegisteredServiceProvider; + +import javax.annotation.Nullable; +import javax.script.SimpleBindings; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public final class IslandMissions extends BuiltinMission implements Listener { + + private String successCheck; + private PlaceholdersService placeholdersService; + + @Override + protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { + if (!section.contains("events")) + throw new MissionLoadException("You must have the \"events\" section in the config."); + + for (String event : section.getStringList("events")) { + boolean targetPlayer = false; + String eventName = event; + + if (event.toLowerCase().endsWith("-target")) { + targetPlayer = true; + eventName = event.split("-")[0]; + } + + try { + registerEventListener(plugin, eventName, targetPlayer); + } catch (ClassNotFoundException error) { + plugin.getLogger().warning("The event " + eventName + " is not valid, skipping"); + } catch (Exception error) { + plugin.getLogger().warning("Cannot register IslandMission for " + eventName + ":"); + error.printStackTrace(); + } + } + + this.successCheck = section.getString("success-check", "true"); + + RegisteredServiceProvider registeredServiceProvider = plugin.getServer() + .getServicesManager().getRegistration(PlaceholdersService.class); + + if (registeredServiceProvider != null) { + this.placeholdersService = registeredServiceProvider.getProvider(); + } + } + + @Override + protected void registerListeners() { + registerListener(this); + } + + @Override + protected void clearModuleData(Boolean data) { + // Do nothing + } + + @Override + public double getProgress(SuperiorPlayer superiorPlayer) { + return get(superiorPlayer) == null ? 0.0 : 1.0; + } + + @Override + public int getProgressValue(SuperiorPlayer superiorPlayer) { + return 0; + } + + private void registerEventListener(Plugin plugin, String eventName, boolean isTarget) throws Exception { + Class eventClass = Class.forName("com.bgsoftware.superiorskyblock.api.events." + eventName); + + if (!Event.class.isAssignableFrom(eventClass)) + return; + + HandlerList handlerList = EventsHelper.getEventListeners(eventClass.asSubclass(Event.class)); + ITimings timings = ITimings.of(plugin, "Plugin: " + plugin.getDescription().getFullName() + + " Event: DynamicRegisteredListener::" + eventName + "(" + eventClass.getSimpleName() + ")"); + + Method getPlayerMethod = getMethodSilently(eventClass, "getPlayer"); + Method getTargetMethod = getMethodSilently(eventClass, "getTarget"); + + handlerList.register(new DynamicRegisteredListener(plugin, (listener, event) -> { + try { + if (eventClass.isAssignableFrom(event.getClass()) && + (event instanceof IslandEvent || event instanceof MissionCompleteEvent)) { + boolean isAsync = event.isAsynchronous(); + + if (!isAsync) { + timings.startTiming(); + } + + SuperiorPlayer superiorPlayer; + SuperiorPlayer targetPlayer; + + if (event instanceof IslandTransferEvent) { + superiorPlayer = ((IslandTransferEvent) event).getOldOwner(); + targetPlayer = ((IslandTransferEvent) event).getNewOwner(); + } else { + superiorPlayer = getPlayerMethod != null ? (SuperiorPlayer) getPlayerMethod.invoke(event) : + event instanceof IslandEvent ? ((IslandEvent) event).getIsland().getOwner() : null; + targetPlayer = getTargetMethod == null ? null : (SuperiorPlayer) getTargetMethod.invoke(event); + } + + tryComplete(event, superiorPlayer, targetPlayer, isTarget); + + if (!isAsync) { + timings.stopTiming(); + } + } + } catch (InvocationTargetException var4) { + throw new EventException(var4.getCause()); + } catch (Throwable var5) { + throw new EventException(var5); + } + })); + } + + private void tryComplete(Event event, @Nullable SuperiorPlayer superiorPlayer, + @Nullable SuperiorPlayer targetPlayer, boolean isTarget) { + boolean success = false; + + SimpleBindings bindings = new SimpleBindings(); + bindings.put("event", event); + + IScriptEngine scriptEngine = this.plugin.getScriptEngine(); + + try { + String result = scriptEngine.eval(successCheck, bindings) + ""; + if (this.placeholdersService != null && superiorPlayer != null) { + result = placeholdersService.parsePlaceholders(superiorPlayer.asOfflinePlayer(), result); + } + success = Boolean.parseBoolean(result); + } catch (Throwable error) { + plugin.getLogger().warning("Error occurred while checking for success condition for IslandMission."); + plugin.getLogger().warning("Current Script Engine: " + scriptEngine); + error.printStackTrace(); + } + + if (success) { + SuperiorPlayer rewardedPlayer = isTarget ? targetPlayer : superiorPlayer; + if (rewardedPlayer != null) { + Bukkit.getScheduler().runTaskLater(plugin, () -> { + insertData(rewardedPlayer, true); + this.plugin.getMissions().rewardMission(this, rewardedPlayer, true); + }, 5L); + } + } + } + + private static Method getMethodSilently(Class clazz, String methodName) { + try { + return clazz.getDeclaredMethod(methodName); + } catch (Exception error) { + return null; + } + } + +} diff --git a/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/DynamicRegisteredListener.java b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/DynamicRegisteredListener.java new file mode 100644 index 0000000000..44746e426d --- /dev/null +++ b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/DynamicRegisteredListener.java @@ -0,0 +1,18 @@ +package com.bgsoftware.superiorskyblock.missions.island; + +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.plugin.EventExecutor; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.TimedRegisteredListener; + +public class DynamicRegisteredListener extends TimedRegisteredListener { + + private static final Listener EMPTY_LISTENER = new Listener() { + }; + + public DynamicRegisteredListener(Plugin plugin, EventExecutor executor) { + super(EMPTY_LISTENER, executor, EventPriority.MONITOR, plugin, true); + } + +} diff --git a/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/EventsHelper.java b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/EventsHelper.java new file mode 100644 index 0000000000..0eb4b179cb --- /dev/null +++ b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/EventsHelper.java @@ -0,0 +1,38 @@ +package com.bgsoftware.superiorskyblock.missions.island; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.plugin.IllegalPluginAccessException; + +import java.lang.reflect.Method; + +public class EventsHelper { + + private EventsHelper() { + + } + + public static HandlerList getEventListeners(Class type) { + try { + Method method = getRegistrationClass(type).getDeclaredMethod("getHandlerList"); + method.setAccessible(true); + return (HandlerList) method.invoke(null); + } catch (Exception var3) { + throw new IllegalPluginAccessException(var3.toString()); + } + } + + private static Class getRegistrationClass(Class clazz) { + try { + clazz.getDeclaredMethod("getHandlerList"); + return clazz; + } catch (NoSuchMethodException var3) { + if (clazz.getSuperclass() != null && !clazz.getSuperclass().equals(Event.class) && Event.class.isAssignableFrom(clazz.getSuperclass())) { + return getRegistrationClass(clazz.getSuperclass().asSubclass(Event.class)); + } else { + throw new IllegalPluginAccessException("Unable to find handler list for event " + clazz.getName() + ". Static getHandlerList method required!"); + } + } + } + +} diff --git a/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/DummyTimings.java b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/DummyTimings.java new file mode 100644 index 0000000000..e30f463838 --- /dev/null +++ b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/DummyTimings.java @@ -0,0 +1,21 @@ +package com.bgsoftware.superiorskyblock.missions.island.timings; + +public class DummyTimings implements ITimings { + + public static final DummyTimings INSTANCE = new DummyTimings(); + + private DummyTimings() { + + } + + @Override + public void startTiming() { + // Do nothing. + } + + @Override + public void stopTiming() { + // Do nothing. + } + +} diff --git a/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/ITimings.java b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/ITimings.java new file mode 100644 index 0000000000..0c321044b7 --- /dev/null +++ b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/ITimings.java @@ -0,0 +1,23 @@ +package com.bgsoftware.superiorskyblock.missions.island.timings; + +import org.bukkit.plugin.Plugin; + +public interface ITimings { + + void startTiming(); + + void stopTiming(); + + static ITimings of(Plugin plugin, String name) { + try { + return TimingsWrapper.create(plugin, name); + } catch (Throwable error) { + try { + return LegacyTimingsWrapper.create(name); + } catch (Throwable error2) { + return DummyTimings.INSTANCE; + } + } + } + +} diff --git a/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/LegacyTimingsWrapper.java b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/LegacyTimingsWrapper.java new file mode 100644 index 0000000000..f34d7b5c56 --- /dev/null +++ b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/LegacyTimingsWrapper.java @@ -0,0 +1,27 @@ +package com.bgsoftware.superiorskyblock.missions.island.timings; + +import org.spigotmc.CustomTimingsHandler; + +public class LegacyTimingsWrapper implements ITimings { + + private final CustomTimingsHandler handle; + + public static ITimings create(String name) { + return new LegacyTimingsWrapper(name); + } + + private LegacyTimingsWrapper(String name) { + this.handle = new CustomTimingsHandler(name); + } + + @Override + public void startTiming() { + this.handle.startTiming(); + } + + @Override + public void stopTiming() { + this.handle.stopTiming(); + } + +} diff --git a/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/TimingsWrapper.java b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/TimingsWrapper.java new file mode 100644 index 0000000000..1fd2086d51 --- /dev/null +++ b/Missions/IslandMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/island/timings/TimingsWrapper.java @@ -0,0 +1,62 @@ +package com.bgsoftware.superiorskyblock.missions.island.timings; + +import co.aikar.timings.Timing; +import co.aikar.timings.Timings; +import co.aikar.timings.TimingsManager; +import com.bgsoftware.common.reflection.ReflectMethod; +import org.bukkit.plugin.Plugin; + +import javax.annotation.Nullable; + +public class TimingsWrapper implements ITimings { + + private static final ReflectMethod START_TIMING = new ReflectMethod<>(Timing.class, "startTiming"); + + @Nullable + private final Timing handle; + + public static ITimings create(Plugin plugin, String name) { + return Timings.isTimingsEnabled() ? new TimingsWrapper(plugin, name) : DummyTimings.INSTANCE; + } + + private static final ReflectMethod TIMINGS_MANAGER_GET_HANDLER_WITH_PROTECT = new ReflectMethod<>( + TimingsManager.class, "getHandler", String.class, String.class, Timing.class, boolean.class); + private static final ReflectMethod TIMINGS_MANAGER_GET_HANDLER = new ReflectMethod<>( + TimingsManager.class, "getHandler", String.class, String.class, Timing.class); + + private TimingsWrapper(Plugin plugin, String name) { + String pluginName = plugin.getName(); + + if (TIMINGS_MANAGER_GET_HANDLER_WITH_PROTECT.isValid()) { + Timing pluginHandler = TIMINGS_MANAGER_GET_HANDLER_WITH_PROTECT.invoke(null, + pluginName, "Combined Total", TimingsManager.PLUGIN_GROUP_HANDLER, false); + this.handle = TIMINGS_MANAGER_GET_HANDLER_WITH_PROTECT.invoke(null, + pluginName, name, pluginHandler, true); + } else if (TIMINGS_MANAGER_GET_HANDLER.isValid()) { + Timing pluginHandler = TIMINGS_MANAGER_GET_HANDLER.invoke(null, + pluginName, "Combined Total", TimingsManager.PLUGIN_GROUP_HANDLER); + this.handle = TIMINGS_MANAGER_GET_HANDLER.invoke(null, + pluginName, name, pluginHandler); + } else { + this.handle = null; + } + } + + @Override + public void startTiming() { + if (this.handle != null) { + try { + this.handle.startTiming(); + } catch (Throwable error) { + START_TIMING.invoke(this.handle); + } + } + } + + @Override + public void stopTiming() { + if (this.handle != null) + this.handle.stopTiming(); + } + +} diff --git a/Missions/ItemsMissions/build.gradle b/Missions/ItemsMissions/build.gradle new file mode 100644 index 0000000000..b323a9110c --- /dev/null +++ b/Missions/ItemsMissions/build.gradle @@ -0,0 +1,9 @@ +group 'Missions:ItemsMissions' + +dependencies { + compileOnly "org.spigotmc:v1_8_R3-Taco:latest" +} + +shadowJar { + relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.items' +} \ No newline at end of file diff --git a/Missions/ItemsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/ItemsMissions.java b/Missions/ItemsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/ItemsMissions.java new file mode 100644 index 0000000000..2a71c31234 --- /dev/null +++ b/Missions/ItemsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/ItemsMissions.java @@ -0,0 +1,280 @@ +package com.bgsoftware.superiorskyblock.missions; + +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; +import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.player.PlayerPickupItemEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +@SuppressWarnings("unused") +public final class ItemsMissions extends BuiltinMission implements Listener { + + private final Map requiredItems = new LinkedHashMap<>(); + + @Override + protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { + ConfigurationSection requiredItemsSection = section.getConfigurationSection("required-items"); + + if (requiredItemsSection == null) + throw new MissionLoadException("You must have the \"required-items\" section in the config."); + + for (String key : requiredItemsSection.getKeys(false)) { + KeySet itemStacks = KeySet.createKeySet(); + section.getStringList("required-items." + key + ".types").forEach(itemStackName -> + itemStacks.add(Key.ofMaterialAndData(itemStackName.toUpperCase(Locale.ENGLISH)))); + int requiredAmount = section.getInt("required-items." + key + ".amount"); + requiredItems.put(new KeyRequirements(itemStacks), requiredAmount); + } + } + + @Override + protected void registerListeners() { + registerListener(this); + } + + @Override + protected void clearModuleData(ItemsTracker data) { + data.itemsTracker.clear(); + } + + @Override + public double getProgress(SuperiorPlayer superiorPlayer) { + double progress = 0.0; + + Player player = superiorPlayer.asPlayer(); + + if (player == null) + return progress; + + Inventory inventory = player.getInventory(); + Map countedItems = countItems(inventory); + + int totalRequiredAmount = 0; + int totalItemAmount = 0; + + ItemsTracker itemsTracker = getOrCreate(superiorPlayer, s -> new ItemsTracker()); + + if (itemsTracker == null) + return 0.0; + + for (Map.Entry entry : requiredItems.entrySet()) { + KeyRequirements requirement = entry.getKey(); + int requiredAmount = entry.getValue(); + + int itemAmount = 0; + for (Key item : requirement) { + try { + //Get the amount of the item. + Material type = Material.valueOf(item.getGlobalKey()); + short data = item.getSubKey().isEmpty() ? 0 : Short.parseShort(item.getSubKey()); + int currentItemAmount = countedItems.get(new ItemStack(type, 1, data)); + + //Making sure to not exceed the required item amount + if (itemAmount + currentItemAmount > requiredAmount) + currentItemAmount = requiredAmount - itemAmount; + + //Summing the amount to a global variable + itemAmount += currentItemAmount; + + //Adding the item to a list, so we can remove it later. + itemsTracker.track(new ItemStack(type, currentItemAmount, data)); + } catch (Exception ignored) { + } + } + + totalRequiredAmount += requiredAmount; + totalItemAmount += itemAmount; + } + + progress = Math.max(progress, (double) totalItemAmount / totalRequiredAmount); + + return progress; + } + + @Override + public int getProgressValue(SuperiorPlayer superiorPlayer) { + Player player = superiorPlayer.asPlayer(); + + if (player == null) + return 0; + + Inventory inventory = player.getInventory(); + Map countedItems = countItems(inventory); + + int totalItemAmount = 0; + + ItemsTracker itemsTracker = getOrCreate(superiorPlayer, s -> new ItemsTracker()); + + if (itemsTracker == null) + return 0; + + for (Map.Entry entry : requiredItems.entrySet()) { + KeyRequirements requirement = entry.getKey(); + int requiredAmount = entry.getValue(); + + int itemAmount = 0; + for (Key item : requirement) { + try { + //Get the amount of the item. + Material type = Material.valueOf(item.getGlobalKey()); + short data = item.getSubKey().isEmpty() ? 0 : Short.parseShort(item.getSubKey()); + int currentItemAmount = countedItems.get(new ItemStack(type, 1, data)); + + //Making sure to not exceed the required item amount + if (itemAmount + currentItemAmount > requiredAmount) + currentItemAmount = requiredAmount - itemAmount; + + //Summing the amount to a global variable + itemAmount += currentItemAmount; + + //Adding the item to a list, so we can remove it later. + itemsTracker.track(new ItemStack(type, currentItemAmount, data)); + } catch (Exception ignored) { + } + } + + totalItemAmount += itemAmount; + } + + return totalItemAmount; + } + + @Override + public void onComplete(SuperiorPlayer superiorPlayer) { + getProgress(superiorPlayer); + ItemsTracker itemsTracker = get(superiorPlayer); + + if (itemsTracker == null) + return; + + Player player = superiorPlayer.asPlayer(); + assert player != null; + + removeItems(player.getInventory(), itemsTracker.getItems().toArray(new ItemStack[0])); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onItemPickup(PlayerPickupItemEvent e) { + ItemStack itemStack = e.getItem().getItemStack(); + handleItemPickup(e.getPlayer(), e.getItem().getItemStack()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryClick(InventoryClickEvent e) { + if (!(e.getWhoClicked() instanceof Player) || e.getClickedInventory() == null || + e.getClickedInventory().getType() != InventoryType.CHEST || e.getClick() != ClickType.SHIFT_LEFT) + return; + + handleItemPickup((Player) e.getWhoClicked(), e.getCurrentItem()); + } + + private void handleItemPickup(Player player, @Nullable ItemStack itemStack) { + if (!isMissionItem(itemStack)) + return; + + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(player); + + if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) + return; + + Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> superiorPlayer.runIfOnline(unused -> { + if (canComplete(superiorPlayer)) + this.plugin.getMissions().rewardMission(this, superiorPlayer, true); + }), 2L); + } + + private boolean isMissionItem(@Nullable ItemStack itemStack) { + if (itemStack == null) + return false; + + for (KeyRequirements requirement : requiredItems.keySet()) { + if (requirement.contains(Key.of(itemStack))) + return true; + } + + return false; + } + + private static Map countItems(Inventory inventory) { + Map countedItems = new HashMap<>(); + + Arrays.stream(inventory.getContents()).filter(Objects::nonNull).forEach(itemStack -> { + ItemStack key = itemStack.clone(); + key.setAmount(1); + countedItems.put(key, countedItems.getOrDefault(key, 0) + itemStack.getAmount()); + }); + + return countedItems; + } + + private static void removeItems(PlayerInventory inventory, ItemStack... itemStacks) { + Collection leftOvers = inventory.removeItem(itemStacks).values(); + + if (leftOvers.isEmpty()) + return; + + // We try to remove the item from the offhand as well. + + ItemStack offHandItem; + + try { + offHandItem = inventory.getItem(40); + } catch (Exception ignored) { + return; + } + + if (offHandItem != null && offHandItem.getType() != Material.AIR) { + for (ItemStack itemStack : leftOvers) { + if (offHandItem.isSimilar(itemStack)) { + if (offHandItem.getAmount() > itemStack.getAmount()) { + offHandItem.setAmount(offHandItem.getAmount() - itemStack.getAmount()); + } else { + itemStack.setAmount(itemStack.getAmount() - offHandItem.getAmount()); + inventory.setItem(40, new ItemStack(Material.AIR)); + } + } + } + } + } + + public static class ItemsTracker { + + private final Set itemsTracker = new HashSet<>(); + + void track(ItemStack itemStack) { + itemsTracker.add(itemStack.clone()); + } + + Set getItems() { + return itemsTracker; + } + + } + +} diff --git a/Missions/KillsMissions/build.gradle b/Missions/KillsMissions/build.gradle new file mode 100644 index 0000000000..749f13ebe7 --- /dev/null +++ b/Missions/KillsMissions/build.gradle @@ -0,0 +1,10 @@ +group 'Missions:KillsMissions' + +dependencies { + compileOnly "org.spigotmc:v1_8_R3-Taco:latest" + compileOnly 'com.bgsoftware:WildStackerAPI:3.6.3' +} + +shadowJar { + relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.kills' +} \ No newline at end of file diff --git a/Missions/KillsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/KillsMissions.java b/Missions/KillsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/KillsMissions.java new file mode 100644 index 0000000000..b0e2cdffe6 --- /dev/null +++ b/Missions/KillsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/KillsMissions.java @@ -0,0 +1,218 @@ +package com.bgsoftware.superiorskyblock.missions; + +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; +import com.bgsoftware.superiorskyblock.missions.common.Placeholders; +import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; +import com.bgsoftware.superiorskyblock.missions.common.tracker.KeyDataTracker; +import com.bgsoftware.wildstacker.api.WildStackerAPI; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.entity.Projectile; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.projectiles.ProjectileSource; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.function.Function; + +public final class KillsMissions extends BuiltinMission implements Listener { + + private final Map requiredEntities = new LinkedHashMap<>(); + + private Function getEntityCount; + + @Override + protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { + ConfigurationSection requiredEntitiesSection = section.getConfigurationSection("required-entities"); + + if (requiredEntitiesSection == null) + throw new MissionLoadException("You must have the \"required-entities\" section in the config."); + + for (String key : requiredEntitiesSection.getKeys(false)) { + KeySet entityTypes = KeySet.createKeySet(); + section.getStringList("required-entities." + key + ".types").forEach(entityTypeName -> + entityTypes.add(Key.ofEntityType(entityTypeName.toUpperCase(Locale.ENGLISH)))); + int requiredAmount = section.getInt("required-entities." + key + ".amount"); + requiredEntities.put(new KeyRequirements(entityTypes), requiredAmount); + } + } + + @Override + protected void registerListeners() { + registerListener(this); + + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { + if (plugin.getServer().getPluginManager().isPluginEnabled("WildStacker")) { + this.getEntityCount = WildStackerAPI::getEntityAmount; + } else { + this.getEntityCount = entity -> 1; + } + }, 1L); + } + + @Override + protected void clearModuleData(KeyDataTracker data) { + data.clear(); + } + + @Override + public double getProgress(SuperiorPlayer superiorPlayer) { + KeyDataTracker killsTracker = get(superiorPlayer); + + if (killsTracker == null) + return 0.0; + + int requiredEntities = 0; + int kills = 0; + + for (Map.Entry requiredEntity : this.requiredEntities.entrySet()) { + requiredEntities += requiredEntity.getValue(); + kills += Math.min(killsTracker.getCounts(requiredEntity.getKey()), requiredEntity.getValue()); + } + + return (double) kills / requiredEntities; + } + + @Override + public int getProgressValue(SuperiorPlayer superiorPlayer) { + KeyDataTracker killsTracker = get(superiorPlayer); + + if (killsTracker == null) + return 0; + + int kills = 0; + + for (Map.Entry requiredEntity : this.requiredEntities.entrySet()) + kills += Math.min(killsTracker.getCounts(requiredEntity.getKey()), requiredEntity.getValue()); + + return kills; + } + + @Override + public void saveProgress(ConfigurationSection section) { + for (Map.Entry entry : entrySet()) { + String uuid = entry.getKey().getUniqueId().toString(); + entry.getValue().getCounts().forEach((killedType, count) -> + section.set(uuid + "." + killedType, count.get())); + } + } + + @Override + public void loadProgress(ConfigurationSection section) { + for (String uuid : section.getKeys(false)) { + KeyDataTracker killsTracker = new KeyDataTracker(); + UUID playerUUID = UUID.fromString(uuid); + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(playerUUID); + + insertData(superiorPlayer, killsTracker); + + for (String key : section.getConfigurationSection(uuid).getKeys(false)) { + killsTracker.load(Key.ofEntityType(key), section.getInt(uuid + "." + key)); + } + } + } + + @Override + public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { + KeyDataTracker killsTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); + + if (killsTracker == null) + return; + + ItemMeta itemMeta = itemStack.getItemMeta(); + + if (itemMeta == null) + return; + + if (itemMeta.hasDisplayName()) + itemMeta.setDisplayName(Placeholders.parseKeyPlaceholders(this.requiredEntities, killsTracker, itemMeta.getDisplayName(), false)); + + if (itemMeta.hasLore()) { + List lore = new ArrayList<>(); + for (String line : Objects.requireNonNull(itemMeta.getLore())) + lore.add(Placeholders.parseKeyPlaceholders(this.requiredEntities, killsTracker, line, false)); + itemMeta.setLore(lore); + } + + itemStack.setItemMeta(itemMeta); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onEntityKill(EntityDeathEvent e) { + if (!isMissionEntity(e.getEntity())) + return; + + EntityDamageEvent damageCause = e.getEntity().getLastDamageCause(); + + if (!(damageCause instanceof EntityDamageByEntityEvent)) + return; + + EntityDamageByEntityEvent entityDamageByEntityEvent = (EntityDamageByEntityEvent) damageCause; + + Player damager = null; + + if (entityDamageByEntityEvent.getDamager() instanceof Player) { + damager = (Player) entityDamageByEntityEvent.getDamager(); + } else if (entityDamageByEntityEvent.getDamager() instanceof Projectile) { + ProjectileSource shooter = ((Projectile) entityDamageByEntityEvent.getDamager()).getShooter(); + if (shooter instanceof Player) + damager = (Player) shooter; + } + + if (damager == null) + return; + + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(damager); + + if (!this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) + return; + + KeyDataTracker killsTracker = getOrCreate(superiorPlayer, s -> new KeyDataTracker()); + + if (killsTracker == null) + return; + + killsTracker.track(Key.of(e.getEntity()), this.getEntityCount.apply(e.getEntity())); + + Bukkit.getScheduler().runTaskLaterAsynchronously(this.plugin, () -> superiorPlayer.runIfOnline(player -> { + if (canComplete(superiorPlayer)) + this.plugin.getMissions().rewardMission(this, superiorPlayer, true); + }), 2L); + } + + private boolean isMissionEntity(@Nullable Entity entity) { + if (entity == null || entity instanceof ArmorStand) + return false; + + Key entityKey = Key.of(entity); + + for (KeyRequirements requirement : requiredEntities.keySet()) { + if (requirement.contains(entityKey)) + return true; + } + + return false; + } + +} diff --git a/Missions/StatisticsMissions/build.gradle b/Missions/StatisticsMissions/build.gradle new file mode 100644 index 0000000000..763c3e926e --- /dev/null +++ b/Missions/StatisticsMissions/build.gradle @@ -0,0 +1,9 @@ +group 'Missions:StatisticsMissions' + +dependencies { + compileOnly "org.spigotmc:v1_8_R3-Taco:latest" +} + +shadowJar { + relocate 'com.bgsoftware.superiorskyblock.missions.common', 'com.bgsoftware.superiorskyblock.missions.statistics' +} \ No newline at end of file diff --git a/Missions/StatisticsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/StatisticsMissions.java b/Missions/StatisticsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/StatisticsMissions.java new file mode 100644 index 0000000000..1d086365de --- /dev/null +++ b/Missions/StatisticsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/StatisticsMissions.java @@ -0,0 +1,248 @@ +package com.bgsoftware.superiorskyblock.missions; + +import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.missions.common.BuiltinMission; +import com.bgsoftware.superiorskyblock.missions.common.Placeholders; +import com.bgsoftware.superiorskyblock.missions.common.requirements.Requirements; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.Statistic; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerStatisticIncrementEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.OptionalInt; + +public final class StatisticsMissions extends BuiltinMission implements Listener { + + private final Map requiredStatistics = new LinkedHashMap<>(); + + @Override + protected void loadConfiguration(ConfigurationSection section) throws MissionLoadException { + ConfigurationSection requiredStatisticsSection = section.getConfigurationSection("required-statistics"); + + if (requiredStatisticsSection == null) + throw new MissionLoadException("You must have the \"required-blocks\" section in the config."); + + for (String key : requiredStatisticsSection.getKeys(false)) { + List statistics = section.getStringList("required-statistics." + key + ".statistics"); + int requiredAmount = section.getInt("required-statistics." + key + ".amount"); + requiredStatistics.put(new Requirements(statistics), requiredAmount); + } + } + + @Override + protected void registerListeners() { + registerListener(this); + } + + @Override + protected void clearModuleData(Void data) { + // Do nothing + } + + @Override + public double getProgress(SuperiorPlayer superiorPlayer) { + double progress = 0.0; + int totalRequiredAmount = 0; + int totalItemAmount = 0; + Player player = superiorPlayer.asPlayer(); + + if (player == null) + return progress; + + for (Map.Entry entry : this.requiredStatistics.entrySet()) { + Requirements requirement = entry.getKey(); + int requiredAmount = entry.getValue(); + + int statisticAmount = 0; + for (String statistic : requirement) { + OptionalInt currentStatisticAmountOptional = getStatisticAmount(player, statistic); + + if (!currentStatisticAmountOptional.isPresent()) + continue; + + int currentStatisticAmount = currentStatisticAmountOptional.getAsInt(); + + //Making sure to not exceed the required item amount + if (statisticAmount + currentStatisticAmount > requiredAmount) + currentStatisticAmount = requiredAmount - statisticAmount; + + //Summing the amount to a global variable + statisticAmount += currentStatisticAmount; + } + + totalRequiredAmount += requiredAmount; + totalItemAmount += statisticAmount; + } + + progress = Math.max(progress, (double) totalItemAmount / totalRequiredAmount); + + return progress; + } + + @Override + public int getProgressValue(SuperiorPlayer superiorPlayer) { + int totalItemAmount = 0; + + Player player = superiorPlayer.asPlayer(); + if (player == null) + return totalItemAmount; + + for (Map.Entry entry : this.requiredStatistics.entrySet()) { + Requirements requirement = entry.getKey(); + int requiredAmount = entry.getValue(); + + int statisticAmount = 0; + for (String statistic : requirement) { + OptionalInt currentItemAmountOptional = getStatisticAmount(player, statistic); + + if (!currentItemAmountOptional.isPresent()) + continue; + + int currentItemAmount = currentItemAmountOptional.getAsInt(); + + //Making sure to not exceed the required item amount + if (statisticAmount + currentItemAmount > requiredAmount) + currentItemAmount = requiredAmount - statisticAmount; + + //Summing the amount to a global variable + statisticAmount += currentItemAmount; + } + + totalItemAmount += statisticAmount; + } + + return totalItemAmount; + } + + @Override + public void formatItem(SuperiorPlayer superiorPlayer, ItemStack itemStack) { + Player player = superiorPlayer.asPlayer(); + + if (player == null) + return; + + ItemMeta itemMeta = itemStack.getItemMeta(); + + if (itemMeta == null) + return; + + Placeholders.PlaceholdersFunctions placeholdersFunctions = new Placeholders.PlaceholdersFunctions() { + @Override + public Requirements getRequirementFromKey(String key) { + for (Requirements requirements : requiredStatistics.keySet()) { + if (requirements.contains(key)) + return requirements; + } + + return null; + } + + @Override + public Optional lookupRequirement(Requirements requirement) { + return Optional.ofNullable(requiredStatistics.get(requirement)); + } + + @Override + public int getCountForRequirement(Requirements requirement) { + int statisticAmount = 0; + + for (String statistic : requirement) { + OptionalInt currentItemAmountOptional = getStatisticAmount(player, statistic); + + if (currentItemAmountOptional.isPresent()) + statisticAmount += currentItemAmountOptional.getAsInt(); + } + + return statisticAmount; + } + }; + + if (itemMeta.hasDisplayName()) + itemMeta.setDisplayName(Placeholders.parsePlaceholders(itemMeta.getDisplayName(), placeholdersFunctions)); + + if (itemMeta.hasLore()) { + List lore = new ArrayList<>(); + for (String line : Objects.requireNonNull(itemMeta.getLore())) + lore.add(Placeholders.parsePlaceholders(line, placeholdersFunctions)); + itemMeta.setLore(lore); + } + + itemStack.setItemMeta(itemMeta); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onPlayerStatistic(PlayerStatisticIncrementEvent e) { + SuperiorPlayer superiorPlayer = this.plugin.getPlayers().getSuperiorPlayer(e.getPlayer()); + + if (!isMissionStatistic(e.getStatistic()) || !this.plugin.getMissions().canCompleteNoProgress(superiorPlayer, this)) + return; + + Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, () -> superiorPlayer.runIfOnline(player -> { + if (canComplete(superiorPlayer)) + this.plugin.getMissions().rewardMission(this, superiorPlayer, true); + }), 2L); + } + + private boolean isMissionStatistic(@Nullable Statistic statistic) { + if (statistic == null) + return false; + + for (Requirements requirement : requiredStatistics.keySet()) { + if (requirement.contains(statistic.name()) || (statistic.isSubstatistic() && + requirement.stream().anyMatch(line -> line.contains(statistic.name())))) + return true; + } + + return false; + } + + private static OptionalInt getStatisticAmount(Player player, String statisticsString) { + String[] sections = statisticsString.split(":"); + OptionalInt currentStatisticAmount = OptionalInt.empty(); + + try { + Statistic statistic = Statistic.valueOf(sections[0]); + + if (sections.length == 1) { + currentStatisticAmount = OptionalInt.of(player.getStatistic(statistic)); + } else if (sections.length == 2) { + Material material = getEnumSafe(Material.class, sections[1]); + if (material != null) { + currentStatisticAmount = OptionalInt.of(player.getStatistic(statistic, material)); + } else { + EntityType entityType = getEnumSafe(EntityType.class, sections[1]); + if (entityType != null) + currentStatisticAmount = OptionalInt.of(player.getStatistic(statistic, entityType)); + } + } + } catch (Exception ignored) { + } + + return currentStatisticAmount; + } + + private static > T getEnumSafe(Class clazz, String name) { + try { + return Enum.valueOf(clazz, name); + } catch (Throwable ex) { + return null; + } + } + +} diff --git a/Missions/build.gradle b/Missions/build.gradle new file mode 100644 index 0000000000..b2ff06f3d4 --- /dev/null +++ b/Missions/build.gradle @@ -0,0 +1,15 @@ +group 'Missions' + +subprojects { + dependencies { + implementation project(":Missions") + compileOnly project(":API") + compileOnly project(":") + } +} + +dependencies { + compileOnly "org.spigotmc:v1_8_R3-Taco:latest" + compileOnly project(":API") + compileOnly project(":") +} \ No newline at end of file diff --git a/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/BuiltinMission.java b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/BuiltinMission.java new file mode 100644 index 0000000000..6bd4ee8876 --- /dev/null +++ b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/BuiltinMission.java @@ -0,0 +1,58 @@ +package com.bgsoftware.superiorskyblock.missions.common; + +import com.bgsoftware.superiorskyblock.api.SuperiorSkyblock; +import com.bgsoftware.superiorskyblock.api.missions.Mission; +import com.bgsoftware.superiorskyblock.api.missions.MissionLoadException; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.LinkedList; +import java.util.List; + +public abstract class BuiltinMission extends Mission { + + private final List registeredListeners = new LinkedList<>(); + + protected SuperiorSkyblock plugin; + + @Override + public final void load(JavaPlugin plugin, ConfigurationSection section) throws MissionLoadException { + this.plugin = (SuperiorSkyblock) plugin; + + loadConfiguration(section); + registerListeners(); + + setClearMethod(this::clearModuleData); + } + + protected abstract void loadConfiguration(ConfigurationSection section) throws MissionLoadException; + + protected abstract void registerListeners(); + + protected abstract void clearModuleData(V data); + + protected final void registerListener(Listener listener) { + Bukkit.getPluginManager().registerEvents(listener, plugin); + this.registeredListeners.add(listener); + } + + @Override + public void onComplete(SuperiorPlayer superiorPlayer) { + + } + + @Override + public void onCompleteFail(SuperiorPlayer superiorPlayer) { + + } + + public final void unload() { + this.registeredListeners.forEach(HandlerList::unregisterAll); + this.registeredListeners.clear(); + } + +} diff --git a/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/Placeholders.java b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/Placeholders.java new file mode 100644 index 0000000000..5d940d092f --- /dev/null +++ b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/Placeholders.java @@ -0,0 +1,140 @@ +package com.bgsoftware.superiorskyblock.missions.common; + +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; +import com.bgsoftware.superiorskyblock.missions.common.requirements.Requirements; +import com.bgsoftware.superiorskyblock.missions.common.tracker.DataTracker; +import org.bukkit.ChatColor; + +import javax.annotation.Nullable; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Placeholders { + + private static final Pattern PERCENTAGE_PATTERN = Pattern.compile("\\{percentage_(.+?)}"); + private static final Pattern VALUES_PATTERN = Pattern.compile("\\{value_(.+?)}"); + + private static final Function MATERIAL_KEY_CREATION = Key::ofMaterialAndData; + private static final Function ENTITY_KEY_CREATION = Key::ofEntityType; + + private Placeholders() { + + } + + public static String parseKeyPlaceholders(Map requirements, + DataTracker dataTracker, + String line, boolean isMaterial) { + Function creationMethod; + + if (isMaterial) { + creationMethod = MATERIAL_KEY_CREATION; + } else { + creationMethod = ENTITY_KEY_CREATION; + } + + return parsePlaceholders(line, new PlaceholdersFunctions() { + @Override + public KeyRequirements getRequirementFromKey(String key) { + Key requirementKey = creationMethod.apply(key); + + for (KeyRequirements requirements : requirements.keySet()) { + if (requirements.contains(requirementKey)) { + return requirements; + } + } + + return null; + } + + @Override + public Optional lookupRequirement(KeyRequirements requirementsKey) { + return Optional.ofNullable(requirements.get(requirementsKey)); + } + + @Override + public int getCountForRequirement(KeyRequirements requirementsKey) { + int totalCount = 0; + + for (Key requirementKey : requirementsKey) { + totalCount += dataTracker.getCount(requirementKey); + } + + return totalCount; + } + }); + } + + public static String parsePlaceholders(Map requirements, DataTracker dataTracker, String line) { + return parsePlaceholders(line, new PlaceholdersFunctions() { + @Override + public Requirements getRequirementFromKey(String key) { + for (Requirements requirements : requirements.keySet()) { + if (requirements.contains(key)) + return requirements; + } + + return null; + } + + @Override + public Optional lookupRequirement(Requirements requirementsKey) { + return Optional.ofNullable(requirements.get(requirementsKey)); + } + + @Override + public int getCountForRequirement(Requirements requirementsKey) { + int totalCount = 0; + + for (String requirementKey : requirementsKey) { + totalCount += dataTracker.getCount(requirementKey); + } + + return totalCount; + } + }); + } + + public static String parsePlaceholders(String line, PlaceholdersFunctions functions) { + Matcher matcher = PERCENTAGE_PATTERN.matcher(line); + if (matcher.find()) { + String requirementKey = matcher.group(1).toUpperCase(Locale.ENGLISH); + E requirement = functions.getRequirementFromKey(requirementKey); + Optional entry = requirement == null ? Optional.empty() : functions.lookupRequirement(requirement); + + if (entry.isPresent()) { + int count = Math.min(functions.getCountForRequirement(requirement), entry.get()); + line = matcher.replaceAll("" + (count * 100) / entry.get()); + } + } + + if ((matcher = VALUES_PATTERN.matcher(line)).find()) { + String requirementKey = matcher.group(1).toUpperCase(Locale.ENGLISH); + E requirement = functions.getRequirementFromKey(requirementKey); + Optional entry = requirement == null ? Optional.empty() : functions.lookupRequirement(requirement); + + if (entry.isPresent()) { + int count = Math.min(functions.getCountForRequirement(requirement), entry.get()); + line = matcher.replaceAll(String.valueOf(count)); + } + } + + return ChatColor.translateAlternateColorCodes('&', line); + } + + public static abstract class PlaceholdersFunctions { + + @Nullable + public abstract E getRequirementFromKey(String key); + + public abstract Optional lookupRequirement(E requirement); + + public abstract int getCountForRequirement(E requirement); + + } + +} diff --git a/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/CustomRequirements.java b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/CustomRequirements.java new file mode 100644 index 0000000000..d9f631feb9 --- /dev/null +++ b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/CustomRequirements.java @@ -0,0 +1,22 @@ +package com.bgsoftware.superiorskyblock.missions.common.requirements; + +import java.util.Collection; +import java.util.LinkedHashSet; + +public class CustomRequirements extends RequirementsAbstract { + + public CustomRequirements() { + super(new LinkedHashSet<>()); + } + + public CustomRequirements(Collection elements) { + this(); + addAll(elements); + } + + @Override + protected boolean isAllElement(E element) { + return false; + } + +} diff --git a/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/IRequirements.java b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/IRequirements.java new file mode 100644 index 0000000000..1977063184 --- /dev/null +++ b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/IRequirements.java @@ -0,0 +1,9 @@ +package com.bgsoftware.superiorskyblock.missions.common.requirements; + +import java.util.Set; + +public interface IRequirements extends Set { + + boolean isContainsAll(); + +} diff --git a/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/KeyRequirements.java b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/KeyRequirements.java new file mode 100644 index 0000000000..0536da1c74 --- /dev/null +++ b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/KeyRequirements.java @@ -0,0 +1,25 @@ +package com.bgsoftware.superiorskyblock.missions.common.requirements; + +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeySet; + +import java.util.Collection; +import java.util.LinkedHashSet; + +public class KeyRequirements extends RequirementsAbstract { + + public KeyRequirements(Collection elements) { + super(KeySet.createKeySet(LinkedHashSet::new)); + addAll(elements); + } + + @Override + protected boolean isAllElement(Key element) { + return element.getGlobalKey().equalsIgnoreCase("ALL"); + } + + public Key getKey(Key original) { + return ((KeySet) delegate()).getKey(original, original); + } + +} diff --git a/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/Requirements.java b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/Requirements.java new file mode 100644 index 0000000000..2aac4cc9eb --- /dev/null +++ b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/Requirements.java @@ -0,0 +1,17 @@ +package com.bgsoftware.superiorskyblock.missions.common.requirements; + +import java.util.Collection; +import java.util.LinkedHashSet; + +public class Requirements extends RequirementsAbstract { + + public Requirements(Collection elements) { + super(new LinkedHashSet<>()); + addAll(elements); + } + + @Override + protected boolean isAllElement(String element) { + return element.equalsIgnoreCase("all"); + } +} diff --git a/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/RequirementsAbstract.java b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/RequirementsAbstract.java new file mode 100644 index 0000000000..e36df14131 --- /dev/null +++ b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/requirements/RequirementsAbstract.java @@ -0,0 +1,45 @@ +package com.bgsoftware.superiorskyblock.missions.common.requirements; + +import com.google.common.collect.ForwardingSet; + +import java.util.Set; + +public abstract class RequirementsAbstract extends ForwardingSet implements IRequirements { + + private final Set handle; + private boolean containsAll = false; + + public RequirementsAbstract(Set handle) { + this.handle = handle; + } + + @Override + public boolean add(E element) { + if (containsAll) + return true; + + if (isAllElement(element)) { + this.containsAll = true; + return true; + } + + return super.add(element); + } + + @Override + public boolean contains(Object object) { + return isContainsAll() || super.contains(object); + } + + public boolean isContainsAll() { + return this.containsAll; + } + + @Override + protected Set delegate() { + return this.handle; + } + + protected abstract boolean isAllElement(E element); + +} diff --git a/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/DataTracker.java b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/DataTracker.java new file mode 100644 index 0000000000..c538b1d6ed --- /dev/null +++ b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/DataTracker.java @@ -0,0 +1,54 @@ +package com.bgsoftware.superiorskyblock.missions.common.tracker; + +import com.bgsoftware.superiorskyblock.core.Counter; +import com.bgsoftware.superiorskyblock.missions.common.requirements.IRequirements; + +import java.util.Collections; +import java.util.Map; +import java.util.Optional; + +public abstract class DataTracker> { + + private final Map trackedData; + private final Counter globalCounter = new Counter(0); + + protected DataTracker(Map trackedData) { + this.trackedData = trackedData; + } + + public void track(K key, int amount) { + this.trackedData.computeIfAbsent(key, k -> new Counter(0)).inc(amount); + globalCounter.inc(amount); + } + + public void load(K blockKey, int amount) { + this.trackedData.put(blockKey, new Counter(amount)); + globalCounter.inc(amount); + } + + public int getCount(K blockKey) { + return Optional.ofNullable(this.trackedData.get(blockKey)).map(Counter::get).orElse(0); + } + + public int getGlobalCounter() { + return this.globalCounter.get(); + } + + public int getCounts(R blocks) { + if (blocks.isContainsAll()) + return getGlobalCounter(); + + Counter blocksCount = new Counter(0); + blocks.forEach(block -> blocksCount.inc(getCount(block))); + return blocksCount.get(); + } + + public void clear() { + this.trackedData.clear(); + } + + public Map getCounts() { + return Collections.unmodifiableMap(this.trackedData); + } + +} diff --git a/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/KeyDataTracker.java b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/KeyDataTracker.java new file mode 100644 index 0000000000..fc6b324803 --- /dev/null +++ b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/KeyDataTracker.java @@ -0,0 +1,13 @@ +package com.bgsoftware.superiorskyblock.missions.common.tracker; + +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.missions.common.requirements.KeyRequirements; + +public class KeyDataTracker extends DataTracker { + + public KeyDataTracker() { + super(KeyMap.createKeyMap()); + } + +} diff --git a/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/RawDataTracker.java b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/RawDataTracker.java new file mode 100644 index 0000000000..1969a04b96 --- /dev/null +++ b/Missions/src/main/java/com/bgsoftware/superiorskyblock/missions/common/tracker/RawDataTracker.java @@ -0,0 +1,13 @@ +package com.bgsoftware.superiorskyblock.missions.common.tracker; + +import com.bgsoftware.superiorskyblock.missions.common.requirements.Requirements; + +import java.util.HashMap; + +public class RawDataTracker extends DataTracker { + + public RawDataTracker() { + super(new HashMap<>()); + } + +} diff --git a/build.gradle b/build.gradle index 3fe0df86ae..cad7c9cb02 100644 --- a/build.gradle +++ b/build.gradle @@ -116,6 +116,19 @@ shadowJar { } } + def missionsProject = project(':Missions'); + + missionsProject.subprojects.forEach { sub -> + def shadowJarTask = sub.tasks.named("shadowJar") + dependsOn(shadowJarTask) + + from(shadowJarTask.map { it.archiveFile }) { + exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' + rename { sub.name } + into("modules/missions") + } + } + dependencies { // This includes the API and all sub-modules in the final JAR include project(':API') diff --git a/settings.gradle b/settings.gradle index f801f82b6b..4cf22939ad 100644 --- a/settings.gradle +++ b/settings.gradle @@ -52,6 +52,17 @@ include 'Hooks:UltimateStacker4' include 'Hooks:VanishNoPacket' include 'Hooks:Vault' include 'Hooks:WildStacker' +include 'Missions' +include 'Missions:BlocksMissions' +include 'Missions:BrewingMissions' +include 'Missions:CraftingMissions' +include 'Missions:EnchantingMissions' +include 'Missions:FarmingMissions' +include 'Missions:FishingMissions' +include 'Missions:IslandMissions' +include 'Missions:ItemsMissions' +include 'Missions:KillsMissions' +include 'Missions:StatisticsMissions' include 'NMS' include 'NMS:Spigot' include 'NMS:Spigot-1_20_3' diff --git a/src/main/resources/modules/missions/BlocksMissions b/src/main/resources/modules/missions/BlocksMissions deleted file mode 100644 index f1b7a9b210f4cc15fefcdffed622ecd5b35bf345..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41443 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�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 diff --git a/src/main/resources/modules/missions/BrewingMissions b/src/main/resources/modules/missions/BrewingMissions deleted file mode 100644 index 963518f4821c5a1c906f067f04071a455b8c2e72..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30011 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 XY8Z$T843yw;-!s?f}&t}`ssfFKoA{c diff --git a/src/main/resources/modules/missions/EnchantingMissions b/src/main/resources/modules/missions/EnchantingMissions deleted file mode 100644 index af297de64af6b1e8fae1d428d0650ba3a00fabeb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30075 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

  1. =Alrm`;i&!h{c=LRAbklv&JghxeQ6O) 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%0Agk!8Ohz?>sf@Y)7~_MgZIlm6Ni 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 diff --git a/src/main/resources/modules/missions/StatisticsMissions b/src/main/resources/modules/missions/StatisticsMissions deleted file mode 100644 index 1823a51d0be6b67dad564ef8eb6da14a5b043095..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24470 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 From 7d76ad79fd87b3b13ba8dda9d9c867463b78be8a Mon Sep 17 00:00:00 2001 From: Michael Bowerman Date: Fri, 17 Apr 2026 12:22:41 -0400 Subject: [PATCH 540/600] Add Plan integration (#2882) --- Hooks/Plan/build.gradle | 23 +++ .../superiorskyblock/external/PlanHook.java | 160 ++++++++++++++++++ gradle.properties | 1 + settings.gradle | 1 + .../external/ProvidersManagerImpl.java | 3 + 5 files changed, 188 insertions(+) create mode 100644 Hooks/Plan/build.gradle create mode 100644 Hooks/Plan/src/main/java/com/bgsoftware/superiorskyblock/external/PlanHook.java diff --git a/Hooks/Plan/build.gradle b/Hooks/Plan/build.gradle new file mode 100644 index 0000000000..5605774da6 --- /dev/null +++ b/Hooks/Plan/build.gradle @@ -0,0 +1,23 @@ +group 'Hooks:Plan' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(8) + } +} + +repositories { + maven { url 'https://jitpack.io' } +} + +dependencies { + compileOnly project(":API") + compileOnly rootProject + compileOnly 'org.spigotmc:v1_8_R3-Taco:latest' + compileOnly 'com.github.plan-player-analytics:Plan:5.7.3232' +} + +if (project.hasProperty('hook.compile_plan') && + !Boolean.valueOf(project.findProperty("hook.compile_plan").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/Hooks/Plan/src/main/java/com/bgsoftware/superiorskyblock/external/PlanHook.java b/Hooks/Plan/src/main/java/com/bgsoftware/superiorskyblock/external/PlanHook.java new file mode 100644 index 0000000000..3bb70a5188 --- /dev/null +++ b/Hooks/Plan/src/main/java/com/bgsoftware/superiorskyblock/external/PlanHook.java @@ -0,0 +1,160 @@ +package com.bgsoftware.superiorskyblock.external; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.island.top.SortingTypes; +import com.djrapitops.plan.capability.CapabilityService; +import com.djrapitops.plan.extension.DataExtension; +import com.djrapitops.plan.extension.ExtensionService; +import com.djrapitops.plan.extension.annotation.NumberProvider; +import com.djrapitops.plan.extension.annotation.PluginInfo; +import com.djrapitops.plan.extension.annotation.TableProvider; +import com.djrapitops.plan.extension.icon.Color; +import com.djrapitops.plan.extension.icon.Icon; +import com.djrapitops.plan.extension.table.Table; + +import java.math.BigDecimal; +import java.util.List; + +public class PlanHook { + + public static void register(SuperiorSkyblockPlugin plugin) { + try { + Log.info("Plan detected - attempting to register SuperiorSkyblock DataExtension."); + + if (CapabilityService.getInstance().hasCapability("DATA_EXTENSION_VALUES")) { + ExtensionService.getInstance().register(new PlanDataExtension(plugin)); + Log.info("Registered SuperiorSkyblock Plan DataExtension."); + } else { + Log.warn("Plan installed but DataExtension capability not available - skipping registration."); + } + } catch (Throwable t) { + Log.error(t, "Failed to initialize Plan integration:"); + } + } + + private PlanHook() { + } + + @PluginInfo(name = "SuperiorSkyblock") + private static class PlanDataExtension implements DataExtension { + + private final SuperiorSkyblockPlugin plugin; + + PlanDataExtension(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + } + + @NumberProvider( + text = "Total Islands", + description = "Total number of islands on the server", + priority = 100 + ) + public long islandCount() { + return plugin.getGrid().getIslandsContainer().getIslandsAmount(); + } + + @NumberProvider( + text = "Total Island Level", + description = "Sum of all island levels", + priority = 90 + ) + public long totalLevel() { + return plugin.getGrid().getTotalLevel().toBigInteger().longValue(); + } + + @NumberProvider( + text = "Total Island Worth", + description = "Sum of all island worths", + priority = 80 + ) + public long totalWorth() { + return plugin.getGrid().getTotalWorth().toBigInteger().longValue(); + } + + @NumberProvider( + text = "Active Islands", + description = "Islands that currently have visitors", + priority = 70 + ) + public long activeIslands() { + return plugin.getGrid().getIslands().stream() + .filter(island -> !island.getIslandVisitors().isEmpty()) + .count(); + } + + @NumberProvider( + text = "Islands With Bank Balance", + description = "Islands that have money in their bank", + priority = 60 + ) + public long islandsWithBankBalance() { + return plugin.getGrid().getIslands().stream() + .filter(island -> island.getIslandBank() != null + && island.getIslandBank().getBalance().compareTo(BigDecimal.ZERO) > 0) + .count(); + } + + @NumberProvider( + text = "Average Island Level", + description = "Average level across all islands", + priority = 50 + ) + public long averageIslandLevel() { + List islands = plugin.getGrid().getIslands(); + if (islands.isEmpty()) + return 0L; + + BigDecimal sum = BigDecimal.ZERO; + int count = 0; + for (Island island : islands) { + BigDecimal lvl = island.getIslandLevel(); + if (lvl != null) { + sum = sum.add(lvl); + count++; + } + } + + if (count == 0) + return 0L; + + return sum.divide(BigDecimal.valueOf(count), 0, plugin.getSettings().getIslandLevelRoundingMode()) + .toBigInteger().longValue(); + } + + @TableProvider( + tableColor = Color.GREEN + ) + public Table topIslandsTable() { + List islands = plugin.getGrid().getIslands(SortingTypes.BY_WORTH); + + Table.Factory table = Table.builder() + .columnOne("Pos", Icon.called("list-ol").build()) + .columnTwo("Owner", Icon.called("user").build()) + .columnThree("Island", Icon.called("home").build()) + .columnFour("Level", Icon.called("star").build()) + .columnFive("Worth", Icon.called("coins").build()); + + int pos = 1; + for (Island island : islands) { + if (pos > 25) + break; + + BigDecimal worth = island.getWorth(); + BigDecimal level = island.getIslandLevel(); + String ownerName = island.getOwner() == null ? "" : island.getOwner().getName(); + String islandName = island.getName() == null || island.getName().isEmpty() ? ownerName : island.getName(); + + table.addRow(pos, ownerName, islandName, + level == null ? 0L : level.toBigInteger().longValue(), + worth == null ? 0L : worth.toBigInteger().longValue() + ); + + pos++; + } + + return table.build(); + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 665fb9b2c1..99bb774c2e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -27,6 +27,7 @@ hook.compile_mvdwplaceholderapi=true hook.compile_oraxen=true hook.compile_papermc=true hook.compile_placeholderapi=true +hook.compile_plan=true hook.compile_protocollib=true hook.compile_pvpingspawners=true hook.compile_rosestacker=true diff --git a/settings.gradle b/settings.gradle index 4cf22939ad..674e94e423 100644 --- a/settings.gradle +++ b/settings.gradle @@ -31,6 +31,7 @@ include 'Hooks:MVdWPlaceholderAPI' include 'Hooks:Nexo' include 'Hooks:OpenJdkNashornEngine' include 'Hooks:Oraxen' +include 'Hooks:Plan' include 'Hooks:PaperMC' include 'Hooks:PlaceholderAPI' include 'Hooks:ProtocolLib' diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java index 17572591f9..3f0910bd2d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java @@ -486,6 +486,9 @@ private void registerGeneralHooks() { if (Bukkit.getPluginManager().isPluginEnabled("ItemsAdder")) registerHook("ItemsAdderHook"); + if (canRegisterHook("Plan")) + registerHook("PlanHook"); + if (Bukkit.getPluginManager().isPluginEnabled("CraftEngine")) // We load the hook with an extra delay to let CraftEngine load its data first BukkitExecutor.sync(() -> registerHook("CraftEngineHook"), 5L); From 45186441abe504737500e9bc8476bd281fed59c6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 18 Apr 2026 16:08:33 +0300 Subject: [PATCH 541/600] Adds support to custom world dimensions --- .../api/SuperiorSkyblockAPI.java | 11 -- .../api/config/SettingsManager.java | 29 +++- .../api/handlers/FactoriesManager.java | 9 -- .../api/handlers/GridManager.java | 23 --- .../api/island/DelegateIsland.java | 18 +-- .../superiorskyblock/api/island/Island.java | 46 +++--- .../api/player/DelegateSuperiorPlayer.java | 12 -- .../DelegatePlayerTeleportAlgorithm.java | 7 - .../algorithm/PlayerTeleportAlgorithm.java | 14 -- .../service/dragon/DragonBattleService.java | 25 ---- .../portals/PortalsManagerService.java | 31 +++- .../api/upgrades/UpgradeLevel.java | 17 --- .../superiorskyblock/api/world/Dimension.java | 6 +- .../superiorskyblock/api/world/WorldInfo.java | 14 -- .../api/wrappers/SuperiorPlayer.java | 21 --- .../SuperiorSkyblockPlugin.java | 2 - .../commands/admin/CmdAdminSyncBonus.java | 4 +- .../commands/admin/CmdAdminTeleport.java | 4 +- .../config/SettingsContainer.java | 104 +++++++------ .../config/SettingsManagerImpl.java | 22 ++- .../config/section/WorldsSection.java | 129 +++++++++++------ .../superiorskyblock/core/LegacyMasks.java | 102 ------------- .../core/database/DataManager.java | 17 +-- .../bridge/IslandsDatabaseBridge.java | 12 +- .../core/database/loader/sql/SQLDatabase.java | 4 +- .../sql/upgrade/v3/DatabaseUpgrade_V3.java | 120 +++++++++++++++ .../serialization/IslandsDeserializer.java | 15 ++ .../serialization/IslandsSerializer.java | 9 ++ .../events/plugin/PluginEventsDispatcher.java | 3 +- .../core/factory/FactoriesManagerImpl.java | 8 - .../worlds/WorldsProvider_Default.java | 6 - .../island/GridManagerImpl.java | 15 +- .../superiorskyblock/island/SIsland.java | 26 +--- .../superiorskyblock/island/SpawnIsland.java | 12 -- .../island/builder/IslandBuilderImpl.java | 27 ---- .../island/upgrade/SUpgradeLevel.java | 14 -- .../listener/PortalsListener.java | 27 +++- .../listeners/GeneratorsListener.java | 4 +- .../player/SSuperiorPlayer.java | 13 -- .../player/SuperiorNPCPlayer.java | 13 -- .../DefaultPlayerTeleportAlgorithm.java | 8 - .../dragon/DragonBattleServiceImpl.java | 19 --- .../placeholders/PlaceholdersServiceImpl.java | 72 ++++----- .../portals/PortalsManagerServiceImpl.java | 137 +++++++++++------- .../superiorskyblock/world/Dimensions.java | 41 ++---- src/main/resources/config.yml | 121 +++++++++------- 46 files changed, 651 insertions(+), 742 deletions(-) delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/LegacyMasks.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v3/DatabaseUpgrade_V3.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java index 5c2d152ede..e9d737c61d 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java @@ -179,17 +179,6 @@ public static Island getSpawnIsland() { return plugin.getGrid().getSpawnIsland(); } - /** - * Get the world of an island by the world's environment. - * - * @deprecated See {@link #getIslandsWorld(Island, Dimension)} - */ - @Nullable - @Deprecated - public static World getIslandsWorld(Island island, World.Environment environment) { - return plugin.getGrid().getIslandsWorld(island, environment); - } - /** * Get the world of an island by the world's dimension. */ diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index 92cc5ea875..ab18174bcd 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import org.bukkit.GameMode; import org.bukkit.Location; +import org.bukkit.PortalType; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.potion.PotionEffectType; @@ -1107,19 +1108,28 @@ interface Worlds { /** * All settings related to the overworld world. * Config-path: worlds.normal + * + * @deprecated See {@link #getDimensionConfig(Dimension)} */ + @Deprecated Normal getNormal(); /** * All settings related to the nether world. * Config-path: worlds.nether + * + * @deprecated See {@link #getDimensionConfig(Dimension)} */ + @Deprecated Nether getNether(); /** * All settings related to the end world. * Config-path: worlds.end + * + * @deprecated See {@link #getDimensionConfig(Dimension)} */ + @Deprecated End getEnd(); /** @@ -1145,33 +1155,44 @@ interface DimensionConfig { /** * Whether this dimension is enabled or not. - * Config-path: worlds..enabled + * Config-path: worlds.dimensions..enabled */ boolean isEnabled(); /** * Whether this dimension is unlocked by default or not. - * Config-path: worlds..unlock + * Config-path: worlds.dimensions..unlock */ boolean isUnlocked(); /** * Whether the schematic for this dimension should be offset or not. - * Config-path: worlds..schematic-offset + * Config-path: worlds.dimensions..schematic-offset */ boolean isSchematicOffset(); /** * Get the default biome for this dimension. + * Config-path: worlds.dimensions..biome */ String getBiome(); /** * Get the world's name for this dimension. - * Config-path: worlds..name + * Config-path: worlds.dimensions..name */ String getName(); + /** + * Get the destination of a specific portal type {@link PortalType} + * Config-path: worlds.dimensions..portals + * + * @param portalType The portal type to get + * @return The destination of that portal type, or null if doesn't exist. + */ + @Nullable + Dimension getPortalDestination(PortalType portalType); + } interface Normal extends DimensionConfig { diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java index 11e56d75e0..363434ae29 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/FactoriesManager.java @@ -194,15 +194,6 @@ BankTransaction createTransaction(@Nullable UUID player, BankAction action, int */ WorldInfo createWorldInfo(String worldName, Dimension dimension); - /** - * Create a new world info. - * - * @param worldName The name of the world. - * @param environment The environment of the world. - */ - @Deprecated - WorldInfo createWorldInfo(String worldName, World.Environment environment); - /** * Create a new game sound instance. * diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java index ec8dd17287..7fe48e1d3d 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/handlers/GridManager.java @@ -295,17 +295,6 @@ void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bo @Nullable Dimension getIslandsWorldDimension(World world); - /** - * Get the world of an island by the environment. - * If the environment is not the normal and that environment is disabled in config, null will be returned. - * - * @param environment The world environment. - * @param island The island to check. - */ - @Deprecated - @Nullable - World getIslandsWorld(Island island, World.Environment environment); - /** * Get the {@link WorldInfo} of the world of an island by the dimension. * The world might not be loaded at the time of calling this method. @@ -317,18 +306,6 @@ void createIsland(SuperiorPlayer superiorPlayer, String schemName, BigDecimal bo @Nullable WorldInfo getIslandsWorldInfo(Island island, Dimension dimension); - /** - * Get the {@link WorldInfo} of the world of an island by the environment. - * The world might not be loaded at the time of calling this method. - * - * @param island The island to check. - * @param environment The world environment. - * @return The world info for the given environment, or null if this environment is not enabled. - */ - @Nullable - @Deprecated - WorldInfo getIslandsWorldInfo(Island island, World.Environment environment); - /** * Get the {@link WorldInfo} of the world of an island by its name. * The world might not be loaded at the time of calling this method. diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index d69ec29572..de1c75ef60 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -630,31 +630,37 @@ public boolean isInsideRange(int chunkX, int chunkZ, double extraRadius) { } @Override + @Deprecated public boolean isNormalEnabled() { return this.handle.isNormalEnabled(); } @Override + @Deprecated public void setNormalEnabled(boolean enabled) { this.handle.setNormalEnabled(enabled); } @Override + @Deprecated public boolean isNetherEnabled() { return this.handle.isNetherEnabled(); } @Override + @Deprecated public void setNetherEnabled(boolean enabled) { this.handle.setNetherEnabled(enabled); } @Override + @Deprecated public boolean isEndEnabled() { return this.handle.isEndEnabled(); } @Override + @Deprecated public void setEndEnabled(boolean enabled) { this.handle.setEndEnabled(enabled); } @@ -674,12 +680,6 @@ public Collection getUnlockedWorlds() { return this.handle.getUnlockedWorlds(); } - @Override - @Deprecated - public int getUnlockedWorldsFlag() { - return this.handle.getUnlockedWorldsFlag(); - } - @Override public boolean hasPermission(CommandSender sender, IslandPrivilege islandPrivilege) { return this.handle.hasPermission(sender, islandPrivilege); @@ -1910,12 +1910,6 @@ public void setSchematicGenerate(Dimension dimension, boolean generated) { this.handle.setSchematicGenerate(dimension, generated); } - @Override - @Deprecated - public int getGeneratedSchematicsFlag() { - return this.handle.getGeneratedSchematicsFlag(); - } - @Override public Collection getGeneratedSchematics() { return this.handle.getGeneratedSchematics(); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java index ba4396f4fc..957637b5b7 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/Island.java @@ -941,32 +941,50 @@ List> getAllChunksAsync(Dimension dimension, @IslandChu /** * Is the normal world enabled for the island? + * + * @deprecated See {@link #isDimensionEnabled(Dimension)} */ + @Deprecated boolean isNormalEnabled(); /** * Enable/disable the normal world for the island. + * + * @deprecated See {@link #setDimensionEnabled(Dimension, boolean)} */ + @Deprecated void setNormalEnabled(boolean enabled); /** * Is the nether world enabled for the island? + * + * @deprecated See {@link #isDimensionEnabled(Dimension)} */ + @Deprecated boolean isNetherEnabled(); /** * Enable/disable the nether world for the island. + * + * @deprecated See {@link #setDimensionEnabled(Dimension, boolean)} */ + @Deprecated void setNetherEnabled(boolean enabled); /** * Is the end world enabled for the island? + * + * @deprecated See {@link #isDimensionEnabled(Dimension)} */ + @Deprecated boolean isEndEnabled(); /** * Enable/disable the end world for the island. + * + * @deprecated See {@link #setDimensionEnabled(Dimension, boolean)} */ + @Deprecated void setEndEnabled(boolean enabled); /** @@ -989,14 +1007,6 @@ List> getAllChunksAsync(Dimension dimension, @IslandChu */ Collection getUnlockedWorlds(); - /** - * Get the unlocked worlds flag. - * - * @deprecated See {@link #getUnlockedWorlds()} - */ - @Deprecated - int getUnlockedWorldsFlag(); - /* * Permissions related methods */ @@ -2735,14 +2745,6 @@ boolean setGeneratorPercentage(Key key, int percentage, Dimension dimension, */ Collection getGeneratedSchematics(); - /** - * Get the generated schematics flag. - * - * @deprecated See {@link #getGeneratedSchematics()} - */ - @Deprecated - int getGeneratedSchematicsFlag(); - /** * Get the schematic that was used to create the island. */ @@ -2847,24 +2849,12 @@ interface Builder { Builder setGeneratedSchematic(Dimension dimension); - @Deprecated - Builder setGeneratedSchematics(int generatedSchematicsMask); - Set getGeneratedSchematics(); - @Deprecated - int getGeneratedSchematicsMask(); - Builder setUnlockedWorld(Dimension dimension); - @Deprecated - Builder setUnlockedWorlds(int unlockedWorldsMask); - Set getUnlockedWorlds(); - @Deprecated - int getUnlockedWorldsMask(); - Builder setLastTimeUpdated(long lastTimeUpdated); long getLastTimeUpdated(); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java index 5b8a5e73a3..e3a1248894 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java @@ -205,18 +205,6 @@ public void teleport(Island island, Dimension dimension, Consumer telep this.handle.teleport(island, dimension, teleportResult); } - @Override - @Deprecated - public void teleport(Island island, World.Environment environment) { - this.handle.teleport(island, environment); - } - - @Override - @Deprecated - public void teleport(Island island, World.Environment environment, @Nullable Consumer teleportResult) { - this.handle.teleport(island, environment, teleportResult); - } - @Override public boolean isInsideIsland() { return this.handle.isInsideIsland(); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/DelegatePlayerTeleportAlgorithm.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/DelegatePlayerTeleportAlgorithm.java index 6b4dce787a..83485c7fd3 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/DelegatePlayerTeleportAlgorithm.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/DelegatePlayerTeleportAlgorithm.java @@ -3,7 +3,6 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.entity.Player; import java.util.concurrent.CompletableFuture; @@ -26,12 +25,6 @@ public CompletableFuture teleport(Player player, Island island) { return this.handle.teleport(player, island); } - @Override - @Deprecated - public CompletableFuture teleport(Player player, Island island, World.Environment environment) { - return this.handle.teleport(player, island, environment); - } - @Override public CompletableFuture teleport(Player player, Island island, Dimension dimension) { return this.handle.teleport(player, island, dimension); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/PlayerTeleportAlgorithm.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/PlayerTeleportAlgorithm.java index 2ccdfc9756..9cf2da4842 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/PlayerTeleportAlgorithm.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/PlayerTeleportAlgorithm.java @@ -3,7 +3,6 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.world.Dimension; import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.entity.Player; import java.util.concurrent.CompletableFuture; @@ -28,19 +27,6 @@ public interface PlayerTeleportAlgorithm { */ CompletableFuture teleport(Player player, Island island); - /** - * Teleport a player to an island in a specific environment. - * - * @param player The player to teleport. - * @param island The island to teleport the player to. - * @param environment The environment to teleport the player to. - * @return CompletableFuture with boolean that indicates whether the teleportation was successful. - */ - @Deprecated - default CompletableFuture teleport(Player player, Island island, World.Environment environment) { - return teleport(player, island, Dimension.getByName(environment.name())); - } - /** * Teleport a player to an island in a specific dimension. * diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/dragon/DragonBattleService.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/dragon/DragonBattleService.java index fca73e690d..0c155b55f3 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/dragon/DragonBattleService.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/dragon/DragonBattleService.java @@ -24,29 +24,12 @@ public interface DragonBattleService { @Nullable EnderDragon getEnderDragon(Island island, Dimension dimension); - /** - * Get the current active ender dragon of an island. - * If there is no active fight, null is returned. - * - * @param island The island to get the dragon for. - */ - @Nullable - @Deprecated - EnderDragon getEnderDragon(Island island); - /** * Stop the dragon battle fight for an island. * The dragon will be killed and {@link #getEnderDragon(Island, Dimension)} will return null. */ void stopEnderDragonBattle(Island island, Dimension dimension); - /** - * Stop the dragon battle fight for an island. - * The dragon will be killed and {@link #getEnderDragon(Island, Dimension)} will return null. - */ - @Deprecated - void stopEnderDragonBattle(Island island); - /** * Reset the dragon battle fight for an island. * @@ -54,13 +37,5 @@ public interface DragonBattleService { */ DragonBattleResetResult resetEnderDragonBattle(Island island, Dimension dimension); - /** - * Reset the dragon battle fight for an island. - * - * @param island The island to reset the fight for. - */ - @Deprecated - DragonBattleResetResult resetEnderDragonBattle(Island island); - } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/portals/PortalsManagerService.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/portals/PortalsManagerService.java index a3795eb676..42ba3d28a2 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/portals/PortalsManagerService.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/service/portals/PortalsManagerService.java @@ -47,6 +47,21 @@ EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPlayer, I Location portalLocation, PortalType portalType, boolean checkImmunedPortalsStatus); + /** + * Handle a player going through a portal on an island. + * + * @param superiorPlayer The player that entered the portal. + * @param island The island the portal is inside. + * @param portalLocation The location of the portal. + * @param portalType The type of the portal. + * @param checkImmunedPortalsStatus Whether to check if the player is immuned to portal teleports. + * @param destinationLocation The location that the player should be teleported to. + * @return The result of going through the portal. + */ + EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPlayer, Island island, + Location portalLocation, PortalType portalType, + Location destinationLocation, boolean checkImmunedPortalsStatus); + /** * Handle an entity going through a portal on an island. * @@ -56,6 +71,20 @@ EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPlayer, I * @param portalType The type of the portal. * @return The result of going through the portal. */ - EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation, PortalType portalType); + EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation, + PortalType portalType); + + /** + * Handle an entity going through a portal on an island. + * + * @param entity The entity that entered the portal. + * @param island The island the portal is inside. + * @param portalLocation The location of the portal. + * @param portalType The type of the portal. + * @param destinationLocation The location that the player should be teleported to. + * @return The result of going through the portal. + */ + EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation, + PortalType portalType, Location destinationLocation); } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/UpgradeLevel.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/UpgradeLevel.java index aba7f710cf..68bcc87c4b 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/UpgradeLevel.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/upgrades/UpgradeLevel.java @@ -168,15 +168,6 @@ public interface UpgradeLevel { */ int getGeneratorAmount(Key key, Dimension dimension); - /** - * Get the generator rate of a block for this level in a specific world. - * - * @param key The block to check. - * @param environment The world environment - */ - @Deprecated - int getGeneratorAmount(Key key, World.Environment environment); - /** * Get all the generator rates for this level in a specific world. * @@ -184,14 +175,6 @@ public interface UpgradeLevel { */ Map getGeneratorAmounts(Dimension dimension); - /** - * Get all the generator rates for this level in a specific world. - * - * @param environment The world environment - */ - @Deprecated - Map getGeneratorAmounts(World.Environment environment); - /** * Get the potion effect for this level. * diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/world/Dimension.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/world/Dimension.java index 809beb00f4..d1e025dfda 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/world/Dimension.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/world/Dimension.java @@ -51,11 +51,11 @@ public static Collection values() { public static Dimension getByName(String name) { Preconditions.checkNotNull(name, "name parameter cannot be null."); - Dimension islandPrivilege = dimensions.get(name.toUpperCase(Locale.ENGLISH)); + Dimension dimension = dimensions.get(name.toUpperCase(Locale.ENGLISH)); - Preconditions.checkNotNull(islandPrivilege, "Couldn't find a Dimension with the name " + name + "."); + Preconditions.checkNotNull(dimension, "Couldn't find a Dimension with the name " + name + "."); - return islandPrivilege; + return dimension; } /** diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/world/WorldInfo.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/world/WorldInfo.java index 51df6319d2..b4df317798 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/world/WorldInfo.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/world/WorldInfo.java @@ -36,20 +36,6 @@ static WorldInfo of(World world) { return of(world.getName(), dimension); } - /** - * Create a new world info. - * - * @param worldName The name of the world. - * @param environment The environment of the world. - * @deprecated See {@link #of(String, Dimension)} - */ - @Deprecated - static WorldInfo of(String worldName, World.Environment environment) { - Preconditions.checkNotNull(worldName, "worldName parameter cannot be null"); - Preconditions.checkNotNull(environment, "environment parameter cannot be null"); - return SuperiorSkyblockAPI.getFactory().createWorldInfo(worldName, environment); - } - /** * Create a new world info. * diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java index 0e812002c0..435c42c7b4 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/wrappers/SuperiorPlayer.java @@ -267,27 +267,6 @@ public interface SuperiorPlayer extends IMissionsHolder, IPersistentDataHolder, */ void teleport(Island island, Dimension dimension, @Nullable Consumer teleportResult); - /** - * Teleport the player to an island. - * - * @param island The island to teleport the player to. - * @param environment The environment to teleport the player to. - * @deprecated See {@link #teleport(Island, Dimension)} - */ - @Deprecated - void teleport(Island island, World.Environment environment); - - /** - * Teleport the player to an island. - * - * @param island The island to teleport the player to. - * @param environment The environment to teleport the player to. - * @param teleportResult Consumer that will be ran when task is finished. - * @deprecated See {@link #teleport(Island, Dimension, Consumer)} - */ - @Deprecated - void teleport(Island island, World.Environment environment, @Nullable Consumer teleportResult); - /** * Check whether or not the player is inside their island. * When the player is offline or he doesn't have an island, false will be returned. diff --git a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java index 1e077cab4a..65c46a7e4e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/SuperiorSkyblockPlugin.java @@ -79,7 +79,6 @@ import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; import com.bgsoftware.superiorskyblock.player.respawn.RespawnActions; import com.bgsoftware.superiorskyblock.service.ServicesHandler; -import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.WorldGenerator; import com.bgsoftware.superiorskyblock.world.chunk.ChunksProvider; import com.bgsoftware.superiorskyblock.world.schematic.SchematicsManagerImpl; @@ -182,7 +181,6 @@ public void onLoad() { IslandFlags.registerFlags(); ClearActions.registerActions(); RespawnActions.registerActions(); - Dimensions.registerDimensions(); IslandCacheKeys.registerCacheKeys(); try { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSyncBonus.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSyncBonus.java index 7f2d9030d2..d467577daa 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSyncBonus.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSyncBonus.java @@ -15,7 +15,6 @@ import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEvent; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsFactory; import com.bgsoftware.superiorskyblock.core.messages.Message; -import com.bgsoftware.superiorskyblock.world.Dimensions; import org.bukkit.command.CommandSender; import java.math.BigDecimal; @@ -122,7 +121,8 @@ private static BigDecimal calculateValue(Island island, boolean calculateWorth) for (Dimension dimension : Dimension.values()) { if (island.wasSchematicGenerated(dimension)) { - String suffix = dimension == Dimensions.NORMAL ? "" : "_" + dimension.getName().toLowerCase(Locale.ENGLISH); + String suffix = dimension == plugin.getSettings().getWorlds().getDefaultWorldDimension() ? "" + : "_" + dimension.getName().toLowerCase(Locale.ENGLISH); Schematic schematic = plugin.getSchematics().getSchematic(generatedSchematic + suffix); if (schematic != null) { value = value.add(_calculateValues(schematic.getBlockCounts(), calculateWorth)); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java index c6990d3502..aa34c8acba 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminTeleport.java @@ -97,13 +97,13 @@ public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullab if (dimension != plugin.getSettings().getWorlds().getDefaultWorldDimension()) { if (!island.wasSchematicGenerated(dimension)) { - PortalType portalType = dimension.getEnvironment() == World.Environment.NETHER ? PortalType.NETHER : PortalType.ENDER; IslandWorlds.accessIslandWorldAsync(island, dimension, true, islandWorldResult -> { islandWorldResult.ifRight(Throwable::printStackTrace).ifLeft(world -> { Location simulatedPortalLocation = island.getCenter( plugin.getSettings().getWorlds().getDefaultWorldDimension()); + Location destinationLocation = island.getCenter(dimension); portalsManager.get().handlePlayerPortalFromIsland(superiorPlayer, island, - simulatedPortalLocation, portalType, false); + simulatedPortalLocation, PortalType.CUSTOM, destinationLocation, false); }); }); return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index 7d35dd280f..c1f9009f54 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -15,7 +15,6 @@ import com.bgsoftware.superiorskyblock.config.section.InteractablesSection; import com.bgsoftware.superiorskyblock.config.section.WorldsSection; import com.bgsoftware.superiorskyblock.core.EnumHelper; -import com.bgsoftware.superiorskyblock.core.SBlockOffset; import com.bgsoftware.superiorskyblock.core.collections.ArrayMap; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; @@ -37,10 +36,10 @@ import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; import com.bgsoftware.superiorskyblock.tag.CompoundTag; import com.bgsoftware.superiorskyblock.tag.ListTag; -import com.bgsoftware.superiorskyblock.world.Dimensions; import org.bukkit.GameMode; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.event.inventory.InventoryType; @@ -358,52 +357,13 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config visitorsSignActive = Formatters.COLOR_FORMATTER.format(config.getString("visitors-sign.active", "&a[Welcome]")); visitorsSignInactive = Formatters.COLOR_FORMATTER.format(config.getString("visitors-sign.inactive", "&c[Welcome]")); visitorsSignDescriptionLineFormat = Formatters.COLOR_FORMATTER.format(config.getString("visitors-sign.description-line-format", "{0}")); + loadDimensions(config.getConfigurationSection("worlds.dimensions")); islandWorldName = config.getString("worlds.world-name", "SuperiorWorld"); - - { - ConfigurationSection normalWorldSection = config.getConfigurationSection("worlds.normal"); - if (normalWorldSection != null) { - dimensionConfigs.put(Dimensions.NORMAL, new WorldsSection.NormalDimensionConfig(normalWorldSection, islandWorldName)); - } else { - dimensionConfigs.put(Dimensions.NORMAL, new WorldsSection.NormalDimensionConfig( - true, true, true, "PLAINS", "", islandWorldName)); - } - } - - { - ConfigurationSection netherWorldSection = config.getConfigurationSection("worlds.nether"); - if (netherWorldSection != null) { - dimensionConfigs.put(Dimensions.NETHER, new WorldsSection.NetherDimensionConfig(netherWorldSection, islandWorldName)); - } else { - dimensionConfigs.put(Dimensions.NETHER, new WorldsSection.NetherDimensionConfig( - false, true, true, "NETHER_WASTES", "", islandWorldName)); - } - } - - { - ConfigurationSection endWorldSection = config.getConfigurationSection("worlds.end"); - if (endWorldSection != null) { - dimensionConfigs.put(Dimensions.THE_END, new WorldsSection.EndDimensionConfig(endWorldSection, islandWorldName)); - } else { - dimensionConfigs.put(Dimensions.THE_END, new WorldsSection.EndDimensionConfig( - false, false, true, "THE_END", "", islandWorldName, - false, SBlockOffset.ZERO)); - } - } - - try { - Dimension defaultWorld = Dimension.getByName(config.getString("worlds.default-world")); - SettingsManager.Worlds.DimensionConfig dimensionConfig = this.dimensionConfigs.get(defaultWorld); - if (dimensionConfig == null || !dimensionConfig.isEnabled()) - throw new Exception(); - this.defaultWorldDimension = defaultWorld; - this.defaultWorldName = dimensionConfig.getName(); - } catch (Exception error) { - throw new ManagerLoadException("Cannot find a default islands world.", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); - } - worldsDifficulty = config.getString("worlds.difficulty", "EASY").toUpperCase(Locale.ENGLISH); seaLevelHeight = config.getInt("worlds.sea-level-height", 100); + this.defaultWorldDimension = Dimension.getByName(config.getString("worlds.default-world")); + loadDimensionConfigs(config.getConfigurationSection("worlds.dimensions")); + this.defaultWorldName = this.dimensionConfigs.get(this.defaultWorldDimension).getName(); spawnLocation = config.getString("spawn.location", "SuperiorWorld, 0, 100, 0, 0, 0"); spawnProtection = config.getBoolean("spawn.protection", true); spawnSettings = Collections.unmodifiableList(new LinkedList<>(config.getStringList("spawn.settings") @@ -637,6 +597,60 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config entityCategories = parseEntityCategories(config.getConfigurationSection("entity-categories")); } + private void loadDimensions(ConfigurationSection dimensionsSection) { + // First register all dimensions + for (String dimensionName : dimensionsSection.getKeys(false)) { + String environmentName = dimensionsSection.getString(dimensionName + ".environment"); + World.Environment environment; + try { + environment = World.Environment.valueOf(environmentName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException error) { + Log.warnFromFile("config.yml", "Cannot load dimension due to invalid environment: ", environmentName, " - skipping..."); + continue; + } + + try { + Dimension.register(dimensionName, environment); + } catch (IllegalStateException ignored) { + } + } + } + + private void loadDimensionConfigs(ConfigurationSection dimensionsSection) throws ManagerLoadException { + for (String dimensionName : dimensionsSection.getKeys(false)) { + ConfigurationSection dimensionSection = dimensionsSection.getConfigurationSection(dimensionName); + + if(dimensionSection == null) { + Log.warnFromFile("config.yml", "Invalid dimension config section for ", dimensionName, " - skipping..."); + continue; + } + + Dimension dimension = Dimension.getByName(dimensionName); + + String worldName = defaultWorldDimension == dimension ? islandWorldName : + islandWorldName + "_" + dimensionName.toLowerCase(Locale.ENGLISH); + + switch (dimension.getEnvironment()) { + case NORMAL: + dimensionConfigs.put(dimension, new WorldsSection.NormalDimensionConfig(dimensionSection, dimension, worldName)); + break; + case NETHER: + dimensionConfigs.put(dimension, new WorldsSection.NetherDimensionConfig(dimensionSection, dimension, worldName)); + break; + case THE_END: + dimensionConfigs.put(dimension, new WorldsSection.EndDimensionConfig(dimensionSection, dimension, worldName)); + break; + } + + } + + // Check the default dimension is valid + SettingsManager.Worlds.DimensionConfig dimensionConfig = this.dimensionConfigs.get(this.defaultWorldDimension); + if (dimensionConfig == null || !dimensionConfig.isEnabled()) { + throw new ManagerLoadException("Cannot find a default islands world.", ManagerLoadException.ErrorLevel.SERVER_SHUTDOWN); + } + } + private List loadClearActions(List clearActionsNames) { List clearActions = new LinkedList<>(); clearActionsNames.forEach(clearAction -> { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index 4672ccd28e..2e26965bb6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -5,7 +5,6 @@ import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; -import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeySet; import com.bgsoftware.superiorskyblock.api.objects.Pair; @@ -49,7 +48,7 @@ public class SettingsManagerImpl extends Manager implements SettingsManager { private static final String[] IGNORED_SECTIONS = new String[]{ - "config.yml", "ladder", "commands-cooldown", "containers", "event-commands", "command-aliases", + "config.yml", "ladder", "commands-cooldown", "containers", "event-commands", "command-aliases", "worlds.dimensions", "island-previews.locations", "default-values.block-limits", "default-values.entity-limits", "default-values.role-limits", "stacked-blocks.limits", "default-values.generator", "message-delays" }; @@ -711,7 +710,7 @@ public void updateValue(String path, Object value) throws IOException { CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(file); cfg.syncWithConfig(file, plugin.getResource("config.yml"), "config.yml", - "ladder", "commands-cooldown", "containers", "event-commands", "command-aliases", "island-previews.locations"); + "ladder", "commands-cooldown", "containers", "event-commands", "command-aliases", "island-previews.locations", "worlds.dimensions"); cfg.set(path, value); @@ -743,6 +742,23 @@ private void loadContainerFromConfig(YamlConfiguration cfg) throws ManagerLoadEx } private void convertData(YamlConfiguration cfg) { + if (cfg.getConfigurationSection("worlds.dimensions") == null) { + cfg.set("worlds.dimensions.normal", cfg.getConfigurationSection("worlds.normal")); + cfg.set("worlds.dimensions.normal.environment", "NORMAL"); + cfg.set("worlds.dimensions.normal.portals.NETHER", "nether"); + cfg.set("worlds.dimensions.normal.portals.ENDER", "the_end"); + cfg.set("worlds.normal", null); + cfg.set("worlds.dimensions.nether", cfg.getConfigurationSection("worlds.nether")); + cfg.set("worlds.dimensions.nether.environment", "NETHER"); + cfg.set("worlds.dimensions.nether.portals.NETHER", "normal"); + cfg.set("worlds.dimensions.nether.portals.ENDER", "the_end"); + cfg.set("worlds.nether", null); + cfg.set("worlds.dimensions.the_end", cfg.getConfigurationSection("worlds.end")); + cfg.set("worlds.dimensions.the_end.environment", "THE_END"); + cfg.set("worlds.dimensions.the_end.portals.NETHER", "nether"); + cfg.set("worlds.dimensions.the_end.portals.ENDER", "normal"); + cfg.set("worlds.end", null); + } if (cfg.get("island-level-formula") != null) { cfg.set("block-level-formula", cfg.getString("island-level-formula")); cfg.set("island-level-formula", null); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java index 21f6c3fbfa..7bb486018d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.config.section; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; @@ -9,11 +10,14 @@ import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.serialization.Serializers; -import com.bgsoftware.superiorskyblock.world.Dimensions; +import org.bukkit.PortalType; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; +import java.util.Collections; +import java.util.EnumMap; import java.util.Locale; +import java.util.Map; public class WorldsSection extends SettingsContainerHolder implements SettingsManager.Worlds { @@ -40,17 +44,17 @@ public String getDefaultWorldName() { @Override public Normal getNormal() { - return (Normal) getDimensionConfig(Dimensions.NORMAL); + return (Normal) getDimensionConfig(Dimension.getByName("NORMAL")); } @Override public Nether getNether() { - return (Nether) getDimensionConfig(Dimensions.NETHER); + return (Nether) getDimensionConfig(Dimension.getByName("NETHER")); } @Override public End getEnd() { - return (End) getDimensionConfig(Dimensions.THE_END); + return (End) getDimensionConfig(Dimension.getByName("THE_END")); } @Override @@ -68,27 +72,77 @@ public DimensionConfig getDimensionConfig(Dimension dimension) { return getContainer().dimensionConfigs.get(dimension); } - public static class DefaultDimensionConfig implements DimensionConfig { + public static abstract class BaseDimensionConfig implements DimensionConfig { private final boolean isEnabled; private final boolean isUnlocked; private final boolean isSchematicOffset; private final String biome; private final String name; - - public DefaultDimensionConfig(ConfigurationSection section, String defaultName) { - this(section.getBoolean("enabled"), section.getBoolean("unlock"), - section.getBoolean("schematic-offset"), section.getString("biome"), - section.getString("name"), defaultName); + private final Map portalAgents; + + protected BaseDimensionConfig(ConfigurationSection section, Dimension dimension, String defaultName) { + this.isEnabled = section.getBoolean("enabled"); + this.isUnlocked = section.getBoolean("unlock"); + this.isSchematicOffset = section.getBoolean("schematic-offset"); + this.biome = section.getString("biome").toUpperCase(Locale.ENGLISH); + String name = section.getString("name"); + this.name = Text.isBlank(name) ? defaultName : name; + this.portalAgents = loadPortalAgents(section.getConfigurationSection("portals"), dimension); } - public DefaultDimensionConfig(boolean isEnabled, boolean isUnlocked, boolean isSchematicOffset, - String biome, String name, String defaultName) { - this.isEnabled = isEnabled; - this.isUnlocked = isUnlocked; - this.isSchematicOffset = isSchematicOffset; - this.biome = biome.toUpperCase(Locale.ENGLISH); - this.name = Text.isBlank(name) ? defaultName : name; + private static Map loadPortalAgents(@Nullable ConfigurationSection portals, Dimension dimension) { + EnumMap portalAgents = new EnumMap<>(PortalType.class); + if (portals == null) { + // Map environment to dimension + Dimension normalDimension; + Dimension netherDimension; + Dimension endDimension; + { + EnumMap environmentToDimension = new EnumMap<>(World.Environment.class); + for (Dimension dim : Dimension.values()) { + Dimension currentDimension = environmentToDimension.get(dim.getEnvironment()); + if (currentDimension == null || dim.ordinal() < currentDimension.ordinal()) + environmentToDimension.put(dim.getEnvironment(), dim); + } + normalDimension = environmentToDimension.get(World.Environment.NORMAL); + netherDimension = environmentToDimension.get(World.Environment.NETHER); + endDimension = environmentToDimension.get(World.Environment.THE_END); + } + // Set portal agent + switch (dimension.getEnvironment()) { + case NORMAL: + if (netherDimension != null) + portalAgents.put(PortalType.NETHER, netherDimension); + if (endDimension != null) + portalAgents.put(PortalType.ENDER, endDimension); + break; + case NETHER: + if (normalDimension != null) + portalAgents.put(PortalType.NETHER, normalDimension); + if (endDimension != null) + portalAgents.put(PortalType.ENDER, endDimension); + break; + case THE_END: + if (netherDimension != null) + portalAgents.put(PortalType.NETHER, netherDimension); + if (normalDimension != null) + portalAgents.put(PortalType.ENDER, normalDimension); + break; + } + } else { + for (PortalType portalType : PortalType.values()) { + String destination = portals.getString(portalType.name()); + if (destination != null) { + try { + portalAgents.put(portalType, Dimension.getByName(destination)); + } catch (NullPointerException error) { + Log.warnFromFile("config.yml", "Cannot find valid dimension ", destination, " - skipping..."); + } + } + } + } + return portalAgents.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(portalAgents); } @Override @@ -115,41 +169,36 @@ public String getBiome() { public String getName() { return this.name; } - } - - public static class NormalDimensionConfig extends DefaultDimensionConfig implements Normal { - public NormalDimensionConfig(ConfigurationSection section, String defaultName) { - super(section, defaultName); + @Override + public Dimension getPortalDestination(PortalType portalType) { + return this.portalAgents.get(portalType); } + } - public NormalDimensionConfig(boolean isEnabled, boolean isUnlocked, boolean isSchematicOffset, - String biome, String name, String defaultName) { - super(isEnabled, isUnlocked, isSchematicOffset, biome, name, defaultName); + public static class NormalDimensionConfig extends BaseDimensionConfig implements Normal { + + public NormalDimensionConfig(ConfigurationSection section, Dimension dimension, String defaultName) { + super(section, dimension, defaultName); } } - public static class NetherDimensionConfig extends DefaultDimensionConfig implements Nether { + public static class NetherDimensionConfig extends BaseDimensionConfig implements Nether { - public NetherDimensionConfig(ConfigurationSection section, String defaultName) { - super(section, defaultName + "_nether"); - } - - public NetherDimensionConfig(boolean isEnabled, boolean isUnlocked, boolean isSchematicOffset, - String biome, String name, String defaultName) { - super(isEnabled, isUnlocked, isSchematicOffset, biome, name, defaultName + "_nether"); + public NetherDimensionConfig(ConfigurationSection section, Dimension dimension, String defaultName) { + super(section, dimension, defaultName); } } - public static class EndDimensionConfig extends DefaultDimensionConfig implements End { + public static class EndDimensionConfig extends BaseDimensionConfig implements End { private final boolean isDragonFlight; private final BlockOffset portalOffset; - public EndDimensionConfig(ConfigurationSection section, String defaultName) { - super(section, defaultName + "_the_end"); + public EndDimensionConfig(ConfigurationSection section, Dimension dimension, String defaultName) { + super(section, dimension, defaultName); this.isDragonFlight = section.getBoolean("dragon-fight.enabled") && ServerVersion.isAtLeast(ServerVersion.v1_9); String portalOffset = section.getString("dragon-fight.portal-offset"); BlockOffset endDragonFightPortalOffset = Serializers.OFFSET_SPACED_SERIALIZER.deserialize(portalOffset); @@ -161,14 +210,6 @@ public EndDimensionConfig(ConfigurationSection section, String defaultName) { } } - public EndDimensionConfig(boolean isEnabled, boolean isUnlocked, boolean isSchematicOffset, - String biome, String name, String defaultName, boolean isDragonFlight, - BlockOffset portalOffset) { - super(isEnabled, isUnlocked, isSchematicOffset, biome, name, defaultName + "_the_end"); - this.isDragonFlight = isDragonFlight && ServerVersion.isAtLeast(ServerVersion.v1_9); - this.portalOffset = portalOffset; - } - @Override public boolean isDragonFight() { return this.isDragonFlight; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/LegacyMasks.java b/src/main/java/com/bgsoftware/superiorskyblock/core/LegacyMasks.java deleted file mode 100644 index ba9d4b207f..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/LegacyMasks.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.bgsoftware.superiorskyblock.core; - -import com.bgsoftware.superiorskyblock.api.world.Dimension; -import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; -import com.bgsoftware.superiorskyblock.world.Dimensions; - -import java.util.Collection; -import java.util.function.Predicate; - -public class LegacyMasks { - - public static EnumerateSet convertGeneratedSchematicsMask(int generatedSchematicsMask) { - EnumerateSet generatedSchematics = new EnumerateSet<>(Dimension.values()); - - if ((generatedSchematicsMask & 8) == 8) - generatedSchematics.add(Dimensions.NORMAL); - - if ((generatedSchematicsMask & 4) == 4) - generatedSchematics.add(Dimensions.NETHER); - - if ((generatedSchematicsMask & 3) == 3) - generatedSchematics.add(Dimensions.THE_END); - - return generatedSchematics; - } - - public static int convertGeneratedSchematicsMask(EnumerateSet generatedSchematics) { - return convertGeneratedSchematicsMaskInternal(generatedSchematics::contains); - } - - public static int convertGeneratedSchematicsMask(Collection generatedSchematics) { - return convertGeneratedSchematicsMaskInternal(generatedSchematics::contains); - } - - public static int convertGeneratedSchematicsMaskInternal(Predicate containsMethod) { - int generatedSchematicsMask = 0; - - // generatedSchematics cannot have dimension that is not default - for (Dimension dimension : Dimension.values()) { - if (dimension != Dimensions.NORMAL && dimension != Dimensions.NETHER && dimension != Dimensions.THE_END && - containsMethod.test(dimension)) - throw new IllegalStateException("Cannot build mask for generated schematics of custom dimensions."); - } - - if (containsMethod.test(Dimensions.NORMAL)) - generatedSchematicsMask |= 8; - if (containsMethod.test(Dimensions.NETHER)) - generatedSchematicsMask |= 4; - if (containsMethod.test(Dimensions.THE_END)) - generatedSchematicsMask |= 3; - - return generatedSchematicsMask; - } - - public static EnumerateSet convertUnlockedWorldsMask(int unlockedWorldsMask) { - EnumerateSet unlockedWorlds = new EnumerateSet<>(Dimension.values()); - - if ((unlockedWorldsMask & 4) == 4) - unlockedWorlds.add(Dimensions.NORMAL); - - if ((unlockedWorldsMask & 1) == 1) - unlockedWorlds.add(Dimensions.NETHER); - - if ((unlockedWorldsMask & 2) == 2) - unlockedWorlds.add(Dimensions.THE_END); - - return unlockedWorlds; - } - - public static int convertUnlockedWorldsMask(EnumerateSet unlockedWorlds) { - return convertUnlockedWorldsMaskInternal(unlockedWorlds::contains); - } - - public static int convertUnlockedWorldsMask(Collection unlockedWorlds) { - return convertUnlockedWorldsMaskInternal(unlockedWorlds::contains); - } - - private static int convertUnlockedWorldsMaskInternal(Predicate containsMethod) { - int generatedSchematicsMask = 0; - - // generatedSchematics cannot have dimension that is not default - for (Dimension dimension : Dimension.values()) { - if (dimension != Dimensions.NORMAL && dimension != Dimensions.NETHER && dimension != Dimensions.THE_END && - containsMethod.test(dimension)) - throw new IllegalStateException("Cannot build mask for unlocked worlds of custom dimensions."); - } - - if (containsMethod.test(Dimensions.NORMAL)) - generatedSchematicsMask |= 4; - if (containsMethod.test(Dimensions.NETHER)) - generatedSchematicsMask |= 1; - if (containsMethod.test(Dimensions.THE_END)) - generatedSchematicsMask |= 2; - - return generatedSchematicsMask; - } - - private LegacyMasks() { - - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java index 4941b93eaf..c7b8db1158 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/DataManager.java @@ -4,11 +4,8 @@ import com.bgsoftware.superiorskyblock.api.data.DatabaseBridge; import com.bgsoftware.superiorskyblock.api.handlers.GridManager; import com.bgsoftware.superiorskyblock.api.island.Island; -import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.LegacyMasks; import com.bgsoftware.superiorskyblock.core.Manager; -import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.database.bridge.GridDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.bridge.IslandsDatabaseBridge; import com.bgsoftware.superiorskyblock.core.database.bridge.PlayersDatabaseBridge; @@ -250,15 +247,13 @@ private void loadIslands() { .setDescription(databaseResult.getString("description").orElse("")) .setLastTimeUpdated(databaseResult.getLong("last_time_updated").orElse(System.currentTimeMillis() / 1000L)); - EnumerateSet generatedSchematics = LegacyMasks.convertGeneratedSchematicsMask( - databaseResult.getInt("generated_schematics").orElse(0)); - EnumerateSet unlockedWorlds = LegacyMasks.convertUnlockedWorldsMask( - databaseResult.getInt("unlocked_worlds").orElse(0)); + databaseResult.getString("generated_schematics").ifPresent(generatedSchematics -> { + IslandsDeserializer.deserializeDimensionsList(generatedSchematics, builder::setGeneratedSchematic); + }); - for (Dimension dimension : Dimension.values()) { - if (generatedSchematics.contains(dimension)) builder.setGeneratedSchematic(dimension); - if (unlockedWorlds.contains(dimension)) builder.setUnlockedWorld(dimension); - } + databaseResult.getString("unlocked_worlds").ifPresent(unlockedWorlds -> { + IslandsDeserializer.deserializeDimensionsList(unlockedWorlds, builder::setUnlockedWorld); + }); databaseResult.getString("dirty_chunks").ifPresent(dirtyChunks -> { IslandsDeserializer.deserializeDirtyChunks(builder, dirtyChunks); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java index 471ac664a7..69ee75b6d1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/bridge/IslandsDatabaseBridge.java @@ -25,7 +25,6 @@ import com.bgsoftware.superiorskyblock.api.wrappers.WorldPosition; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; -import com.bgsoftware.superiorskyblock.core.LegacyMasks; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.database.DBColumn; import com.bgsoftware.superiorskyblock.core.database.serialization.IslandsSerializer; @@ -33,7 +32,6 @@ import com.bgsoftware.superiorskyblock.island.IslandNames; import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; import com.bgsoftware.superiorskyblock.island.upgrade.IslandUpgradeConstants; -import com.bgsoftware.superiorskyblock.world.Dimensions; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffectType; @@ -161,7 +159,7 @@ public static void saveVisitorLocation(Island island, Dimension dimension, @Null public static void saveUnlockedWorlds(Island island) { updateIslandValue(island, "unlocked_worlds", - LegacyMasks.convertUnlockedWorldsMask(island.getUnlockedWorlds())); + IslandsSerializer.serializeDimensions(island.getUnlockedWorlds())); } public static void savePlayerPermission(Island island, SuperiorPlayer superiorPlayer, IslandPrivilege privilege, @@ -563,7 +561,7 @@ public static void clearGeneratorRates(Island island, Dimension dimension) { public static void saveGeneratedSchematics(Island island) { updateIslandValue(island, "generated_schematics", - LegacyMasks.convertGeneratedSchematicsMask(island.getGeneratedSchematics())); + IslandsSerializer.serializeDimensions(island.getGeneratedSchematics())); } public static void saveDirtyChunks(DirtyChunksContainer dirtyChunksContainer) { @@ -752,7 +750,7 @@ public static void clearIslandSettings(Island island) { public static void insertIsland(Island island, @Nullable List dirtyChunks) { runOperationIfRunning(island.getDatabaseBridge(), databaseBridge -> { BlockPosition centerPosition = island.getCenterPosition(); - WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, Dimensions.NORMAL); + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, plugin.getSettings().getWorlds().getDefaultWorldDimension()); try (ObjectsPools.Batch pool = ObjectsPools.DB_COLUMN_BATCH.obtain()) { databaseBridge.insertObject("islands", pool.obtain().withNameAndValue("uuid", island.getUniqueId().toString()), @@ -768,8 +766,8 @@ public static void insertIsland(Island island, @Nullable List dir pool.obtain().withNameAndValue("ignored", island.isIgnored()), pool.obtain().withNameAndValue("name", IslandNames.getNameForDatabase(island)), pool.obtain().withNameAndValue("description", island.getDescription()), - pool.obtain().withNameAndValue("generated_schematics", LegacyMasks.convertGeneratedSchematicsMask(island.getGeneratedSchematics())), - pool.obtain().withNameAndValue("unlocked_worlds", LegacyMasks.convertUnlockedWorldsMask(island.getUnlockedWorlds())), + pool.obtain().withNameAndValue("generated_schematics", IslandsSerializer.serializeDimensions(island.getGeneratedSchematics())), + pool.obtain().withNameAndValue("unlocked_worlds", IslandsSerializer.serializeDimensions(island.getUnlockedWorlds())), pool.obtain().withNameAndValue("last_time_updated", System.currentTimeMillis() / 1000L), pool.obtain().withNameAndValue("dirty_chunks", dirtyChunks == null ? "" : IslandsSerializer.serializeDirtyChunkPositions(dirtyChunks)), pool.obtain().withNameAndValue("block_counts", IslandsSerializer.serializeBlockCounts(island.getBlockCountsAsBigInteger())), diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java index d7c11af4ef..6a76a6c30a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java @@ -5,6 +5,7 @@ import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v0.DatabaseUpgrade_V0; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v1.DatabaseUpgrade_V1; import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v2.DatabaseUpgrade_V2; +import com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v3.DatabaseUpgrade_V3; import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; import com.bgsoftware.superiorskyblock.core.mutable.MutableInt; @@ -15,7 +16,8 @@ public class SQLDatabase { private static final Runnable[] DATABASE_UPGRADES = new Runnable[]{ DatabaseUpgrade_V0.INSTANCE, DatabaseUpgrade_V1.INSTANCE, - DatabaseUpgrade_V2.INSTANCE + DatabaseUpgrade_V2.INSTANCE, + DatabaseUpgrade_V3.INSTANCE }; private SQLDatabase() { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v3/DatabaseUpgrade_V3.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v3/DatabaseUpgrade_V3.java new file mode 100644 index 0000000000..8c226b1483 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/upgrade/v3/DatabaseUpgrade_V3.java @@ -0,0 +1,120 @@ +package com.bgsoftware.superiorskyblock.core.database.loader.sql.upgrade.v3; + +import com.bgsoftware.common.databasebridge.sql.query.QueryResult; +import com.bgsoftware.common.databasebridge.sql.transaction.CustomSQLDatabaseTransaction; +import com.bgsoftware.superiorskyblock.core.database.DatabaseResult; +import com.bgsoftware.superiorskyblock.core.database.sql.DBSession; +import com.bgsoftware.superiorskyblock.core.database.sql.ResultSetMapBridge; +import com.bgsoftware.superiorskyblock.core.mutable.MutableBoolean; + +import java.sql.ResultSet; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ExecutionException; + +public class DatabaseUpgrade_V3 implements Runnable { + + public static final DatabaseUpgrade_V3 INSTANCE = new DatabaseUpgrade_V3(); + + private DatabaseUpgrade_V3() { + + } + + @Override + public void run() { + List itemsToUpdate = new LinkedList<>(); + + MutableBoolean isFailed = new MutableBoolean(false); + + DBSession.select("islands", "", new QueryResult().onSuccess(resultSet -> { + while (resultSet.next()) { + DatabaseResult databaseResult = new DatabaseResult(new ResultSetMapBridge(resultSet)); + + String uuid = databaseResult.getString("uuid").orElse(null); + if (uuid == null) + continue; + + Integer generatedSchematics = databaseResult.getInt("generated_schematics").orElse(null); + if (generatedSchematics == null) + continue; + + Integer unlockedWorlds = databaseResult.getInt("unlocked_worlds").orElse(null); + if (unlockedWorlds == null) + continue; + + itemsToUpdate.add(new DatabaseItem(uuid, convertGeneratedSchematicsMask(generatedSchematics), + convertUnlockedWorldsMask(unlockedWorlds))); + } + }).onFail(error -> isFailed.set(true))); + + if (isFailed.get()) + return; + + DBSession.modifyColumnType("islands", "generated_schematics", "TEXT"); + DBSession.modifyColumnType("islands", "unlocked_worlds", "TEXT"); + + CustomSQLDatabaseTransaction updateTransaction = new CustomSQLDatabaseTransaction( + "UPDATE {prefix}islands SET generated_schematics=?,unlocked_worlds=? WHERE uuid=?"); + updateManyItems(itemsToUpdate, updateTransaction); + } + + private static String convertGeneratedSchematicsMask(int generatedSchematicsMask) { + StringBuilder generatedSchematics = new StringBuilder(); + + if ((generatedSchematicsMask & 8) == 8) + generatedSchematics.append(",NORMAL"); + + if ((generatedSchematicsMask & 4) == 4) + generatedSchematics.append(",NETHER"); + + if ((generatedSchematicsMask & 3) == 3) + generatedSchematics.append(",THE_END"); + + return generatedSchematics.length() == 0 ? generatedSchematics.toString() : generatedSchematics.substring(1); + } + + private static String convertUnlockedWorldsMask(int unlockedWorldsMask) { + StringBuilder unlockedWorlds = new StringBuilder(); + + if ((unlockedWorldsMask & 4) == 4) + unlockedWorlds.append(",NORMAL"); + + if ((unlockedWorldsMask & 1) == 1) + unlockedWorlds.append(",NETHER"); + + if ((unlockedWorldsMask & 2) == 2) + unlockedWorlds.append(",THE_END"); + + return unlockedWorlds.length() == 0 ? unlockedWorlds.toString() : unlockedWorlds.substring(1); + } + + private static void updateManyItems(List items, CustomSQLDatabaseTransaction updateTransaction) { + for (DatabaseItem item : items) { + updateTransaction + .bindObject(item.generatedWorlds) + .bindObject(item.unlockedWorlds) + .bindObject(item.uuid) + .newBatch(); + } + + try { + DBSession.execute(updateTransaction).get(); + } catch (InterruptedException | ExecutionException ignored) { + } + } + + private static class DatabaseItem { + + private final String uuid; + private final String generatedWorlds; + private final String unlockedWorlds; + + DatabaseItem(String uuid, String generatedWorlds, String unlockedWorlds) { + this.uuid = uuid; + this.generatedWorlds = generatedWorlds; + this.unlockedWorlds = unlockedWorlds; + } + + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java index 2e947c4383..5cdce0db15 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsDeserializer.java @@ -37,6 +37,7 @@ import java.math.BigInteger; import java.util.Optional; import java.util.UUID; +import java.util.function.Consumer; public class IslandsDeserializer { @@ -312,6 +313,20 @@ public static void deserializeEntityCounts(Island.Builder builder, String entiti }); } + public static void deserializeDimensionsList(String dimensions, Consumer consumer) { + if (Text.isBlank(dimensions)) + return; + + for (String dimensionName : dimensions.split(",")) { + try { + Dimension dimension = Dimension.getByName(dimensionName); + consumer.accept(dimension); + } catch (NullPointerException ignored) { + + } + } + } + public static void deserializeBlockLimits(DatabaseBridge databaseBridge, DatabaseCache databaseCache) { databaseBridge.loadAllObjects("islands_block_limits", blockLimitRow -> { DatabaseResult blockLimits = new DatabaseResult(blockLimitRow); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsSerializer.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsSerializer.java index 0b94bb9ffd..2780629767 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsSerializer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/serialization/IslandsSerializer.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.core.database.serialization; import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.DirtyChunk; import com.bgsoftware.superiorskyblock.island.chunk.DirtyChunksContainer; @@ -11,6 +12,7 @@ import com.google.gson.JsonPrimitive; import java.math.BigInteger; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -75,6 +77,13 @@ public static String serializeDirtyChunkPositions(DirtyChunksContainer container return gson.toJson(dirtyChunksObject); } + public static String serializeDimensions(Collection dimensions) { + StringBuilder serialized = new StringBuilder(); + for (Dimension dimension : dimensions) + serialized.append(",").append(dimension.getName()); + return serialized.length() == 0 ? serialized.toString() : serialized.substring(1); + } + private static void serializeDirtyChunkPosition(JsonObject dirtyChunksObject, ChunkPosition dirtyChunk) { JsonArray dirtyChunksArray; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java index ad86e870b2..988e267d92 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java @@ -17,6 +17,7 @@ import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; +import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.entity.EntityCategories; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; @@ -47,7 +48,7 @@ public void registerDefaultListeners() { EntityCategories.registerListeners(this); WorldsProvider_Default.registerListeners(this); IslandPlayerDetectorHelper.registerListeners(this); - + Dimensions.registerListeners(this); } public void registerCallback(PluginEventType type, Runnable callback) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java index ccb0e230d1..59f8cb43bd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/factory/FactoriesManagerImpl.java @@ -45,14 +45,12 @@ import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.player.algorithm.DefaultPlayerTeleportAlgorithm; import com.bgsoftware.superiorskyblock.player.builder.SuperiorPlayerBuilderImpl; -import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.schematic.options.SchematicOptionsBuilderImpl; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.Sound; -import org.bukkit.World; import java.math.BigDecimal; import java.util.UUID; @@ -204,12 +202,6 @@ public WorldInfo createWorldInfo(String worldName, Dimension dimension) { return new WorldInfoImpl(worldName, dimension); } - @Override - @Deprecated - public WorldInfo createWorldInfo(String worldName, World.Environment environment) { - return createWorldInfo(worldName, Dimensions.fromEnvironment(environment)); - } - @Override public GameSound createGameSound(Sound sound, float volume, float pitch) { Preconditions.checkNotNull(sound, "sound parameter cannot be null"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java index 85556de1bc..c7284bc6fc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/worlds/WorldsProvider_Default.java @@ -12,7 +12,6 @@ import com.bgsoftware.superiorskyblock.core.collections.EnumerateMap; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; -import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.WorldGenerator; import com.google.common.base.Preconditions; import com.google.common.collect.Sets; @@ -136,11 +135,6 @@ public void prepareTeleport(Island island, Location location, Runnable finishCal finishCallback.run(); } - @Override - public boolean isEndUnlocked() { - return isDimensionUnlocked(Dimensions.THE_END); - } - @Override public boolean isDimensionEnabled(Dimension dimension) { SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java index dcb5aa1f18..7b613f14c6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/GridManagerImpl.java @@ -46,7 +46,6 @@ import com.bgsoftware.superiorskyblock.island.preview.SIslandPreview; import com.bgsoftware.superiorskyblock.island.purge.IslandsPurger; import com.bgsoftware.superiorskyblock.player.chat.PlayerChat; -import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.WorldBlocks; import com.bgsoftware.superiorskyblock.world.schematic.BaseSchematic; import com.google.common.base.Preconditions; @@ -732,12 +731,6 @@ public Dimension getIslandsWorldDimension(World world) { return plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(world); } - @Override - @Deprecated - public World getIslandsWorld(Island island, World.Environment environment) { - return getIslandsWorld(island, Dimensions.fromEnvironment(environment)); - } - @Override public WorldInfo getIslandsWorldInfo(Island island, Dimension dimension) { Preconditions.checkNotNull(island, "island parameter cannot be null."); @@ -759,12 +752,6 @@ public WorldInfo getIslandsWorldInfo(Island island, Dimension dimension) { return world == null ? null : WorldInfo.of(world); } - @Override - @Deprecated - public WorldInfo getIslandsWorldInfo(Island island, World.Environment environment) { - return getIslandsWorldInfo(island, Dimensions.fromEnvironment(environment)); - } - @Nullable @Override public WorldInfo getIslandsWorldInfo(Island island, String worldName) { @@ -775,7 +762,7 @@ public WorldInfo getIslandsWorldInfo(Island island, String worldName) { if (island instanceof SpawnIsland) return ((SpawnIsland) island).getSpawnWorldInfo(); - return WorldInfo.of(island.getIslandHome(Dimensions.NORMAL).getWorld()); + return WorldInfo.of(island.getIslandHome(plugin.getSettings().getWorlds().getDefaultWorldDimension()).getWorld()); } WorldsProvider worldsProvider = plugin.getProviders().getWorldsProvider(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 72ba40f023..f0f42245d1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -46,7 +46,6 @@ import com.bgsoftware.superiorskyblock.core.IslandWorldsPlayersStrategy; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; -import com.bgsoftware.superiorskyblock.core.LegacyMasks; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.SequentialListBuilder; @@ -104,7 +103,6 @@ import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeCropGrowth; import com.bgsoftware.superiorskyblock.module.upgrades.type.UpgradeTypeIslandEffects; import com.bgsoftware.superiorskyblock.player.inventory.ClearActions; -import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import com.bgsoftware.superiorskyblock.world.GeneratorType; import com.bgsoftware.superiorskyblock.world.WorldBlocks; @@ -1454,32 +1452,32 @@ private boolean isIslandWorld(@Nullable String worldName) { @Override public boolean isNormalEnabled() { - return isDimensionEnabled(Dimensions.NORMAL); + return isDimensionEnabled(Dimension.getByName("NORMAL")); } @Override public void setNormalEnabled(boolean enabled) { - setDimensionEnabled(Dimensions.NORMAL, enabled); + setDimensionEnabled(Dimension.getByName("NORMAL"), enabled); } @Override public boolean isNetherEnabled() { - return isDimensionEnabled(Dimensions.NETHER); + return isDimensionEnabled(Dimension.getByName("NETHER")); } @Override public void setNetherEnabled(boolean enabled) { - setDimensionEnabled(Dimensions.NETHER, enabled); + setDimensionEnabled(Dimension.getByName("NETHER"), enabled); } @Override public boolean isEndEnabled() { - return isDimensionEnabled(Dimensions.THE_END); + return isDimensionEnabled(Dimension.getByName("THE_END")); } @Override public void setEndEnabled(boolean enabled) { - setDimensionEnabled(Dimensions.THE_END, enabled); + setDimensionEnabled(Dimension.getByName("THE_END"), enabled); } @Override @@ -1506,12 +1504,6 @@ public Set getUnlockedWorlds() { unlockedWorlds.collect(Dimension.values()))); } - @Override - @Deprecated - public int getUnlockedWorldsFlag() { - return this.unlockedWorlds.readAndGet(LegacyMasks::convertUnlockedWorldsMask); - } - /* * Permissions related methods */ @@ -4443,12 +4435,6 @@ public Set getGeneratedSchematics() { generatedSchematics.collect(Dimension.values()))); } - @Override - @Deprecated - public int getGeneratedSchematicsFlag() { - return this.generatedSchematics.readAndGet(LegacyMasks::convertGeneratedSchematicsMask); - } - @Override public String getSchematicName() { return this.schematicName == null ? "" : this.schematicName; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java index 7f0cbc872e..ac3020b289 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SpawnIsland.java @@ -853,12 +853,6 @@ public Collection getUnlockedWorlds() { return Collections.emptyList(); } - @Override - @Deprecated - public int getUnlockedWorldsFlag() { - return 0; - } - @Override public boolean hasPermission(CommandSender sender, IslandPrivilege islandPrivilege) { return sender instanceof ConsoleCommandSender || hasPermission(plugin.getPlayers().getSuperiorPlayer(sender), islandPrivilege); @@ -2063,12 +2057,6 @@ public Collection getGeneratedSchematics() { return Collections.emptySet(); } - @Override - @Deprecated - public int getGeneratedSchematicsFlag() { - return 0; - } - @Override public String getSchematicName() { return ""; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java index 96969a03f9..5a5fa93afe 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/builder/IslandBuilderImpl.java @@ -22,7 +22,6 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.DirtyChunk; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; -import com.bgsoftware.superiorskyblock.core.LegacyMasks; import com.bgsoftware.superiorskyblock.core.SBlockPosition; import com.bgsoftware.superiorskyblock.core.SWorldPosition; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; @@ -285,48 +284,22 @@ public Island.Builder setGeneratedSchematic(Dimension dimension) { return this; } - @Override - @Deprecated - public Island.Builder setGeneratedSchematics(int generatedSchematicsMask) { - this.generatedSchematics.addAll(LegacyMasks.convertGeneratedSchematicsMask(generatedSchematicsMask)); - return this; - } - @Override public Set getGeneratedSchematics() { return Collections.unmodifiableSet(this.generatedSchematics.collect(Dimension.values())); } - @Override - @Deprecated - public int getGeneratedSchematicsMask() { - return LegacyMasks.convertGeneratedSchematicsMask(this.generatedSchematics); - } - @Override public Island.Builder setUnlockedWorld(Dimension dimension) { this.unlockedWorlds.add(dimension); return this; } - @Override - @Deprecated - public Island.Builder setUnlockedWorlds(int unlockedWorldsMask) { - this.unlockedWorlds.addAll(LegacyMasks.convertUnlockedWorldsMask(unlockedWorldsMask)); - return this; - } - @Override public Set getUnlockedWorlds() { return Collections.unmodifiableSet(this.unlockedWorlds.collect(Dimension.values())); } - @Override - @Deprecated - public int getUnlockedWorldsMask() { - return LegacyMasks.convertUnlockedWorldsMask(this.unlockedWorlds); - } - @Override public Island.Builder setLastTimeUpdated(long lastTimeUpdated) { this.lastTimeUpdated = lastTimeUpdated; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java index 6c087d470b..609cd85fe8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/upgrade/SUpgradeLevel.java @@ -21,10 +21,8 @@ import com.bgsoftware.superiorskyblock.core.value.IntValue; import com.bgsoftware.superiorskyblock.core.value.Value; import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; -import com.bgsoftware.superiorskyblock.world.Dimensions; import com.google.common.base.Preconditions; import org.bukkit.OfflinePlayer; -import org.bukkit.World; import org.bukkit.entity.EntityType; import org.bukkit.potion.PotionEffectType; @@ -258,12 +256,6 @@ public int getGeneratorAmount(Key key, Dimension dimension) { return (generatorRates == null ? 0 : generatorRates.getOrDefault(key, 0)); } - @Override - @Deprecated - public int getGeneratorAmount(Key key, World.Environment environment) { - return getGeneratorAmount(key, Dimensions.fromEnvironment(environment)); - } - @Override public Map getGeneratorAmounts(Dimension dimension) { Preconditions.checkNotNull(dimension, "dimension parameter cannot be null."); @@ -273,12 +265,6 @@ public Map getGeneratorAmounts(Dimension dimension) { Map.Entry::getValue)); } - @Override - @Deprecated - public Map getGeneratorAmounts(World.Environment environment) { - return getGeneratorAmounts(Dimensions.fromEnvironment(environment)); - } - @Override public int getPotionEffect(PotionEffectType potionEffectType) { Preconditions.checkNotNull(potionEffectType, "potionEffectType parameter cannot be null."); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java index d94ef68d6b..eca10680a4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.listener; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.player.PlayerStatus; import com.bgsoftware.superiorskyblock.api.service.portals.EntityPortalResult; @@ -138,11 +139,17 @@ private void handlePlayerPortal(GameEvent e) { return; } + Island island = plugin.getGrid().getIslandAt(e.getArgs().from); + if (island == null) + return; + PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? PortalType.NETHER : PortalType.ENDER; - EntityPortalResult portalResult = this.portalsManager.get().handlePlayerPortal( - superiorPlayer, e.getArgs().from, portalType, e.getArgs().to, true); + Location toLocation = calculateDestination(island, e.getArgs().from, e.getArgs().to, portalType); + + EntityPortalResult portalResult = this.portalsManager.get().handlePlayerPortalFromIsland( + superiorPlayer, island, e.getArgs().from, portalType, toLocation, true); handleEntityPortalResult(portalResult, e); } @@ -154,16 +161,30 @@ public void handleEntityPortalResult(GameEvent if (to == null || to.getWorld() == null || from == null || from.getWorld() == null) return; + Island island = plugin.getGrid().getIslandAt(e.getArgs().from); + if (island == null) + return; + Entity entity = e.getArgs().entity; PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? PortalType.NETHER : PortalType.ENDER; - EntityPortalResult portalResult = this.portalsManager.get().handleEntityPortal(entity, from, portalType, to); + Location toLocation = calculateDestination(island, e.getArgs().from, e.getArgs().to, portalType); + + EntityPortalResult portalResult = this.portalsManager.get().handleEntityPortalFromIsland( + entity, island, from, portalType, toLocation); handleEntityPortalResult(portalResult, e); } + private Location calculateDestination(Island island, Location fromLocation, Location toLocation, PortalType portalType) { + Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(fromLocation.getWorld()); + SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(portalDimension); + Dimension portalDestination = dimensionConfig == null ? null : dimensionConfig.getPortalDestination(portalType); + return portalDestination == null ? toLocation : island.getCenter(portalDestination); + } + private void handleEntityPortalResult(EntityPortalResult portalResult, GameEvent event) { switch (portalResult) { case PORTAL_NOT_IN_ISLAND: diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java index 299f3f7683..42824fa3d9 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/generators/listeners/GeneratorsListener.java @@ -54,7 +54,7 @@ public void onBlockFormEvent(BlockFormEvent e) { Dimension dimension; if (BuiltinModules.GENERATORS.getConfiguration().isMatchGeneratorWorld()) { - dimension = Dimensions.NETHER; + dimension = Dimensions.fromEnvironment(World.Environment.NETHER); } else { World blockWorld = blockLocation.getWorld(); dimension = Optional.ofNullable(plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(blockWorld)) @@ -98,7 +98,7 @@ public void onBlockFromToEvent(BlockFromToEvent e) { Dimension dimension; if (BuiltinModules.GENERATORS.getConfiguration().isMatchGeneratorWorld()) { - dimension = generatorType == GeneratorType.BASALT ? Dimensions.NETHER : Dimensions.NORMAL; + dimension = Dimensions.fromEnvironment(generatorType == GeneratorType.BASALT ? World.Environment.NETHER : World.Environment.NORMAL); } else { dimension = Optional.ofNullable(plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(blockWorld)) .orElseGet(() -> Dimensions.fromEnvironment(blockWorld.getEnvironment())); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java index b8cdc3f096..3d1b38ce44 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SSuperiorPlayer.java @@ -37,7 +37,6 @@ import com.bgsoftware.superiorskyblock.player.builder.SuperiorPlayerBuilderImpl; import com.bgsoftware.superiorskyblock.player.cache.PlayerCacheImpl; import com.bgsoftware.superiorskyblock.player.permissions.PlayerPermissionsStore; -import com.bgsoftware.superiorskyblock.world.Dimensions; import com.google.common.base.Preconditions; import org.bukkit.Bukkit; import org.bukkit.GameMode; @@ -503,18 +502,6 @@ public void teleport(Island island, Dimension dimension, @Nullable Consumer teleportResult) { - teleport(island, Dimensions.fromEnvironment(environment), teleportResult); - } - @Override public boolean isInsideIsland() { Player player = asPlayer(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java b/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java index 888d9c58f2..fd35a72b00 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/SuperiorNPCPlayer.java @@ -227,19 +227,6 @@ public void teleport(Island unused, @Nullable Consumer teleportResult) teleportResult.accept(false); } - @Override - @Deprecated - public void teleport(Island island, World.Environment environment) { - // Do nothing. - } - - @Override - @Deprecated - public void teleport(Island unused, World.Environment unused2, @Nullable Consumer teleportResult) { - if (teleportResult != null) - teleportResult.accept(false); - } - @Override public boolean isInsideIsland() { return false; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java b/src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java index d5e97cdad1..c3e027b3bc 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/algorithm/DefaultPlayerTeleportAlgorithm.java @@ -7,11 +7,9 @@ import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.logging.Debug; import com.bgsoftware.superiorskyblock.core.logging.Log; -import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import com.google.common.base.Preconditions; import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.entity.Player; import java.util.concurrent.CompletableFuture; @@ -52,12 +50,6 @@ public CompletableFuture teleport(Player player, Island island, Dimensi return result; } - @Override - @Deprecated - public CompletableFuture teleport(Player player, Island island, World.Environment environment) { - return teleport(player, island, Dimensions.fromEnvironment(environment)); - } - public void teleportInternal(Player player, Island island, Dimension dimension, CompletableFuture result) { Location homeLocation = island.getIslandHome(dimension); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java index 17dfd370fd..f2b07b5c5f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/dragon/DragonBattleServiceImpl.java @@ -9,7 +9,6 @@ import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.service.IService; -import com.bgsoftware.superiorskyblock.world.Dimensions; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.World; @@ -45,12 +44,6 @@ public EnderDragon getEnderDragon(Island island, Dimension dimension) { return plugin.getNMSDragonFight().getEnderDragon(island, dimension); } - @Override - @Deprecated - public EnderDragon getEnderDragon(Island island) { - return getEnderDragon(island, Dimensions.THE_END); - } - @Override public void stopEnderDragonBattle(Island island, Dimension dimension) { Preconditions.checkNotNull(island, "island parameter cannot be null"); @@ -60,12 +53,6 @@ public void stopEnderDragonBattle(Island island, Dimension dimension) { plugin.getNMSDragonFight().removeDragonBattle(island, dimension); } - @Override - @Deprecated - public void stopEnderDragonBattle(Island island) { - stopEnderDragonBattle(island, Dimensions.THE_END); - } - @Override public DragonBattleResetResult resetEnderDragonBattle(Island island, Dimension dimension) { Preconditions.checkNotNull(island, "island parameter cannot be null"); @@ -96,10 +83,4 @@ public DragonBattleResetResult resetEnderDragonBattle(Island island, Dimension d return DragonBattleResetResult.SUCCESS; } - @Override - @Deprecated - public DragonBattleResetResult resetEnderDragonBattle(Island island) { - return resetEnderDragonBattle(island, Dimensions.THE_END); - } - } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index a58c279df4..baeb22e04b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -28,7 +28,6 @@ import com.bgsoftware.superiorskyblock.island.role.SPlayerRole; import com.bgsoftware.superiorskyblock.island.top.SortingTypes; import com.bgsoftware.superiorskyblock.service.IService; -import com.bgsoftware.superiorskyblock.world.Dimensions; import com.google.common.collect.ImmutableMap; import org.bukkit.Location; import org.bukkit.OfflinePlayer; @@ -69,9 +68,9 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { private static final Pattern FLAG_PLACEHOLDER_PATTERN = Pattern.compile("flag_(.+)"); private static final Pattern GENERATOR_AMOUNT_PLACEHOLDER_PATTERN = Pattern.compile("island_generator_amount_(.+)"); private static final Pattern GENERATOR_PERCENTAGE_PLACEHOLDER_PATTERN = Pattern.compile("island_generator_percentage_(.+)"); - private static final Pattern GENERATOR_NORMAL_PLACEHOLDER_PATTERN = Pattern.compile("normal_(.+)"); - private static final Pattern GENERATOR_NETHER_PLACEHOLDER_PATTERN = Pattern.compile("nether_(.+)"); - private static final Pattern GENERATOR_END_PLACEHOLDER_PATTERN = Pattern.compile("end_(.+)"); + private static final Pattern WORLD_UNLOCKED_PLACEHOLDER_PATTERN = Pattern.compile("island_world_unlocked_(.+)"); + private static final Pattern WORLD_ENABLED_PLACEHOLDER_PATTERN = Pattern.compile("island_world_enabled_(.+)"); + private static final Pattern WORLD_GENERATED_PLACEHOLDER_PATTERN = Pattern.compile("island_world_generated_(.+)"); private static final Pattern MEMBER_PLACEHOLDER_PATTERN = Pattern.compile("member_(.+)"); private static final Pattern MISSIONS_COMPLETED_PATTERN = Pattern.compile("missions_completed_(.+)"); private static final Pattern MISSION_STATUS_PATTERN = Pattern.compile("mission_status_(.+)"); @@ -217,8 +216,6 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { island.getDiscord()) .put("drops_multiplier", (island, superiorPlayer) -> island.getMobDropsMultiplier() + "") - .put("end_unlocked", (island, superiorPlayer) -> - Formatters.BOOLEAN_FORMATTER.format(island.isEndEnabled(), superiorPlayer.getUserLocale())) .put("exists", (island, superiorPlayer) -> Formatters.BOOLEAN_FORMATTER.format(island != null, superiorPlayer.getUserLocale())) .put("home", (island, superiorPlayer) -> { @@ -260,10 +257,6 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { .put("name_leader", (island, superiorPlayer) -> island.getName().isEmpty() ? island.getOwner().getName() : island.getName()) .put("name_stripped", (island, superiorPlayer) -> island.getStrippedName()) - .put("nether_unlocked", (island, superiorPlayer) -> - Formatters.BOOLEAN_FORMATTER.format(island.isNetherEnabled(), superiorPlayer.getUserLocale())) - .put("normal_unlocked", (island, superiorPlayer) -> - Formatters.BOOLEAN_FORMATTER.format(island.isNormalEnabled(), superiorPlayer.getUserLocale())) .put("paypal", (island, superiorPlayer) -> island.hasPermission(superiorPlayer, IslandPrivileges.PAYPAL_SHOW) ? island.getPaypal() : "None") .put("paypal_all", (island, superiorPlayer) -> @@ -608,6 +601,21 @@ private static Optional parsePlaceholdersForIsland(@Nullable Island isla return handleGeneratorPercentagesPlaceholder(island, matcher.group(1)); } + if ((matcher = WORLD_UNLOCKED_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + boolean unlockedWorld = island.getUnlockedWorlds().contains(Dimension.getByName(matcher.group(1))); + return Optional.of(Formatters.BOOLEAN_FORMATTER.format(unlockedWorld, superiorPlayer.getUserLocale())); + } + + if ((matcher = WORLD_ENABLED_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + boolean enabledWorld = island.isDimensionEnabled(Dimension.getByName(matcher.group(1))); + return Optional.of(Formatters.BOOLEAN_FORMATTER.format(enabledWorld, superiorPlayer.getUserLocale())); + } + + if ((matcher = WORLD_GENERATED_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { + boolean generatedWorld = island.getGeneratedSchematics().contains(Dimension.getByName(matcher.group(1))); + return Optional.of(Formatters.BOOLEAN_FORMATTER.format(generatedWorld, superiorPlayer.getUserLocale())); + } + if ((matcher = MISSIONS_COMPLETED_PATTERN.matcher(subPlaceholder)).matches()) { String categoryName = matcher.group(1); return Optional.of(island.getCompletedMissions().stream().filter(mission -> @@ -743,41 +751,37 @@ private static Optional handleFlagsPlaceholder(@NotNull Island island, } private static Optional handleGeneratorAmountsPlaceholder(@Nullable Island island, String placeholder) { - Matcher matcher; - Dimension dimension = null; - - if ((matcher = GENERATOR_NORMAL_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { - dimension = Dimensions.NORMAL; - } else if ((matcher = GENERATOR_NETHER_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { - dimension = Dimensions.NETHER; - } else if ((matcher = GENERATOR_END_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { - dimension = Dimensions.THE_END; - } + String[] placeholderSections = placeholder.split("_"); + + if (placeholderSections.length <= 1) + return Optional.empty(); - if (dimension == null) + Dimension dimension; + try { + dimension = Dimension.getByName(placeholderSections[0]); + } catch (NullPointerException error) { return Optional.empty(); + } - String keyName = matcher.group(1); + String keyName = String.join("_", placeholderSections).substring(placeholderSections[0].length() + 1); return Optional.of(island.getGeneratorAmount(Keys.ofMaterialAndData(keyName), dimension) + ""); } private static Optional handleGeneratorPercentagesPlaceholder(@Nullable Island island, String placeholder) { - Matcher matcher; - Dimension dimension = null; - - if ((matcher = GENERATOR_NORMAL_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { - dimension = Dimensions.NORMAL; - } else if ((matcher = GENERATOR_NETHER_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { - dimension = Dimensions.NETHER; - } else if ((matcher = GENERATOR_END_PLACEHOLDER_PATTERN.matcher(placeholder)).matches()) { - dimension = Dimensions.THE_END; - } + String[] placeholderSections = placeholder.split("_"); - if (dimension == null) + if (placeholderSections.length <= 1) return Optional.empty(); - String keyName = matcher.group(1); + Dimension dimension; + try { + dimension = Dimension.getByName(placeholderSections[0]); + } catch (NullPointerException error) { + return Optional.empty(); + } + + String keyName = String.join("_", placeholderSections).substring(placeholderSections[0].length() + 1); return Optional.of(IslandUtils.getGeneratorPercentageDecimal(island, Keys.ofMaterialAndData(keyName), dimension) + ""); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java index 9d63d7cc53..39687c3c25 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java @@ -23,7 +23,6 @@ import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.player.SuperiorNPCPlayer; import com.bgsoftware.superiorskyblock.service.IService; -import com.bgsoftware.superiorskyblock.world.Dimensions; import com.bgsoftware.superiorskyblock.world.EntityTeleports; import com.google.common.base.Preconditions; import org.bukkit.Location; @@ -63,26 +62,32 @@ public Class getAPIClass() { @Override public EntityPortalResult handlePlayerPortal(SuperiorPlayer superiorPlayer, Location portalLocation, - PortalType portalType, Location unused, + PortalType portalType, Location destinationLocation, boolean checkImmunedPortalsStatus) { Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null."); Preconditions.checkNotNull(portalLocation, "portalLocation cannot be null."); Preconditions.checkNotNull(portalType, "portalType cannot be null."); + Preconditions.checkNotNull(destinationLocation, "destinationLocation cannot be null."); Preconditions.checkArgument(!(superiorPlayer instanceof SuperiorNPCPlayer), "superiorPlayer cannot be an NPC."); Preconditions.checkArgument(portalLocation.getWorld() != null, "portalLocation's world cannot be null"); + Preconditions.checkArgument(destinationLocation.getWorld() != null, "destinationLocation's world cannot be null"); - return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, checkImmunedPortalsStatus, null); + Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld()); + return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, destinationDimension, checkImmunedPortalsStatus, null); } @Override public EntityPortalResult handleEntityPortal(Entity entity, Location portalLocation, - PortalType portalType, Location unused) { + PortalType portalType, Location destinationLocation) { Preconditions.checkNotNull(entity, "entity cannot be null."); Preconditions.checkNotNull(portalLocation, "portalLocation cannot be null."); Preconditions.checkNotNull(portalType, "portalType cannot be null."); + Preconditions.checkNotNull(destinationLocation, "destinationLocation cannot be null."); Preconditions.checkArgument(portalLocation.getWorld() != null, "portalLocation's world cannot be null"); + Preconditions.checkArgument(destinationLocation.getWorld() != null, "destinationLocation's world cannot be null"); - return handleEntityPortalInternal(entity, portalLocation, portalType, null); + Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld()); + return handleEntityPortalInternal(entity, portalLocation, portalType, destinationDimension, null); } @Override @@ -97,25 +102,67 @@ public EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPl Preconditions.checkArgument(portalLocation.getWorld() != null, "portalLocation's world cannot be null"); Preconditions.checkArgument(island.isInside(portalLocation), "portalLocation is not inside the island."); - return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, checkImmunedPortalsStatus, island); + Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(portalLocation.getWorld()); + Dimension destinationDimension = getDestinationDimension(portalDimension, portalType); + return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, destinationDimension, checkImmunedPortalsStatus, island); } @Override - public EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation, PortalType portalType) { + public EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPlayer, Island island, + Location portalLocation, PortalType portalType, + Location destinationLocation, boolean checkImmunedPortalsStatus) { + Preconditions.checkNotNull(superiorPlayer, "superiorPlayer cannot be null."); + Preconditions.checkNotNull(island, "island cannot be null."); + Preconditions.checkNotNull(portalLocation, "portalLocation cannot be null."); + Preconditions.checkNotNull(portalType, "portalType cannot be null."); + Preconditions.checkNotNull(destinationLocation, "destinationLocation cannot be null."); + Preconditions.checkArgument(!(superiorPlayer instanceof SuperiorNPCPlayer), "superiorPlayer cannot be an NPC."); + Preconditions.checkArgument(portalLocation.getWorld() != null, "portalLocation's world cannot be null"); + Preconditions.checkArgument(island.isInside(portalLocation), "portalLocation is not inside the island."); + Preconditions.checkArgument(destinationLocation.getWorld() != null, "destinationLocation's world cannot be null"); + Preconditions.checkArgument(island.isInside(destinationLocation), "destinationLocation is not inside the island."); + + Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld()); + return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, destinationDimension, checkImmunedPortalsStatus, island); + } + + @Override + public EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation, + PortalType portalType) { + Preconditions.checkNotNull(entity, "entity cannot be null."); + Preconditions.checkNotNull(island, "island cannot be null."); + Preconditions.checkNotNull(portalLocation, "portalLocation cannot be null."); + Preconditions.checkNotNull(portalType, "portalType cannot be null."); + Preconditions.checkArgument(!(entity instanceof HumanEntity), "entity cannot be a Player."); + Preconditions.checkArgument(portalLocation.getWorld() != null, "portalLocation's world cannot be null"); + Preconditions.checkArgument(island.isInside(portalLocation), "portalLocation is not inside the island."); + + Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(portalLocation.getWorld()); + Dimension destinationDimension = getDestinationDimension(portalDimension, portalType); + return handleEntityPortalInternal(entity, portalLocation, portalType, destinationDimension, island); + } + + @Override + public EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island island, Location portalLocation, + PortalType portalType, Location destinationLocation) { Preconditions.checkNotNull(entity, "entity cannot be null."); Preconditions.checkNotNull(island, "island cannot be null."); Preconditions.checkNotNull(portalLocation, "portalLocation cannot be null."); Preconditions.checkNotNull(portalType, "portalType cannot be null."); + Preconditions.checkNotNull(destinationLocation, "destinationLocation cannot be null."); Preconditions.checkArgument(!(entity instanceof HumanEntity), "entity cannot be a Player."); Preconditions.checkArgument(portalLocation.getWorld() != null, "portalLocation's world cannot be null"); Preconditions.checkArgument(island.isInside(portalLocation), "portalLocation is not inside the island."); + Preconditions.checkArgument(destinationLocation.getWorld() != null, "destinationLocation's world cannot be null"); + Preconditions.checkArgument(island.isInside(destinationLocation), "destinationLocation is not inside the island."); - return handleEntityPortalInternal(entity, portalLocation, portalType, island); + Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld()); + return handleEntityPortalInternal(entity, portalLocation, portalType, destinationDimension, island); } private EntityPortalResult handlePlayerPortalInternal(SuperiorPlayer superiorPlayer, Location portalLocation, - PortalType portalType, boolean checkImmunedPortalsStatus, - @Nullable Island island) { + PortalType portalType, Dimension destinationDimension, + boolean checkImmunedPortalsStatus, @Nullable Island island) { if (island == null) { island = plugin.getGrid().getIslandAt(portalLocation); @@ -127,21 +174,19 @@ private EntityPortalResult handlePlayerPortalInternal(SuperiorPlayer superiorPla return EntityPortalResult.PLAYER_IMMUNED_TO_PORTAL; EntityPortalResult portalResult = simulateEntityPortalFromIsland(superiorPlayer.asPlayer(), island, - portalLocation, portalType); + portalType, destinationDimension); if (portalResult == EntityPortalResult.WORLD_NOT_UNLOCKED) { - Dimension originalDestination = getTargetWorld(portalLocation, portalType); - Message.WORLD_NOT_UNLOCKED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(originalDestination.getName())); + Message.WORLD_NOT_UNLOCKED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(destinationDimension.getName())); } else if (portalResult == EntityPortalResult.DESTINATION_WORLD_DISABLED) { - Dimension originalDestination = getTargetWorld(portalLocation, portalType); - Message.WORLD_NOT_ENABLED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(originalDestination.getName())); + Message.WORLD_NOT_ENABLED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(destinationDimension.getName())); } return portalResult; } - private EntityPortalResult handleEntityPortalInternal(Entity entity, Location portalLocation, - PortalType portalType, @Nullable Island island) { + private EntityPortalResult handleEntityPortalInternal(Entity entity, Location portalLocation, PortalType portalType, + Dimension destinationDimension, @Nullable Island island) { if (island == null) { island = plugin.getGrid().getIslandAt(portalLocation); @@ -149,23 +194,24 @@ private EntityPortalResult handleEntityPortalInternal(Entity entity, Location po return EntityPortalResult.PORTAL_NOT_IN_ISLAND; } - return simulateEntityPortalFromIsland(entity, island, portalLocation, portalType); + return simulateEntityPortalFromIsland(entity, island, portalType, destinationDimension); } - private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island island, Location portalLocation, - PortalType portalType) { - Dimension originalDestination = getTargetWorld(portalLocation, portalType); - - SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(originalDestination); - if (dimensionConfig != null && !dimensionConfig.isEnabled()) { - return EntityPortalResult.DESTINATION_WORLD_DISABLED; + private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island island, PortalType portalType, + Dimension portalDestination) { + { + SettingsManager.Worlds.DimensionConfig destinationConfig = portalDestination == null ? null : + plugin.getSettings().getWorlds().getDimensionConfig(portalDestination); + if (portalDestination == null || destinationConfig == null || !destinationConfig.isEnabled()) { + return EntityPortalResult.DESTINATION_WORLD_DISABLED; + } } - if (plugin.getGrid().getIslandsWorld(island, originalDestination) == null) { + if (plugin.getGrid().getIslandsWorld(island, portalDestination) == null) { return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; } - if (!island.isDimensionEnabled(originalDestination)) { + if (!island.isDimensionEnabled(portalDestination)) { return EntityPortalResult.WORLD_NOT_UNLOCKED; } @@ -174,14 +220,14 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island if (generatingSchematicsIslands.contains(island.getUniqueId())) return EntityPortalResult.SCHEMATIC_GENERATING_COOLDOWN; - String destinationEnvironmentName = originalDestination.getName().toLowerCase(Locale.ENGLISH); + String destinationDimensionName = portalDestination.getName().toLowerCase(Locale.ENGLISH); String islandSchematic = island.getSchematicName(); Schematic originalSchematic = plugin.getSchematics().getSchematic(islandSchematic.isEmpty() ? - plugin.getSchematics().getDefaultSchematic(originalDestination) : - islandSchematic + "_" + destinationEnvironmentName); + plugin.getSchematics().getDefaultSchematic(portalDestination) : + islandSchematic + "_" + destinationDimensionName); - boolean schematicGenerated = island.wasSchematicGenerated(originalDestination); + boolean schematicGenerated = island.wasSchematicGenerated(portalDestination); SuperiorPlayer superiorPlayer = entity instanceof Player ? plugin.getPlayers().getSuperiorPlayer(entity) : null; Dimension destination; @@ -190,7 +236,7 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island if (superiorPlayer != null) { PluginEvent event = PluginEventsFactory.callIslandEnterPortalEvent( - island, superiorPlayer, portalType, originalDestination, schematicGenerated ? null : originalSchematic, + island, superiorPlayer, portalType, portalDestination, schematicGenerated ? null : originalSchematic, schematicGenerated); if (event.isCancelled()) @@ -200,15 +246,15 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island schematic = event.getArgs().schematic; ignoreInvalidSchematic = event.getArgs().ignoreInvalidSchematic; } else { - destination = originalDestination; + destination = portalDestination; schematic = schematicGenerated ? null : originalSchematic; ignoreInvalidSchematic = schematicGenerated; } if (schematic == null && !ignoreInvalidSchematic) { if (superiorPlayer != null) { - String schematicName = islandSchematic + "_" + destinationEnvironmentName; - Message.SCHEMATIC_NOT_ADDED.send(superiorPlayer, destinationEnvironmentName, schematicName); + String schematicName = islandSchematic + "_" + destinationDimensionName; + Message.SCHEMATIC_NOT_ADDED.send(superiorPlayer, destinationDimensionName, schematicName); } return EntityPortalResult.INVALID_SCHEMATIC; } @@ -291,23 +337,10 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island return EntityPortalResult.SUCCEED; } - private static Dimension getTargetWorld(Location portalLocation, PortalType portalType) { - World.Environment portalEnvironment = portalLocation.getWorld().getEnvironment(); - World.Environment environment; - - switch (portalType) { - case ENDER: - environment = World.Environment.THE_END; - break; - case NETHER: - environment = World.Environment.NETHER; - break; - default: - environment = World.Environment.NORMAL; - break; - } - - return environment == portalEnvironment ? Dimensions.NORMAL : Dimensions.fromEnvironment(environment); + private Dimension getDestinationDimension(Dimension dimension, PortalType portalType) { + SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); + Dimension destination = dimensionConfig == null ? null : dimensionConfig.getPortalDestination(portalType); + return destination == null ? plugin.getSettings().getWorlds().getDefaultWorldDimension() : destination; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/Dimensions.java b/src/main/java/com/bgsoftware/superiorskyblock/world/Dimensions.java index 73f2e72e72..c0f8cb8fd2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/Dimensions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/Dimensions.java @@ -1,43 +1,34 @@ package com.bgsoftware.superiorskyblock.world; -import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import org.bukkit.World; -import java.util.Objects; +import java.util.EnumMap; public class Dimensions { - public static final Dimension NORMAL = register("NORMAL", World.Environment.NORMAL); - public static final Dimension NETHER = register("NETHER", World.Environment.NETHER); - public static final Dimension THE_END = register("THE_END", World.Environment.THE_END); + private static final EnumMap ENVIRONMENT_TO_DIMENSION = new EnumMap<>(World.Environment.class); - public static void registerDimensions() { - // Do nothing, only trigger all the register calls + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, Dimensions::onSettingsUpdate); } - @Nullable - public static Dimension fromEnvironment(@Nullable World.Environment environment) { - if (environment == null) - return null; - - switch (environment) { - case NORMAL: - return NORMAL; - case NETHER: - return NETHER; - case THE_END: - return THE_END; - } + private static void onSettingsUpdate() { + ENVIRONMENT_TO_DIMENSION.clear(); - return Dimension.getByName(environment.name()); + for (Dimension dimension : Dimension.values()) { + Dimension currentDimension = ENVIRONMENT_TO_DIMENSION.get(dimension.getEnvironment()); + if (currentDimension == null || dimension.ordinal() < currentDimension.ordinal()) + ENVIRONMENT_TO_DIMENSION.put(dimension.getEnvironment(), dimension); + } } - @NotNull - private static Dimension register(String name, World.Environment environment) { - Dimension.register(name, environment); - return Objects.requireNonNull(Dimension.getByName(name)); + @Nullable + public static Dimension fromEnvironment(World.Environment environment) { + return ENVIRONMENT_TO_DIMENSION.get(environment); } private Dimensions() { diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 84e6e140c4..a5d5f98d5e 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -332,64 +332,83 @@ visitors-sign: # Settings related to the island worlds. worlds: # The default world that will be used. - # Use normal, nether or the_end. - # If nether or the_end are used but they are disabled below, they wi + # Use one of the dimensions from below. + # The dimension must be enabled or the server won't start. default-world: normal # Set the name of the islands world. world-name: SuperiorWorld - # Settings related to the normal world. - normal: - # Should the normal world be enabled? - enabled: true - # Should the normal be unlocked by default to islands? - unlock: true - # Should the schematics in this world will not be counted towards worth and level values? - schematic-offset: true - # The default biome for the world. - # If the biome is invalid, PLAINS will be set. - biome: PLAINS - # Settings related to the nether world. - nether: - # Should the nether world be enabled? - enabled: false - # Should the nether be unlocked by default to islands? - unlock: true - # Custom name for the nether world. - # When empty, the name will be "_nether" - name: '' - # Should the schematics in this world will not be counted towards worth and level values? - schematic-offset: true - # The default biome for the world. - # If the biome is invalid, NETHER (or it's 1.16 equivalent) will be used. - biome: NETHER_WASTES - end: - # Should the end world be enabled? - enabled: false - # Should the end be unlocked by default to islands? - unlock: false - # Custom name for the end world. - # When empty, the name will be "_the_end" - name: '' - # Should the schematics in this world will not be counted towards worth and level values? - schematic-offset: true - # The default biome for the world. - # If the biome is invalid, THE_END will be used. - biome: THE_END - # Settings related to dragon fights on the server. - dragon-fight: - # Whether dragon fights should be enabled. - # If enabled, each island will have it's own ender dragon to battle with. - enabled: false - # The offset of the end portal (where it should be spawning) from the middle of the island. - # The format is ', , ' (may be negative). - # Having the offset going beyond the island-radius is an undefined behavior! - portal-offset: '0, 0, 0' - # The difficulty of the island worlds. difficulty: EASY - # Set the sea level height for island worlds. sea-level-height: 100 + # Settings related to the dimensions of the plugin. + # You can create custom dimensions by adding them here. + dimensions: + # Settings related to the normal world. + normal: + # Should the normal world be enabled? + enabled: true + # Should the normal be unlocked by default to islands? + unlock: true + # Should the schematics in this world will not be counted towards worth and level values? + schematic-offset: true + # The environment of this world + environment: NORMAL + # The default biome for the world. + # If the biome is invalid, PLAINS will be set. + biome: PLAINS + # Configure the portal agents + portals: + NETHER: nether + ENDER: the_end + # Settings related to the nether world. + nether: + # Should the nether world be enabled? + enabled: false + # Should the nether be unlocked by default to islands? + unlock: true + # Custom name for the nether world. + # When empty, the name will be "_nether" + name: '' + # Should the schematics in this world will not be counted towards worth and level values? + schematic-offset: true + # The environment of this world + environment: NETHER + # The default biome for the world. + # If the biome is invalid, NETHER (or it's 1.16 equivalent) will be used. + biome: NETHER_WASTES + # Configure the portal agents + portals: + NETHER: normal + ENDER: the_end + the_end: + # Should the end world be enabled? + enabled: false + # Should the end be unlocked by default to islands? + unlock: false + # Custom name for the end world. + # When empty, the name will be "_the_end" + name: '' + # Should the schematics in this world will not be counted towards worth and level values? + schematic-offset: true + # The environment of this world + environment: THE_END + # The default biome for the world. + # If the biome is invalid, THE_END will be used. + biome: THE_END + # Configure the portal agents + portals: + NETHER: nether + ENDER: normal + # Settings related to dragon fights on the server. + dragon-fight: + # Whether dragon fights should be enabled. + # If enabled, each island will have it's own ender dragon to battle with. + enabled: false + # The offset of the end portal (where it should be spawning) from the middle of the island. + # The format is ', , ' (may be negative). + # Having the offset going beyond the island-radius is an undefined behavior! + portal-offset: '0, 0, 0' # All settings related to the spawn island. spawn: From 6186a474740efdafd90d2962228bb8b350ccdc0f Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 18 Apr 2026 19:04:09 +0300 Subject: [PATCH 542/600] Add support to custom entity interactions --- .../api/config/SettingsManager.java | 31 +++ .../api/entity/EntityCategory.java | 23 ++ .../external/SlimefunHook.java | 2 +- .../config/SettingsContainer.java | 33 ++- .../config/SettingsManagerImpl.java | 48 +++- .../section/EntityCategoriesSection.java | 212 ++++++++++++++++++ .../config/section/GlobalSection.java | 2 +- .../events/plugin/PluginEventsDispatcher.java | 4 +- .../island/flag/IslandFlags.java | 4 - .../island/privilege/IslandPrivileges.java | 19 -- .../listener/IslandFlagsListener.java | 33 +-- .../listener/ProtectionListener.java | 106 ++++++--- .../region/RegionManagerServiceImpl.java | 148 ++++++------ .../world/BukkitEntities.java | 23 ++ .../world/entity/EntityCategories.java | 205 ----------------- .../world/entity/EntityCategory.java | 78 ------- .../world/entity/EntityCategoryImpl.java | 74 ++++++ src/main/resources/config.yml | 16 +- src/main/resources/entity-categories.yml | 127 +++++++++++ 19 files changed, 726 insertions(+), 462 deletions(-) create mode 100644 API/src/main/java/com/bgsoftware/superiorskyblock/api/entity/EntityCategory.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategories.java delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategory.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategoryImpl.java create mode 100644 src/main/resources/entity-categories.yml diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java index ab18174bcd..ecc75eedeb 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/config/SettingsManager.java @@ -1,6 +1,7 @@ package com.bgsoftware.superiorskyblock.api.config; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; @@ -783,8 +784,14 @@ public interface SettingsManager { * Custom entity categories to be used by the plugin. * Config-path: entity-categories */ + @Deprecated Map getEntityCategories(); + /** + * Custom entity categories to be used by the plugin. + */ + EntityCategories getEntityCategoriesMap(); + interface Database { /** @@ -1433,4 +1440,28 @@ interface Interactables { } + interface EntityCategories { + + /** + * Get all the categories from the entity-categories file. + */ + List getCategories(); + + /** + * Get the entity categories for a specific entity key. + * + * @param key The entity's key + */ + List getCategories(Key key); + + /** + * Get an entity category by its name + * + * @param name The name of the category. + */ + @Nullable + EntityCategory getCategoryByName(String name); + + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/entity/EntityCategory.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/entity/EntityCategory.java new file mode 100644 index 0000000000..d803dfa3fd --- /dev/null +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/entity/EntityCategory.java @@ -0,0 +1,23 @@ +package com.bgsoftware.superiorskyblock.api.entity; + +import com.bgsoftware.superiorskyblock.api.island.IslandFlag; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.key.KeySet; + +public interface EntityCategory { + + String getName(); + + KeySet getEntities(); + + IslandPrivilege getSpawnPrivilege(); + + IslandPrivilege getDamagePrivilege(); + + IslandPrivilege getInteractPrivilege(); + + IslandFlag getSpawnerSpawningIslandFlag(); + + IslandFlag getNaturalSpawningIslandFlag(); + +} diff --git a/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java b/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java index 2b20700ac3..c93e56a6df 100644 --- a/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java +++ b/Hooks/Slimefun/src/main/java/com/bgsoftware/superiorskyblock/external/SlimefunHook.java @@ -112,7 +112,7 @@ private static boolean checkPermission(OfflinePlayer offlinePlayer, Location loc islandPrivilege = plugin.getSettings().getInteractablesMap().getRequiredPrivilege(ConstantKeys.CHEST); break; default: - islandPrivilege = IslandPrivileges.INTERACT; + islandPrivilege = IslandPrivileges.BREAK; break; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index c1f9009f54..a1e3228369 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; import com.bgsoftware.superiorskyblock.api.player.respawn.RespawnAction; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.config.section.EntityCategoriesSection; import com.bgsoftware.superiorskyblock.config.section.InteractablesSection; import com.bgsoftware.superiorskyblock.config.section.WorldsSection; import com.bgsoftware.superiorskyblock.core.EnumHelper; @@ -242,7 +243,7 @@ public class SettingsContainer { public final boolean helpOnNoPermission; public final boolean helpOnInvalidCommand; public final boolean cacheSchematics; - public final Map entityCategories; + public final SettingsManager.EntityCategories entityCategories; public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config) throws ManagerLoadException { databaseType = config.getString("database.type").toUpperCase(Locale.ENGLISH); @@ -594,7 +595,7 @@ public SettingsContainer(SuperiorSkyblockPlugin plugin, YamlConfiguration config helpOnInvalidCommand = config.getBoolean("help-on-invalid-command", true); helpOnNoPermission = config.getBoolean("help-on-no-permission", false); cacheSchematics = config.getBoolean("cache-schematics", true); - entityCategories = parseEntityCategories(config.getConfigurationSection("entity-categories")); + entityCategories = loadEntityCategories(plugin); } private void loadDimensions(ConfigurationSection dimensionsSection) { @@ -620,7 +621,7 @@ private void loadDimensionConfigs(ConfigurationSection dimensionsSection) throws for (String dimensionName : dimensionsSection.getKeys(false)) { ConfigurationSection dimensionSection = dimensionsSection.getConfigurationSection(dimensionName); - if(dimensionSection == null) { + if (dimensionSection == null) { Log.warnFromFile("config.yml", "Invalid dimension config section for ", dimensionName, " - skipping..."); continue; } @@ -698,6 +699,17 @@ private SettingsManager.Interactables loadInteractables(SuperiorSkyblockPlugin p return interactables; } + private SettingsManager.EntityCategories loadEntityCategories(SuperiorSkyblockPlugin plugin) { + File file = new File(plugin.getDataFolder(), "entity-categories.yml"); + + if (!file.exists()) + plugin.saveResource("entity-categories.yml", false); + + YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file); + + return new EntityCategoriesSection(cfg); + } + private KeySet loadSafeBlocks(SuperiorSkyblockPlugin plugin) { File file = new File(plugin.getDataFolder(), "safe_blocks.yml"); @@ -738,21 +750,6 @@ private void loadGenerator(YamlConfiguration config, String path, Dimension dime this.defaultGenerator.put(dimension, KeyMaps.unmodifiableKeyMap(defaultGenerator)); } - private static Map parseEntityCategories(ConfigurationSection section) { - Map entityCategories = new HashMap<>(); - - for (String categoryName : section.getKeys(false)) { - KeySet entityTypes = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); - for (String entityType : section.getStringList(categoryName)) { - entityTypes.add(Keys.ofEntityType(entityType)); - } - if (!entityTypes.isEmpty()) - entityCategories.put(categoryName, KeySets.unmodifiableKeySet(entityTypes)); - } - - return entityCategories.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(entityCategories); - } - private static void loadListOrSection(YamlConfiguration config, String path, String parseName, BiConsumer consumer) { Object value = config.get(path); if (value == null) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index 2e26965bb6..1a4dc2f629 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -3,6 +3,7 @@ import com.bgsoftware.common.config.CommentedConfiguration; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; +import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.enums.TopIslandMembersSorting; import com.bgsoftware.superiorskyblock.api.handlers.BlockValuesManager; import com.bgsoftware.superiorskyblock.api.key.Key; @@ -39,8 +40,10 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -82,6 +85,7 @@ public void loadData() throws ManagerLoadException { CommentedConfiguration cfg = CommentedConfiguration.loadConfiguration(file); convertData(cfg); convertInteractables(plugin, cfg); + convertEntityCategories(plugin, cfg); try { cfg.syncWithConfig(file, plugin.getResource("config.yml"), IGNORED_SECTIONS); @@ -699,7 +703,16 @@ public boolean isCacheSchematics() { @Override public Map getEntityCategories() { - return this.global.getEntityCategories(); + Map categories = new HashMap<>(); + for (EntityCategory entityCategory : getEntityCategoriesMap().getCategories()) { + categories.put(entityCategory.getName(), entityCategory.getEntities()); + } + return categories.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(categories); + } + + @Override + public EntityCategories getEntityCategoriesMap() { + return this.global.getEntityCategoriesMap(); } public void updateValue(String path, Object value) throws IOException { @@ -898,11 +911,42 @@ private void convertInteractables(SuperiorSkyblockPlugin plugin, YamlConfigurati try { commentedConfig.save(file); + cfg.set("interactables", null); } catch (Exception error) { - Log.error(error, file, "An unexpected error occurred while saving new interactables file:"); + Log.errorFromFile(error, file.getName(), "An unexpected error occurred while saving file:"); } + } + + private void convertEntityCategories(SuperiorSkyblockPlugin plugin, YamlConfiguration cfg) { + if (!cfg.isConfigurationSection("entity-categories")) + return; + + File file = new File(plugin.getDataFolder(), "entity-categories.yml"); + + if (!file.exists()) + plugin.saveResource("entity-categories.yml", false); + CommentedConfiguration commentedConfig = CommentedConfiguration.loadConfiguration(file); + + for (String categoryName : cfg.getConfigurationSection("entity-categories").getKeys(false)) { + List entities = cfg.getStringList("entity-categories." + categoryName); + if (!entities.isEmpty()) { + categoryName = categoryName.toUpperCase(Locale.ENGLISH); + commentedConfig.set(categoryName + ".entities", entities); + commentedConfig.set(categoryName + ".actions.SPAWN", categoryName + "_SPAWN"); + commentedConfig.set(categoryName + ".actions.DAMAGE", categoryName + "_DAMAGE"); + commentedConfig.set(categoryName + ".actions.SPAWNER_SPAWN", "SPAWNER_" + categoryName + "_SPAWN"); + commentedConfig.set(categoryName + ".actions.NATURAL_SPAWN", "NATURAL_" + categoryName + "_SPAWN"); + } + } + + try { + commentedConfig.save(file); + cfg.set("entity-categories", null); + } catch (Exception error) { + Log.errorFromFile(error, file.getName(), "An unexpected error occurred while saving file:"); + } } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java new file mode 100644 index 0000000000..d758bf6391 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java @@ -0,0 +1,212 @@ +package com.bgsoftware.superiorskyblock.config.section; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.config.SettingsManager; +import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; +import com.bgsoftware.superiorskyblock.api.island.IslandFlag; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.key.KeyMap; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; +import com.bgsoftware.superiorskyblock.core.key.set.KeySets; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.world.entity.EntityCategoryImpl; +import com.google.common.base.Preconditions; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Ambient; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Flying; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Slime; +import org.bukkit.entity.Tameable; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class EntityCategoriesSection implements SettingsManager.EntityCategories { + + @Nullable + private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); + @Nullable + private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); + @Nullable + private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); + @Nullable + private static final Class ZOMBIE_NAUTILUS_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieNautilus"); + + private static final KeySet TAMEABLE_ENTITY_KEYS = createTameableEntityKeys(); + private static final KeySet ANIMAL_ENTITY_KEYS = createAnimalEntityKeys(); + private static final KeySet MONSTER_ENTITY_KEYS = createMonsterEntityKeys(); + + private final Map nameToCategory; + private final KeyMap> entityToCategory; + + private final LazyReference> entityCategories = new LazyReference>() { + @Override + protected List create() { + return nameToCategory.isEmpty() ? Collections.emptyList() : + Collections.unmodifiableList(new LinkedList<>(nameToCategory.values())); + } + }; + + public EntityCategoriesSection(YamlConfiguration cfg) { + this.nameToCategory = loadInternal(cfg); + this.entityToCategory = convertEntityToCategoryInternal(this.nameToCategory.values()); + } + + private static Map loadInternal(YamlConfiguration cfg) { + Map entityCategories = new HashMap<>(); + for (String categoryName : cfg.getKeys(false)) { + String key = categoryName.toLowerCase(Locale.ENGLISH); + + if (entityCategories.containsKey(categoryName)) { + Log.warnFromFile("entity-categories.yml", "Duplicate entity category ", categoryName, " - skipping..."); + continue; + } + + ConfigurationSection section = cfg.getConfigurationSection(categoryName); + + KeySet entities; + if (categoryName.equalsIgnoreCase("TAMEABLE")) { + entities = TAMEABLE_ENTITY_KEYS; + } else if (categoryName.equalsIgnoreCase("ANIMAL")) { + entities = ANIMAL_ENTITY_KEYS; + } else if (categoryName.equalsIgnoreCase("MONSTER")) { + entities = MONSTER_ENTITY_KEYS; + } else { + entities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE, section.getStringList("entities")); + } + + IslandPrivilege spawnPrivilege = getOrRegisterPrivilege(section.getString("actions.SPAWN")); + IslandPrivilege damagePrivilege = getOrRegisterPrivilege(section.getString("actions.DAMAGE")); + IslandPrivilege interactPrivilege = getOrRegisterPrivilege(section.getString("actions.INTERACT")); + IslandFlag spawnerSpawnFlag = getOrRegisterFlag(section.getString("actions.SPAWNER_SPAWN")); + IslandFlag naturalSpawnFlag = getOrRegisterFlag(section.getString("actions.NATURAL_SPAWN")); + + entityCategories.put(key, new EntityCategoryImpl(categoryName, entities, spawnPrivilege, damagePrivilege, + interactPrivilege, spawnerSpawnFlag, naturalSpawnFlag)); + } + return entityCategories.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(entityCategories); + } + + private static KeyMap> convertEntityToCategoryInternal(Collection entityCategories) { + KeyMap> categories = KeyMaps.createHashMap(KeyIndicator.ENTITY_TYPE); + for (EntityCategory entityCategory : entityCategories) { + for (Key key : entityCategory.getEntities()) { + categories.computeIfAbsent(key, k -> new LinkedList<>()).add(entityCategory); + } + } + if (categories.isEmpty()) + return KeyMaps.createEmptyMap(); + + // Convert keyMap to unmodifiable. + KeyMap> categoriesUnmodifiable = KeyMaps.createHashMap(KeyIndicator.ENTITY_TYPE); + categories.forEach((key, value) -> categoriesUnmodifiable.put(key, Collections.unmodifiableList(value))); + return KeyMaps.unmodifiableKeyMap(categoriesUnmodifiable); + } + + @Override + public List getCategories() { + return this.entityCategories.get(); + } + + @Override + public List getCategories(Key key) { + Preconditions.checkNotNull(key, "key parameter cannot be null"); + return this.entityToCategory.getOrDefault(key, Collections.emptyList()); + } + + @Override + public EntityCategory getCategoryByName(String name) { + Preconditions.checkNotNull(name, "name parameter cannot be null"); + return this.nameToCategory.get(name.toLowerCase(Locale.ENGLISH)); + } + + private static KeySet createTameableEntityKeys() { + KeySet tameableEntities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); + for (EntityType entityType : EntityType.values()) { + if (entityType.getEntityClass() != null && Tameable.class.isAssignableFrom(entityType.getEntityClass())) { + tameableEntities.add(Keys.of(entityType)); + } + } + return tameableEntities; + } + + private static KeySet createAnimalEntityKeys() { + KeySet animalEntities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); + for (EntityType entityType : EntityType.values()) { + Class entityClass = entityType.getEntityClass(); + if (entityClass != null && !isMonsterType(entityClass) && + (Creature.class.isAssignableFrom(entityClass) || Ambient.class.isAssignableFrom(entityClass))) { + animalEntities.add(Keys.of(entityType)); + } + } + return animalEntities; + } + + private static boolean isMonsterType(Class entityClass) { + return Monster.class.isAssignableFrom(entityClass) || + Slime.class.isAssignableFrom(entityClass) || Flying.class.isAssignableFrom(entityClass) || + entityClass == HOGLIN_CLASS || entityClass == SKELETON_HORSE_CLASS || + entityClass == ZOMBIE_HORSE_CLASS || entityClass == ZOMBIE_NAUTILUS_CLASS; + } + + private static KeySet createMonsterEntityKeys() { + KeySet monsterEntities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); + for (EntityType entityType : EntityType.values()) { + Class entityClass = entityType.getEntityClass(); + if (entityClass != null && isMonsterType(entityClass)) { + monsterEntities.add(Keys.of(entityType)); + } + } + return monsterEntities; + } + + @Nullable + private static IslandPrivilege getOrRegisterPrivilege(@Nullable String name) { + if (name == null) + return null; + + try { + return IslandPrivilege.getByName(name); + } catch (NullPointerException error) { + IslandPrivilege.register(name); + return IslandPrivilege.getByName(name); + } + } + + @Nullable + private static IslandFlag getOrRegisterFlag(@Nullable String name) { + if (name == null) + return null; + + try { + return IslandFlag.getByName(name); + } catch (NullPointerException error) { + IslandFlag.register(name); + return IslandFlag.getByName(name); + } + } + + @Nullable + private static Class getEntityTypeClass(String clazz) { + try { + return Class.forName(clazz); + } catch (ClassNotFoundException error) { + return null; + } + } + +} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java index 4b7975b76a..227c3f9240 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/GlobalSection.java @@ -428,7 +428,7 @@ public boolean isCacheSchematics() { return getContainer().cacheSchematics; } - public Map getEntityCategories() { + public SettingsManager.EntityCategories getEntityCategoriesMap() { return getContainer().entityCategories; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java index 988e267d92..c197316d5f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java @@ -17,8 +17,8 @@ import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; +import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.Dimensions; -import com.bgsoftware.superiorskyblock.world.entity.EntityCategories; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; @@ -45,10 +45,10 @@ public void registerDefaultListeners() { CmdAdmin.registerListeners(this); Message.registerListeners(this); SSuperiorPlayer.registerListeners(this); - EntityCategories.registerListeners(this); WorldsProvider_Default.registerListeners(this); IslandPlayerDetectorHelper.registerListeners(this); Dimensions.registerListeners(this); + BukkitEntities.registerListeners(this); } public void registerCallback(PluginEventType type, Runnable callback) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/flag/IslandFlags.java b/src/main/java/com/bgsoftware/superiorskyblock/island/flag/IslandFlags.java index 851a8bbc29..5d59f5700f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/flag/IslandFlags.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/flag/IslandFlags.java @@ -21,11 +21,7 @@ public class IslandFlags { public static final IslandFlag FIRE_SPREAD = register("FIRE_SPREAD"); public static final IslandFlag GHAST_FIREBALL = register("GHAST_FIREBALL"); public static final IslandFlag LAVA_FLOW = register("LAVA_FLOW"); - public static final IslandFlag NATURAL_ANIMALS_SPAWN = register("NATURAL_ANIMALS_SPAWN"); - public static final IslandFlag NATURAL_MONSTER_SPAWN = register("NATURAL_MONSTER_SPAWN"); public static final IslandFlag PVP = register("PVP"); - public static final IslandFlag SPAWNER_ANIMALS_SPAWN = register("SPAWNER_ANIMALS_SPAWN"); - public static final IslandFlag SPAWNER_MONSTER_SPAWN = register("SPAWNER_MONSTER_SPAWN"); public static final IslandFlag TNT_EXPLOSION = register("TNT_EXPLOSION"); public static final IslandFlag TREE_GROWTH = register("TREE_GROWTH"); public static final IslandFlag WATER_FLOW = register("WATER_FLOW"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index bfcc09b235..54658ad930 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -3,10 +3,8 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; -import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; -import org.bukkit.entity.EntityType; import java.util.Comparator; import java.util.Locale; @@ -15,11 +13,8 @@ public class IslandPrivileges { public static final IslandPrivilege ALL = register("ALL"); - public static final IslandPrivilege ALLAY_INTERACT = register("ALLAY_INTERACT", ServerVersion.isAtLeast(ServerVersion.v1_19)); public static final IslandPrivilege ANIMAL_BREED = register("ANIMAL_BREED"); - public static final IslandPrivilege ANIMAL_DAMAGE = register("ANIMAL_DAMAGE"); public static final IslandPrivilege ANIMAL_SHEAR = register("ANIMAL_SHEAR"); - public static final IslandPrivilege ANIMAL_SPAWN = register("ANIMAL_SPAWN"); public static final IslandPrivilege BAN_MEMBER = register("BAN_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege BREAK = register("BREAK"); public static final IslandPrivilege BRUSH = register("BRUSH", ServerVersion.isAtLeast(ServerVersion.v1_20)); @@ -29,7 +24,6 @@ public class IslandPrivileges { public static final IslandPrivilege CLOSE_BYPASS = register("CLOSE_BYPASS"); public static final IslandPrivilege CLOSE_ISLAND = register("CLOSE_ISLAND", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege COOP_MEMBER = register("COOP_MEMBER", IslandPrivilege.Type.COMMAND); - public static final IslandPrivilege COPPER_GOLEM_INTERACT = register("COPPER_GOLEM_INTERACT", EnumHelper.getEnum(EntityType.class, "COPPER_GOLEM") != null); public static final IslandPrivilege DELETE_WARP = register("DELETE_WARP", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege DEMOTE_MEMBERS = register("DEMOTE_MEMBERS", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege DEPOSIT_MONEY = register("DEPOSIT_MONEY", IslandPrivilege.Type.COMMAND); @@ -44,32 +38,20 @@ public class IslandPrivileges { public static final IslandPrivilege FERTILIZE = register("FERTILIZE"); public static final IslandPrivilege FISH = register("FISH"); public static final IslandPrivilege FLY = register("FLY"); - public static final IslandPrivilege HORSE_INTERACT = register("HORSE_INTERACT"); public static final IslandPrivilege IGNITE_CREEPER = register("IGNITE_CREEPER"); - // TODO - get rid of INTERACT - public static final IslandPrivilege INTERACT = register("INTERACT"); public static final IslandPrivilege INVITE_MEMBER = register("INVITE_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege ISLAND_CHEST = register("ISLAND_CHEST", IslandPrivilege.Type.COMMAND); - public static final IslandPrivilege ITEM_FRAME = register("ITEM_FRAME"); public static final IslandPrivilege KICK_MEMBER = register("KICK_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege LEASH = register("LEASH"); - public static final IslandPrivilege MINECART_DAMAGE = register("MINECART_DAMAGE"); public static final IslandPrivilege MINECART_ENTER = register("MINECART_ENTER"); public static final IslandPrivilege MINECART_OPEN = register("MINECART_OPEN"); public static final IslandPrivilege MINECART_PLACE = register("MINECART_PLACE"); public static final IslandPrivilege MONSTER_DAMAGE = register("MONSTER_DAMAGE"); - public static final IslandPrivilege MONSTER_SPAWN = register("MONSTER_SPAWN"); - public static final IslandPrivilege NAUTILUS_INTERACT = register("NAUTILUS_INTERACT", EnumHelper.getEnum(EntityType.class, "NAUTILUS") != null); public static final IslandPrivilege NAME_ENTITY = register("NAME_ENTITY"); public static final IslandPrivilege OPEN_ISLAND = register("OPEN_ISLAND", IslandPrivilege.Type.COMMAND); - public static final IslandPrivilege PAINTING = register("PAINTING"); public static final IslandPrivilege PAYPAL_SHOW = register("PAYPAL_SHOW"); - @Nullable - public static final IslandPrivilege PICKUP_AXOLOTL = register("PICKUP_AXOLOTL", ServerVersion.isAtLeast(ServerVersion.v1_17)); public static final IslandPrivilege PICKUP_DROPS = register("PICKUP_DROPS"); @Nullable - public static final IslandPrivilege PICKUP_FISH = register("PICKUP_FISH", !ServerVersion.isLegacy()); - @Nullable public static final IslandPrivilege PROMOTE_MEMBERS = register("PROMOTE_MEMBERS", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege RANKUP = register("RANKUP", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege RATINGS_SHOW = register("RATINGS_SHOW", IslandPrivilege.Type.COMMAND); @@ -85,7 +67,6 @@ public class IslandPrivileges { public static final IslandPrivilege SET_SETTINGS = register("SET_SETTINGS", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SET_WARP = register("SET_WARP", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege SPAWNER_BREAK = register("SPAWNER_BREAK"); - public static final IslandPrivilege TAMED_ANIMAL_DAMAGE = register("TAMED_ANIMAL_DAMAGE"); @Nullable public static final IslandPrivilege UNCOOP_MEMBER = register("UNCOOP_MEMBER", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege VALUABLE_BREAK = register("VALUABLE_BREAK"); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java index a29825b278..5e3598a5c6 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/IslandFlagsListener.java @@ -2,6 +2,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.core.EnumHelper; @@ -9,7 +10,6 @@ import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; @@ -17,7 +17,6 @@ import com.bgsoftware.superiorskyblock.platform.event.GameEventType; import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.world.BukkitEntities; -import com.bgsoftware.superiorskyblock.world.entity.EntityCategory; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -82,24 +81,28 @@ private void onEntitySpawn(GameEvent e) { private boolean checkPreventEntitySpawn(GameEvent e, Location entityLocation) { CreatureSpawnEvent.SpawnReason spawnReason = e.getArgs().spawnReason; - IslandFlag actionFlag; - if (spawnReason == CreatureSpawnEvent.SpawnReason.SPAWNER || spawnReason == CreatureSpawnEvent.SpawnReason.SPAWNER_EGG) { - EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(e.getArgs().entity)); - if (entityCategory == null) - return false; - actionFlag = entityCategory.getSpawnerSpawnFlag(); + List entityCategories = BukkitEntities.getCategories(e.getArgs().entity); + IslandFlag islandFlag; + for (EntityCategory entityCategory : entityCategories) { + islandFlag = entityCategory.getSpawnerSpawningIslandFlag(); + if (islandFlag != null && preventAction(entityLocation, islandFlag)) { + return true; + } + } } else if (NATURAL_SPAWN_REASONS.contains(spawnReason)) { - EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(e.getArgs().entity)); - if (entityCategory == null) - return false; - actionFlag = entityCategory.getNaturalSpawnFlag(); - } else { - return false; + List entityCategories = BukkitEntities.getCategories(e.getArgs().entity); + IslandFlag islandFlag; + for (EntityCategory entityCategory : entityCategories) { + islandFlag = entityCategory.getNaturalSpawningIslandFlag(); + if (islandFlag != null && preventAction(entityLocation, islandFlag)) { + return true; + } + } } - return actionFlag != null && preventAction(entityLocation, actionFlag); + return false; } private boolean checkPreventEggLay(GameEvent e, Location entityLocation) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index c4c28579e0..114da0a0e5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -2,6 +2,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.service.region.InteractionResult; @@ -23,7 +24,6 @@ import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; import com.bgsoftware.superiorskyblock.service.region.ProtectionHelper; import com.bgsoftware.superiorskyblock.world.BukkitEntities; -import com.bgsoftware.superiorskyblock.world.entity.EntityCategory; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; @@ -49,6 +49,7 @@ import org.bukkit.util.Vector; import java.util.Iterator; +import java.util.List; public class ProtectionListener extends AbstractGameEventListener { @@ -430,19 +431,34 @@ private void onVehicleOpen(GameEvent e) { if (!(inventoryHolder instanceof Vehicle)) return; - IslandPrivilege islandPrivilege = BukkitEntities.isHorse((Vehicle) inventoryHolder) ? IslandPrivileges.HORSE_INTERACT : - BukkitEntities.isNautilus(((Vehicle) inventoryHolder).getType()) ? IslandPrivileges.NAUTILUS_INTERACT : - inventoryHolder instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_OPEN; - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().bukkitEvent.getPlayer()); - InteractionResult interactionResult; + + List entityCategories = BukkitEntities.getCategories((Entity) inventoryHolder); + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location minecartLocation = ((Vehicle) inventoryHolder).getLocation(wrapper.getHandle()); - interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, + + if (!entityCategories.isEmpty()) { + InteractionResult interactionResult; + for (EntityCategory entityCategory : entityCategories) { + if (entityCategory.getInteractPrivilege() != null) { + interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, + minecartLocation, entityCategory.getInteractPrivilege()); + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { + e.setCancelled(); + return; + } + } + } + } + + IslandPrivilege islandPrivilege = inventoryHolder instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_OPEN; + InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, minecartLocation, islandPrivilege); + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { + e.setCancelled(); + } } - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) - e.setCancelled(); } private void onPlayerCollideWithEntity(GameEvent e) { @@ -491,27 +507,41 @@ private void onPlayerLaunchProjectile(GameEvent { EntityType entityType = entity.getType(); - IslandPrivilege islandPrivilege; - if (entity instanceof FishHook && !ServerVersion.isLegacy()) { - islandPrivilege = IslandPrivileges.FISH; - } else if (entityType == TRIDENT) { - islandPrivilege = IslandPrivileges.PICKUP_DROPS; - } else if (entity instanceof Egg) { - islandPrivilege = IslandPrivileges.ANIMAL_SPAWN; - } else if (entity instanceof EnderPearl) { - islandPrivilege = IslandPrivileges.ENDER_PEARL; - } else if (entityType == WIND_CHARGE) { - islandPrivilege = IslandPrivileges.WIND_CHARGE; - } else { - return; - } - InteractionResult interactionResult; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = entity.getLocation(wrapper.getHandle()); + + if (entity instanceof Egg) { + List entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(entity)); + for (EntityCategory entityCategory : entityCategories) { + if (entityCategory.getSpawnPrivilege() != null) { + interactionResult = this.protectionManager.get().handleCustomInteraction(launcherPlayer, + entityLocation, entityCategory.getSpawnPrivilege()); + if (ProtectionHelper.shouldPreventInteraction(interactionResult, launcherPlayer, true)) { + e.setCancelled(); + return; + } + } + } + } + + IslandPrivilege islandPrivilege; + if (entity instanceof FishHook && !ServerVersion.isLegacy()) { + islandPrivilege = IslandPrivileges.FISH; + } else if (entityType == TRIDENT) { + islandPrivilege = IslandPrivileges.PICKUP_DROPS; + } else if (entity instanceof EnderPearl) { + islandPrivilege = IslandPrivileges.ENDER_PEARL; + } else if (entityType == WIND_CHARGE) { + islandPrivilege = IslandPrivileges.WIND_CHARGE; + } else { + return; + } + interactionResult = this.protectionManager.get().handleCustomInteraction(launcherPlayer, entityLocation, islandPrivilege); } + if (ProtectionHelper.shouldPreventInteraction(interactionResult, launcherPlayer, true)) e.setCancelled(); }); @@ -531,13 +561,20 @@ private void onProjectileHit(GameEvent e) { if (hitEntity == null) return; - EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(entity)); - if (entityCategory == null) - return; - - location = hitEntity.getLocation(wrapper.getHandle()); - islandPrivilege = entityCategory.getDamagePrivilege(); hitBlock = null; + location = hitEntity.getLocation(wrapper.getHandle()); + + List entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(entity)); + interactionResult = InteractionResult.SUCCESS; + + for (EntityCategory entityCategory : entityCategories) { + if (entityCategory.getDamagePrivilege() != null) { + interactionResult = this.protectionManager.get().handleCustomInteraction( + shooterPlayer, location, entityCategory.getDamagePrivilege()); + if (interactionResult != InteractionResult.SUCCESS) + break; + } + } } else { hitBlock = e.getArgs().hitBlock; Material hitBlockType = hitBlock == null ? null : hitBlock.getType(); @@ -549,13 +586,14 @@ private void onProjectileHit(GameEvent e) { location = hitBlock.getLocation(wrapper.getHandle()); islandPrivilege = hitBlockType == TARGET ? requiredPrivilege : IslandPrivileges.BREAK; - } - if (islandPrivilege == null) - return; + if (islandPrivilege == null) + return; - interactionResult = this.protectionManager.get().handleCustomInteraction(shooterPlayer, location, islandPrivilege); + interactionResult = this.protectionManager.get().handleCustomInteraction(shooterPlayer, location, islandPrivilege); + } } + if (ProtectionHelper.shouldPreventInteraction(interactionResult, shooterPlayer, true)) { entity.remove(); if (hitBlock != null) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 463dc970c9..46b1c15d16 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -2,6 +2,7 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.events.IslandEnterEvent; import com.bgsoftware.superiorskyblock.api.events.IslandLeaveEvent; import com.bgsoftware.superiorskyblock.api.events.IslandRestrictMoveEvent; @@ -17,7 +18,6 @@ import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; -import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.collections.EnumerateSet; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; @@ -32,22 +32,17 @@ import com.bgsoftware.superiorskyblock.service.IService; import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.BukkitItems; -import com.bgsoftware.superiorskyblock.world.entity.EntityCategory; import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.WeatherType; import org.bukkit.block.Block; import org.bukkit.entity.Animals; -import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Arrow; import org.bukkit.entity.Creeper; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; -import org.bukkit.entity.Fish; import org.bukkit.entity.Item; -import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.Painting; import org.bukkit.entity.Player; import org.bukkit.entity.Sheep; import org.bukkit.entity.Villager; @@ -58,6 +53,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitTask; +import java.util.List; import java.util.Optional; public class RegionManagerServiceImpl implements RegionManagerService, IService { @@ -192,6 +188,20 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc return InteractionResult.SUCCESS; EntityType spawnType = usedItem == null ? EntityType.UNKNOWN : BukkitItems.getEntityType(usedItem); + + if (spawnType != EntityType.UNKNOWN) { + List entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(spawnType)); + for (EntityCategory entityCategory : entityCategories) { + if (entityCategory.getSpawnPrivilege() != null) { + InteractionResult interactionResult = handleInteractionInternal(superiorPlayer, blockLocation, + entityCategory.getSpawnPrivilege(), 0, true, true); + if (interactionResult != InteractionResult.SUCCESS) + return interactionResult; + } + } + return InteractionResult.SUCCESS; + } + Material blockType = block.getType(); Material usedItemType = usedItem == null ? null : usedItem.getType(); @@ -209,11 +219,6 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc islandPrivilege = IslandPrivileges.FERTILIZE; } else if (stackedBlockAmount > 1) { islandPrivilege = IslandPrivileges.BREAK; - } else if (spawnType != EntityType.UNKNOWN) { - EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(spawnType)); - if (entityCategory != null && entityCategory.getSpawnPrivilege() != null) { - islandPrivilege = entityCategory.getSpawnPrivilege(); - } } return handleInteractionInternal(superiorPlayer, blockLocation, islandPrivilege, @@ -257,11 +262,12 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent EntityType entityType = entity.getType(); Material usedItemType = usedItem == null ? Material.AIR : usedItem.getType(); - IslandPrivilege islandPrivilege; + if (entity instanceof Villager || BukkitEntities.isHorse(entity) || BukkitEntities.isNautilus(entityType)) { + closeInventory = true; + } - if (entity instanceof ArmorStand) { - islandPrivilege = IslandPrivileges.INTERACT; - } else if (usedItem != null && entity instanceof Animals && plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) entity)) { + IslandPrivilege islandPrivilege = null; + if (usedItem != null && entity instanceof Animals && plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) entity)) { islandPrivilege = IslandPrivileges.ANIMAL_BREED; } else if (usedItemType == Material.NAME_TAG) { islandPrivilege = IslandPrivileges.NAME_ENTITY; @@ -269,42 +275,41 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent (entityType == HAPPY_GHAST_TYPE && Materials.isHarness(usedItemType)) || (usedItemType == Material.SHEARS && plugin.getNMSEntities().canShearSaddleFromEntity(entity))) { islandPrivilege = IslandPrivileges.SADDLE_ENTITY; - } else if (entity instanceof Villager) { - islandPrivilege = IslandPrivileges.VILLAGER_TRADING; - closeInventory = true; - } else if (BukkitEntities.isHorse(entity)) { - islandPrivilege = IslandPrivileges.HORSE_INTERACT; - closeInventory = true; - } else if (BukkitEntities.isNautilus(entityType)) { - islandPrivilege = IslandPrivileges.NAUTILUS_INTERACT; - closeInventory = true; - } else if (entityType == COPPER_GOLEM_TYPE) { - islandPrivilege = IslandPrivileges.COPPER_GOLEM_INTERACT; - } else if (entityType == ALLAY_TYPE) { - islandPrivilege = IslandPrivileges.ALLAY_INTERACT; } else if (usedItemType == Material.FLINT_AND_STEEL && entity instanceof Creeper) { islandPrivilege = IslandPrivileges.IGNITE_CREEPER; - } else if (usedItemType == Material.WATER_BUCKET && entityType == AXOLOTL_TYPE && ServerVersion.isAtLeast(ServerVersion.v1_17)) { - islandPrivilege = IslandPrivileges.PICKUP_AXOLOTL; - } else if (entity instanceof ItemFrame) { - islandPrivilege = IslandPrivileges.ITEM_FRAME; - } else if (entity instanceof Painting) { - islandPrivilege = IslandPrivileges.PAINTING; - } else if (entity instanceof Fish && !ServerVersion.isLegacy()) { - islandPrivilege = IslandPrivileges.PICKUP_FISH; } else if (usedItem != null && entity instanceof PoweredMinecart && plugin.getNMSEntities().isMinecartFuel(usedItem, (PoweredMinecart) entity)) { islandPrivilege = IslandPrivileges.MINECART_OPEN; } else if (entity instanceof Sheep && Materials.isDye(usedItemType)) { islandPrivilege = IslandPrivileges.DYE_SHEEP; - } else if (entityType == PARROT_TYPE && usedItemType == Material.COOKIE) { - islandPrivilege = BukkitEntities.isTameable(entity) ? IslandPrivileges.TAMED_ANIMAL_DAMAGE : IslandPrivileges.ANIMAL_DAMAGE; - } else { - return InteractionResult.SUCCESS; } - interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, islandPrivilege, - 0, true, true); + if (islandPrivilege != null) { + interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, islandPrivilege, + 0, true, true); + } else { + interactionResult = InteractionResult.SUCCESS; + List entityCategories = BukkitEntities.getCategories(entity); + if (entityType == PARROT_TYPE && usedItemType == Material.COOKIE) { + for (EntityCategory entityCategory : entityCategories) { + if (entityCategory.getDamagePrivilege() != null) { + interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, + entityCategory.getDamagePrivilege(), 0, true, true); + if (interactionResult != InteractionResult.SUCCESS) + break; + } + } + } else { + for (EntityCategory entityCategory : entityCategories) { + if (entityCategory.getInteractPrivilege() != null) { + interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, + entityCategory.getInteractPrivilege(), 0, true, true); + if (interactionResult != InteractionResult.SUCCESS) + break; + } + } + } + } } if (closeInventory && interactionResult != InteractionResult.SUCCESS) { @@ -336,32 +341,27 @@ public InteractionResult handleEntityDamage(Entity damager, Entity entity) { if (!damagerSource.isPresent()) return InteractionResult.SUCCESS; - InteractionResult interactionResult; - - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location entityLocation = entity.getLocation(wrapper.getHandle()); - - IslandPrivilege islandPrivilege; - if (BukkitEntities.isTameable(entity)) { - islandPrivilege = IslandPrivileges.TAMED_ANIMAL_DAMAGE; - } else { - EntityCategory entityCategory = EntityCategory.getEntityCategory(Keys.of(entity)); - if (entityCategory == null) - return InteractionResult.SUCCESS; - islandPrivilege = entityCategory.getDamagePrivilege(); + List entityCategories = BukkitEntities.getCategories(entity); + if (!entityCategories.isEmpty()) { + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { + Location entityLocation = entity.getLocation(wrapper.getHandle()); + + InteractionResult interactionResult; + for (EntityCategory entityCategory : entityCategories) { + if (entityCategory.getDamagePrivilege() != null) { + interactionResult = handleInteractionInternal(damagerSource.get(), entityLocation, + entityCategory.getDamagePrivilege(), 0, true, false); + if (interactionResult != InteractionResult.SUCCESS) { + if (damager instanceof Arrow && entity.getFireTicks() > 0) + entity.setFireTicks(0); + return interactionResult; + } + } + } } - - if (islandPrivilege == null) - return InteractionResult.SUCCESS; - - interactionResult = handleInteractionInternal(damagerSource.get(), entityLocation, islandPrivilege, - 0, true, false); } - if (interactionResult != InteractionResult.SUCCESS && damager instanceof Arrow && entity.getFireTicks() > 0) - entity.setFireTicks(0); - - return interactionResult; + return InteractionResult.SUCCESS; } @Override @@ -374,12 +374,24 @@ public InteractionResult handleEntityRide(SuperiorPlayer superiorPlayer, Entity if (!plugin.getSettings().getSpawn().isProtected() && !plugin.getGrid().isIslandsWorld(vehicle.getWorld())) return InteractionResult.SUCCESS; - IslandPrivilege islandPrivilege = BukkitEntities.isHorse(vehicle) ? IslandPrivileges.HORSE_INTERACT : - BukkitEntities.isNautilus(vehicle.getType()) ? IslandPrivileges.NAUTILUS_INTERACT : - vehicle instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_ENTER; + List entityCategories = BukkitEntities.getCategories(vehicle); try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Location entityLocation = vehicle.getLocation(wrapper.getHandle()); + + if (!entityCategories.isEmpty()) { + InteractionResult interactionResult; + for (EntityCategory entityCategory : entityCategories) { + if (entityCategory.getInteractPrivilege() != null) { + interactionResult = handleInteractionInternal(superiorPlayer, entityLocation, + entityCategory.getInteractPrivilege(), 0, true, false); + if (interactionResult != InteractionResult.SUCCESS) + return interactionResult; + } + } + } + + IslandPrivilege islandPrivilege = vehicle instanceof Animals ? IslandPrivileges.ENTITY_RIDE : IslandPrivileges.MINECART_ENTER; return handleInteractionInternal(superiorPlayer, entityLocation, islandPrivilege, 0, true, false); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java index cc3e49fd33..50a33199d2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java @@ -2,12 +2,15 @@ import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; import com.bgsoftware.superiorskyblock.api.hooks.EntitiesProvider; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import org.bukkit.Material; @@ -43,6 +46,17 @@ public class BukkitEntities { @Nullable private static final EntityType ZOMBIE_NAUTILUS_TYPE = EnumHelper.getEnum(EntityType.class, "ZOMBIE_NAUTILUS"); + @Nullable + private static EntityCategory TAMEABLE_CATEGORY; + + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, BukkitEntities::onSettingsUpdate); + } + + private static void onSettingsUpdate() { + TAMEABLE_CATEGORY = plugin.getSettings().getEntityCategoriesMap().getCategoryByName("TAMEABLE"); + } + private BukkitEntities() { } @@ -160,4 +174,13 @@ public static boolean isNautilus(EntityType entityType) { return entityType == NAUTILUS_TYPE || entityType == ZOMBIE_NAUTILUS_TYPE; } + public static List getCategories(Entity entity) { + List categories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(entity)); + if (TAMEABLE_CATEGORY != null && isTameable(entity)) { + categories = new LinkedList<>(categories); + categories.add(TAMEABLE_CATEGORY); + } + return categories; + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategories.java b/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategories.java deleted file mode 100644 index bf6c3503cf..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategories.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.bgsoftware.superiorskyblock.world.entity; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.IslandFlag; -import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; -import com.bgsoftware.superiorskyblock.api.key.KeySet; -import com.bgsoftware.superiorskyblock.core.EnumHelper; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.Keys; -import com.bgsoftware.superiorskyblock.core.key.set.KeySets; -import com.bgsoftware.superiorskyblock.island.flag.IslandFlags; -import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import org.bukkit.entity.Ambient; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Flying; -import org.bukkit.entity.Monster; -import org.bukkit.entity.Slime; -import org.bukkit.entity.Vehicle; - -import java.util.Map; -import java.util.function.Predicate; - -public class EntityCategories { - - private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - - private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); - private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); - private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); - @Nullable - private static final EntityType GLOW_ITEM_FRAME = EnumHelper.getEnum(EntityType.class, "GLOW_ITEM_FRAME"); - - public static void registerListeners(PluginEventsDispatcher dispatcher) { - dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, EntityCategories::onSettingsUpdate); - } - - private static void onSettingsUpdate() { - EntityCategory.clear(); - - // Load built-in categories with low priority - new Builder("ANIMAL", createEntityTypesSet(EntityCategories::isAnimalType)) - .spawnerSpawnFlag(IslandFlags.SPAWNER_ANIMALS_SPAWN).naturalSpawnFlag(IslandFlags.NATURAL_ANIMALS_SPAWN).build(); - new Builder("MONSTER", createEntityTypesSet(EntityCategories::isMonsterType)).build(); - - // Load config categories, which can override the categories above - Map entityCategories = plugin.getSettings().getEntityCategories(); - entityCategories.forEach((name, entityTypes) -> { - new Builder(name, entityTypes).build(); - }); - - // Register built-in categories with high priority - new Builder("PAINTING", createEntityTypesSet(EntityType.PAINTING)) - .damagePrivilege(IslandPrivileges.PAINTING).spawnPrivilege(IslandPrivileges.BUILD) - .naturalSpawnFlag(null).spawnerSpawnFlag(null).build(); - new Builder("ITEM_FRAME", createEntityTypesSet(EntityType.ITEM_FRAME, GLOW_ITEM_FRAME)) - .damagePrivilege(IslandPrivileges.ITEM_FRAME).spawnPrivilege(IslandPrivileges.BUILD) - .naturalSpawnFlag(null).spawnerSpawnFlag(null).build(); - new Builder("ARMOR_STAND", createEntityTypesSet(EntityType.ARMOR_STAND)) - .damagePrivilege(IslandPrivileges.BREAK).spawnPrivilege(IslandPrivileges.BUILD) - .naturalSpawnFlag(null).spawnerSpawnFlag(null).build(); - new Builder("VEHICLE", createEntityTypesSet(EntityCategories::isVehicleType)) - .damagePrivilege(IslandPrivileges.MINECART_DAMAGE).spawnPrivilege(IslandPrivileges.MINECART_PLACE) - .naturalSpawnFlag(null).spawnerSpawnFlag(null).build(); - } - - private EntityCategories() { - - } - - private static boolean isAnimalType(EntityType entityType) { - Class entityClass = entityType.getEntityClass(); - // This call is done after Monster category is checked. - // Therefore, the checks below are enough. - return entityClass != null && - // We check that the entity type is whether a Creature or an Ambient - (Creature.class.isAssignableFrom(entityClass) || Ambient.class.isAssignableFrom(entityClass)) && - // We make sure this is not Hoglin; In Bukkit, they are considered Animals. - entityClass != HOGLIN_CLASS && - // We make sure this is not Skeleton/Zombie horses; In Bukkit, they are considered Animals. - entityClass != SKELETON_HORSE_CLASS && entityClass != ZOMBIE_HORSE_CLASS; - } - - private static boolean isMonsterType(EntityType entityType) { - Class entityClass = entityType.getEntityClass(); - return entityClass != null && (Monster.class.isAssignableFrom(entityClass) || - // Checks for slimes & magma cubes - Slime.class.isAssignableFrom(entityClass) || - // Checks for ghasts and phantoms - Flying.class.isAssignableFrom(entityClass) || - // In Bukkit, Hoglins are considered as Animals for no reason. - // We want to explicitly tell the plugin its monster type. - entityClass == HOGLIN_CLASS || - // In Bukkit, Skeleton and Zombie horses are considered Horses, - // and therefore they are animals. We want to explicit tell the plugin - // they are monsters. - entityClass == SKELETON_HORSE_CLASS || entityClass == ZOMBIE_HORSE_CLASS - ); - } - - private static boolean isVehicleType(EntityType entityType) { - Class entityClass = entityType.getEntityClass(); - return entityClass != null && Vehicle.class.isAssignableFrom(entityClass) && !Creature.class.isAssignableFrom(entityClass); - } - - private static KeySet createEntityTypesSet(Predicate predicate) { - KeySet entityTypes = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); - for (EntityType entityType : EntityType.values()) { - if (predicate.test(entityType)) - entityTypes.add(Keys.of(entityType)); - } - return entityTypes; - } - - private static KeySet createEntityTypesSet(EntityType... entityTypes) { - KeySet entities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); - for (EntityType entityType : entityTypes) { - if (entityType != null) - entities.add(Keys.of(entityType)); - } - return entities; - } - - private static Class getEntityTypeClass(String clazz) { - try { - return Class.forName(clazz); - } catch (ClassNotFoundException error) { - return null; - } - } - - private static IslandPrivilege getOrRegisterPrivilege(@Nullable String name) { - if (name == null) - return null; - - try { - return IslandPrivilege.getByName(name); - } catch (NullPointerException error) { - IslandPrivilege.register(name); - return IslandPrivilege.getByName(name); - } - } - - private static IslandFlag getOrRegisterFlag(@Nullable String name) { - if (name == null) - return null; - - try { - return IslandFlag.getByName(name); - } catch (NullPointerException error) { - IslandFlag.register(name); - return IslandFlag.getByName(name); - } - } - - private static class Builder { - - private final KeySet entityTypes; - - private String damagePrivilege; - private String spawnPrivilege; - private String spawnerSpawnFlag; - private String naturalSpawnFlag; - - public Builder(String name, KeySet entityTypes) { - this.entityTypes = entityTypes; - this.damagePrivilege = name + "_DAMAGE"; - this.spawnPrivilege = name + "_SPAWN"; - this.spawnerSpawnFlag = "SPAWNER_" + name + "_SPAWN"; - this.naturalSpawnFlag = "NATURAL_" + name + "_SPAWN"; - } - - public Builder damagePrivilege(@Nullable IslandPrivilege damagePrivilege) { - this.damagePrivilege = damagePrivilege == null ? null : damagePrivilege.getName(); - return this; - } - - public Builder spawnPrivilege(@Nullable IslandPrivilege spawnPrivilege) { - this.spawnPrivilege = spawnPrivilege == null ? null : spawnPrivilege.getName(); - return this; - } - - public Builder spawnerSpawnFlag(@Nullable IslandFlag spawnerSpawnFlag) { - this.spawnerSpawnFlag = spawnerSpawnFlag == null ? null : spawnerSpawnFlag.getName(); - return this; - } - - public Builder naturalSpawnFlag(@Nullable IslandFlag naturalSpawnFlag) { - this.naturalSpawnFlag = naturalSpawnFlag == null ? null : naturalSpawnFlag.getName(); - return this; - } - - public EntityCategory build() { - return EntityCategory.register(this.entityTypes, - getOrRegisterPrivilege(this.damagePrivilege), getOrRegisterPrivilege(this.spawnPrivilege), - getOrRegisterFlag(this.spawnerSpawnFlag), getOrRegisterFlag(this.naturalSpawnFlag)); - } - - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategory.java b/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategory.java deleted file mode 100644 index 424cf8fd29..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategory.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.bgsoftware.superiorskyblock.world.entity; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.api.island.IslandFlag; -import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.api.key.KeyMap; -import com.bgsoftware.superiorskyblock.api.key.KeySet; -import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; -import com.google.common.base.Preconditions; - -public class EntityCategory { - - private static final KeyMap entityToCategories = KeyMaps.createHashMap(KeyIndicator.ENTITY_TYPE); - - @Nullable - private final IslandPrivilege damagePrivilege; - @Nullable - private final IslandPrivilege spawnPrivilege; - @Nullable - private final IslandFlag spawnerSpawnFlag; - @Nullable - private final IslandFlag naturalSpawnFlag; - - private EntityCategory(KeySet entityTypes, @Nullable IslandPrivilege damagePrivilege, - @Nullable IslandPrivilege spawnPrivilege, @Nullable IslandFlag spawnerSpawnFlag, - @Nullable IslandFlag naturalSpawnFlag) { - this.damagePrivilege = damagePrivilege; - this.spawnPrivilege = spawnPrivilege; - this.spawnerSpawnFlag = spawnerSpawnFlag; - this.naturalSpawnFlag = naturalSpawnFlag; - setCategoryForEntities(entityTypes); - } - - private void setCategoryForEntities(KeySet entityTypes) { - for (Key entityType : entityTypes) { - entityToCategories.put(entityType, this); - } - } - - @Nullable - public IslandPrivilege getDamagePrivilege() { - return damagePrivilege; - } - - @Nullable - public IslandPrivilege getSpawnPrivilege() { - return spawnPrivilege; - } - - @Nullable - public IslandFlag getSpawnerSpawnFlag() { - return spawnerSpawnFlag; - } - - @Nullable - public IslandFlag getNaturalSpawnFlag() { - return naturalSpawnFlag; - } - - @Nullable - public static EntityCategory getEntityCategory(Key entityType) { - return entityToCategories.get(entityType); - } - - public static EntityCategory register(KeySet entityTypes, @Nullable IslandPrivilege damagePrivilege, - @Nullable IslandPrivilege spawnPrivilege, @Nullable IslandFlag spawnerSpawnFlag, - @Nullable IslandFlag naturalSpawnFlag) { - Preconditions.checkNotNull(entityTypes, "entityTypes parameter cannot be null."); - return new EntityCategory(entityTypes, damagePrivilege, spawnPrivilege, spawnerSpawnFlag, naturalSpawnFlag); - } - - public static void clear() { - entityToCategories.clear(); - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategoryImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategoryImpl.java new file mode 100644 index 0000000000..7b0f0d440d --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/entity/EntityCategoryImpl.java @@ -0,0 +1,74 @@ +package com.bgsoftware.superiorskyblock.world.entity; + +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; +import com.bgsoftware.superiorskyblock.api.island.IslandFlag; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.key.set.KeySets; + +import java.util.HashSet; + +public class EntityCategoryImpl implements EntityCategory { + + private final String name; + private final KeySet entities; + @Nullable + private final IslandPrivilege spawnPrivilege; + @Nullable + private final IslandPrivilege damagePrivilege; + @Nullable + private final IslandPrivilege interactPrivilege; + @Nullable + private final IslandFlag spawnerSpawnFlag; + @Nullable + private final IslandFlag naturalSpawnFlag; + + public EntityCategoryImpl(String name, KeySet entities, @Nullable IslandPrivilege spawnPrivilege, + @Nullable IslandPrivilege damagePrivilege, @Nullable IslandPrivilege interactPrivilege, + @Nullable IslandFlag spawnerSpawnFlag, @Nullable IslandFlag naturalSpawnFlag) { + this.name = name; + this.entities = KeySets.unmodifiableKeySet(entities); + this.spawnPrivilege = spawnPrivilege; + this.damagePrivilege = damagePrivilege; + this.interactPrivilege = interactPrivilege; + this.spawnerSpawnFlag = spawnerSpawnFlag; + this.naturalSpawnFlag = naturalSpawnFlag; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public KeySet getEntities() { + return this.entities; + } + + @Override + public IslandPrivilege getSpawnPrivilege() { + return this.spawnPrivilege; + } + + @Override + public IslandPrivilege getDamagePrivilege() { + return this.damagePrivilege; + } + + @Override + public IslandPrivilege getInteractPrivilege() { + return this.interactPrivilege; + } + + @Override + public IslandFlag getSpawnerSpawningIslandFlag() { + return this.spawnerSpawnFlag; + } + + @Override + public IslandFlag getNaturalSpawningIslandFlag() { + return this.naturalSpawnFlag; + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index a5d5f98d5e..8fdd692f7b 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -968,18 +968,4 @@ help-on-invalid-command: true # Should players receive a help instead of a `NO_COMMAND_PERMISSION` message # when using a command they don't have permission for? -help-on-no-permission: false - -# Configure custom entity categories. -# By default, there are two entity categories - ANIMALS and MONSTER -# You can add your own custom categories in here, and configure which entities are part of the category. -# Entities in the custom categories will have custom privileges and flags for damaging and spawning them. -# You can add the custom privileges and island flags manually to the menus. -# For example: -# entity-categories: -# VILLAGERS: -# - VILLAGER -# The `VILLAGERS` category will have VILLAGER entities in it. -# The privileges `VILLAGERS_SPAWN` and `VILLAGERS_DAMAGE` will be required by players, and the island flags -# `SPAWNER_VILLAGERS_SPAWN` and `NATURAL_VILLAGERS_SPAWN` will be required to be enabled for the island. -entity-categories: { } \ No newline at end of file +help-on-no-permission: false \ No newline at end of file diff --git a/src/main/resources/entity-categories.yml b/src/main/resources/entity-categories.yml new file mode 100644 index 0000000000..fc6e4915bd --- /dev/null +++ b/src/main/resources/entity-categories.yml @@ -0,0 +1,127 @@ +###################################################### +## ## +## SuperiorSkyblock 2 ## +## Developed by Ome_R ## +## ## +###################################################### + +# Configure the categories of entities of the plugin. +# The format of the file is as so: +# : +# entities: +# - +# actions: +# # The privilege required to spawn the entities using spawn eggs +# SPAWN: +# # The privilege required to damage the entities +# DAMAGE: +# # The privilege required to interact with the entities +# INTERACT: +# # The island flag required so the entities can spawn from spawners +# SPAWNER_SPAWN: +# # The island flag required so the entities can spawn vanilla +# NATURAL_SPAWN: +# You can create as many custom categories as you want. +# There are custom groups used for detecting animals, monsters and tameable entities. +# These groups do not have `entities` and the entities are added automatically depending on your Minecraft version. + +# Custom interact groups +ALLAY: + entities: + - ALLAY + actions: + INTERACT: ALLAY_INTERACT + +AXOLOTL: + entities: + - AXOLOTL + actions: + INTERACT: PICKUP_AXOLOTL + +COPPER_GOLEM: + entities: + - COPPER_GOLEM + actions: + INTERACT: COPPER_GOLEM_INTERACT + +FISH: + entities: + - COD + - PUFFERFISH + - SALMON + - TADPOLE + - TROPICAL_FISH + actions: + INTERACT: PICKUP_FISH + +HORSES: + entities: + - CAMEL + - CAMEL_HUSK + - DONKEY + - HORSE + - LLAMA + - MULE + - SKELETON_HORSE + - TRADER_LLAMA + - ZOMBIE_HORSE + actions: + INTERACT: HORSE_INTERACT + +NAUTILUS: + entities: + - NAUTILUS + - ZOMBIE_NAUTILUS + actions: + INTERACT: NAUTILUS_INTERACT + +VILLAGERS: + entities: + - VILLAGER + actions: + INTERACT: VILLAGER_TRADING + +# Custom entities with custom functionalities +ARMOR_STAND: + entities: + - ARMOR_STAND + actions: + SPAWN: BUILD + DAMAGE: BREAK + INTERACT: BUILD + +ITEM_FRAME: + entities: + - GLOW_ITEM_FRAME + - ITEM_FRAME + actions: + SPAWN: ITEM_FRAME + DAMAGE: ITEM_FRAME + INTERACT: ITEM_FRAME + +PAINTING: + entities: + - PAINTING + actions: + SPAWN: PAINTING + DAMAGE: PAINTING + INTERACT: PAINTING + +# Custom built-in groups +TAMEABLE: + actions: + DAMAGE: TAMED_ANIMAL_DAMAGE + +ANIMAL: + actions: + SPAWN: ANIMAL_SPAWN + DAMAGE: ANIMAL_DAMAGE + SPAWNER_SPAWN: SPAWNER_ANIMALS_SPAWN + NATURAL_SPAWN: NATURAL_ANIMALS_SPAWN + +MONSTER: + actions: + SPAWN: MONSTER_SPAWN + DAMAGE: MONSTER_DAMAGE + SPAWNER_SPAWN: SPAWNER_MONSTER_SPAWN + NATURAL_SPAWN: NATURAL_MONSTER_SPAWN From ff056e35b0cb1d04b35cbb53124e61e74c5f0a5f Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 18 Apr 2026 18:05:02 +0200 Subject: [PATCH 543/600] Fixed displaying Potted Golden Dandelion in Block Counts menu (#2905) --- .../core/menu/button/impl/CountsPagedObjectButton.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java index 3851962846..c16c737760 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/button/impl/CountsPagedObjectButton.java @@ -157,6 +157,7 @@ public class CountsPagedObjectButton extends AbstractPagedMenuButton Date: Sat, 18 Apr 2026 19:13:02 +0300 Subject: [PATCH 544/600] Fix the ability to breed animals with golden dandelions on other islands (#2904) --- .../module/upgrades/type/UpgradeTypeEntityLimits.java | 7 ++++++- .../service/region/RegionManagerServiceImpl.java | 9 +++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java index 61d42798c2..e2f917cdd1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeEntityLimits.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.commands.ISuperiorCommand; +import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.PlayerHand; @@ -49,6 +50,9 @@ public class UpgradeTypeEntityLimits implements IUpgradeType { + @Nullable + private static final Material GOLDEN_DANDELION_TYPE = EnumHelper.getEnum(Material.class, "GOLDEN_DANDELION"); + private final Map entityBreederPlayers = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS); private final Map vehiclesOwners = AutoRemovalMap.newMap(2, TimeUnit.SECONDS, Location2ObjectMap::new); private final Map spawnEggPlayers = AutoRemovalMap.newHashMap(2, TimeUnit.SECONDS); @@ -292,7 +296,8 @@ public void onEntityFeed(PlayerInteractAtEntityEvent e) { PlayerHand usedHand = BukkitItems.getHand(e); ItemStack usedItem = BukkitItems.getHandItem(e.getPlayer(), usedHand); - if (usedItem == null || !plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) e.getRightClicked())) + if (usedItem == null || (usedItem.getType() != GOLDEN_DANDELION_TYPE && + !plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) e.getRightClicked()))) return; // We want to calculate the amount of items consumed by breeding this animal. diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index 46b1c15d16..fd6cd28ef3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -72,17 +72,13 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService @Nullable private static final Material OMINOUS_TRIAL_KEY = EnumHelper.getEnum(Material.class, "OMINOUS_TRIAL_KEY"); @Nullable - private static final EntityType ALLAY_TYPE = EnumHelper.getEnum(EntityType.class, "ALLAY"); - @Nullable - private static final EntityType AXOLOTL_TYPE = EnumHelper.getEnum(EntityType.class, "AXOLOTL"); - @Nullable private static final EntityType LLAMA_TYPE = EnumHelper.getEnum(EntityType.class, "LLAMA"); @Nullable private static final EntityType HAPPY_GHAST_TYPE = EnumHelper.getEnum(EntityType.class, "HAPPY_GHAST"); @Nullable private static final EntityType PARROT_TYPE = EnumHelper.getEnum(EntityType.class, "PARROT"); @Nullable - private static final EntityType COPPER_GOLEM_TYPE = EnumHelper.getEnum(EntityType.class, "COPPER_GOLEM"); + private static final Material GOLDEN_DANDELION_TYPE = EnumHelper.getEnum(Material.class, "GOLDEN_DANDELION"); private static final int MAX_PICKUP_DISTANCE = 1; private static EnumerateSet WORLD_PERMISSIONS_CACHE; @@ -267,7 +263,8 @@ public InteractionResult handleEntityInteract(SuperiorPlayer superiorPlayer, Ent } IslandPrivilege islandPrivilege = null; - if (usedItem != null && entity instanceof Animals && plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) entity)) { + if (usedItem != null && entity instanceof Animals && (usedItemType == GOLDEN_DANDELION_TYPE || + plugin.getNMSEntities().isAnimalFood(usedItem, (Animals) entity))) { islandPrivilege = IslandPrivileges.ANIMAL_BREED; } else if (usedItemType == Material.NAME_TAG) { islandPrivilege = IslandPrivileges.NAME_ENTITY; From a7b204f6e7104c93f8c0757b92b2ac8654b865ff Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 18 Apr 2026 19:18:24 +0300 Subject: [PATCH 545/600] Fixed the ability to shear some blocks on other islands (#2904) --- src/main/resources/interactables.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/resources/interactables.yml b/src/main/resources/interactables.yml index 536d39bcfd..9000838c4b 100644 --- a/src/main/resources/interactables.yml +++ b/src/main/resources/interactables.yml @@ -14,7 +14,6 @@ # You can create as many custom privileges as you want. interactables: - - 'TEST' - 'ACACIA_BUTTON' - 'ACACIA_DOOR' - 'ACACIA_FENCE' @@ -173,6 +172,7 @@ interactables: - 'JUNGLE_TRAPDOOR' - 'JUNGLE_WALL_HANGING_SIGN' - 'JUNGLE_WALL_SIGN' + - 'KELP' - 'LECTERN' - 'LEVER' - 'LIGHT_BLUE_BED' @@ -320,6 +320,7 @@ interactables: - 'TRAP_DOOR' - 'TRAPPED_CHEST' - 'TURTLE_EGG' + - 'TWISTING_VINES' - 'VAULT' - 'WALL_SIGN' - 'WARPED_BUTTON' @@ -353,6 +354,7 @@ interactables: - 'WEATHERED_COPPER_DOOR' - 'WEATHERED_COPPER_GOLEM_STATUE' - 'WEATHERED_COPPER_TRAPDOOR' + - 'WEEPING_VINES' - 'WHITE_BED' - 'WHITE_CANDLE' - 'WHITE_SHULKER_BOX' From d9c084e33077f8c6901fa1631abbf8994fa67c0a Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 18 Apr 2026 19:28:44 +0300 Subject: [PATCH 546/600] Fixed the ability to harvest sweet berry bush by growing them (#2904) --- .../service/region/RegionManagerServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index fd6cd28ef3..e5d32733ce 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -211,7 +211,8 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc } else if (action == Action.PHYSICAL && blockType == TURTLE_EGG) { islandPrivilege = IslandPrivileges.BUILD; } else if (blockType == SWEET_BERRY_BUSH && action == Action.RIGHT_CLICK_BLOCK && - Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem)) { + Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem) && + ((org.bukkit.block.data.Ageable) plugin.getNMSWorld().getBlockData(block)).getAge() < 3) { islandPrivilege = IslandPrivileges.FERTILIZE; } else if (stackedBlockAmount > 1) { islandPrivilege = IslandPrivileges.BREAK; From 97554b3bc7e188313d3153a55e0f84962fcb3edb Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 18 Apr 2026 19:51:05 +0300 Subject: [PATCH 547/600] Fixed the ability to harvest cave vines by growing them (#2904) --- NMS/src/main/templates/AbstractNMSWorld.java.template | 6 ++++++ .../com/bgsoftware/superiorskyblock/nms/NMSWorld.java | 4 ++++ .../service/region/RegionManagerServiceImpl.java | 8 ++++++++ 3 files changed, 18 insertions(+) diff --git a/NMS/src/main/templates/AbstractNMSWorld.java.template b/NMS/src/main/templates/AbstractNMSWorld.java.template index bc9cdf6ca4..9f6277b310 100644 --- a/NMS/src/main/templates/AbstractNMSWorld.java.template +++ b/NMS/src/main/templates/AbstractNMSWorld.java.template @@ -51,6 +51,7 @@ import org.bukkit.World; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.BubbleColumn; +import org.bukkit.block.data.type.CaveVinesPlant; import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.WallSign; import ${CRAFTBUKKIT_PACKAGE}.CraftWorld; @@ -235,6 +236,11 @@ public abstract class AbstractNMSWorld implements NMSWorld { return SignType.UNKNOWN; } + @Override + public boolean hasBerries(org.bukkit.block.Block block) { + return ((CaveVinesPlant) block.getBlockData()).isBerries(); + } + @Override public PistonPushReaction getPistonReaction(org.bukkit.block.Block block) { BlockState blockState = NMSUtilsVersioned.getBlockState(block); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java index 3373471704..032dbb48b4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java @@ -48,6 +48,10 @@ default SignType getSignType(Block block) { SignType getSignType(Object sign); + default boolean hasBerries(Block block) { + return false; + } + PistonPushReaction getPistonReaction(Block block); int getDefaultAmount(Block block); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index e5d32733ce..b1f63b1139 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -66,6 +66,10 @@ public class RegionManagerServiceImpl implements RegionManagerService, IService @Nullable private static final Material SWEET_BERRY_BUSH = EnumHelper.getEnum(Material.class, "SWEET_BERRY_BUSH"); @Nullable + private static final Material CAVE_VINES = EnumHelper.getEnum(Material.class, "CAVE_VINES"); + @Nullable + private static final Material CAVE_VINES_PLANT = EnumHelper.getEnum(Material.class, "CAVE_VINES_PLANT"); + @Nullable private static final Material VAULT = EnumHelper.getEnum(Material.class, "VAULT"); @Nullable private static final Material TRIAL_KEY = EnumHelper.getEnum(Material.class, "TRIAL_KEY"); @@ -214,6 +218,10 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem) && ((org.bukkit.block.data.Ageable) plugin.getNMSWorld().getBlockData(block)).getAge() < 3) { islandPrivilege = IslandPrivileges.FERTILIZE; + } else if ((blockType == CAVE_VINES || blockType == CAVE_VINES_PLANT) && action == Action.RIGHT_CLICK_BLOCK && + Materials.BONE_MEAL.toBukkitItem().isSimilar(usedItem) && + !plugin.getNMSWorld().hasBerries(block)) { + islandPrivilege = IslandPrivileges.FERTILIZE; } else if (stackedBlockAmount > 1) { islandPrivilege = IslandPrivileges.BREAK; } From b8c945135a08bb07bfd0475c8e0c2e8d8d19d9d8 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 18 Apr 2026 20:01:03 +0300 Subject: [PATCH 548/600] Do not send protected message for off-hand interactions --- .../listener/ProtectionListener.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 114da0a0e5..7ac5e1b22e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; +import com.bgsoftware.superiorskyblock.core.PlayerHand; import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; @@ -98,7 +99,7 @@ private void onPlayerInteract(GameEvent e) { if (handleBrushUse(e)) return; if (handleMinecartPlace(e)) return; if (handleEntityInteract(e)) return; - handleBlockInteract(e, e.getArgs().player, e.getArgs().action, e.getArgs().clickedBlock, e.getArgs().usedItem); + handleBlockInteract(e, e.getArgs().player, e.getArgs().action, e.getArgs().clickedBlock, e.getArgs().usedHand, e.getArgs().usedItem); } private void onEntityInteractBlock(GameEvent e) { @@ -114,7 +115,7 @@ private void onEntityInteractBlock(GameEvent if (!(projectileSource instanceof Player)) return; - if (handleBlockInteract(e, (Player) projectileSource, Action.PHYSICAL, clickedBlock, null)) { + if (handleBlockInteract(e, (Player) projectileSource, Action.PHYSICAL, clickedBlock, null, null)) { // We want to remove the projectile as well when it is not possible to interact entity.remove(); } @@ -243,15 +244,16 @@ private boolean handleEntityInteract(GameEvent e, Player player, Action action, - @Nullable Block clickedBlock, @Nullable ItemStack usedItem) { + private boolean handleBlockInteract(GameEvent e, Player player, Action action, @Nullable Block clickedBlock, + @Nullable PlayerHand usedHand, @Nullable ItemStack usedItem) { if (clickedBlock == null) return false; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player); InteractionResult interactionResult = this.protectionManager.get().handleBlockInteract( superiorPlayer, clickedBlock, action, usedItem); - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, + usedItem != null || usedHand != PlayerHand.OFF_HAND)) { e.setCancelled(); return true; } From b548c7b54a3445cdec329ef72a9822e74d901788 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Sat, 18 Apr 2026 19:05:58 +0200 Subject: [PATCH 549/600] Added warning about missing permissions and settings in their menu files (#2895) --- .../core/menu/impl/MenuIslandFlags.java | 13 +++++++++++++ .../core/menu/impl/MenuIslandPrivileges.java | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java index 4b81a9e722..9efe25829a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java @@ -12,6 +12,7 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; @@ -28,9 +29,12 @@ import java.io.File; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Optional; +import java.util.Set; public class MenuIslandFlags extends AbstractPagedMenu { @@ -63,17 +67,26 @@ public static MenuIslandFlags createInstance() { YamlConfiguration cfg = menuParseResult.getConfig(); List islandFlags = new LinkedList<>(); + Set detectedFlags = new HashSet<>(); Optional.ofNullable(cfg.getConfigurationSection("settings")).ifPresent(settingsSection -> { for (String islandFlagName : settingsSection.getKeys(false)) { Optional.ofNullable(settingsSection.getConfigurationSection(islandFlagName)).ifPresent(islandFlagSection -> { if (islandFlagSection.getBoolean("display-menu", true)) { islandFlags.add(loadIslandFlagInfo(islandFlagSection, islandFlagName, islandFlags.size())); + detectedFlags.add(islandFlagName.toUpperCase(Locale.ENGLISH)); } }); } }); + for (IslandFlag islandFlag : IslandFlag.values()) { + String islandFlagName = islandFlag.getName(); + if (!detectedFlags.contains(islandFlagName)) { + Log.warnFromFile("settings.yml", "Potentially missing setting ", islandFlagName); + } + } + return new MenuIslandFlags(menuParseResult, islandFlags); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java index 5e17cabaad..21671e79b1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java @@ -13,6 +13,7 @@ import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.io.MenuParserImpl; import com.bgsoftware.superiorskyblock.core.itemstack.ItemBuilder; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.menu.AbstractPagedMenu; import com.bgsoftware.superiorskyblock.core.menu.MenuIdentifiers; import com.bgsoftware.superiorskyblock.core.menu.MenuParseResult; @@ -29,9 +30,12 @@ import java.io.File; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Optional; +import java.util.Set; public class MenuIslandPrivileges extends AbstractPagedMenu< MenuIslandPrivileges.View, MenuIslandPrivileges.Args, MenuIslandPrivileges.IslandPrivilegeInfo> { @@ -91,17 +95,26 @@ public static MenuIslandPrivileges createInstance() { String higherRolePermission = cfg.getString("messages.higher-role-permission", ""); List islandPrivileges = new LinkedList<>(); + Set detectedPrivileges = new HashSet<>(); Optional.ofNullable(cfg.getConfigurationSection("permissions")).ifPresent(permissionsSection -> { for (String islandPrivilegeName : permissionsSection.getKeys(false)) { Optional.ofNullable(permissionsSection.getConfigurationSection(islandPrivilegeName)).ifPresent(islandPrivilegeSection -> { if (islandPrivilegeSection.getBoolean("display-menu", true)) { islandPrivileges.add(loadIslandPrivilegeInfo(islandPrivilegeSection, islandPrivilegeName, islandPrivileges.size())); + detectedPrivileges.add(islandPrivilegeName.toUpperCase(Locale.ENGLISH)); } }); } }); + for (IslandPrivilege islandPrivilege : IslandPrivilege.values()) { + String islandPrivilegeName = islandPrivilege.getName(); + if (!detectedPrivileges.contains(islandPrivilegeName)) { + Log.warnFromFile("permissions.yml", "Potentially missing permission ", islandPrivilegeName); + } + } + return new MenuIslandPrivileges(menuParseResult, islandPrivileges, noRolePermission, exactRolePermission, higherRolePermission); } From 57a802dca6ade6c7c4f489172a878ccb8e153d48 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 18 Apr 2026 20:42:27 +0300 Subject: [PATCH 550/600] Fix calculation of unloaded chunks not working in 1.16-1.17 (#2893) --- .../superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java | 5 +++-- .../bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java index 91eb999006..206e94f9e4 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java @@ -261,8 +261,9 @@ public void onUnloadedChunk(ChunkPosition chunkPosition, NBTTagCompound unloaded byte yPosition = sectionCompound.getByte("Y"); if (sectionCompound.hasKeyOfType("Palette", 9) && sectionCompound.hasKeyOfType("BlockStates", 12)) { //noinspection deprecation - chunkSections[i] = new ChunkSection(yPosition << 4); - chunkSections[i].getBlocks().a(sectionCompound.getList("Palette", 10), sectionCompound.getLongArray("BlockStates")); + ChunkSection chunkSection = chunkSections[i] = new ChunkSection(yPosition << 4); + chunkSection.getBlocks().a(sectionCompound.getList("Palette", 10), sectionCompound.getLongArray("BlockStates")); + chunkSection.recalcBlockCounts(); } } diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java index 712c5bd6d8..561acfb78d 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java @@ -218,9 +218,10 @@ public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound byte yPosition = sectionCompound.getByte("Y"); if (sectionCompound.contains("Palette", 9) && sectionCompound.contains("BlockStates", 12)) { //noinspection deprecation - levelChunkSections[i] = new LevelChunkSection(yPosition); - levelChunkSections[i].getStates().read(sectionCompound.getList("Palette", 10), + LevelChunkSection levelChunkSection = levelChunkSections[i] = new LevelChunkSection(yPosition); + levelChunkSection.getStates().read(sectionCompound.getList("Palette", 10), sectionCompound.getLongArray("BlockStates")); + levelChunkSection.recalcBlockCounts(); } } From 08603a3a6c2bfdf564500b51ef3ca2a922308f23 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 18 Apr 2026 22:40:58 +0300 Subject: [PATCH 551/600] Fix safe blocks not working as expected in some cases (#2900) --- .../templates/AbstractNMSWorld.java.template | 25 +++++++++++++ .../nms/v1_12_R1/NMSWorldImpl.java | 28 ++++++++++++++- .../nms/v1_16_R3/NMSWorldImpl.java | 25 +++++++++++++ .../nms/v1_8_R3/NMSWorldImpl.java | 28 ++++++++++++++- .../superiorskyblock/nms/NMSWorld.java | 2 ++ .../world/EntityTeleports.java | 4 +-- .../superiorskyblock/world/WorldBlocks.java | 35 ++++++++++++------- 7 files changed, 131 insertions(+), 16 deletions(-) diff --git a/NMS/src/main/templates/AbstractNMSWorld.java.template b/NMS/src/main/templates/AbstractNMSWorld.java.template index 9f6277b310..1f77a2d5b1 100644 --- a/NMS/src/main/templates/AbstractNMSWorld.java.template +++ b/NMS/src/main/templates/AbstractNMSWorld.java.template @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; import com.bgsoftware.superiorskyblock.nms.ICachedBlock; @@ -30,6 +31,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundInitializeBorderPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.EmptyBlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -88,7 +90,16 @@ public abstract class AbstractNMSWorld implements NMSWorld { @Override public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + try { + return getBlockKeyInternal(chunkSnapshot, x, y, z); + } catch (ArrayIndexOutOfBoundsException error) { + return ConstantKeys.AIR; + } + } + + private Key getBlockKeyInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); + Location location = new Location( Bukkit.getWorld(chunkSnapshot.getWorldName()), (chunkSnapshot.getX() << 4) + x, @@ -99,6 +110,20 @@ public abstract class AbstractNMSWorld implements NMSWorld { return Keys.of(KeyBlocksCache.getBlockKey(block), location); } + @Override + public boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + try { + return canPlayerSuffocateInternal(chunkSnapshot, x, y, z); + } catch (ArrayIndexOutOfBoundsException error) { + return true; + } + } + + private boolean canPlayerSuffocateInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + BlockState blockState = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState(); + return !blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty(); + } + @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { SpawnerBlockEntity spawnerBlockEntity = NMSUtils.getBlockEntityAt(location, SpawnerBlockEntity.class); diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java index 6559f82fda..037621d9de 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSWorldImpl.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -68,8 +69,16 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { } @Override - @SuppressWarnings("deprecation") public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + try { + return getBlockKeyInternal(chunkSnapshot, x, y, z); + } catch (ArrayIndexOutOfBoundsException error) { + return ConstantKeys.AIR; + } + } + + @SuppressWarnings("deprecation") + private Key getBlockKeyInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { int blockId = chunkSnapshot.getBlockTypeId(x, y, z); int blockData = chunkSnapshot.getBlockData(x, y, z); int combinedId = blockId + (blockData << 12); @@ -84,6 +93,23 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { return Keys.of(KeyBlocksCache.getBlockKey(Block.getByCombinedId(combinedId)), location); } + @Override + public boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + try { + return canPlayerSuffocateInternal(chunkSnapshot, x, y, z); + } catch (ArrayIndexOutOfBoundsException error) { + return true; + } + } + + @SuppressWarnings("deprecation") + private boolean canPlayerSuffocateInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + int blockId = chunkSnapshot.getBlockTypeId(x, y, z); + int blockData = chunkSnapshot.getBlockData(x, y, z); + int combinedId = blockId + (blockData << 12); + return Block.getByCombinedId(combinedId).r(); + } + @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { TileEntityMobSpawner mobSpawner = NMSUtils.getTileEntityAt(location, TileEntityMobSpawner.class); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java index adf738a68d..39db4e0d39 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSWorldImpl.java @@ -10,6 +10,7 @@ import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -29,6 +30,7 @@ import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; import com.destroystokyo.paper.antixray.ChunkPacketBlockController; import net.minecraft.server.v1_16_R3.Block; +import net.minecraft.server.v1_16_R3.BlockAccessAir; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.BlockPropertySlabType; import net.minecraft.server.v1_16_R3.BlockStepAbstract; @@ -79,7 +81,16 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { @Override public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + try { + return getBlockKeyInternal(chunkSnapshot, x, y, z); + } catch (ArrayIndexOutOfBoundsException error) { + return ConstantKeys.AIR; + } + } + + private Key getBlockKeyInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { Block block = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState().getBlock(); + Location location = new Location( Bukkit.getWorld(chunkSnapshot.getWorldName()), (chunkSnapshot.getX() << 4) + x, @@ -90,6 +101,20 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { return Keys.of(KeyBlocksCache.getBlockKey(block), location); } + @Override + public boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + try { + return canPlayerSuffocateInternal(chunkSnapshot, x, y, z); + } catch (ArrayIndexOutOfBoundsException error) { + return true; + } + } + + private boolean canPlayerSuffocateInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + IBlockData blockData = ((CraftBlockData) chunkSnapshot.getBlockData(x, y, z)).getState(); + return !blockData.getCollisionShape(BlockAccessAir.INSTANCE, BlockPosition.ZERO).isEmpty(); + } + @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { TileEntityMobSpawner mobSpawner = NMSUtils.getTileEntityAt(location, TileEntityMobSpawner.class); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java index 7ba4c3a09c..55f0a4ae13 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSWorldImpl.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.island.signs.IslandSigns; @@ -67,8 +68,16 @@ public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { } @Override - @SuppressWarnings("deprecation") public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + try { + return getBlockKeyInternal(chunkSnapshot, x, y, z); + } catch (ArrayIndexOutOfBoundsException error) { + return ConstantKeys.AIR; + } + } + + @SuppressWarnings("deprecation") + private Key getBlockKeyInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { int blockId = chunkSnapshot.getBlockTypeId(x, y, z); int blockData = chunkSnapshot.getBlockData(x, y, z); int combinedId = blockId + (blockData << 12); @@ -83,6 +92,23 @@ public Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z) { return Keys.of(KeyBlocksCache.getBlockKey(Block.getByCombinedId(combinedId)), location); } + @Override + public boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + try { + return canPlayerSuffocateInternal(chunkSnapshot, x, y, z); + } catch (ArrayIndexOutOfBoundsException error) { + return true; + } + } + + @SuppressWarnings("deprecation") + private boolean canPlayerSuffocateInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + int blockId = chunkSnapshot.getBlockTypeId(x, y, z); + int blockData = chunkSnapshot.getBlockData(x, y, z); + int combinedId = blockId + (blockData << 12); + return Block.getByCombinedId(combinedId).getBlock().w(); + } + @Override public void listenSpawner(Location location, IntFunction delayChangeCallback) { TileEntityMobSpawner mobSpawner = NMSUtils.getTileEntityAt(location, TileEntityMobSpawner.class); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java index 032dbb48b4..b36a402d57 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSWorld.java @@ -22,6 +22,8 @@ public interface NMSWorld { Key getBlockKey(ChunkSnapshot chunkSnapshot, int x, int y, int z); + boolean canPlayerSuffocate(ChunkSnapshot chunkSnapshot, int x, int y, int z); + void listenSpawner(Location location, IntFunction delayChangeCallback); default void replaceTrialBlockPlayerDetector(Island island, Location location) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java index 7214dac92f..3bde5f9dc1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java @@ -213,9 +213,9 @@ private static void findSafeSpotInChunk(Island island, Queue isla // returned block and the block below it. Location safeSpot; if (WorldBlocks.isSafeBlock(chunkSnapshot, x, y, z)) { - safeSpot = new Location(islandsWorld, worldX, y + 1, worldZ); - } else if (y - 1 >= worldMinLimit && WorldBlocks.isSafeBlock(chunkSnapshot, x, y - 1, z)) { safeSpot = new Location(islandsWorld, worldX, y, worldZ); + } else if (WorldBlocks.isSafeBlock(chunkSnapshot, x, y - 1, z)) { + safeSpot = new Location(islandsWorld, worldX, y - 1, worldZ); } else { continue; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java b/src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java index 1fc8ead85f..dee9586205 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/WorldBlocks.java @@ -6,6 +6,7 @@ import com.bgsoftware.superiorskyblock.core.ChunkPosition; import com.bgsoftware.superiorskyblock.core.LazyWorldLocation; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; import org.bukkit.Bukkit; import org.bukkit.ChunkSnapshot; import org.bukkit.Location; @@ -35,23 +36,33 @@ private static boolean isSafeBlockInternal(Block block) { } private static boolean canPlayerSuffocateFromBlock(Block block) { - return block.getType() == Material.LAVA || plugin.getNMSWorld().canPlayerSuffocate(block); + return canPlayerGetHurtFromBlock(block.getType()) || plugin.getNMSWorld().canPlayerSuffocate(block); } public static boolean isSafeBlock(ChunkSnapshot chunkSnapshot, int x, int y, int z) { - Key feetBlockKey = plugin.getNMSWorld().getBlockKey(chunkSnapshot, x, y + 1, z); - Key headBlockKey = plugin.getNMSWorld().getBlockKey(chunkSnapshot, x, y + 2, z); + return isSafeBlockInternal(chunkSnapshot, x, y, z) || isSafeBlockInternal(chunkSnapshot, x, y - 1, z); + } - try { - if (Material.valueOf(feetBlockKey.getGlobalKey()).isSolid() || - Material.valueOf(headBlockKey.getGlobalKey()).isSolid()) - return false; - } catch (IllegalArgumentException error) { - return false; - } + private static boolean isSafeBlockInternal(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + // Checks that the block in the parameter is safe for teleportation. + // This means that the block below it is considered "safe", and the two blocks above the safe blocks + // cannot suffocate the player. + + return !canPlayerSuffocateFromBlock(chunkSnapshot, x, y, z) && + !canPlayerSuffocateFromBlock(chunkSnapshot, x, y + 1, z) && + plugin.getSettings().getSafeBlocks().contains(plugin.getNMSWorld().getBlockKey(chunkSnapshot, x, y - 1, z)); + } + + private static boolean canPlayerSuffocateFromBlock(ChunkSnapshot chunkSnapshot, int x, int y, int z) { + if (plugin.getNMSWorld().canPlayerSuffocate(chunkSnapshot, x, y, z)) + return true; + + Key blockKey = plugin.getNMSWorld().getBlockKey(chunkSnapshot, x, y, z); + return blockKey != null && canPlayerGetHurtFromBlock(((MaterialKey) blockKey).getMaterial()); + } - Key standingBlockKey = plugin.getNMSWorld().getBlockKey(chunkSnapshot, x, y, z); - return plugin.getSettings().getSafeBlocks().contains(standingBlockKey); + private static boolean canPlayerGetHurtFromBlock(Material material) { + return material == Material.LAVA || material == Material.FIRE; } public static boolean isChunkEmpty(Island island, ChunkSnapshot chunkSnapshot) { From 5bfd78eac4e2ca3230974edc43a14a13cc167660 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 18 Apr 2026 23:04:21 +0300 Subject: [PATCH 552/600] Fixed items missions not taking items out of armor slots (#2906) --- .../missions/ItemsMissions.java | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/Missions/ItemsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/ItemsMissions.java b/Missions/ItemsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/ItemsMissions.java index 2a71c31234..62e0a1c0db 100644 --- a/Missions/ItemsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/ItemsMissions.java +++ b/Missions/ItemsMissions/src/main/java/com/bgsoftware/superiorskyblock/missions/ItemsMissions.java @@ -35,6 +35,9 @@ @SuppressWarnings("unused") public final class ItemsMissions extends BuiltinMission implements Listener { + private static final int ADDITIONAL_SLOT_START = 36; // Boots + private static final int ADDITIONAL_SLOT_END = 40; // Off hand + private final Map requiredItems = new LinkedHashMap<>(); @Override @@ -241,22 +244,24 @@ private static void removeItems(PlayerInventory inventory, ItemStack... itemStac // We try to remove the item from the offhand as well. - ItemStack offHandItem; + for (int additionalSlot = ADDITIONAL_SLOT_START; additionalSlot < ADDITIONAL_SLOT_END; ++additionalSlot) { + ItemStack additionalItem; - try { - offHandItem = inventory.getItem(40); - } catch (Exception ignored) { - return; - } + try { + additionalItem = inventory.getItem(additionalSlot); + } catch (Exception ignored) { + continue; + } - if (offHandItem != null && offHandItem.getType() != Material.AIR) { - for (ItemStack itemStack : leftOvers) { - if (offHandItem.isSimilar(itemStack)) { - if (offHandItem.getAmount() > itemStack.getAmount()) { - offHandItem.setAmount(offHandItem.getAmount() - itemStack.getAmount()); - } else { - itemStack.setAmount(itemStack.getAmount() - offHandItem.getAmount()); - inventory.setItem(40, new ItemStack(Material.AIR)); + if (additionalItem != null && additionalItem.getType() != Material.AIR) { + for (ItemStack itemStack : leftOvers) { + if (additionalItem.isSimilar(itemStack)) { + if (additionalItem.getAmount() > itemStack.getAmount()) { + additionalItem.setAmount(additionalItem.getAmount() - itemStack.getAmount()); + } else { + itemStack.setAmount(itemStack.getAmount() - additionalItem.getAmount()); + inventory.setItem(additionalSlot, new ItemStack(Material.AIR)); + } } } } From f44046e9e37e27e5d96281bd403414eb9bc29ce1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 18 Apr 2026 23:06:42 +0300 Subject: [PATCH 553/600] Fix warning about missing permissions / flags is printed when display-menu is set to false (#2907) --- .../superiorskyblock/core/menu/impl/MenuIslandFlags.java | 2 +- .../superiorskyblock/core/menu/impl/MenuIslandPrivileges.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java index 9efe25829a..6b872a9445 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandFlags.java @@ -74,8 +74,8 @@ public static MenuIslandFlags createInstance() { Optional.ofNullable(settingsSection.getConfigurationSection(islandFlagName)).ifPresent(islandFlagSection -> { if (islandFlagSection.getBoolean("display-menu", true)) { islandFlags.add(loadIslandFlagInfo(islandFlagSection, islandFlagName, islandFlags.size())); - detectedFlags.add(islandFlagName.toUpperCase(Locale.ENGLISH)); } + detectedFlags.add(islandFlagName.toUpperCase(Locale.ENGLISH)); }); } }); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java index 21671e79b1..ea06255b8f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandPrivileges.java @@ -102,8 +102,8 @@ public static MenuIslandPrivileges createInstance() { Optional.ofNullable(permissionsSection.getConfigurationSection(islandPrivilegeName)).ifPresent(islandPrivilegeSection -> { if (islandPrivilegeSection.getBoolean("display-menu", true)) { islandPrivileges.add(loadIslandPrivilegeInfo(islandPrivilegeSection, islandPrivilegeName, islandPrivileges.size())); - detectedPrivileges.add(islandPrivilegeName.toUpperCase(Locale.ENGLISH)); } + detectedPrivileges.add(islandPrivilegeName.toUpperCase(Locale.ENGLISH)); }); } }); From 4c7aeea6a46885c431c500d000ea26a8509b4638 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Tue, 21 Apr 2026 15:59:42 +0200 Subject: [PATCH 554/600] Added support for setting custom biomes for islands and island worlds (#2910) --- .../nms/v1_12_R1/NMSAlgorithmsImpl.java | 11 ++++ .../nms/v1_16_R3/NMSAlgorithmsImpl.java | 11 ++++ .../nms/v1_17/NMSAlgorithmsImpl.java | 11 ++++ .../nms/v1_18/NMSAlgorithmsImpl.java | 11 ++++ .../nms/v1_19/NMSAlgorithmsImpl.java | 40 +++++++-------- .../nms/v1_20_3/NMSAlgorithmsImpl.java | 47 +++++++++++++++++ .../nms/v1_20_4/NMSAlgorithmsImpl.java | 50 +++++++++++++++++++ .../nms/v1_21/NMSAlgorithmsImpl.java | 29 +++++++++-- .../nms/v1_21_10/NMSAlgorithmsImpl.java | 29 +++++++++-- .../nms/v1_21_3/NMSAlgorithmsImpl.java | 29 +++++++++-- .../nms/v1_21_4/NMSAlgorithmsImpl.java | 29 +++++++++-- .../nms/v1_21_5/NMSAlgorithmsImpl.java | 29 +++++++++-- .../nms/v1_21_7/NMSAlgorithmsImpl.java | 30 +++++++++-- .../nms/v1_21_9/NMSAlgorithmsImpl.java | 29 +++++++++-- .../nms/v1_8_R3/NMSAlgorithmsImpl.java | 10 ++++ .../nms/v26_1/NMSAlgorithmsImpl.java | 29 +++++++++-- .../commands/admin/CmdAdminSetBiome.java | 2 +- .../commands/arguments/CommandArguments.java | 8 ++- .../config/section/WorldsSection.java | 3 +- .../core/menu/MenuConfig.java | 3 +- .../core/menu/impl/MenuBiomes.java | 6 +-- .../core/menu/impl/MenuIslandCreation.java | 11 ++-- .../superiorskyblock/island/IslandUtils.java | 2 +- .../superiorskyblock/nms/NMSAlgorithms.java | 2 + 24 files changed, 393 insertions(+), 68 deletions(-) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java index 4070e975ee..98fe929917 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java @@ -21,6 +21,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.Biome; import org.bukkit.block.BlockState; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_12_R1.CraftServer; @@ -39,6 +40,7 @@ import org.bukkit.potion.PotionEffect; import java.lang.reflect.Field; +import java.util.Locale; import java.util.Optional; public class NMSAlgorithmsImpl implements NMSAlgorithms { @@ -192,6 +194,15 @@ public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHo return defaultHolder; } + @Override + public Biome getBiome(String biomeName) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { + return null; + } + } + private static Enchantment initializeGlowEnchantment() { int enchantId = 100; while (Enchantment.getById(enchantId) != null) diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java index e59674ff44..7f931d3f65 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java @@ -32,6 +32,7 @@ import net.minecraft.server.v1_16_R3.IRegistry; import net.minecraft.server.v1_16_R3.MinecraftServer; import net.minecraft.server.v1_16_R3.World; +import org.bukkit.block.Biome; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -59,6 +60,7 @@ import java.lang.reflect.Field; import java.util.EnumMap; +import java.util.Locale; import java.util.Optional; import java.util.function.BiFunction; @@ -261,6 +263,15 @@ public Object createMenuInventoryHolder(InventoryType inventoryType, InventoryHo return menuCreator == null ? null : menuCreator.apply(defaultHolder, title); } + @Override + public Biome getBiome(String biomeName) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { + return null; + } + } + private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java index c162e979c0..2c3fc79587 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSAlgorithmsImpl.java @@ -5,6 +5,7 @@ import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_17_R1.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; @@ -12,6 +13,7 @@ import org.bukkit.inventory.meta.ItemMeta; import java.lang.reflect.Field; +import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_17.AbstractNMSAlgorithms { @@ -42,6 +44,15 @@ public double getCurrentTps() { } } + @Override + public Biome getBiome(String biomeName) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { + return null; + } + } + private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java index d820a0fa70..a9900c2a48 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSAlgorithmsImpl.java @@ -5,6 +5,7 @@ import net.minecraft.core.Registry; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_18_R2.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; @@ -12,6 +13,7 @@ import org.bukkit.inventory.meta.ItemMeta; import java.lang.reflect.Field; +import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_18.AbstractNMSAlgorithms { @@ -42,6 +44,15 @@ public double getCurrentTps() { } } + @Override + public Biome getBiome(String biomeName) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { + return null; + } + } + private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java index 0fb353682b..cee04ee67d 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java @@ -7,19 +7,16 @@ import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_19_R3.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.trim.ArmorTrim; -import org.bukkit.inventory.meta.trim.TrimMaterial; -import org.bukkit.inventory.meta.trim.TrimPattern; import java.lang.reflect.Field; import java.util.Locale; -import java.util.Objects; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_19.AbstractNMSAlgorithms { @@ -30,24 +27,6 @@ public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]); } - @Override - public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { - if (itemMeta instanceof ArmorMeta armorMeta) { - TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); - TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); - - if (material == null) - throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + - " into trim material, skipping..."); - if (pattern == null) - throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + - " into trim pattern, skipping..."); - - ArmorTrim armorTrim = new ArmorTrim(material, pattern); - armorMeta.setTrim(armorTrim); - } - } - @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); @@ -68,6 +47,21 @@ public double getCurrentTps() { } } + @Override + public Biome getBiome(String biomeName) { + NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); + if (key == null) { + return null; + } + + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry == null) { + return null; + } + + return registry.get(key); + } + private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java index 7f0d521fba..330e424d55 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java @@ -6,15 +6,22 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; +import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; import org.bukkit.Registry; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.v1_20_R3.CraftRegistry; import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; +import java.util.Locale; import java.util.Map; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSAlgorithms { @@ -29,6 +36,31 @@ public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0]); } + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); + Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); + + if (materialRegistry == null || patternRegistry == null) { + return; + } + + TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); @@ -49,6 +81,21 @@ public double getCurrentTps() { } } + @Override + public Biome getBiome(String biomeName) { + NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); + if (key == null) { + return null; + } + + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry == null) { + return null; + } + + return registry.get(key); + } + private static Enchantment initializeGlowEnchantment() { Enchantment glowEnchant; diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java index 02d804b95e..e2c684816b 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java @@ -3,10 +3,20 @@ import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; + +import java.util.Locale; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSAlgorithms { @@ -15,6 +25,31 @@ public String parseSignLine(String original) { return Component.Serializer.toJson(CraftChatMessage.fromString(original)[0], MinecraftServer.getServer().registryAccess()); } + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); + Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); + + if (materialRegistry == null || patternRegistry == null) { + return; + } + + TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); @@ -35,4 +70,19 @@ public double getCurrentTps() { } } + @Override + public Biome getBiome(String biomeName) { + NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); + if (key == null) { + return null; + } + + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry == null) { + return null; + } + + return registry.get(key); + } + } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java index 23f4116a48..8d47dbe506 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java @@ -5,6 +5,8 @@ import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; @@ -16,7 +18,6 @@ import org.bukkit.inventory.meta.trim.TrimPattern; import java.util.Locale; -import java.util.Objects; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSAlgorithms { @@ -33,8 +34,15 @@ public void setRarity(ItemMeta itemMeta, String rarity) { @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { - TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); - TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); + Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); + + if (materialRegistry == null || patternRegistry == null) { + return; + } + + TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + @@ -68,4 +76,19 @@ public double getCurrentTps() { } } + @Override + public Biome getBiome(String biomeName) { + NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); + if (key == null) { + return null; + } + + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry == null) { + return null; + } + + return registry.get(key); + } + } diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java index bcfff72f40..8873ca16ea 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java @@ -12,6 +12,8 @@ import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; @@ -24,7 +26,6 @@ import java.lang.reflect.Modifier; import java.util.Locale; -import java.util.Objects; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10.AbstractNMSAlgorithms { @@ -54,8 +55,15 @@ public void setRarity(ItemMeta itemMeta, String rarity) { @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { - TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); - TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); + Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); + + if (materialRegistry == null || patternRegistry == null) { + return; + } + + TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + @@ -84,4 +92,19 @@ public double getCurrentTps() { return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0]; } + @Override + public Biome getBiome(String biomeName) { + NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); + if (key == null) { + return null; + } + + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry == null) { + return null; + } + + return registry.get(key); + } + } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java index 17a8a56960..7f80d3e495 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java @@ -5,6 +5,8 @@ import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; @@ -16,7 +18,6 @@ import org.bukkit.inventory.meta.trim.TrimPattern; import java.util.Locale; -import java.util.Objects; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSAlgorithms { @@ -38,8 +39,15 @@ public void setRarity(ItemMeta itemMeta, String rarity) { @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { - TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); - TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); + Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); + + if (materialRegistry == null || patternRegistry == null) { + return; + } + + TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + @@ -73,4 +81,19 @@ public double getCurrentTps() { } } + @Override + public Biome getBiome(String biomeName) { + NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); + if (key == null) { + return null; + } + + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry == null) { + return null; + } + + return registry.get(key); + } + } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index 3f211c1c27..080baa8185 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -5,6 +5,8 @@ import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; @@ -16,7 +18,6 @@ import org.bukkit.inventory.meta.trim.TrimPattern; import java.util.Locale; -import java.util.Objects; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSAlgorithms { @@ -38,8 +39,15 @@ public void setRarity(ItemMeta itemMeta, String rarity) { @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { - TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); - TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); + Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); + + if (materialRegistry == null || patternRegistry == null) { + return; + } + + TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + @@ -73,4 +81,19 @@ public double getCurrentTps() { } } + @Override + public Biome getBiome(String biomeName) { + NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); + if (key == null) { + return null; + } + + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry == null) { + return null; + } + + return registry.get(key); + } + } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java index 05993a282b..0efc1230d2 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java @@ -5,6 +5,8 @@ import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; @@ -16,7 +18,6 @@ import org.bukkit.inventory.meta.trim.TrimPattern; import java.util.Locale; -import java.util.Objects; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSAlgorithms { @@ -38,8 +39,15 @@ public void setRarity(ItemMeta itemMeta, String rarity) { @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { - TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); - TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); + Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); + + if (materialRegistry == null || patternRegistry == null) { + return; + } + + TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + @@ -73,4 +81,19 @@ public double getCurrentTps() { } } + @Override + public Biome getBiome(String biomeName) { + NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); + if (key == null) { + return null; + } + + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry == null) { + return null; + } + + return registry.get(key); + } + } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java index 88191fb920..fd0ae6dd11 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java @@ -6,12 +6,13 @@ import com.google.gson.JsonParseException; import com.mojang.serialization.JsonOps; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentSerialization; import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; @@ -23,7 +24,6 @@ import org.bukkit.inventory.meta.trim.TrimPattern; import java.util.Locale; -import java.util.Objects; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSAlgorithms { @@ -50,8 +50,15 @@ public void setRarity(ItemMeta itemMeta, String rarity) { @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { - TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); - TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); + Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); + + if (materialRegistry == null || patternRegistry == null) { + return; + } + + TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + @@ -85,4 +92,19 @@ public double getCurrentTps() { } } + @Override + public Biome getBiome(String biomeName) { + NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); + if (key == null) { + return null; + } + + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry == null) { + return null; + } + + return registry.get(key); + } + } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java index fdb91ad9d8..e0935c14b0 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java @@ -12,6 +12,8 @@ import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; @@ -24,7 +26,6 @@ import java.lang.reflect.Modifier; import java.util.Locale; -import java.util.Objects; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.AbstractNMSAlgorithms { @@ -54,8 +55,15 @@ public void setRarity(ItemMeta itemMeta, String rarity) { @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { - TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); - TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); + Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); + + if (materialRegistry == null || patternRegistry == null) { + return; + } + + TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + @@ -84,4 +92,19 @@ public double getCurrentTps() { return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0]; } + @Override + public Biome getBiome(String biomeName) { + NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); + if (key == null) { + return null; + } + + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry == null) { + return null; + } + + return registry.get(key); + } + } diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java index cca2224f7a..fa2ceb12a2 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java @@ -21,6 +21,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.Biome; import org.bukkit.block.BlockState; import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.craftbukkit.v1_8_R3.CraftServer; @@ -39,6 +40,7 @@ import org.bukkit.potion.PotionEffect; import java.lang.reflect.Field; +import java.util.Locale; import java.util.Optional; public class NMSAlgorithmsImpl implements NMSAlgorithms { @@ -185,6 +187,14 @@ public int getDataVersion() { return -1; } + @Override + public Biome getBiome(String biomeName) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { + return null; + } + } private static Enchantment initializeGlowEnchantment() { int enchantId = 100; while (Enchantment.getById(enchantId) != null) diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java index 99887f9ada..ed060104f7 100644 --- a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java @@ -12,6 +12,8 @@ import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.inventory.ItemRarity; @@ -24,7 +26,6 @@ import java.lang.reflect.Modifier; import java.util.Locale; -import java.util.Objects; public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.AbstractNMSAlgorithms { @@ -54,8 +55,15 @@ public void setRarity(ItemMeta itemMeta, String rarity) { @Override public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { if (itemMeta instanceof ArmorMeta armorMeta) { - TrimMaterial material = Objects.requireNonNull(Bukkit.getRegistry(TrimMaterial.class)).get(NamespacedKey.minecraft(trimMaterial)); - TrimPattern pattern = Objects.requireNonNull(Bukkit.getRegistry(TrimPattern.class)).get(NamespacedKey.minecraft(trimPattern)); + Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); + Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); + + if (materialRegistry == null || patternRegistry == null) { + return; + } + + TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); if (material == null) throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + @@ -84,4 +92,19 @@ public double getCurrentTps() { return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0]; } + @Override + public Biome getBiome(String biomeName) { + NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); + if (key == null) { + return null; + } + + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry == null) { + return null; + } + + return registry.get(key); + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBiome.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBiome.java index e5fbfc221f..98fa148f74 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBiome.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/admin/CmdAdminSetBiome.java @@ -64,7 +64,7 @@ public boolean supportMultipleIslands() { @Override public void execute(SuperiorSkyblockPlugin plugin, CommandSender sender, @Nullable SuperiorPlayer targetPlayer, List islands, String[] args) { - Biome biome = CommandArguments.getBiome(sender, args[3]); + Biome biome = CommandArguments.getBiome(plugin, sender, args[3]); if (biome == null) return; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java index 6ce5d83c9c..6e540af2e8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java @@ -315,12 +315,10 @@ public static IslandWarp getWarp(CommandSender sender, Island island, String[] a return islandWarp; } - public static Biome getBiome(CommandSender sender, String argument) { - Biome biome = null; + public static Biome getBiome(SuperiorSkyblockPlugin plugin, CommandSender sender, String argument) { + Biome biome = plugin.getNMSAlgorithms().getBiome(argument); - try { - biome = Biome.valueOf(argument.toUpperCase(Locale.ENGLISH)); - } catch (Exception ex) { + if (biome == null) { Message.INVALID_BIOME.send(sender, argument); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java index 7bb486018d..a4d6c685fe 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/WorldsSection.java @@ -16,7 +16,6 @@ import java.util.Collections; import java.util.EnumMap; -import java.util.Locale; import java.util.Map; public class WorldsSection extends SettingsContainerHolder implements SettingsManager.Worlds { @@ -85,7 +84,7 @@ protected BaseDimensionConfig(ConfigurationSection section, Dimension dimension, this.isEnabled = section.getBoolean("enabled"); this.isUnlocked = section.getBoolean("unlock"); this.isSchematicOffset = section.getBoolean("schematic-offset"); - this.biome = section.getString("biome").toUpperCase(Locale.ENGLISH); + this.biome = section.getString("biome"); String name = section.getString("name"); this.name = Text.isBlank(name) ? defaultName : name; this.portalAgents = loadPortalAgents(section.getConfigurationSection("portals"), dimension); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java index 10d6790c1a..7054d87613 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java @@ -6,7 +6,6 @@ import com.bgsoftware.superiorskyblock.api.schematic.Schematic; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; -import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandCreationButton; import org.bukkit.block.Biome; @@ -37,7 +36,7 @@ public IslandCreation(Schematic schematic, IslandCreationButton.Template templat this.schematic = schematic; this.template = template; Biome biome = template == null ? null : template.getBiome(); - this.biome = biome == null ? EnumHelper.getEnum(Biome.class, plugin.getSettings().getWorlds().getDimensionConfig( + this.biome = biome == null ? plugin.getNMSAlgorithms().getBiome(plugin.getSettings().getWorlds().getDimensionConfig( plugin.getSettings().getWorlds().getDefaultWorldDimension()).getBiome()) : biome; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java index 99652a2eb7..a07483716d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuBiomes.java @@ -66,11 +66,9 @@ public static MenuBiomes createInstance() { continue; String biomeName = itemSection.getString("biome"); - Biome biome; + Biome biome = plugin.getNMSAlgorithms().getBiome(biomeName);; - try { - biome = Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); - } catch (IllegalArgumentException error) { + if (biome == null) { Log.warnFromFile("biomes.yml", "Biome '", biomeName, "' is not valid, skipping..."); continue; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java index d9171b1dc3..4e1f1e4746 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/impl/MenuIslandCreation.java @@ -71,15 +71,16 @@ public static MenuIslandCreation createInstance() { { String biomeName = itemSection.getString("biome"); - if(biomeName != null) { - try { - Biome biome = Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); - buttonBuilder.setBiome(biome); - } catch (IllegalArgumentException error) { + if (biomeName != null) { + Biome biome = plugin.getNMSAlgorithms().getBiome(biomeName); + + if (biome == null) { Log.warnFromFile("island-creation.yml", "Invalid biome name for item ", itemSectionName, ": ", biomeName); continue; } + + buttonBuilder.setBiome(biome); } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java index 5cf5c00700..6dc0dfbf69 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/IslandUtils.java @@ -69,7 +69,7 @@ private static Biome getDefaultBiomeForEnvironment(World.Environment environment static { for (Dimension dimension : Dimension.values()) { Biome biome = Optional.ofNullable(plugin.getSettings().getWorlds().getDimensionConfig(dimension)) - .map(config -> EnumHelper.getEnum(Biome.class, config.getBiome())) + .map(config -> plugin.getNMSAlgorithms().getBiome(config.getBiome())) .orElseGet(() -> getDefaultBiomeForEnvironment(dimension.getEnvironment())); DEFAULT_WORLD_BIOMES.put(dimension, biome); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java index 32f1a9ab54..1aa505725b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java @@ -82,6 +82,8 @@ public String getName(Biome enumValue) { int getDataVersion(); + Biome getBiome(String biomeName); + default ClassProcessor getClassProcessor() { return null; } From cae9b978ec0ec97e0f784202dade4ed41135500d Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 22 Apr 2026 18:47:17 +0300 Subject: [PATCH 555/600] Fixed errors when going through portals to disabled worlds (#2912) --- .../listener/PortalsListener.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java index eca10680a4..dc7ccddd3d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java @@ -1,5 +1,6 @@ package com.bgsoftware.superiorskyblock.listener; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.config.SettingsManager; import com.bgsoftware.superiorskyblock.api.island.Island; @@ -148,8 +149,13 @@ private void handlePlayerPortal(GameEvent e) { Location toLocation = calculateDestination(island, e.getArgs().from, e.getArgs().to, portalType); - EntityPortalResult portalResult = this.portalsManager.get().handlePlayerPortalFromIsland( - superiorPlayer, island, e.getArgs().from, portalType, toLocation, true); + EntityPortalResult portalResult; + if (toLocation == null) { + portalResult = EntityPortalResult.DESTINATION_WORLD_DISABLED; + } else { + portalResult = this.portalsManager.get().handlePlayerPortalFromIsland( + superiorPlayer, island, e.getArgs().from, portalType, toLocation, true); + } handleEntityPortalResult(portalResult, e); } @@ -172,17 +178,24 @@ public void handleEntityPortalResult(GameEvent Location toLocation = calculateDestination(island, e.getArgs().from, e.getArgs().to, portalType); - EntityPortalResult portalResult = this.portalsManager.get().handleEntityPortalFromIsland( - entity, island, from, portalType, toLocation); + EntityPortalResult portalResult; + if (toLocation == null) { + portalResult = EntityPortalResult.DESTINATION_WORLD_DISABLED; + } else { + portalResult = this.portalsManager.get().handleEntityPortalFromIsland( + entity, island, from, portalType, toLocation); + } handleEntityPortalResult(portalResult, e); } + @Nullable private Location calculateDestination(Island island, Location fromLocation, Location toLocation, PortalType portalType) { Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(fromLocation.getWorld()); SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(portalDimension); Dimension portalDestination = dimensionConfig == null ? null : dimensionConfig.getPortalDestination(portalType); - return portalDestination == null ? toLocation : island.getCenter(portalDestination); + SettingsManager.Worlds.DimensionConfig destinationConfig = plugin.getSettings().getWorlds().getDimensionConfig(portalDestination); + return portalDestination == null || !destinationConfig.isEnabled() ? null : island.getCenter(portalDestination); } private void handleEntityPortalResult(EntityPortalResult portalResult, GameEvent event) { From fdd1d829682e0af1b6a869067d3aa67c06b3e7d4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 22 Apr 2026 18:48:31 +0300 Subject: [PATCH 556/600] Fix for possible NPE due to recent commit --- .../superiorskyblock/listener/PortalsListener.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java index dc7ccddd3d..3183f8ae2d 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java @@ -147,7 +147,7 @@ private void handlePlayerPortal(GameEvent e) { PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? PortalType.NETHER : PortalType.ENDER; - Location toLocation = calculateDestination(island, e.getArgs().from, e.getArgs().to, portalType); + Location toLocation = calculateDestination(island, e.getArgs().from, portalType); EntityPortalResult portalResult; if (toLocation == null) { @@ -176,7 +176,7 @@ public void handleEntityPortalResult(GameEvent PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? PortalType.NETHER : PortalType.ENDER; - Location toLocation = calculateDestination(island, e.getArgs().from, e.getArgs().to, portalType); + Location toLocation = calculateDestination(island, e.getArgs().from, portalType); EntityPortalResult portalResult; if (toLocation == null) { @@ -190,12 +190,14 @@ public void handleEntityPortalResult(GameEvent } @Nullable - private Location calculateDestination(Island island, Location fromLocation, Location toLocation, PortalType portalType) { + private Location calculateDestination(Island island, Location fromLocation, PortalType portalType) { Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(fromLocation.getWorld()); SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(portalDimension); Dimension portalDestination = dimensionConfig == null ? null : dimensionConfig.getPortalDestination(portalType); + if (portalDestination == null) + return null; SettingsManager.Worlds.DimensionConfig destinationConfig = plugin.getSettings().getWorlds().getDimensionConfig(portalDestination); - return portalDestination == null || !destinationConfig.isEnabled() ? null : island.getCenter(portalDestination); + return !destinationConfig.isEnabled() ? null : island.getCenter(portalDestination); } private void handleEntityPortalResult(EntityPortalResult portalResult, GameEvent event) { From 0631b508eafe4c42b928d70c984a6186fef2b5b9 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 22 Apr 2026 19:21:53 +0300 Subject: [PATCH 557/600] Make CAVE_VINES and CAVE_VINES_PLANT be under the FARM_TRAMPING category --- .../config/section/InteractablesSection.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/InteractablesSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/InteractablesSection.java index 0f9f865ea3..2d5807cad5 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/InteractablesSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/InteractablesSection.java @@ -49,6 +49,10 @@ public class InteractablesSection implements SettingsManager.Interactables { @Nullable private static final Material SWEET_BERRY_BUSH = EnumHelper.getEnum(Material.class, "SWEET_BERRY_BUSH"); @Nullable + private static final Material CAVE_VINES = EnumHelper.getEnum(Material.class, "CAVE_VINES"); + @Nullable + private static final Material CAVE_VINES_PLANT = EnumHelper.getEnum(Material.class, "CAVE_VINES_PLANT"); + @Nullable private static final Material LECTERN = EnumHelper.getEnum(Material.class, "LECTERN"); @Nullable private static final Material VAULT = EnumHelper.getEnum(Material.class, "VAULT"); @@ -165,7 +169,8 @@ private static void loadLegacyInternal(YamlConfiguration cfg, Map Date: Wed, 22 Apr 2026 20:55:00 +0300 Subject: [PATCH 558/600] Version 2026.1 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index cad7c9cb02..96d0f6a201 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'SuperiorSkyblock' -version = "2025.2.1" +version = "2026.1" project.ext { targetFolder = file("target/") From ad130d326ee5d46540b1cecb299a14076ed47fdd Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Wed, 22 Apr 2026 20:56:32 +0300 Subject: [PATCH 559/600] API version 16 --- .../bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java index e9d737c61d..f31e70db8a 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java @@ -71,7 +71,7 @@ public static void setPluginInstance(SuperiorSkyblock plugin) { * Everytime a change is made to the API, the version of it changes. */ public static int getAPIVersion() { - return 15; + return 16; } /* From d266beabf87f0e58a2ef7e97221673e657844901 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Fri, 24 Apr 2026 20:10:49 +0200 Subject: [PATCH 560/600] Added "hideTooltip" option for items (#2914) --- NMS/src/main/templates/AbstractNMSAlgorithms.java.template | 5 +++++ .../superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java | 5 +++++ .../superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java | 5 +++++ .../superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java | 5 +++++ .../superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java | 5 +++++ .../superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java | 5 +++++ .../superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java | 5 +++++ .../superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java | 5 +++++ .../superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java | 5 +++++ .../superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java | 5 +++++ .../superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java | 5 +++++ .../superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java | 5 +++++ .../superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java | 5 +++++ .../bgsoftware/superiorskyblock/core/io/MenuParserImpl.java | 4 ++++ .../superiorskyblock/core/itemstack/ItemBuilder.java | 6 ++++++ .../com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java | 2 ++ 16 files changed, 77 insertions(+) diff --git a/NMS/src/main/templates/AbstractNMSAlgorithms.java.template b/NMS/src/main/templates/AbstractNMSAlgorithms.java.template index 0b4c757298..318c1f730c 100644 --- a/NMS/src/main/templates/AbstractNMSAlgorithms.java.template +++ b/NMS/src/main/templates/AbstractNMSAlgorithms.java.template @@ -219,6 +219,11 @@ public abstract class AbstractNMSAlgorithms implements NMSAlgorithms { // Doesn't exist } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + // Doesn't exist + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java index 98fe929917..330114950c 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSAlgorithmsImpl.java @@ -150,6 +150,11 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) // Doesn't exist } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + // Doesn't exist + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java index 7f931d3f65..7716ca26a3 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSAlgorithmsImpl.java @@ -206,6 +206,11 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) // Doesn't exist } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + // Doesn't exist + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { if (!potionMeta.hasCustomEffects()) diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java index e2c684816b..4706f19432 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java @@ -50,6 +50,11 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + itemMeta.setHideTooltip(true); + } + @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java index 8d47dbe506..1ba5175b8a 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java @@ -56,6 +56,11 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + itemMeta.setHideTooltip(true); + } + @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java index 8873ca16ea..6172b04c8c 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java @@ -77,6 +77,11 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + itemMeta.setHideTooltip(true); + } + @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java index 7f80d3e495..f3e2853f77 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java @@ -61,6 +61,11 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + itemMeta.setHideTooltip(true); + } + @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index 080baa8185..6167c50d1f 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -61,6 +61,11 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + itemMeta.setHideTooltip(true); + } + @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java index 0efc1230d2..ebb9a8c27b 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java @@ -61,6 +61,11 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + itemMeta.setHideTooltip(true); + } + @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java index fd0ae6dd11..ad4f9c67c7 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java @@ -72,6 +72,11 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + itemMeta.setHideTooltip(true); + } + @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java index e0935c14b0..d7f94d8039 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java @@ -77,6 +77,11 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + itemMeta.setHideTooltip(true); + } + @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java index fa2ceb12a2..4ec0a1e86e 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSAlgorithmsImpl.java @@ -150,6 +150,11 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) // Doesn't exist } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + // Doesn't exist + } + @Override public void addPotion(PotionMeta potionMeta, PotionEffect potionEffect) { potionMeta.addCustomEffect(potionEffect, true); diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java index ed060104f7..71f2dbf5bc 100644 --- a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java @@ -77,6 +77,11 @@ public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) } } + @Override + public void setHideTooltip(ItemMeta itemMeta) { + itemMeta.setHideTooltip(true); + } + @Override public String getMinecraftKey(ItemStack itemStack) { return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java index 4f2bf8dc38..189bac51fd 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/io/MenuParserImpl.java @@ -366,6 +366,10 @@ private static TemplateItem getItemStackUnsafe(String fileName, ConfigurationSec itemBuilder.setUnbreakable(); } + if (section.getBoolean("hideTooltip", false)) { + itemBuilder.setHideTooltip(); + } + if (section.isConfigurationSection("effects")) { ConfigurationSection effectsSection = section.getConfigurationSection("effects"); for (String effectName : effectsSection.getKeys(false)) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java b/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java index b9bc8cd726..d6e1da8ee1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/itemstack/ItemBuilder.java @@ -221,6 +221,12 @@ public ItemBuilder setUnbreakable() { return this; } + public ItemBuilder setHideTooltip() { + if (itemMeta != null) + plugin.getNMSAlgorithms().setHideTooltip(itemMeta); + return this; + } + public ItemBuilder withPotionEffect(PotionEffect potionEffect) { if (itemMeta instanceof PotionMeta) plugin.getNMSAlgorithms().addPotion((PotionMeta) itemMeta, potionEffect); diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java index 1aa505725b..23e2d1cc92 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java @@ -67,6 +67,8 @@ public String getName(Biome enumValue) { void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) throws IllegalArgumentException; + void setHideTooltip(ItemMeta itemMeta); + void addPotion(PotionMeta potionMeta, PotionEffect potionEffect); String getMinecraftKey(ItemStack itemStack); From f92bd52ac3c4adfe16e0ee0cf2dbfed593fef1b1 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 24 Apr 2026 21:21:50 +0300 Subject: [PATCH 561/600] Do not create "entity-categories" in the config file --- .../superiorskyblock/config/SettingsManagerImpl.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java index 1a4dc2f629..d729a33010 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsManagerImpl.java @@ -776,9 +776,6 @@ private void convertData(YamlConfiguration cfg) { cfg.set("block-level-formula", cfg.getString("island-level-formula")); cfg.set("island-level-formula", null); } - if (!cfg.isConfigurationSection("entity-categories")) { - cfg.createSection("entity-categories"); - } if (cfg.get("protected-message-delay") instanceof Number) { long delay = cfg.getLong("protected-message-delay") * 50; cfg.set("message-delays.ISLAND_PROTECTED", delay); From 86e556e69c864fe9a08ed61fd97f7fc03f5f856e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 24 Apr 2026 21:38:54 +0300 Subject: [PATCH 562/600] Remove invalid entities from default entity-categories when creating it for the first time (#2915) --- .../config/SettingsContainer.java | 10 +++++- .../section/EntityCategoriesSection.java | 34 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java index a1e3228369..a0f763aa2a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/SettingsContainer.java @@ -702,11 +702,19 @@ private SettingsManager.Interactables loadInteractables(SuperiorSkyblockPlugin p private SettingsManager.EntityCategories loadEntityCategories(SuperiorSkyblockPlugin plugin) { File file = new File(plugin.getDataFolder(), "entity-categories.yml"); - if (!file.exists()) + boolean removeInvalidEntityKeys = false; + + if (!file.exists()) { plugin.saveResource("entity-categories.yml", false); + removeInvalidEntityKeys = true; + } YamlConfiguration cfg = YamlConfiguration.loadConfiguration(file); + if (removeInvalidEntityKeys) { + EntityCategoriesSection.removeInvalidEntityKeys(cfg, file); + } + return new EntityCategoriesSection(cfg); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java index d758bf6391..4e24965bde 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.key.KeyMap; import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; import com.bgsoftware.superiorskyblock.core.key.Keys; @@ -27,9 +28,12 @@ import org.bukkit.entity.Slime; import org.bukkit.entity.Tameable; +import java.io.File; +import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -66,6 +70,36 @@ public EntityCategoriesSection(YamlConfiguration cfg) { this.entityToCategory = convertEntityToCategoryInternal(this.nameToCategory.values()); } + public static void removeInvalidEntityKeys(YamlConfiguration cfg, File file) { + boolean removed = false; + for (String categoryName : cfg.getKeys(false)) { + if (!categoryName.equals("TAMEABLE") && !categoryName.equals("ANIMAL") && !categoryName.equals("MONSTER")) { + List entities = cfg.getStringList(categoryName + ".entities"); + Iterator iterator = entities.iterator(); + while (iterator.hasNext()) { + EntityType entityType = EnumHelper.getEnum(EntityType.class, iterator.next()); + if (entityType == null) { + iterator.remove(); + removed = true; + } + } + if (entities.isEmpty()) { + cfg.set(categoryName, null); + } else { + cfg.set(categoryName + ".entities", entities); + } + } + } + + if (removed) { + try { + cfg.save(file); + } catch (IOException ignored) { + } + } + + } + private static Map loadInternal(YamlConfiguration cfg) { Map entityCategories = new HashMap<>(); for (String categoryName : cfg.getKeys(false)) { From cc36c7b06c18244e6be0c81791581e370292ff02 Mon Sep 17 00:00:00 2001 From: Lemvs <48791834+Lemvs@users.noreply.github.com> Date: Mon, 27 Apr 2026 07:40:05 +0200 Subject: [PATCH 563/600] Added missing "Minecart Place" permission to permissions menu for 1.8 and 1.12 (#2918) --- src/main/resources/menus/permissions.yml | 33 +++++++++++++++++++ ...permissions1_9.yml => permissions1_12.yml} | 33 +++++++++++++++++++ 2 files changed, 66 insertions(+) rename src/main/resources/menus/{permissions1_9.yml => permissions1_12.yml} (98%) diff --git a/src/main/resources/menus/permissions.yml b/src/main/resources/menus/permissions.yml index 5e2a3779dc..633c2cf8ec 100644 --- a/src/main/resources/menus/permissions.yml +++ b/src/main/resources/menus/permissions.yml @@ -1363,6 +1363,39 @@ permissions: volume: 0.2 pitch: 0.2 + minecart_place: + display-menu: true + permission-enabled: + type: MINECART + name: '&6Minecart Place' + lore: + - '&7Access to place minecarts inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: MINECART + name: '&6Minecart Place' + lore: + - '&7Access to place minecarts inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: MINECART + name: '&6Minecart Place' + lore: + - '&7Access to place minecarts inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: ANVIL_LAND + volume: 0.2 + pitch: 0.2 + monster_damage: display-menu: true permission-enabled: diff --git a/src/main/resources/menus/permissions1_9.yml b/src/main/resources/menus/permissions1_12.yml similarity index 98% rename from src/main/resources/menus/permissions1_9.yml rename to src/main/resources/menus/permissions1_12.yml index e0411d368c..922b6660fe 100644 --- a/src/main/resources/menus/permissions1_9.yml +++ b/src/main/resources/menus/permissions1_12.yml @@ -1396,6 +1396,39 @@ permissions: volume: 0.2 pitch: 0.2 + minecart_place: + display-menu: true + permission-enabled: + type: MINECART + name: '&6Minecart Place' + lore: + - '&7Access to place minecarts inside the island.' + - '&7Currently &aENABLED&7.' + permission-disabled: + type: MINECART + name: '&6Minecart Place' + lore: + - '&7Access to place minecarts inside the island.' + - '&7Currently &cDISABLED&7.' + role-permission: + type: MINECART + name: '&6Minecart Place' + lore: + - '&7Access to place minecarts inside the island.' + - '&7Role: &e{}&7.' + - '' + - '{0}' + has-access: + sound: + type: ENTITY_EXPERIENCE_ORB_PICKUP + volume: 0.2 + pitch: 0.2 + no-access: + sound: + type: BLOCK_ANVIL_PLACE + volume: 0.2 + pitch: 0.2 + monster_damage: display-menu: true permission-enabled: From 98c07484cd4fa12798fab74c079e4be354d6e6a3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 27 Apr 2026 22:29:18 +0300 Subject: [PATCH 564/600] Fixed cases where errors were thrown when going through portals in non-island worlds (#2912) --- .../listener/PortalsListener.java | 30 ++++++++++-------- .../portals/PortalsManagerServiceImpl.java | 31 +++++++++++++++++-- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java index 3183f8ae2d..1e4640432f 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java @@ -9,6 +9,7 @@ import com.bgsoftware.superiorskyblock.api.service.portals.PortalsManagerService; import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.core.Either; import com.bgsoftware.superiorskyblock.core.IslandWorlds; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.Materials; @@ -147,14 +148,14 @@ private void handlePlayerPortal(GameEvent e) { PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? PortalType.NETHER : PortalType.ENDER; - Location toLocation = calculateDestination(island, e.getArgs().from, portalType); + Either destinationResult = calculateDestination(island, e.getArgs().from, portalType); EntityPortalResult portalResult; - if (toLocation == null) { - portalResult = EntityPortalResult.DESTINATION_WORLD_DISABLED; - } else { + if (destinationResult.getLeft() != null) { portalResult = this.portalsManager.get().handlePlayerPortalFromIsland( - superiorPlayer, island, e.getArgs().from, portalType, toLocation, true); + superiorPlayer, island, e.getArgs().from, portalType, destinationResult.getLeft(), true); + } else { + portalResult = destinationResult.getRight(); } handleEntityPortalResult(portalResult, e); @@ -176,28 +177,31 @@ public void handleEntityPortalResult(GameEvent PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? PortalType.NETHER : PortalType.ENDER; - Location toLocation = calculateDestination(island, e.getArgs().from, portalType); + Either destinationResult = calculateDestination(island, e.getArgs().from, portalType); EntityPortalResult portalResult; - if (toLocation == null) { - portalResult = EntityPortalResult.DESTINATION_WORLD_DISABLED; - } else { + if (destinationResult.getLeft() != null) { portalResult = this.portalsManager.get().handleEntityPortalFromIsland( - entity, island, from, portalType, toLocation); + entity, island, from, portalType, destinationResult.getLeft()); + } else { + portalResult = destinationResult.getRight(); } handleEntityPortalResult(portalResult, e); } @Nullable - private Location calculateDestination(Island island, Location fromLocation, PortalType portalType) { + private Either calculateDestination(Island island, Location fromLocation, PortalType portalType) { Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(fromLocation.getWorld()); + if (portalDimension == null) + return Either.right(EntityPortalResult.PORTAL_NOT_IN_ISLAND); SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(portalDimension); Dimension portalDestination = dimensionConfig == null ? null : dimensionConfig.getPortalDestination(portalType); if (portalDestination == null) - return null; + return Either.right(EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD); SettingsManager.Worlds.DimensionConfig destinationConfig = plugin.getSettings().getWorlds().getDimensionConfig(portalDestination); - return !destinationConfig.isEnabled() ? null : island.getCenter(portalDestination); + return !destinationConfig.isEnabled() ? Either.right(EntityPortalResult.DESTINATION_WORLD_DISABLED) : + Either.left(island.getCenter(portalDestination)); } private void handleEntityPortalResult(EntityPortalResult portalResult, GameEvent event) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java index 39687c3c25..de1e94a6f4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/portals/PortalsManagerServiceImpl.java @@ -73,6 +73,9 @@ public EntityPortalResult handlePlayerPortal(SuperiorPlayer superiorPlayer, Loca Preconditions.checkArgument(destinationLocation.getWorld() != null, "destinationLocation's world cannot be null"); Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld()); + if (destinationDimension == null) + return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; + return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, destinationDimension, checkImmunedPortalsStatus, null); } @@ -87,6 +90,9 @@ public EntityPortalResult handleEntityPortal(Entity entity, Location portalLocat Preconditions.checkArgument(destinationLocation.getWorld() != null, "destinationLocation's world cannot be null"); Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld()); + if (destinationDimension == null) + return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; + return handleEntityPortalInternal(entity, portalLocation, portalType, destinationDimension, null); } @@ -103,7 +109,13 @@ public EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPl Preconditions.checkArgument(island.isInside(portalLocation), "portalLocation is not inside the island."); Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(portalLocation.getWorld()); + if (portalDimension == null) + return EntityPortalResult.PORTAL_NOT_IN_ISLAND; + Dimension destinationDimension = getDestinationDimension(portalDimension, portalType); + if (destinationDimension == null) + return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; + return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, destinationDimension, checkImmunedPortalsStatus, island); } @@ -123,6 +135,9 @@ public EntityPortalResult handlePlayerPortalFromIsland(SuperiorPlayer superiorPl Preconditions.checkArgument(island.isInside(destinationLocation), "destinationLocation is not inside the island."); Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld()); + if (destinationDimension == null) + return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; + return handlePlayerPortalInternal(superiorPlayer, portalLocation, portalType, destinationDimension, checkImmunedPortalsStatus, island); } @@ -138,7 +153,13 @@ public EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island isl Preconditions.checkArgument(island.isInside(portalLocation), "portalLocation is not inside the island."); Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(portalLocation.getWorld()); + if (portalDimension == null) + return EntityPortalResult.PORTAL_NOT_IN_ISLAND; + Dimension destinationDimension = getDestinationDimension(portalDimension, portalType); + if (destinationDimension == null) + return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; + return handleEntityPortalInternal(entity, portalLocation, portalType, destinationDimension, island); } @@ -157,6 +178,9 @@ public EntityPortalResult handleEntityPortalFromIsland(Entity entity, Island isl Preconditions.checkArgument(island.isInside(destinationLocation), "destinationLocation is not inside the island."); Dimension destinationDimension = plugin.getGrid().getIslandsWorldDimension(destinationLocation.getWorld()); + if (destinationDimension == null) + return EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD; + return handleEntityPortalInternal(entity, portalLocation, portalType, destinationDimension, island); } @@ -337,10 +361,13 @@ private EntityPortalResult simulateEntityPortalFromIsland(Entity entity, Island return EntityPortalResult.SUCCEED; } + @Nullable private Dimension getDestinationDimension(Dimension dimension, PortalType portalType) { SettingsManager.Worlds.DimensionConfig dimensionConfig = plugin.getSettings().getWorlds().getDimensionConfig(dimension); - Dimension destination = dimensionConfig == null ? null : dimensionConfig.getPortalDestination(portalType); - return destination == null ? plugin.getSettings().getWorlds().getDefaultWorldDimension() : destination; + if (dimensionConfig == null) + return null; + + return dimensionConfig.getPortalDestination(portalType); } } From b8ac0eaa536ccf66d3a0d9127a59b4fdc8c78317 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 28 Apr 2026 22:53:14 +0300 Subject: [PATCH 565/600] Fixed more issues regarding portals (#2912) --- .../listener/PortalsListener.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java index 1e4640432f..abe0c29170 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java @@ -8,6 +8,7 @@ import com.bgsoftware.superiorskyblock.api.service.portals.EntityPortalResult; import com.bgsoftware.superiorskyblock.api.service.portals.PortalsManagerService; import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.core.Either; import com.bgsoftware.superiorskyblock.core.IslandWorlds; @@ -15,6 +16,8 @@ import com.bgsoftware.superiorskyblock.core.Materials; import com.bgsoftware.superiorskyblock.core.ObjectsPools; import com.bgsoftware.superiorskyblock.core.ServerVersion; +import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.messages.Message; import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; import com.bgsoftware.superiorskyblock.platform.event.GameEvent; import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; @@ -148,7 +151,7 @@ private void handlePlayerPortal(GameEvent e) { PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? PortalType.NETHER : PortalType.ENDER; - Either destinationResult = calculateDestination(island, e.getArgs().from, portalType); + Either destinationResult = calculateDestination(island, superiorPlayer, e.getArgs().from, portalType); EntityPortalResult portalResult; if (destinationResult.getLeft() != null) { @@ -177,7 +180,7 @@ public void handleEntityPortalResult(GameEvent PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? PortalType.NETHER : PortalType.ENDER; - Either destinationResult = calculateDestination(island, e.getArgs().from, portalType); + Either destinationResult = calculateDestination(island, null, e.getArgs().from, portalType); EntityPortalResult portalResult; if (destinationResult.getLeft() != null) { @@ -191,7 +194,10 @@ public void handleEntityPortalResult(GameEvent } @Nullable - private Either calculateDestination(Island island, Location fromLocation, PortalType portalType) { + private Either calculateDestination(Island island, @Nullable SuperiorPlayer superiorPlayer, Location fromLocation, PortalType portalType) { + if (island.isSpawn()) + return Either.right(EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD); + Dimension portalDimension = plugin.getGrid().getIslandsWorldDimension(fromLocation.getWorld()); if (portalDimension == null) return Either.right(EntityPortalResult.PORTAL_NOT_IN_ISLAND); @@ -200,8 +206,17 @@ private Either calculateDestination(Island island, if (portalDestination == null) return Either.right(EntityPortalResult.DESTINATION_NOT_ISLAND_WORLD); SettingsManager.Worlds.DimensionConfig destinationConfig = plugin.getSettings().getWorlds().getDimensionConfig(portalDestination); - return !destinationConfig.isEnabled() ? Either.right(EntityPortalResult.DESTINATION_WORLD_DISABLED) : - Either.left(island.getCenter(portalDestination)); + if (destinationConfig.isEnabled()) { + // Check if the world actually exists + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(island, portalDestination); + if (worldInfo != null) + return Either.left(island.getCenter(portalDestination)); + } + + if (superiorPlayer != null) + Message.WORLD_NOT_ENABLED.send(superiorPlayer, Formatters.CAPITALIZED_FORMATTER.format(portalDestination.getName())); + + return Either.right(EntityPortalResult.DESTINATION_WORLD_DISABLED); } private void handleEntityPortalResult(EntityPortalResult portalResult, GameEvent event) { From 411b2d658bee1d5823f8c47c16a0a26b25260cfe Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Thu, 30 Apr 2026 09:25:42 +0300 Subject: [PATCH 566/600] Fixed portals in islands world teleport to normal nether if they are not inside an island (#2912) --- .../listener/PortalsListener.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java index abe0c29170..d6a37efe2a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/PortalsListener.java @@ -50,7 +50,7 @@ public PortalsListener(SuperiorSkyblockPlugin plugin) { } private void registerListeners() { - registerCallback(GameEventType.ENTITY_PORTAL_EVENT, GameEventPriority.MONITOR, this::onEntityPortal); + registerCallback(GameEventType.ENTITY_PORTAL_EVENT, GameEventPriority.HIGHEST, this::onEntityPortal); registerCallback(GameEventType.ENTITY_ENTER_PORTAL_EVENT, GameEventPriority.HIGHEST, this::onEntityEnterPortal); } @@ -68,17 +68,20 @@ private void onEntityEnterPortal(GameEvent Entity entity = e.getArgs().entity; + Location portalLocation = e.getArgs().portalLocation; + + World world = portalLocation.getWorld(); + Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { island = plugin.getGrid().getIslandAt(entity.getLocation(wrapper.getHandle())); } - if (island == null) + if (island == null) { + if (plugin.getGrid().isIslandsWorld(world)) + e.setCancelled(); return; - - Location portalLocation = e.getArgs().portalLocation; - - World world = portalLocation.getWorld(); + } // Simulate end portal if (world.getEnvironment() == World.Environment.THE_END) { @@ -145,8 +148,11 @@ private void handlePlayerPortal(GameEvent e) { } Island island = plugin.getGrid().getIslandAt(e.getArgs().from); - if (island == null) + if (island == null) { + if (plugin.getGrid().isIslandsWorld(e.getArgs().from.getWorld())) + e.setCancelled(); return; + } PortalType portalType = (e.getArgs().cause == PlayerTeleportEvent.TeleportCause.NETHER_PORTAL) ? PortalType.NETHER : PortalType.ENDER; From 2966af3844225b400879a696533c627af9e3de2c Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 1 May 2026 17:07:34 +0300 Subject: [PATCH 567/600] Fix the plugin not loading on older versions of the game (#2913) --- build.gradle | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 96d0f6a201..67a8dfa21a 100644 --- a/build.gradle +++ b/build.gradle @@ -44,6 +44,10 @@ allprojects { throw new GradleException("Found debug messages: " + filesWithDebug) } + shadowJar { + relocate 'com.bgsoftware.common', 'com.bgsoftware.superiorskyblock.libs.com.bgsoftware.common' + } + build { dependsOn checkDebug dependsOn shadowJar @@ -63,7 +67,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b18' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b19' implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b2' implementation 'org.bstats:bstats-bukkit:3.0.0' @@ -88,7 +92,6 @@ subprojects.each { evaluationDependsOn(it.path) } shadowJar { relocate 'org.bstats', 'com.bgsoftware.superiorskyblock.libs.org.bstats' - relocate 'com.bgsoftware.common', 'com.bgsoftware.superiorskyblock.libs.com.bgsoftware.common' archiveClassifier.set('') @@ -105,11 +108,24 @@ shadowJar { try { def reobfTask = sub.tasks.named('reobfJar') dependsOn(reobfTask) - from(reobfTask.flatMap { it.outputJar }.map { zipTree(it) }) { + from(reobfTask.map { it.outputJar }) { exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' + rename { sub.name } + into("nms") } + return; } catch (Exception ignored) { - from sub.sourceSets.main.output + } + } + + if (sub.path.startsWith(':NMS:v')) { + def shadowJarTask = sub.tasks.named("shadowJar") + dependsOn(shadowJarTask) + + from(shadowJarTask.map { it.archiveFile }) { + exclude 'META-INF/MANIFEST.MF', 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA' + rename { sub.name } + into("nms") } } else { from sub.sourceSets.main.output From 4468030d082e7418ffb3511599ac529b1e9c68cd Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 2 May 2026 00:13:30 +0300 Subject: [PATCH 568/600] Better handling of built-in entity categories + add VEHICLE built-in entity category (#2917) --- .../api/entity/EntityCategory.java | 27 +++++ .../nms/v1_21/trial/IslandPlayerDetector.java | 9 +- .../v1_21_10/trial/IslandPlayerDetector.java | 6 +- .../v1_21_3/trial/IslandPlayerDetector.java | 6 +- .../v1_21_4/trial/IslandPlayerDetector.java | 6 +- .../v1_21_5/trial/IslandPlayerDetector.java | 6 +- .../v1_21_7/trial/IslandPlayerDetector.java | 6 +- .../v1_21_9/trial/IslandPlayerDetector.java | 6 +- .../nms/v26_1/trial/IslandPlayerDetector.java | 6 +- .../section/EntityCategoriesSection.java | 101 +++------------- .../events/plugin/PluginEventsDispatcher.java | 6 +- .../island/privilege/IslandPrivileges.java | 24 +++- .../listener/ProtectionListener.java | 29 +++-- .../IslandPlayerDetectorHelper.java | 37 ------ .../region/RegionManagerServiceImpl.java | 14 +-- .../world/BukkitEntities.java | 18 +-- .../world/entity/BuiltinEntityCategory.java | 114 ++++++++++++++++++ src/main/resources/entity-categories.yml | 5 + 18 files changed, 244 insertions(+), 182 deletions(-) delete mode 100644 src/main/java/com/bgsoftware/superiorskyblock/nms/player_detector/IslandPlayerDetectorHelper.java create mode 100644 src/main/java/com/bgsoftware/superiorskyblock/world/entity/BuiltinEntityCategory.java diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/entity/EntityCategory.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/entity/EntityCategory.java index d803dfa3fd..6fc05a4516 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/entity/EntityCategory.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/entity/EntityCategory.java @@ -1,23 +1,50 @@ package com.bgsoftware.superiorskyblock.api.entity; +import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.api.island.IslandFlag; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.key.KeySet; public interface EntityCategory { + /** + * Get the name of the entity category. + */ String getName(); + /** + * Get the entities this category contains. + */ KeySet getEntities(); + /** + * Get the required {@link IslandPrivilege} to spawn entities from this category on an island. + */ + @Nullable IslandPrivilege getSpawnPrivilege(); + /** + * Get the required {@link IslandPrivilege} to damage entities from this category on an island. + */ + @Nullable IslandPrivilege getDamagePrivilege(); + /** + * Get the required {@link IslandPrivilege} to interact with entities from this category on an island. + */ + @Nullable IslandPrivilege getInteractPrivilege(); + /** + * Get the required {@link IslandFlag} for entities from this category to spawn on an island from a spawner. + */ + @Nullable IslandFlag getSpawnerSpawningIslandFlag(); + /** + * Get the required {@link IslandFlag} for entities from this category to spawn on an island naturally. + */ + @Nullable IslandFlag getNaturalSpawningIslandFlag(); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java index 57392d9252..27539a1e18 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/trial/IslandPlayerDetector.java @@ -1,14 +1,11 @@ package com.bgsoftware.superiorskyblock.nms.v1_21.trial; -import com.bgsoftware.common.annotations.Nullable; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; -import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; -import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; +import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -28,11 +25,11 @@ public class IslandPlayerDetector implements PlayerDetector { private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java index 3f57852c90..25f7ae78f0 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/trial/IslandPlayerDetector.java @@ -5,7 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; +import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -25,11 +25,11 @@ public class IslandPlayerDetector implements PlayerDetector { private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java index 5b8ca04a60..0c1663900c 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/trial/IslandPlayerDetector.java @@ -5,7 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; +import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -25,11 +25,11 @@ public class IslandPlayerDetector implements PlayerDetector { private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java index 237044292d..598830bd4b 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/trial/IslandPlayerDetector.java @@ -5,7 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; +import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -25,11 +25,11 @@ public class IslandPlayerDetector implements PlayerDetector { private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java index aef668efbd..700b9563e8 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/trial/IslandPlayerDetector.java @@ -5,7 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; +import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -25,11 +25,11 @@ public class IslandPlayerDetector implements PlayerDetector { private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java index 43787f1fed..85dca9f171 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/trial/IslandPlayerDetector.java @@ -5,7 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; +import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -25,11 +25,11 @@ public class IslandPlayerDetector implements PlayerDetector { private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java index bf78ea8ede..a20ccbd98f 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/trial/IslandPlayerDetector.java @@ -5,7 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; +import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -25,11 +25,11 @@ public class IslandPlayerDetector implements PlayerDetector { private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java index ee0f58415a..4118e2ca4b 100644 --- a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/trial/IslandPlayerDetector.java @@ -5,7 +5,7 @@ import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; -import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; +import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; @@ -25,11 +25,11 @@ public class IslandPlayerDetector implements PlayerDetector { private final Supplier requiredPrivilege; public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, IslandPlayerDetectorHelper.getTrialVaultIslandPrivilege()); + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); } public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { - return new IslandPlayerDetector(island, original, () -> IslandPrivileges.MONSTER_DAMAGE); + return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); } private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java b/src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java index 4e24965bde..c8b6cc9d29 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/config/section/EntityCategoriesSection.java @@ -11,22 +11,15 @@ import com.bgsoftware.superiorskyblock.core.EnumHelper; import com.bgsoftware.superiorskyblock.core.LazyReference; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.set.KeySets; import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import com.bgsoftware.superiorskyblock.world.entity.EntityCategoryImpl; import com.google.common.base.Preconditions; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Ambient; -import org.bukkit.entity.Creature; -import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; -import org.bukkit.entity.Flying; -import org.bukkit.entity.Monster; -import org.bukkit.entity.Slime; -import org.bukkit.entity.Tameable; import java.io.File; import java.io.IOException; @@ -41,19 +34,6 @@ public class EntityCategoriesSection implements SettingsManager.EntityCategories { - @Nullable - private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); - @Nullable - private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); - @Nullable - private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); - @Nullable - private static final Class ZOMBIE_NAUTILUS_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieNautilus"); - - private static final KeySet TAMEABLE_ENTITY_KEYS = createTameableEntityKeys(); - private static final KeySet ANIMAL_ENTITY_KEYS = createAnimalEntityKeys(); - private static final KeySet MONSTER_ENTITY_KEYS = createMonsterEntityKeys(); - private final Map nameToCategory; private final KeyMap> entityToCategory; @@ -73,7 +53,7 @@ public EntityCategoriesSection(YamlConfiguration cfg) { public static void removeInvalidEntityKeys(YamlConfiguration cfg, File file) { boolean removed = false; for (String categoryName : cfg.getKeys(false)) { - if (!categoryName.equals("TAMEABLE") && !categoryName.equals("ANIMAL") && !categoryName.equals("MONSTER")) { + if (EnumHelper.getEnum(BuiltinEntityCategory.class, categoryName) == null) { List entities = cfg.getStringList(categoryName + ".entities"); Iterator iterator = entities.iterator(); while (iterator.hasNext()) { @@ -102,6 +82,7 @@ public static void removeInvalidEntityKeys(YamlConfiguration cfg, File file) { private static Map loadInternal(YamlConfiguration cfg) { Map entityCategories = new HashMap<>(); + for (String categoryName : cfg.getKeys(false)) { String key = categoryName.toLowerCase(Locale.ENGLISH); @@ -112,16 +93,11 @@ private static Map loadInternal(YamlConfiguration cfg) { ConfigurationSection section = cfg.getConfigurationSection(categoryName); - KeySet entities; - if (categoryName.equalsIgnoreCase("TAMEABLE")) { - entities = TAMEABLE_ENTITY_KEYS; - } else if (categoryName.equalsIgnoreCase("ANIMAL")) { - entities = ANIMAL_ENTITY_KEYS; - } else if (categoryName.equalsIgnoreCase("MONSTER")) { - entities = MONSTER_ENTITY_KEYS; - } else { - entities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE, section.getStringList("entities")); - } + BuiltinEntityCategory builtinEntityCategory = EnumHelper.getEnum(BuiltinEntityCategory.class, + categoryName.toUpperCase(Locale.ENGLISH)); + + KeySet entities = builtinEntityCategory != null ? builtinEntityCategory.getEntities() : + KeySets.createHashSet(KeyIndicator.ENTITY_TYPE, section.getStringList("entities")); IslandPrivilege spawnPrivilege = getOrRegisterPrivilege(section.getString("actions.SPAWN")); IslandPrivilege damagePrivilege = getOrRegisterPrivilege(section.getString("actions.DAMAGE")); @@ -132,7 +108,17 @@ private static Map loadInternal(YamlConfiguration cfg) { entityCategories.put(key, new EntityCategoryImpl(categoryName, entities, spawnPrivilege, damagePrivilege, interactPrivilege, spawnerSpawnFlag, naturalSpawnFlag)); } - return entityCategories.isEmpty() ? Collections.emptyMap() : Collections.unmodifiableMap(entityCategories); + + // Add rest of built-in entity categories + for (BuiltinEntityCategory builtinEntityCategory : BuiltinEntityCategory.values()) { + if (!entityCategories.containsKey(builtinEntityCategory.name())) { + entityCategories.put(builtinEntityCategory.name(), new EntityCategoryImpl(builtinEntityCategory.name(), + builtinEntityCategory.getEntities(), null, null, + null, null, null)); + } + } + + return Collections.unmodifiableMap(entityCategories); } private static KeyMap> convertEntityToCategoryInternal(Collection entityCategories) { @@ -168,46 +154,6 @@ public EntityCategory getCategoryByName(String name) { return this.nameToCategory.get(name.toLowerCase(Locale.ENGLISH)); } - private static KeySet createTameableEntityKeys() { - KeySet tameableEntities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); - for (EntityType entityType : EntityType.values()) { - if (entityType.getEntityClass() != null && Tameable.class.isAssignableFrom(entityType.getEntityClass())) { - tameableEntities.add(Keys.of(entityType)); - } - } - return tameableEntities; - } - - private static KeySet createAnimalEntityKeys() { - KeySet animalEntities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); - for (EntityType entityType : EntityType.values()) { - Class entityClass = entityType.getEntityClass(); - if (entityClass != null && !isMonsterType(entityClass) && - (Creature.class.isAssignableFrom(entityClass) || Ambient.class.isAssignableFrom(entityClass))) { - animalEntities.add(Keys.of(entityType)); - } - } - return animalEntities; - } - - private static boolean isMonsterType(Class entityClass) { - return Monster.class.isAssignableFrom(entityClass) || - Slime.class.isAssignableFrom(entityClass) || Flying.class.isAssignableFrom(entityClass) || - entityClass == HOGLIN_CLASS || entityClass == SKELETON_HORSE_CLASS || - entityClass == ZOMBIE_HORSE_CLASS || entityClass == ZOMBIE_NAUTILUS_CLASS; - } - - private static KeySet createMonsterEntityKeys() { - KeySet monsterEntities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); - for (EntityType entityType : EntityType.values()) { - Class entityClass = entityType.getEntityClass(); - if (entityClass != null && isMonsterType(entityClass)) { - monsterEntities.add(Keys.of(entityType)); - } - } - return monsterEntities; - } - @Nullable private static IslandPrivilege getOrRegisterPrivilege(@Nullable String name) { if (name == null) @@ -234,13 +180,4 @@ private static IslandFlag getOrRegisterFlag(@Nullable String name) { } } - @Nullable - private static Class getEntityTypeClass(String clazz) { - try { - return Class.forName(clazz); - } catch (ClassNotFoundException error) { - return null; - } - } - } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java index c197316d5f..dd3c92f94b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/events/plugin/PluginEventsDispatcher.java @@ -14,10 +14,9 @@ import com.bgsoftware.superiorskyblock.external.worlds.WorldsProvider_Default; import com.bgsoftware.superiorskyblock.island.SIsland; import com.bgsoftware.superiorskyblock.island.SpawnIsland; -import com.bgsoftware.superiorskyblock.nms.player_detector.IslandPlayerDetectorHelper; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; import com.bgsoftware.superiorskyblock.player.SSuperiorPlayer; import com.bgsoftware.superiorskyblock.service.region.RegionManagerServiceImpl; -import com.bgsoftware.superiorskyblock.world.BukkitEntities; import com.bgsoftware.superiorskyblock.world.Dimensions; import org.bukkit.Bukkit; import org.bukkit.event.Cancellable; @@ -46,9 +45,8 @@ public void registerDefaultListeners() { Message.registerListeners(this); SSuperiorPlayer.registerListeners(this); WorldsProvider_Default.registerListeners(this); - IslandPlayerDetectorHelper.registerListeners(this); + IslandPrivileges.registerListeners(this); Dimensions.registerListeners(this); - BukkitEntities.registerListeners(this); } public void registerCallback(PluginEventType type, Runnable callback) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java index 54658ad930..ca812c8354 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/privilege/IslandPrivileges.java @@ -2,9 +2,14 @@ import com.bgsoftware.common.annotations.NotNull; import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ServerVersion; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; +import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; +import com.bgsoftware.superiorskyblock.core.key.Keys; import java.util.Comparator; import java.util.Locale; @@ -12,6 +17,7 @@ public class IslandPrivileges { + // Builtin privileges public static final IslandPrivilege ALL = register("ALL"); public static final IslandPrivilege ANIMAL_BREED = register("ANIMAL_BREED"); public static final IslandPrivilege ANIMAL_SHEAR = register("ANIMAL_SHEAR"); @@ -45,8 +51,6 @@ public class IslandPrivileges { public static final IslandPrivilege LEASH = register("LEASH"); public static final IslandPrivilege MINECART_ENTER = register("MINECART_ENTER"); public static final IslandPrivilege MINECART_OPEN = register("MINECART_OPEN"); - public static final IslandPrivilege MINECART_PLACE = register("MINECART_PLACE"); - public static final IslandPrivilege MONSTER_DAMAGE = register("MONSTER_DAMAGE"); public static final IslandPrivilege NAME_ENTITY = register("NAME_ENTITY"); public static final IslandPrivilege OPEN_ISLAND = register("OPEN_ISLAND", IslandPrivilege.Type.COMMAND); public static final IslandPrivilege PAYPAL_SHOW = register("PAYPAL_SHOW"); @@ -74,6 +78,10 @@ public class IslandPrivileges { public static final IslandPrivilege WIND_CHARGE = register("WIND_CHARGE", ServerVersion.isAtLeast(ServerVersion.v1_21)); public static final IslandPrivilege WITHDRAW_MONEY = register("WITHDRAW_MONEY", IslandPrivilege.Type.COMMAND); + // Privileges from configurations + @Nullable + public static IslandPrivilege CONFIG_VAULT_INTERACT; + private static String ALL_PRIVILEGE_NAMES; private static int KNOWN_PRIVILEGES_COUNT; @@ -85,6 +93,18 @@ public static void registerPrivileges() { // Do nothing, only trigger all the register calls } + public static void registerListeners(PluginEventsDispatcher dispatcher) { + dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, IslandPrivileges::onSettingsUpdate); + } + + private static void onSettingsUpdate() { + CONFIG_VAULT_INTERACT = null; + + SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + Key vaultKey = Keys.ofMaterialAndData("VAULT"); + CONFIG_VAULT_INTERACT = plugin.getSettings().getInteractablesMap().getRequiredPrivilege(vaultKey); + } + public static String getPrivilegesNames() { if (ALL_PRIVILEGE_NAMES == null || KNOWN_PRIVILEGES_COUNT != IslandPrivilege.values().size()) { ALL_PRIVILEGE_NAMES = Formatters.COMMA_FORMATTER.format(IslandPrivilege.values().stream() diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java index 7ac5e1b22e..2149b49bde 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ProtectionListener.java @@ -211,19 +211,32 @@ private boolean handleMinecartPlace(GameEvent Material handItemType = usedItem.getType(); Material clickedBlockType = e.getArgs().clickedBlock.getType(); - if (!Materials.isBoat(handItemType) && (!Materials.isMinecart(handItemType) || !Materials.isRail(clickedBlockType))) + + EntityType spawnType = Materials.isMinecart(handItemType) && Materials.isRail(clickedBlockType) ? EntityType.MINECART : + Materials.isBoat(handItemType) ? EntityType.BOAT : null; + if (spawnType == null) return false; SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(e.getArgs().player); - InteractionResult interactionResult; + List entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(spawnType)); + + if (entityCategories.isEmpty()) + return false; + try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - interactionResult = this.protectionManager.get().handleCustomInteraction(superiorPlayer, - e.getArgs().clickedBlock.getLocation(wrapper.getHandle()), IslandPrivileges.MINECART_PLACE); - } - if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { - e.setCancelled(); - return true; + Location clickedBlockLocation = e.getArgs().clickedBlock.getLocation(wrapper.getHandle()); + + for (EntityCategory entityCategory : entityCategories) { + if (entityCategory.getSpawnPrivilege() != null) { + InteractionResult interactionResult = this.protectionManager.get().handleCustomInteraction( + superiorPlayer, clickedBlockLocation, entityCategory.getSpawnPrivilege()); + if (ProtectionHelper.shouldPreventInteraction(interactionResult, superiorPlayer, true)) { + e.setCancelled(); + return true; + } + } + } } return false; diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/player_detector/IslandPlayerDetectorHelper.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/player_detector/IslandPlayerDetectorHelper.java deleted file mode 100644 index c8aa3c39d3..0000000000 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/player_detector/IslandPlayerDetectorHelper.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.bgsoftware.superiorskyblock.nms.player_detector; - -import com.bgsoftware.common.annotations.Nullable; -import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; -import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; -import com.bgsoftware.superiorskyblock.api.key.Key; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; -import com.bgsoftware.superiorskyblock.core.key.Keys; - -import java.util.function.Supplier; - -public class IslandPlayerDetectorHelper { - - @Nullable - private static IslandPrivilege CACHED_TRIAL_VAULT_PRIVILEGE; - - public static void registerListeners(PluginEventsDispatcher dispatcher) { - dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, IslandPlayerDetectorHelper::onSettingsUpdate); - } - - private static void onSettingsUpdate() { - SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - // Do not call in static-initializator, otherwise will cause errors - Key vaultKey = Keys.ofMaterialAndData("VAULT"); - CACHED_TRIAL_VAULT_PRIVILEGE = plugin.getSettings().getInteractablesMap().getRequiredPrivilege(vaultKey); - } - - public static Supplier getTrialVaultIslandPrivilege() { - return () -> CACHED_TRIAL_VAULT_PRIVILEGE; - } - - private IslandPlayerDetectorHelper() { - - } - -} diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java index b1f63b1139..0c14277874 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/region/RegionManagerServiceImpl.java @@ -187,7 +187,12 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc if (!isInteractableItem && stackedBlockAmount <= 1 && islandPrivilege == null) return InteractionResult.SUCCESS; - EntityType spawnType = usedItem == null ? EntityType.UNKNOWN : BukkitItems.getEntityType(usedItem); + Material blockType = block.getType(); + Material usedItemType = usedItem == null ? null : usedItem.getType(); + + EntityType spawnType = usedItem == null ? EntityType.UNKNOWN : + Materials.isMinecart(usedItemType) && Materials.isRail(blockType) ? EntityType.MINECART : + Materials.isBoat(blockType) ? EntityType.BOAT : BukkitItems.getEntityType(usedItem); if (spawnType != EntityType.UNKNOWN) { List entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(spawnType)); @@ -202,12 +207,7 @@ public InteractionResult handleBlockInteract(SuperiorPlayer superiorPlayer, Bloc return InteractionResult.SUCCESS; } - Material blockType = block.getType(); - Material usedItemType = usedItem == null ? null : usedItem.getType(); - - if (usedItem != null && Materials.isMinecart(usedItemType) ? Materials.isRail(blockType) : Materials.isBoat(blockType)) { - islandPrivilege = IslandPrivileges.MINECART_PLACE; - } else if (usedItem != null && blockType == VAULT && usedItemType != TRIAL_KEY && usedItemType != OMINOUS_TRIAL_KEY) { + if (usedItem != null && blockType == VAULT && usedItemType != TRIAL_KEY && usedItemType != OMINOUS_TRIAL_KEY) { return InteractionResult.SUCCESS; } else if (action == Action.PHYSICAL && blockType == FARMLAND || blockType == ROOTED_DIRT || (usedItem != null && Materials.isHoe(usedItemType))) { diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java index 50a33199d2..12b3590f71 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/BukkitEntities.java @@ -9,10 +9,9 @@ import com.bgsoftware.superiorskyblock.core.ServerVersion; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Int2ObjectMapView; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; -import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventsDispatcher; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; import org.bukkit.Material; import org.bukkit.entity.AbstractHorse; import org.bukkit.entity.ArmorStand; @@ -46,17 +45,6 @@ public class BukkitEntities { @Nullable private static final EntityType ZOMBIE_NAUTILUS_TYPE = EnumHelper.getEnum(EntityType.class, "ZOMBIE_NAUTILUS"); - @Nullable - private static EntityCategory TAMEABLE_CATEGORY; - - public static void registerListeners(PluginEventsDispatcher dispatcher) { - dispatcher.registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, BukkitEntities::onSettingsUpdate); - } - - private static void onSettingsUpdate() { - TAMEABLE_CATEGORY = plugin.getSettings().getEntityCategoriesMap().getCategoryByName("TAMEABLE"); - } - private BukkitEntities() { } @@ -176,9 +164,9 @@ public static boolean isNautilus(EntityType entityType) { public static List getCategories(Entity entity) { List categories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(entity)); - if (TAMEABLE_CATEGORY != null && isTameable(entity)) { + if (isTameable(entity)) { categories = new LinkedList<>(categories); - categories.add(TAMEABLE_CATEGORY); + categories.add(BuiltinEntityCategory.TAMEABLE.getEntityCategory()); } return categories; } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/entity/BuiltinEntityCategory.java b/src/main/java/com/bgsoftware/superiorskyblock/world/entity/BuiltinEntityCategory.java new file mode 100644 index 0000000000..f7625309f8 --- /dev/null +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/entity/BuiltinEntityCategory.java @@ -0,0 +1,114 @@ +package com.bgsoftware.superiorskyblock.world.entity; + +import com.bgsoftware.common.annotations.NotNull; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; +import com.bgsoftware.superiorskyblock.api.key.KeySet; +import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.set.KeySets; +import org.bukkit.entity.Ambient; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Flying; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Slime; +import org.bukkit.entity.Tameable; +import org.bukkit.entity.Vehicle; + +import java.lang.ref.WeakReference; +import java.util.Objects; + +public enum BuiltinEntityCategory { + + TAMEABLE { + @Override + protected boolean isEntityListedInternal(Class entityClass) { + return Tameable.class.isAssignableFrom(entityClass); + } + }, + VEHICLE { + @Override + protected boolean isEntityListedInternal(Class entityClass) { + return Vehicle.class.isAssignableFrom(entityClass) && !Creature.class.isAssignableFrom(entityClass); + } + }, + MONSTER { + @Override + protected boolean isEntityListedInternal(Class entityClass) { + return Monster.class.isAssignableFrom(entityClass) || + Slime.class.isAssignableFrom(entityClass) || Flying.class.isAssignableFrom(entityClass) || + entityClass == HOGLIN_CLASS || entityClass == SKELETON_HORSE_CLASS || + entityClass == ZOMBIE_HORSE_CLASS || entityClass == ZOMBIE_NAUTILUS_CLASS; + } + }, + ANIMAL { + @Override + protected boolean isEntityListedInternal(Class entityClass) { + return !BuiltinEntityCategory.MONSTER.isEntityListedInternal(entityClass) && + (Creature.class.isAssignableFrom(entityClass) || Ambient.class.isAssignableFrom(entityClass)); + } + }; + + @Nullable + private static final Class HOGLIN_CLASS = getEntityTypeClass("org.bukkit.entity.Hoglin"); + @Nullable + private static final Class SKELETON_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.SkeletonHorse"); + @Nullable + private static final Class ZOMBIE_HORSE_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieHorse"); + @Nullable + private static final Class ZOMBIE_NAUTILUS_CLASS = getEntityTypeClass("org.bukkit.entity.ZombieNautilus"); + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final KeySet entities = getEntitiesInternal(); + private WeakReference entityCategoryReference; + + public KeySet getEntities() { + return entities; + } + + @NotNull + public EntityCategory getEntityCategory() { + if (this.entityCategoryReference == null) { + EntityCategory entityCategory = plugin.getSettings().getEntityCategoriesMap().getCategoryByName(name()); + this.entityCategoryReference = new WeakReference<>(entityCategory); + return Objects.requireNonNull(entityCategory); + } + + EntityCategory entityCategory = this.entityCategoryReference.get(); + if (entityCategory == null) { + entityCategory = plugin.getSettings().getEntityCategoriesMap().getCategoryByName(name()); + this.entityCategoryReference = new WeakReference<>(entityCategory); + } + + return Objects.requireNonNull(entityCategory); + } + + private KeySet getEntitiesInternal() { + KeySet entities = KeySets.createHashSet(KeyIndicator.ENTITY_TYPE); + for (EntityType entityType : EntityType.values()) { + Class entityClass = entityType.getEntityClass(); + if (entityClass != null && isEntityListedInternal(entityClass)) { + entities.add(Keys.of(entityType)); + } + } + return entities.isEmpty() ? KeySets.createEmptySet() : KeySets.unmodifiableKeySet(entities); + } + + protected boolean isEntityListedInternal(Class entityClass) { + throw new UnsupportedOperationException(); + } + + @Nullable + private static Class getEntityTypeClass(String clazz) { + try { + return Class.forName(clazz); + } catch (ClassNotFoundException error) { + return null; + } + } + +} diff --git a/src/main/resources/entity-categories.yml b/src/main/resources/entity-categories.yml index fc6e4915bd..4f6316b9f9 100644 --- a/src/main/resources/entity-categories.yml +++ b/src/main/resources/entity-categories.yml @@ -112,6 +112,11 @@ TAMEABLE: actions: DAMAGE: TAMED_ANIMAL_DAMAGE +VEHICLE: + actions: + SPAWN: MINECART_PLACE + DAMAGE: MINECART_DAMAGE + ANIMAL: actions: SPAWN: ANIMAL_SPAWN From b62311fe044908857d08567f6b9fe3ca2e9b46d3 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 2 May 2026 12:32:35 +0300 Subject: [PATCH 569/600] Another fix for plugin not working on older versions (#2913) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 67a8dfa21a..262037f357 100644 --- a/build.gradle +++ b/build.gradle @@ -67,7 +67,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b19' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b20' implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b2' implementation 'org.bstats:bstats-bukkit:3.0.0' From b9ab67ed679eb3df0c77e9d607cf105c949d59eb Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 2 May 2026 13:58:06 +0300 Subject: [PATCH 570/600] Fixed crop growth multiplier stop working after switching to other island worlds (#2763) --- .../templates/AbstractNMSChunks.java.template | 4 ++-- .../crops/CropsBlockEntity.java.template | 20 ++++++++++--------- .../nms/v1_12_R1/NMSChunksImpl.java | 4 ++-- .../chunks/CropsTickingTileEntity.java | 11 +++++----- .../nms/v1_16_R3/NMSChunksImpl.java | 4 ++-- .../crops/CropsTickingTileEntity.java | 13 ++++++------ .../nms/v1_8_R3/NMSChunksImpl.java | 8 ++++---- .../chunks/CropsTickingTileEntity.java | 13 ++++++------ 8 files changed, 39 insertions(+), 38 deletions(-) diff --git a/NMS/src/main/templates/AbstractNMSChunks.java.template b/NMS/src/main/templates/AbstractNMSChunks.java.template index 5524ad86e5..b100f0d06d 100644 --- a/NMS/src/main/templates/AbstractNMSChunks.java.template +++ b/NMS/src/main/templates/AbstractNMSChunks.java.template @@ -170,13 +170,13 @@ public abstract class AbstractNMSChunks implements NMSChunks { if (stop) { long packedPos = NMSUtils.getChunkPackedPos(chunk.getX(), chunk.getZ()); - CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(packedPos); + CropsBlockEntity cropsBlockEntity = CropsBlockEntity.remove(chunk.getWorld().getName(), packedPos); if (cropsBlockEntity != null) cropsBlockEntity.remove(); } else { ServerLevel serverLevel = ((CraftWorld) chunk.getWorld()).getHandle(); LevelChunk levelChunk = serverLevel.getChunk(chunk.getX(), chunk.getZ()); - CropsBlockEntity.create(island, levelChunk); + CropsBlockEntity.create(island, chunk.getWorld().getName(), levelChunk); } } diff --git a/NMS/src/main/templates/crops/CropsBlockEntity.java.template b/NMS/src/main/templates/crops/CropsBlockEntity.java.template index 24c9b953e1..e3c55f216a 100644 --- a/NMS/src/main/templates/crops/CropsBlockEntity.java.template +++ b/NMS/src/main/templates/crops/CropsBlockEntity.java.template @@ -3,11 +3,8 @@ package com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops; import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; -import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsTickingBlockEntity; -import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.crops.CropsTickingMethod; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.BlockEntity; @@ -23,7 +20,7 @@ public class CropsBlockEntity extends BlockEntity { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); + private static final Chunk2ObjectMap tickingChunks = new Chunk2ObjectMap<>(); private final WeakReference island; private final WeakReference chunk; @@ -41,18 +38,18 @@ public class CropsBlockEntity extends BlockEntity { this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; } - public static void create(Island island, LevelChunk levelChunk) { + public static void create(Island island, String worldName, LevelChunk levelChunk) { int chunkX = levelChunk.locX; int chunkZ = levelChunk.locZ; long packedPos = NMSUtils.getChunkPackedPos(chunkX, chunkZ); - tickingChunks.computeIfAbsent(packedPos, p -> { + tickingChunks.computeIfAbsent(worldName, packedPos, () -> { BlockPos blockPos = new BlockPos(chunkX << 4, 1, chunkZ << 4); return new CropsBlockEntity(island, levelChunk, blockPos); }); } - public static CropsBlockEntity remove(long chunkPos) { - return tickingChunks.remove(chunkPos); + public static CropsBlockEntity remove(String worldName, long chunkPos) { + return tickingChunks.remove(worldName, chunkPos); } public static void forEachChunk(List chunkPositions, Consumer cropsBlockEntityConsumer) { @@ -71,6 +68,11 @@ public class CropsBlockEntity extends BlockEntity { return true; } + private net.minecraft.world.level.ChunkPos getPos() { + LevelChunk levelChunk = this.chunk.get(); + return levelChunk == null ? null : levelChunk.getPos(); + } + public void remove() { this.remove = true; } diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java index 10ad1699b7..833aa82fb0 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/NMSChunksImpl.java @@ -316,11 +316,11 @@ public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean sto if (stop) { CropsTickingTileEntity cropsTickingTileEntity = CropsTickingTileEntity.remove( - ChunkCoordIntPair.a(chunk.getX(), chunk.getZ())); + chunk.getWorld().getName(), ChunkCoordIntPair.a(chunk.getX(), chunk.getZ())); if (cropsTickingTileEntity != null) cropsTickingTileEntity.getWorld().tileEntityListTick.remove(cropsTickingTileEntity); } else { - CropsTickingTileEntity.create(island, ((CraftChunk) chunk).getHandle()); + CropsTickingTileEntity.create(island, chunk.getWorld().getName(), ((CraftChunk) chunk).getHandle()); } } diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java index f82386b2b8..2334cc96e7 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; @@ -36,7 +37,7 @@ public class CropsTickingTileEntity extends TileEntity implements ITickable { plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingTileEntity::onSettingsUpdate); } - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); + private static final Chunk2ObjectMap tickingChunks = new Chunk2ObjectMap<>(); private static int random = ThreadLocalRandom.current().nextInt(); private final WeakReference island; @@ -52,13 +53,13 @@ public static void register() { // Calls the static initializer which registers the callback. } - public static void create(Island island, Chunk chunk) { + public static void create(Island island, String worldName, Chunk chunk) { long chunkKey = ChunkCoordIntPair.a(chunk.locX, chunk.locZ); - tickingChunks.computeIfAbsent(chunkKey, i -> new CropsTickingTileEntity(island, chunk)); + tickingChunks.computeIfAbsent(worldName, chunkKey, () -> new CropsTickingTileEntity(island, chunk)); } - public static CropsTickingTileEntity remove(long chunkCoords) { - return tickingChunks.remove(chunkCoords); + public static CropsTickingTileEntity remove(String worldName, long chunkCoords) { + return tickingChunks.remove(worldName, chunkCoords); } public static void forEachChunk(List chunkPositions, Consumer cropsTickingTileEntityConsumer) { diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java index 206e94f9e4..b225b882ff 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/NMSChunksImpl.java @@ -380,12 +380,12 @@ public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean sto if (stop) { CropsTickingTileEntity cropsTickingTileEntity = CropsTickingTileEntity.remove( - ChunkCoordIntPair.pair(chunk.getX(), chunk.getZ())); + chunk.getWorld().getName(), ChunkCoordIntPair.pair(chunk.getX(), chunk.getZ())); World world = cropsTickingTileEntity == null ? null : cropsTickingTileEntity.getWorld(); if (cropsTickingTileEntity != null && world != null) world.tileEntityListTick.remove(cropsTickingTileEntity); } else { - CropsTickingTileEntity.create(island, ((CraftChunk) chunk).getHandle()); + CropsTickingTileEntity.create(island, chunk.getWorld().getName(), ((CraftChunk) chunk).getHandle()); } } diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java index 1a7173b3f5..7f53d71ecf 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java @@ -3,8 +3,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import net.minecraft.server.v1_16_R3.BlockPosition; import net.minecraft.server.v1_16_R3.Chunk; import net.minecraft.server.v1_16_R3.ChunkCoordIntPair; @@ -21,7 +20,7 @@ public class CropsTickingTileEntity extends TileEntity implements ITickable { private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); + private static final Chunk2ObjectMap tickingChunks = new Chunk2ObjectMap<>(); private final WeakReference island; private final WeakReference chunk; @@ -49,13 +48,13 @@ private CropsTickingTileEntity(Island island, Chunk chunk) { this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; } - public static void create(Island island, Chunk chunk) { + public static void create(Island island, String worldName, Chunk chunk) { long chunkPair = chunk.getPos().pair(); - tickingChunks.computeIfAbsent(chunkPair, i -> new CropsTickingTileEntity(island, chunk)); + tickingChunks.computeIfAbsent(worldName, chunkPair, () -> new CropsTickingTileEntity(island, chunk)); } - public static CropsTickingTileEntity remove(long chunkCoords) { - return tickingChunks.remove(chunkCoords); + public static CropsTickingTileEntity remove(String worldName, long chunkCoords) { + return tickingChunks.remove(worldName, chunkCoords); } public static void forEachChunk(List chunkPositions, Consumer cropsTickingTileEntityConsumer) { diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java index 26711ec42a..8a641cade2 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/NMSChunksImpl.java @@ -10,8 +10,8 @@ import com.bgsoftware.superiorskyblock.core.Counter; import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.key.KeyIndicator; -import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.key.map.KeyMaps; import com.bgsoftware.superiorskyblock.core.threads.Synchronized; import com.bgsoftware.superiorskyblock.nms.NMSChunks; import com.bgsoftware.superiorskyblock.nms.v1_8_R3.chunks.CropsTickingTileEntity; @@ -109,7 +109,7 @@ public void onFinish() { @Override public CompletableFuture> calculateChunks(List chunkPositions, - Synchronized> unloadedChunksCache) { + Synchronized> unloadedChunksCache) { List allCalculatedChunks = new LinkedList<>(); List chunkPositionsToCalculate = new LinkedList<>(); @@ -245,7 +245,7 @@ public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean sto if (stop) { CropsTickingTileEntity cropsTickingTileEntity = CropsTickingTileEntity.remove( - ChunkCoordIntPair.a(chunk.getX(), chunk.getZ())); + chunk.getWorld().getName(), ChunkCoordIntPair.a(chunk.getX(), chunk.getZ())); if (cropsTickingTileEntity != null) { try { cropsTickingTileEntity.getWorld().tileEntityList.remove(cropsTickingTileEntity); @@ -254,7 +254,7 @@ public void startTickingChunk(Island island, org.bukkit.Chunk chunk, boolean sto } } } else { - CropsTickingTileEntity.create(island, ((CraftChunk) chunk).getHandle()); + CropsTickingTileEntity.create(island, chunk.getWorld().getName(), ((CraftChunk) chunk).getHandle()); } } diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java index 0ef342b1ab..3fd12429bf 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java @@ -4,8 +4,7 @@ import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.key.Key; import com.bgsoftware.superiorskyblock.core.ChunkPosition; -import com.bgsoftware.superiorskyblock.core.collections.CollectionsFactory; -import com.bgsoftware.superiorskyblock.core.collections.view.Long2ObjectMapView; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; import com.bgsoftware.superiorskyblock.core.events.plugin.PluginEventType; import com.bgsoftware.superiorskyblock.core.key.Keys; import com.bgsoftware.superiorskyblock.core.key.types.MaterialKey; @@ -36,7 +35,7 @@ public class CropsTickingTileEntity extends TileEntity implements IUpdatePlayerL plugin.getPluginEventsDispatcher().registerCallback(PluginEventType.SETTINGS_UPDATE_EVENT, CropsTickingTileEntity::onSettingsUpdate); } - private static final Long2ObjectMapView tickingChunks = CollectionsFactory.createLong2ObjectHashMap(); + private static final Chunk2ObjectMap tickingChunks = new Chunk2ObjectMap<>(); private static int random = ThreadLocalRandom.current().nextInt(); private final WeakReference island; @@ -52,13 +51,13 @@ public static void register() { // Calls the static initializer which registers the callback. } - public static CropsTickingTileEntity remove(long chunkCoords) { - return tickingChunks.remove(chunkCoords); + public static CropsTickingTileEntity remove(String worldName, long chunkCoords) { + return tickingChunks.remove(worldName, chunkCoords); } - public static void create(Island island, Chunk chunk) { + public static void create(Island island, String worldName, Chunk chunk) { long chunkKey = ChunkCoordIntPair.a(chunk.locX, chunk.locZ); - tickingChunks.computeIfAbsent(chunkKey, i -> new CropsTickingTileEntity(island, chunk)); + tickingChunks.computeIfAbsent(worldName, chunkKey, () -> new CropsTickingTileEntity(island, chunk)); } public static void forEachChunk(List chunkPositions, Consumer cropsTickingTileEntityConsumer) { From fa673a1c5f7773001a1e5b5e43b446d218d48ad4 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 May 2026 12:36:58 +0300 Subject: [PATCH 571/600] Fix crop growth not working properly (#2763) --- NMS/src/main/templates/crops/CropsBlockEntity.java.template | 2 +- .../nms/v1_12_R1/chunks/CropsTickingTileEntity.java | 2 +- .../nms/v1_16_R3/crops/CropsTickingTileEntity.java | 2 +- .../nms/v1_8_R3/chunks/CropsTickingTileEntity.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NMS/src/main/templates/crops/CropsBlockEntity.java.template b/NMS/src/main/templates/crops/CropsBlockEntity.java.template index e3c55f216a..fd7fc352fa 100644 --- a/NMS/src/main/templates/crops/CropsBlockEntity.java.template +++ b/NMS/src/main/templates/crops/CropsBlockEntity.java.template @@ -58,7 +58,7 @@ public class CropsBlockEntity extends BlockEntity { chunkPositions.forEach(chunkPosition -> { long chunkKey = chunkPosition.asPair(); - CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkKey); + CropsBlockEntity cropsBlockEntity = tickingChunks.get(chunkPosition.getWorldName(), chunkKey); if (cropsBlockEntity != null) cropsBlockEntityConsumer.accept(cropsBlockEntity); }); diff --git a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java index 2334cc96e7..a1963ed786 100644 --- a/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java +++ b/NMS/v1_12_R1/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_12_R1/chunks/CropsTickingTileEntity.java @@ -68,7 +68,7 @@ public static void forEachChunk(List chunkPositions, Consumer { long chunkKey = chunkPosition.asPair(); - CropsTickingTileEntity cropsTickingTileEntity = tickingChunks.get(chunkKey); + CropsTickingTileEntity cropsTickingTileEntity = tickingChunks.get(chunkPosition.getWorldName(), chunkKey); if (cropsTickingTileEntity != null) cropsTickingTileEntityConsumer.accept(cropsTickingTileEntity); }); diff --git a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java index 7f53d71ecf..85734a65fe 100644 --- a/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java +++ b/NMS/v1_16_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_16_R3/crops/CropsTickingTileEntity.java @@ -63,7 +63,7 @@ public static void forEachChunk(List chunkPositions, Consumer { long chunkKey = chunkPosition.asPair(); - CropsTickingTileEntity cropsTickingTileEntity = tickingChunks.get(chunkKey); + CropsTickingTileEntity cropsTickingTileEntity = tickingChunks.get(chunkPosition.getWorldName(), chunkKey); if (cropsTickingTileEntity != null) cropsTickingTileEntityConsumer.accept(cropsTickingTileEntity); }); diff --git a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java index 3fd12429bf..25f3d5ccb7 100644 --- a/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java +++ b/NMS/v1_8_R3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_8_R3/chunks/CropsTickingTileEntity.java @@ -66,7 +66,7 @@ public static void forEachChunk(List chunkPositions, Consumer { long chunkKey = chunkPosition.asPair(); - CropsTickingTileEntity cropsTickingTileEntity = tickingChunks.get(chunkKey); + CropsTickingTileEntity cropsTickingTileEntity = tickingChunks.get(chunkPosition.getWorldName(), chunkKey); if (cropsTickingTileEntity != null) cropsTickingTileEntityConsumer.accept(cropsTickingTileEntity); }); From 8616fa1804fa5d45d1e9bfe9f9fc6f20d57ef190 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 May 2026 12:51:48 +0300 Subject: [PATCH 572/600] Do not call "startTickingChunk" every time a crop grows --- .../upgrades/type/UpgradeTypeCropGrowth.java | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java index 93045784af..2e7fa9e21a 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeCropGrowth.java @@ -26,7 +26,7 @@ public UpgradeTypeCropGrowth(SuperiorSkyblockPlugin plugin) { @Override public List getListeners() { - return Collections.singletonList(new CropGrowthListener()); + return Collections.emptyList(); } @Override @@ -34,19 +34,4 @@ public List getCommands() { return Arrays.asList(new CmdAdminAddCropGrowth(), new CmdAdminSetCropGrowth()); } - private class CropGrowthListener implements Listener { - - // Should potentially fix crop growth tile entities "disappearing" - @EventHandler(priority = EventPriority.LOWEST) - public void onBlockGrow(BlockGrowEvent e) { - try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { - Location blockLocation = e.getBlock().getLocation(wrapper.getHandle()); - Island island = plugin.getGrid().getIslandAt(blockLocation); - if (island != null && island.isInsideRange(blockLocation)) - plugin.getNMSChunks().startTickingChunk(island, e.getBlock().getChunk(), false); - } - } - - } - } From efbdfcea6b70c34ad3c00fc884bb9dcab891a447 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 8 May 2026 17:04:13 +0300 Subject: [PATCH 573/600] Fix custom sorting types not working with placeholders (#2888) --- .../placeholders/PlaceholdersServiceImpl.java | 26 +++++-------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index baeb22e04b..d57833e40b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -80,10 +80,7 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { private static final Pattern ROLE_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile("island_role_limit_(.+)"); private static final Pattern UPGRADE_PLACEHOLDER_PATTERN = Pattern.compile("island_upgrade_(.+)"); private static final Pattern TOP_PLACEHOLDER_PATTERN = Pattern.compile("island_top_(.+)"); - private static final Pattern TOP_WORTH_PLACEHOLDER_PATTERN = Pattern.compile("worth_(.+)"); - private static final Pattern TOP_LEVEL_PLACEHOLDER_PATTERN = Pattern.compile("level_(.+)"); - private static final Pattern TOP_RATING_PLACEHOLDER_PATTERN = Pattern.compile("rating_(.+)"); - private static final Pattern TOP_PLAYERS_PLACEHOLDER_PATTERN = Pattern.compile("players_(.+)"); + private static final Pattern TOP_TYPE_PLACEHOLDER_PATTERN = Pattern.compile("(.+)_(.+)"); private static final Pattern TOP_VALUE_FORMAT_PLACEHOLDER_PATTERN = Pattern.compile("value_format_(.+)"); private static final Pattern TOP_VALUE_RAW_PLACEHOLDER_PATTERN = Pattern.compile("value_raw_(.+)"); private static final Pattern TOP_VALUE_PLACEHOLDER_PATTERN = Pattern.compile("value_(.+)"); @@ -826,26 +823,15 @@ private static Optional handlePermissionRolesPlaceholder(@NotNull Island private static Optional handleTopIslandsPlaceholder(@Nullable Island island, @Nullable SuperiorPlayer superiorPlayer, String subPlaceholder) { - Matcher matcher; - SortingType sortingType; - - if ((matcher = TOP_WORTH_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { - sortingType = SortingTypes.BY_WORTH; - } else if ((matcher = TOP_LEVEL_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { - sortingType = SortingTypes.BY_LEVEL; - } else if ((matcher = TOP_RATING_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { - sortingType = SortingTypes.BY_RATING; - } else if ((matcher = TOP_PLAYERS_PLACEHOLDER_PATTERN.matcher(subPlaceholder)).matches()) { - sortingType = SortingTypes.BY_PLAYERS; - } else { - String sortingTypeName = subPlaceholder.split("_")[0]; - sortingType = SortingType.getByName(sortingTypeName); - } + Matcher matcher = TOP_TYPE_PLACEHOLDER_PATTERN.matcher(subPlaceholder); + if (!matcher.matches()) + return Optional.empty(); + SortingType sortingType = SortingType.getByName(matcher.group(1).toUpperCase(Locale.ENGLISH)); if (sortingType == null) return Optional.empty(); - String placeholderValue = matcher.group(1); + String placeholderValue = matcher.group(2); if (placeholderValue.equals("position")) return island == null ? Optional.empty() : Optional.of((plugin.getGrid().getIslandPosition(island, sortingType) + 1) + ""); From 6596172de51c89a98fd82afb9e503dc81eff8462 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 9 May 2026 19:29:33 +0300 Subject: [PATCH 574/600] Fixed the ability to bypass block limits by placing blocks in the off hand (#2796) --- .../module/upgrades/type/UpgradeTypeBlockLimits.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java index 3adf00408c..d4fde9018e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/module/upgrades/type/UpgradeTypeBlockLimits.java @@ -83,9 +83,6 @@ public void onPlayerRightClickBlock(PlayerInteractEvent e) { return; PlayerHand playerHand = BukkitItems.getHand(e); - if (playerHand != PlayerHand.MAIN_HAND) - return; - ItemStack handItem = BukkitItems.getHandItem(e.getPlayer(), playerHand); if (handItem == null) return; From 6837a41c541e273f57c5349a70e43a5b72baad73 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 9 May 2026 20:14:17 +0300 Subject: [PATCH 575/600] Fixed the plugin loads chunks infinitely in some cases in old versions --- .../service/world/WorldRecordServiceImpl.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java index e04e6da871..3dc0d0f2a4 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/world/WorldRecordServiceImpl.java @@ -23,6 +23,7 @@ import com.google.common.base.Preconditions; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; @@ -228,11 +229,14 @@ private void recordBlockBreakInternal(Island island, Key blockKey, Location bloc } } + World world = block.getWorld(); + int chunkX = block.getX() >> 4; + int chunkZ = block.getZ() >> 4; + BukkitExecutor.sync(() -> { - if (dirtyChunks) { + if (dirtyChunks && world.isChunkLoaded(chunkX, chunkZ)) { if (plugin.getNMSChunks().isChunkEmpty(block.getChunk())) { - island.markChunkEmpty(block.getWorld(), block.getX() >> 4, - block.getZ() >> 4, true); + island.markChunkEmpty(world, chunkX, chunkZ, true); } } if (handleNearbyBlocks) { From 3c0881824404c641e8d4065b89c0cf206bf88059 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 9 May 2026 21:07:33 +0300 Subject: [PATCH 576/600] Do not mark entities as despawned when chunks are unloaded as it breaks level recalculation when chunks are unloaded (#2922) --- .../bgsoftware/superiorskyblock/listener/ChunksListener.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java index fb9d7b5de5..8780a850ed 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/ChunksListener.java @@ -94,8 +94,6 @@ private void handleIslandChunkUnload(Island island, Chunk chunk) { if (!plugin.getNMSChunks().isChunkEmpty(chunk)) island.markChunkDirty(chunk.getWorld(), chunk.getX(), chunk.getZ(), true); - - Arrays.stream(chunk.getEntities()).forEach(this.worldRecordService.get()::recordEntityDespawn); } private void handleChunkLoad(Chunk chunk, boolean isNewChunk) { From 40d3ffcfb53d1ddb1ce6c536c708227d43181906 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 11 May 2026 23:16:40 +0300 Subject: [PATCH 577/600] Fixed detection of reached block is not always accurate when changing spawner types (#2796) --- .../java/com/bgsoftware/superiorskyblock/island/SIsland.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index f0f42245d1..1b6b8d1687 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -3204,7 +3204,7 @@ public boolean hasReachedBlockLimit(Key key, @Size int amount) { //Checking for the specific provided key. if (blockLimit >= 0) { - return getBlockCountAsBigInteger(key).add(BigInteger.valueOf(amount)) + return getExactBlockCountAsBigInteger(key).add(BigInteger.valueOf(amount)) .compareTo(BigInteger.valueOf(blockLimit)) > 0; } From eb4182859e1cae4714cb11fb62e40ba2e92b23ac Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Mon, 11 May 2026 23:35:10 +0300 Subject: [PATCH 578/600] Potential fix for "Duplicate key" errors in some cases (#2928) --- .../core/key/map/AbstractKeyMap.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java index cb21560c28..7661652c00 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java @@ -19,6 +19,7 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.function.BiFunction; import java.util.function.Predicate; public class AbstractKeyMap extends AbstractMap implements KeyMap { @@ -238,6 +239,20 @@ public V getOrDefault(Object key, V defaultValue) { return value == null ? defaultValue : value; } + @Override + public V merge(Key key, @NotNull V value, @NotNull BiFunction remappingFunction) { + Objects.requireNonNull(remappingFunction); + Objects.requireNonNull(value); + V oldValue = getRaw(key, null); + V newValue = (oldValue == null) ? value : remappingFunction.apply(oldValue, value); + if (newValue == null) { + remove(key); + } else { + put(key, newValue); + } + return newValue; + } + @Override public Map asMap() { return this; From 77b58b0659ea3fb0d99c9acb108393dafbfb46fa Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 16 May 2026 17:38:35 +0300 Subject: [PATCH 579/600] Do not apply teleport clear action if the world does not exist --- .../superiorskyblock/player/inventory/ClearActions.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java b/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java index 6e60bff589..d5c9b82814 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java @@ -7,6 +7,7 @@ import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; import org.bukkit.OfflinePlayer; +import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffect; @@ -102,7 +103,8 @@ public static void runClearActions(SuperiorPlayer superiorPlayer, Collection clearAction.doClear(onlinePlayer)); if (offlinePlayerData != null) { - if (islandToTeleport != null) + World world = plugin.getGrid().getIslandsWorld(islandToTeleport, plugin.getSettings().getWorlds().getDefaultWorldDimension()); + if (islandToTeleport != null && world != null) offlinePlayerData.setLocation(islandToTeleport.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension())); offlinePlayerData.applyChanges(); } else if (islandToTeleport != null) { From 5d11e03a51a86cdf365ce6f59277da4bf53f8c38 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 16 May 2026 17:42:53 +0300 Subject: [PATCH 580/600] Do not apply teleport clear action if the world does not exist --- .../superiorskyblock/player/inventory/ClearActions.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java b/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java index d5c9b82814..352d9ea1d2 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/player/inventory/ClearActions.java @@ -4,10 +4,11 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.island.Island; import com.bgsoftware.superiorskyblock.api.player.inventory.ClearAction; +import com.bgsoftware.superiorskyblock.api.world.WorldInfo; import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; import com.bgsoftware.superiorskyblock.nms.player.OfflinePlayerData; +import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; -import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffect; @@ -103,9 +104,9 @@ public static void runClearActions(SuperiorPlayer superiorPlayer, Collection clearAction.doClear(onlinePlayer)); if (offlinePlayerData != null) { - World world = plugin.getGrid().getIslandsWorld(islandToTeleport, plugin.getSettings().getWorlds().getDefaultWorldDimension()); - if (islandToTeleport != null && world != null) - offlinePlayerData.setLocation(islandToTeleport.getCenter(plugin.getSettings().getWorlds().getDefaultWorldDimension())); + WorldInfo worldInfo = plugin.getGrid().getIslandsWorldInfo(islandToTeleport, plugin.getSettings().getWorlds().getDefaultWorldDimension()); + if (islandToTeleport != null && worldInfo != null && Bukkit.getWorld(worldInfo.getName()) != null) + offlinePlayerData.setLocation(islandToTeleport.getCenter(worldInfo.getDimension())); offlinePlayerData.applyChanges(); } else if (islandToTeleport != null) { superiorPlayer.teleport(islandToTeleport); From 8defa85e82092fc53a1e9f7cf8f033ca6b21dd59 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 16 May 2026 21:06:01 +0300 Subject: [PATCH 581/600] Fixed errors when enabling dragon fights (#2931) --- NMS/src/main/templates/NMSDragonFightImpl.java.template | 3 ++- .../main/templates/dragon/IslandEndDragonFight.java.template | 2 +- .../nms/v1_17/dragon/EndDragonFightWrapper.java | 2 +- .../nms/v1_18/dragon/EndDragonFightWrapper.java | 2 +- .../nms/v1_19/dragon/EndDragonFightWrapper.java | 2 +- .../nms/v1_20_3/dragon/EndDragonFightWrapper.java | 2 +- .../nms/v1_20_4/dragon/EndDragonFightWrapper.java | 2 +- .../nms/v1_21/dragon/EndDragonFightWrapper.java | 2 +- .../nms/v1_21_10/dragon/EndDragonFightWrapper.java | 2 +- .../nms/v1_21_3/dragon/EndDragonFightWrapper.java | 2 +- .../nms/v1_21_4/dragon/EndDragonFightWrapper.java | 2 +- .../nms/v1_21_5/dragon/EndDragonFightWrapper.java | 2 +- .../nms/v1_21_7/dragon/EndDragonFightWrapper.java | 2 +- .../nms/v1_21_9/dragon/EndDragonFightWrapper.java | 2 +- .../nms/v26_1/dragon/EndDragonFightWrapper.java | 3 ++- 15 files changed, 17 insertions(+), 15 deletions(-) diff --git a/NMS/src/main/templates/NMSDragonFightImpl.java.template b/NMS/src/main/templates/NMSDragonFightImpl.java.template index 0ef7b2c597..d1cf666b3e 100644 --- a/NMS/src/main/templates/NMSDragonFightImpl.java.template +++ b/NMS/src/main/templates/NMSDragonFightImpl.java.template @@ -11,6 +11,7 @@ import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.IslandEntityEnd import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.dragon.SpikesCache; import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.utils.NMSUtilsVersioned; import com.google.common.cache.LoadingCache; +import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.boss.enderdragon.EnderDragon; @@ -49,7 +50,7 @@ public class NMSDragonFightImpl implements NMSDragonFight { @Override public void prepareEndWorld(World bukkitWorld) { ServerLevel serverLevel = ((CraftWorld) bukkitWorld).getHandle(); - WORLD_DRAGON_BATTLE.set(serverLevel, new EndDragonFightWrapper(serverLevel)); + WORLD_DRAGON_BATTLE.set(serverLevel, new EndDragonFightWrapper(serverLevel, BlockPos.ZERO)); if (firstWorldPreparation) { firstWorldPreparation = false; diff --git a/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template b/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template index d1499d015a..5cd799965e 100644 --- a/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template +++ b/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template @@ -76,7 +76,7 @@ public class IslandEndDragonFight extends EndDragonFightWrapper { public IslandEndDragonFight(Island island, ServerLevel serverLevel, BlockPos islandBlockPos, @Nullable IslandEntityEnderDragon islandEntityEnderDragon) { - super(serverLevel); + super(serverLevel, islandBlockPos); this.island = island; this.islandBlockPos = islandBlockPos; diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndDragonFightWrapper.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndDragonFightWrapper.java index 9a6a0d60f1..754e5f08ea 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndDragonFightWrapper.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/dragon/EndDragonFightWrapper.java @@ -9,7 +9,7 @@ public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos unused) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndDragonFightWrapper.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndDragonFightWrapper.java index 59afbcbe30..bcdec1c659 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndDragonFightWrapper.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/dragon/EndDragonFightWrapper.java @@ -9,7 +9,7 @@ public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos unused) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndDragonFightWrapper.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndDragonFightWrapper.java index 1ffe3aa974..7fd68e25a9 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndDragonFightWrapper.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/dragon/EndDragonFightWrapper.java @@ -9,7 +9,7 @@ public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos unused) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndDragonFightWrapper.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndDragonFightWrapper.java index 73cce416fa..fe0b75e089 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndDragonFightWrapper.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/dragon/EndDragonFightWrapper.java @@ -9,7 +9,7 @@ public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos unused) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndDragonFightWrapper.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndDragonFightWrapper.java index eb66afb754..82bf610e50 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndDragonFightWrapper.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/dragon/EndDragonFightWrapper.java @@ -9,7 +9,7 @@ public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos unused) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndDragonFightWrapper.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndDragonFightWrapper.java index d2d2316ba8..ae499ec758 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndDragonFightWrapper.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/dragon/EndDragonFightWrapper.java @@ -9,7 +9,7 @@ public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos unused) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/EndDragonFightWrapper.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/EndDragonFightWrapper.java index 8e18d50e0a..4e2c8ce58d 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/EndDragonFightWrapper.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/dragon/EndDragonFightWrapper.java @@ -9,7 +9,7 @@ public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos unused) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndDragonFightWrapper.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndDragonFightWrapper.java index 594004c520..cb320d6624 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndDragonFightWrapper.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/dragon/EndDragonFightWrapper.java @@ -9,7 +9,7 @@ public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos unused) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndDragonFightWrapper.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndDragonFightWrapper.java index 5704cc6170..5bbdb1b3ad 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndDragonFightWrapper.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/dragon/EndDragonFightWrapper.java @@ -9,7 +9,7 @@ public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos unused) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndDragonFightWrapper.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndDragonFightWrapper.java index 5c5a5fdcb9..2a418f8623 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndDragonFightWrapper.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/dragon/EndDragonFightWrapper.java @@ -9,7 +9,7 @@ public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos unused) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndDragonFightWrapper.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndDragonFightWrapper.java index 1bd33b4a61..b9ea1270d8 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndDragonFightWrapper.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/dragon/EndDragonFightWrapper.java @@ -9,7 +9,7 @@ public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos unused) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/EndDragonFightWrapper.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/EndDragonFightWrapper.java index e661634d40..d68f5c7475 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/EndDragonFightWrapper.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/dragon/EndDragonFightWrapper.java @@ -9,7 +9,7 @@ public class EndDragonFightWrapper extends EndDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos unused) { super(serverLevel, serverLevel.getSeed(), serverLevel.serverLevelData.endDragonFightData()); } diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/EndDragonFightWrapper.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/EndDragonFightWrapper.java index 3708ef0d5f..204b67ce3f 100644 --- a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/EndDragonFightWrapper.java +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/dragon/EndDragonFightWrapper.java @@ -13,8 +13,9 @@ public class EndDragonFightWrapper extends EnderDragonFight { public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); - public EndDragonFightWrapper(ServerLevel serverLevel) { + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos islandPos) { super(true, false, false, Optional.empty(), 0, Optional.empty(), Optional.empty(), new ObjectArrayList(), List.of()); + init(serverLevel, serverLevel.getSeed(), islandPos); } @Override From 8e2c68df39236d0914f8ebdfea994d798f6030ae Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 22 May 2026 19:22:18 +0300 Subject: [PATCH 582/600] Fixed errors when looking for safe blocks (#2937) --- .../bgsoftware/superiorskyblock/world/EntityTeleports.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java index 3bde5f9dc1..7bb63e282b 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/world/EntityTeleports.java @@ -195,14 +195,14 @@ private static void findSafeSpotInChunk(Island island, Queue isla Location closestSafeSpot = null; double closestSafeSpotDistance = 0; - int worldBuildLimit = islandsWorld.getMaxHeight() - 1; + int worldBuildLimit = islandsWorld.getMaxHeight(); int worldMinLimit = plugin.getNMSWorld().getMinHeight(islandsWorld); for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { int y = chunkSnapshot.getHighestBlockYAt(x, z); - if (y < worldMinLimit || y + 2 > worldBuildLimit) + if (y - 1 <= worldMinLimit || y + 1 >= worldBuildLimit) continue; int worldX = chunkSnapshot.getX() * 16 + x; From 41f81cec72e1509a2a9a859a0f5a7673d2bea415 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 22 May 2026 19:27:10 +0300 Subject: [PATCH 583/600] Delete gemini workflow --- .github/workflows/gemini.yml | 49 ------------------------------------ 1 file changed, 49 deletions(-) delete mode 100644 .github/workflows/gemini.yml diff --git a/.github/workflows/gemini.yml b/.github/workflows/gemini.yml deleted file mode 100644 index 012d4ce1a8..0000000000 --- a/.github/workflows/gemini.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Gemini Issue Fixer -on: - issues: - types: [opened, edited] - issue_comment: - types: [created] - -jobs: - gemini-fix: - if: contains(github.event.issue.labels.*.name, 'bug') || contains(github.event.comment.body, '@gemini') - runs-on: ubuntu-latest - permissions: - contents: write - pull-requests: write - issues: write - id-token: write - steps: - - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.10' - - name: Install Aider (The Agent Engine) - run: | - python -m pip install --upgrade pip - pip install aider-chat - - name: Run Gemini Fix - env: - GEMINI_API_KEY: ${{ secrets.GOOGLE_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git config --global user.name "Gemini AI" - git config --global user.email "gemini-ai@github.com" - - BRANCH_NAME="bugfix/issue-${{ github.event.issue.number }}" - git checkout -b "$BRANCH_NAME" - - aider --model gemini/gemini-3-flash-preview \ - --yes \ - --commit \ - --message "Analyze the following issue and provide a fix in a new branch with a PR. Make changes to the source code and commit the changes to the branch $$BRANCH_NAME. Title: ${{ github.event.issue.title }} Description: ${{ github.event.issue.body }}" - - git push origin "$BRANCH_NAME" - - gh pr create \ - --title "Fix: ${{ github.event.issue.title }}" \ - --body "Automated fix for #${{ github.event.issue.number }} generated by Gemini." \ - --base dev \ - --head "$BRANCH_NAME" \ No newline at end of file From 7b73288a222b5498e0976fe643bbf1a1e544a9ca Mon Sep 17 00:00:00 2001 From: Djoey Date: Sat, 23 May 2026 11:29:27 +0200 Subject: [PATCH 584/600] Fix top placeholder regex regression for value/leader/raw subkeys (#2935) --- .../service/placeholders/PlaceholdersServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index d57833e40b..fcc91f43c8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -80,7 +80,7 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { private static final Pattern ROLE_LIMIT_PLACEHOLDER_PATTERN = Pattern.compile("island_role_limit_(.+)"); private static final Pattern UPGRADE_PLACEHOLDER_PATTERN = Pattern.compile("island_upgrade_(.+)"); private static final Pattern TOP_PLACEHOLDER_PATTERN = Pattern.compile("island_top_(.+)"); - private static final Pattern TOP_TYPE_PLACEHOLDER_PATTERN = Pattern.compile("(.+)_(.+)"); + private static final Pattern TOP_TYPE_PLACEHOLDER_PATTERN = Pattern.compile("(.+?)_(.+)"); private static final Pattern TOP_VALUE_FORMAT_PLACEHOLDER_PATTERN = Pattern.compile("value_format_(.+)"); private static final Pattern TOP_VALUE_RAW_PLACEHOLDER_PATTERN = Pattern.compile("value_raw_(.+)"); private static final Pattern TOP_VALUE_PLACEHOLDER_PATTERN = Pattern.compile("value_(.+)"); From 24e309b41a3a1c418b49965cde5dae08eb1c7ea6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 23 May 2026 12:53:22 +0300 Subject: [PATCH 585/600] Fix delegate classes do not override hashCode or equals methods --- .../api/factory/DelegateBanksFactory.java | 9 +++++++++ .../api/factory/DelegateDatabaseBridgeFactory.java | 10 ++++++++++ .../api/factory/DelegateIslandsFactory.java | 10 ++++++++++ .../api/factory/DelegatePlayersFactory.java | 10 ++++++++++ .../superiorskyblock/api/island/DelegateIsland.java | 10 ++++++++++ .../api/island/DelegateIslandChest.java | 10 ++++++++++ .../api/island/DelegateIslandPreview.java | 10 ++++++++++ .../api/island/DelegatePermissionNode.java | 10 ++++++++++ .../DelegateIslandBlocksTrackerAlgorithm.java | 10 ++++++++++ .../algorithms/DelegateIslandCalculationAlgorithm.java | 10 ++++++++++ .../DelegateIslandEntitiesTrackerAlgorithm.java | 10 ++++++++++ .../api/island/bank/DelegateBankTransaction.java | 10 ++++++++++ .../api/island/bank/DelegateIslandBank.java | 10 ++++++++++ .../api/island/container/DelegateIslandsContainer.java | 10 ++++++++++ .../api/island/warps/DelegateIslandWarp.java | 10 ++++++++++ .../api/island/warps/DelegateWarpCategory.java | 10 ++++++++++ .../persistence/DelegatePersistentDataContainer.java | 9 +++++++++ .../api/player/DelegateSuperiorPlayer.java | 10 ++++++++++ .../algorithm/DelegatePlayerTeleportAlgorithm.java | 10 ++++++++++ .../api/player/container/DelegatePlayersContainer.java | 10 ++++++++++ .../algorithm/DelegateIslandCreationAlgorithm.java | 10 ++++++++++ 21 files changed, 208 insertions(+) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateBanksFactory.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateBanksFactory.java index 3bbc8a6ac4..be7b807b56 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateBanksFactory.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateBanksFactory.java @@ -16,4 +16,13 @@ public IslandBank createIslandBank(Island island, IslandBank original) { return this.handle.createIslandBank(island, original); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateDatabaseBridgeFactory.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateDatabaseBridgeFactory.java index bd011c9053..89a302f7bf 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateDatabaseBridgeFactory.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateDatabaseBridgeFactory.java @@ -35,4 +35,14 @@ public DatabaseBridge createStackedBlocksDatabaseBridge(@Nullable StackedBlocksM return this.handle.createStackedBlocksDatabaseBridge(stackedBlocksManager, original); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateIslandsFactory.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateIslandsFactory.java index 8b91549d3d..5b902c7d8d 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateIslandsFactory.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegateIslandsFactory.java @@ -57,4 +57,14 @@ public PersistentDataContainer createPersistentDataContainer(Island island, Pers return this.handle.createPersistentDataContainer(island, original); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegatePlayersFactory.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegatePlayersFactory.java index 97520d6513..5bbbb55b55 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegatePlayersFactory.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/factory/DelegatePlayersFactory.java @@ -33,4 +33,14 @@ public PersistentDataContainer createPersistentDataContainer(SuperiorPlayer supe return this.handle.createPersistentDataContainer(superiorPlayer, original); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java index de1c75ef60..f27ee081bc 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIsland.java @@ -1940,6 +1940,16 @@ public void setChestRows(int index, int rows) { this.handle.setChestRows(index, rows); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + @Override public int compareTo(Island o) { return this.handle.compareTo(o); diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandChest.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandChest.java index be307cb4c7..a626e830f1 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandChest.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandChest.java @@ -47,4 +47,14 @@ public Inventory getInventory() { return this.handle.getInventory(); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java index 13daf669ae..2bdffab993 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegateIslandPreview.java @@ -57,4 +57,14 @@ public void handleEscape() { this.handle.handleEscape(); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegatePermissionNode.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegatePermissionNode.java index 568a6f4baa..899b06d9e8 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegatePermissionNode.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/DelegatePermissionNode.java @@ -25,4 +25,14 @@ public Map getCustomPermissions() { return this.handle.getCustomPermissions(); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandBlocksTrackerAlgorithm.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandBlocksTrackerAlgorithm.java index 749b7dd8b7..ecbd7c631e 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandBlocksTrackerAlgorithm.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandBlocksTrackerAlgorithm.java @@ -48,4 +48,14 @@ public void setLoadingDataMode(boolean loadingDataMode) { this.handle.setLoadingDataMode(loadingDataMode); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandCalculationAlgorithm.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandCalculationAlgorithm.java index e7d8cf56d0..c9d316fb66 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandCalculationAlgorithm.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandCalculationAlgorithm.java @@ -23,4 +23,14 @@ public CompletableFuture calculateIsland(Island island) return this.handle.calculateIsland(island); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandEntitiesTrackerAlgorithm.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandEntitiesTrackerAlgorithm.java index a43e31e0c5..23fb17beca 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandEntitiesTrackerAlgorithm.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/algorithms/DelegateIslandEntitiesTrackerAlgorithm.java @@ -47,4 +47,14 @@ public boolean canRecalculateEntityCounts() { return this.handle.canRecalculateEntityCounts(); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/DelegateBankTransaction.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/DelegateBankTransaction.java index 784073cf83..03b825b746 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/DelegateBankTransaction.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/DelegateBankTransaction.java @@ -50,4 +50,14 @@ public BigDecimal getAmount() { return this.handle.getAmount(); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/DelegateIslandBank.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/DelegateIslandBank.java index 003bbd7433..e5ca6b498f 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/DelegateIslandBank.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/bank/DelegateIslandBank.java @@ -70,4 +70,14 @@ public void loadTransaction(BankTransaction bankTransaction) { this.handle.loadTransaction(bankTransaction); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/DelegateIslandsContainer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/DelegateIslandsContainer.java index b7137f7d4c..a7dd4079c8 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/DelegateIslandsContainer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/container/DelegateIslandsContainer.java @@ -107,4 +107,14 @@ public void addSortingType(SortingType sortingType, boolean sort) { this.handle.addSortingType(sortingType, sort); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java index a541558d8c..1297bc08a1 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateIslandWarp.java @@ -93,4 +93,14 @@ public WarpCategory getCategory() { return this.handle.getCategory(); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateWarpCategory.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateWarpCategory.java index 02d46babf5..e4409ec084 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateWarpCategory.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/island/warps/DelegateWarpCategory.java @@ -60,4 +60,14 @@ public void setIcon(@Nullable ItemStack icon) { this.handle.setIcon(icon); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/DelegatePersistentDataContainer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/DelegatePersistentDataContainer.java index 92b92bffb0..339f00a0f0 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/DelegatePersistentDataContainer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/persistence/DelegatePersistentDataContainer.java @@ -93,4 +93,13 @@ public void load(byte[] data) throws IllegalArgumentException { this.handle.load(data); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java index e3a1248894..49b36418b9 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/DelegateSuperiorPlayer.java @@ -585,4 +585,14 @@ public void savePersistentDataContainer() { this.handle.savePersistentDataContainer(); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/DelegatePlayerTeleportAlgorithm.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/DelegatePlayerTeleportAlgorithm.java index 83485c7fd3..a59c06b9d7 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/DelegatePlayerTeleportAlgorithm.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/algorithm/DelegatePlayerTeleportAlgorithm.java @@ -30,4 +30,14 @@ public CompletableFuture teleport(Player player, Island island, Dimensi return this.handle.teleport(player, island, dimension); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/container/DelegatePlayersContainer.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/container/DelegatePlayersContainer.java index 41b58934e0..6be2abaee3 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/container/DelegatePlayersContainer.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/player/container/DelegatePlayersContainer.java @@ -41,4 +41,14 @@ public void removePlayer(SuperiorPlayer superiorPlayer) { this.handle.removePlayer(superiorPlayer); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/world/algorithm/DelegateIslandCreationAlgorithm.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/world/algorithm/DelegateIslandCreationAlgorithm.java index 5342ad21d0..de78554f90 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/world/algorithm/DelegateIslandCreationAlgorithm.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/world/algorithm/DelegateIslandCreationAlgorithm.java @@ -29,4 +29,14 @@ public CompletableFuture createIsland(Island.Builder build return this.handle.createIsland(builder, lastIsland); } + @Override + public int hashCode() { + return this.handle.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.handle.equals(o); + } + } From c3e4994fd4c454e3c7d9f580bca9d6ba01371b68 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 24 May 2026 19:40:47 +0300 Subject: [PATCH 586/600] Fix plugin not working on Windows (#2940) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 262037f357..f31e003881 100644 --- a/build.gradle +++ b/build.gradle @@ -67,7 +67,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b20' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b21' implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b2' implementation 'org.bstats:bstats-bukkit:3.0.0' From 59f8b92b772f6766bdf45637c696051fc404ac82 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 24 May 2026 20:32:14 +0300 Subject: [PATCH 587/600] Fixed biomes can be null in config file, causing errors when creating islands (#2938) --- .../core/menu/MenuConfig.java | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java index 7054d87613..a2b933d6fa 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/menu/MenuConfig.java @@ -4,14 +4,17 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.menu.MenuIslandCreationConfig; import com.bgsoftware.superiorskyblock.api.schematic.Schematic; +import com.bgsoftware.superiorskyblock.api.world.Dimension; import com.bgsoftware.superiorskyblock.api.world.GameSound; import com.bgsoftware.superiorskyblock.api.wrappers.BlockOffset; import com.bgsoftware.superiorskyblock.core.menu.button.impl.IslandCreationButton; +import com.bgsoftware.superiorskyblock.island.IslandUtils; import org.bukkit.block.Biome; import java.math.BigDecimal; import java.util.Collection; import java.util.Collections; +import java.util.Objects; public class MenuConfig { @@ -35,9 +38,7 @@ public IslandCreation(IslandCreationButton.Template template) { public IslandCreation(Schematic schematic, IslandCreationButton.Template template) { this.schematic = schematic; this.template = template; - Biome biome = template == null ? null : template.getBiome(); - this.biome = biome == null ? plugin.getNMSAlgorithms().getBiome(plugin.getSettings().getWorlds().getDimensionConfig( - plugin.getSettings().getWorlds().getDefaultWorldDimension()).getBiome()) : biome; + this.biome = Objects.requireNonNull(getBiomeInternal(template)); } @Override @@ -79,6 +80,25 @@ public BigDecimal getBonusLevel() { public Biome getBiome() { return this.biome; } + + private static Biome getBiomeInternal(@Nullable IslandCreationButton.Template template) { + if (template != null) { + Biome biome = template.getBiome(); + if (biome != null) + return biome; + } + + Dimension defaultDimension = plugin.getSettings().getWorlds().getDefaultWorldDimension(); + + Biome biome = plugin.getNMSAlgorithms().getBiome(plugin.getSettings().getWorlds() + .getDimensionConfig(defaultDimension).getBiome()); + + if (biome != null) + return biome; + + return IslandUtils.getDefaultWorldBiome(defaultDimension); + } + } } From 1f2bd63516b59d5a72c170701f3acbc37eca1bce Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 7 Jun 2026 23:21:11 +0300 Subject: [PATCH 588/600] Do not parse placeholders for message arguments (#2946) --- .../core/messages/MessageContent.java | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java index b0de09ee13..69ec154138 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/messages/MessageContent.java @@ -4,6 +4,7 @@ import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; import com.bgsoftware.superiorskyblock.api.service.placeholders.PlaceholdersService; import com.bgsoftware.superiorskyblock.core.LazyReference; +import com.bgsoftware.superiorskyblock.core.Text; import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import org.bukkit.OfflinePlayer; @@ -82,7 +83,11 @@ public Optional getContent(@Nullable OfflinePlayer offlinePlayer, Object StringBuilder content = new StringBuilder(); for (IPart part : contentParts) { if (part instanceof StaticPart) { - content.append(((StaticPart) part).content); + String partContent = ((StaticPart) part).content; + if (((StaticPart) part).parsePlaceholders) { + partContent = placeholdersService.get().parsePlaceholders(offlinePlayer, partContent); + } + content.append(partContent); } else { int argumentIndex = ((ArgumentPart) part).argumentIndex; if (argumentIndex >= 0 && argumentIndex < arguments.length) { @@ -96,7 +101,7 @@ public Optional getContent(@Nullable OfflinePlayer offlinePlayer, Object if (content.length() == 0) return Optional.empty(); - return Optional.of(placeholdersService.get().parsePlaceholders(offlinePlayer, content.toString())); + return Optional.of(content.toString()); } public static String getArgumentString(Object argument) { @@ -112,9 +117,31 @@ private interface IPart { private static class StaticPart implements IPart { private final String content; + private boolean parsePlaceholders; StaticPart(String content) { this.content = content; + this.parsePlaceholders = checkForPlaceholders(content); + } + + private static boolean checkForPlaceholders(String value) { + if (Text.isBlank(value)) + return false; + + int openBracket = value.indexOf('{'); + if (openBracket >= 0) { + // Open bracket was found, let's find close bracket + int closeBracket = value.indexOf('}', openBracket); + if (closeBracket >= 0) + return true; + } + + // Look for two % + int firstPercentage = value.indexOf('%'); + if (firstPercentage < 0) + return false; + + return value.indexOf('%', firstPercentage) >= 0; } } From 64a8746d571b0d0d36db17f28448283b2b565252 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 7 Jun 2026 23:52:04 +0300 Subject: [PATCH 589/600] Warning about using deprecated placeholders (#2945) --- .../placeholders/PlaceholdersServiceImpl.java | 54 +++++++++++++++---- 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java index fcc91f43c8..0e02c63b84 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/service/placeholders/PlaceholdersServiceImpl.java @@ -21,6 +21,7 @@ import com.bgsoftware.superiorskyblock.core.formatting.Formatters; import com.bgsoftware.superiorskyblock.core.key.ConstantKeys; import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.logging.Log; import com.bgsoftware.superiorskyblock.core.values.BlockValue; import com.bgsoftware.superiorskyblock.external.placeholders.PlaceholdersProvider; import com.bgsoftware.superiorskyblock.island.IslandUtils; @@ -401,15 +402,21 @@ public class PlaceholdersServiceImpl implements PlaceholdersService, IService { island.getWorth().toBigInteger().toString()) .put("worth_raw", (island, superiorPlayer) -> island.getWorth().toString()) - // Renamed Island Placeholders - .put("hoppers_limit", (island, superiorPlayer) -> - island.getBlockLimit(ConstantKeys.HOPPER) + "") - .put("x", (island, superiorPlayer) -> - island.getCenterPosition().getX() + "") - .put("y", (island, superiorPlayer) -> - island.getCenterPosition().getY() + "") - .put("z", (island, superiorPlayer) -> - island.getCenterPosition().getZ() + "") + // Deprecated Island Placeholders + .put("end_unlocked", legacyPlaceholder("superior_island_end_unlocked", "superior_island_world_unlocked_the_end", (island, superiorPlayer) -> + Formatters.BOOLEAN_FORMATTER.format(island.isEndEnabled(), superiorPlayer.getUserLocale()))) + .put("nether_unlocked", legacyPlaceholder("superior_island_nether_unlocked", "superior_island_world_unlocked_nether", (island, superiorPlayer) -> + Formatters.BOOLEAN_FORMATTER.format(island.isNetherEnabled(), superiorPlayer.getUserLocale()))) + .put("normal_unlocked", legacyPlaceholder("superior_island_normal_unlocked", "superior_island_world_unlocked_normal", (island, superiorPlayer) -> + Formatters.BOOLEAN_FORMATTER.format(island.isNormalEnabled(), superiorPlayer.getUserLocale()))) + .put("hoppers_limit", legacyPlaceholder("superior_island_hoppers_limit", "superior_island_block_limit_hopper", (island, superiorPlayer) -> + island.getBlockLimit(ConstantKeys.HOPPER) + "")) + .put("x", legacyPlaceholder("superior_island_x", "superior_island_center_x", (island, superiorPlayer) -> + island.getCenterPosition().getX() + "")) + .put("y", legacyPlaceholder("superior_island_y", "superior_island_center_y", (island, superiorPlayer) -> + island.getCenterPosition().getY() + "")) + .put("z", legacyPlaceholder("superior_island_z", "superior_island_center_z", (island, superiorPlayer) -> + island.getCenterPosition().getZ() + "")) // Global Placeholders .put("total_count", (island, superiorPlayer) -> Formatters.NUMBER_FORMATTER.format(plugin.getGrid().getIslands().size())) @@ -881,4 +888,33 @@ private static Dimension getDefaultWorldDimension() { return plugin.getSettings().getWorlds().getDefaultWorldDimension(); } + private static IslandPlaceholderParser legacyPlaceholder(String placeholder, String correctPlaceholder, IslandPlaceholderParser placeholderParser) { + return new LegacyIslandPlaceholderParser(placeholder, correctPlaceholder, placeholderParser); + } + + private static class LegacyIslandPlaceholderParser implements IslandPlaceholderParser { + + private final String placeholder; + private final String correctPlaceholder; + private final IslandPlaceholderParser originalPlaceholderParser; + private boolean promptDeprecated = true; + + LegacyIslandPlaceholderParser(String placeholder, String correctPlaceholder, IslandPlaceholderParser originalPlaceholderParser) { + this.placeholder = placeholder; + this.correctPlaceholder = correctPlaceholder; + this.originalPlaceholderParser = originalPlaceholderParser; + } + + @Override + public String apply(Island island, SuperiorPlayer superiorPlayer) { + if (this.promptDeprecated) { + this.promptDeprecated = false; + Log.error(new Throwable(), "Deprecated placeholder was used: " + this.placeholder + ". Use this one instead: " + this.correctPlaceholder); + } + + return this.originalPlaceholderParser.apply(island, superiorPlayer); + } + + } + } From 9fd49c172828f3afc907309436846ba420e7cb8c Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 12 Jun 2026 19:32:16 +0300 Subject: [PATCH 590/600] Fixed getIslandWhereStanding returning the wrong target player (#2949) --- .../commands/arguments/CommandArguments.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java index 6e540af2e8..a1083d5fc8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/commands/arguments/CommandArguments.java @@ -120,12 +120,18 @@ public static IslandArgument getIslandWhereStanding(SuperiorSkyblockPlugin plugi return IslandArgument.EMPTY; } - SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); + SuperiorPlayer superiorPlayer; Island island; try (ObjectsPools.Wrapper wrapper = ObjectsPools.LOCATION.obtain()) { Island locationIsland = plugin.getGrid().getIslandAt(((Player) sender).getLocation(wrapper.getHandle())); - island = locationIsland == null || locationIsland.isSpawn() ? superiorPlayer.getIsland() : locationIsland; + if (locationIsland == null || locationIsland.isSpawn()) { + superiorPlayer = plugin.getPlayers().getSuperiorPlayer(sender); + island = superiorPlayer.getIsland(); + } else { + island = locationIsland; + superiorPlayer = island.getOwner(); + } } if (island == null) From d8056a3ba8dc68acf0b28a3e00770430929b95fb Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 13 Jun 2026 16:56:23 +0300 Subject: [PATCH 591/600] Fix IllegalStateException in some cases when running /is admin show (#2928) --- .../core/key/map/LazyLoadedKeyMap.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/LazyLoadedKeyMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/LazyLoadedKeyMap.java index 8257f98754..5ecc3a1a27 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/LazyLoadedKeyMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/LazyLoadedKeyMap.java @@ -11,7 +11,9 @@ import java.util.AbstractMap; import java.util.Collections; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -120,6 +122,20 @@ public V getOrDefault(Object key, V defaultValue) { return runOnMap(m -> m.getOrDefault(key, defaultValue), defaultValue); } + @Override + public V merge(Key key, @NotNull V value, @NotNull BiFunction remappingFunction) { + Objects.requireNonNull(remappingFunction); + Objects.requireNonNull(value); + V oldValue = getRaw(key, null); + V newValue = (oldValue == null) ? value : remappingFunction.apply(oldValue, value); + if (newValue == null) { + remove(key); + } else { + put(key, newValue); + } + return newValue; + } + @Override public Map asMap() { return runOnMap(KeyMap::asMap, this); From 5cfe9e134e46bf852e11350cdfdd774c490b77bd Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 13 Jun 2026 17:40:43 +0300 Subject: [PATCH 592/600] Fix syncupgrades command leaves some limits as "-2" (#2928) --- .../core/key/map/AbstractKeyMap.java | 1 + .../superiorskyblock/island/SIsland.java | 25 ++++++++----------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java index 7661652c00..e333b5c32e 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/key/map/AbstractKeyMap.java @@ -351,6 +351,7 @@ public Entry next() { @Override public void remove() { this.currIterator.remove(); + --AbstractKeyMap.this.size; } } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java index 1b6b8d1687..d38bcf33c8 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/island/SIsland.java @@ -5032,32 +5032,23 @@ private void clearUpgrades(boolean overrideCustom) { return bankLimit; }); - blockLimits.entrySet().stream() - .filter(entry -> overrideCustom || entry.getValue().isSynced()) - .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE))); + clearSyncedMapEntries(blockLimits, overrideCustom); - entityLimits.entrySet().stream() - .filter(entry -> overrideCustom || entry.getValue().isSynced()) - .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE))); + clearSyncedMapEntries(entityLimits, overrideCustom); cobbleGeneratorValues.write(cobbleGeneratorValues -> { - cobbleGeneratorValues.values().forEach(cobbleGeneratorValue -> { - cobbleGeneratorValue.entrySet().stream() - .filter(entry -> overrideCustom || entry.getValue().isSynced()) - .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE))); - }); + cobbleGeneratorValues.values().forEach(cobbleGeneratorValue -> + clearSyncedMapEntries(cobbleGeneratorValue, overrideCustom)); }); - islandEffects.entrySet().stream() - .filter(entry -> overrideCustom || entry.getValue().isSynced()) - .forEach(entry -> entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE))); + clearSyncedMapEntries(islandEffects, overrideCustom); roleLimits.write(roleLimits -> { Iterator> iterator = roleLimits.entryIterator(); while (iterator.hasNext()) { Int2ObjectMapView.Entry entry = iterator.next(); if (overrideCustom || entry.getValue().isSynced()) - entry.setValue(IntValue.syncedFixed(IslandUpgradeConstants.SYNCED_VALUE)); + iterator.remove(); } }); @@ -5065,6 +5056,10 @@ private void clearUpgrades(boolean overrideCustom) { IslandsDatabaseBridge.clearIslandSettings(this); } + private static void clearSyncedMapEntries(Map map, boolean overrideCustom) { + map.entrySet().removeIf(entry -> overrideCustom || entry.getValue().isSynced()); + } + private void syncUpgrade(SUpgradeLevel upgradeLevel, boolean overrideCustom) { if (upgradeLevel.hasCropGrowth()) { cropGrowth.set(cropGrowth -> { From e1c643e53d3c52bb6fb7ae97104863b7dc4e714e Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 13 Jun 2026 18:46:54 +0300 Subject: [PATCH 593/600] [CI SKIP] Add CLAUDE.md --- .gitignore | 3 +- CLAUDE.md | 320 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 322 insertions(+), 1 deletion(-) create mode 100644 CLAUDE.md diff --git a/.gitignore b/.gitignore index dccb93145f..93889b2444 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ build # Ignore output generated files target -out \ No newline at end of file +out +graphify-out/ \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..cf30f15fe5 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,320 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Build Commands + +**Build the entire project:** +```bash +gradle build +``` +This compiles all modules (API, NMS versions, Hooks, Missions) and creates fat JARs with shadow JAR plugin. Artifacts are placed in `/target`. + +**Build API only:** +```bash +gradle :API:build +``` + +**Build without debug checks:** +```bash +gradle build -x checkDebug +``` + +**Clean build artifacts:** +```bash +gradle clean +``` + +Note: The gradlew wrapper (gradle-wrapper.properties) specifies Gradle 9.4.1. The project uses Java 8 as baseline, with support up to Java 21 for newer NMS versions. + +## Code Quality + +**Debug check (automatic on build):** +The `checkDebug` task scans for `Bukkit.broadcastMessage` debug statements and fails the build if found. This is part of the standard build process. To bypass (not recommended): `gradle build -x checkDebug`. + +**No automated linting:** The project has no static analysis configured (no spotbugs, checkstyle, etc.). Code review and manual inspection are the primary quality gates. + +## Testing + +**No test suite:** This codebase has no automated tests. Validation is manual and would require a running Spigot/Paper server. + +## High-Level Architecture + +SuperiorSkyblock2 is a Bukkit/Spigot/Paper plugin providing a complete Skyblock gamemode implementation. The codebase uses a **Manager pattern** with a clean API/implementation separation. + +### Core Plugin Entry Point + +`SuperiorSkyblockPlugin` (extends `JavaPlugin`, implements `SuperiorSkyblock` interface) initializes and orchestrates all systems: +- Loads configuration, database, NMS handlers +- Initializes managers for grids, players, islands, roles, upgrades, missions +- Registers event listeners and commands +- Bootstraps the module system and services + +### Manager System + +All major systems extend `Manager` (abstract base with `loadData()` contract): + +- **GridManager**: Island creation, placement, and global island tracking. Uses `IslandBuilderImpl` (builder pattern) to construct islands with all dependencies. +- **PlayersManager**: Maps Bukkit Players to `SuperiorPlayer` wrappers. Handles offline players and NPC support via metadata checking. +- **RolesManager**: Defines island member roles and their permission hierarchies. +- **UpgradesManager**: Manages upgradeable island properties (size, team limits, bank limits, etc.) with level-based costing. +- **MissionsManager**: Tracks island missions and mission holders. Integrated with mission modules. +- **SchematicManager**: Loads island schematics from YAML files for initial island generation. +- **BlockValuesManager**: Maintains block worth calculations for island level scoring. +- **ModulesManager**: Dynamically loads and manages plugin modules (builtin: Generators, Missions, Bank, Upgrades; external: custom JAR modules). + +Each manager owns a **Container** (IslandsContainer, PlayersContainer, etc.) that stores and retrieves cached objects, with database bridges handling persistence. + +### Island System + +`Island` objects represent player islands and are the central domain model: +- **Island hierarchy**: Owner, members (with roles and privileges), co-op players +- **Island properties**: Upgrades, flags, warps, bank (money storage), settings, ratings +- **Island data**: Block counts (cached), world locations, schematics, permissions +- **Island operations**: Invite/kick, promote/demote, disband, recalculate worth + +Related packages: +- `island.builder`: `IslandBuilderImpl` - fluent island construction from database/scratch +- `island.privilege`: Permission nodes and role-based privilege checking +- `island.flag`: Toggleable island behavior flags +- `island.upgrade`: Upgrade leveling system with costs and effects +- `island.cache`: Caches block counts, levels, worth to avoid recalculation +- `island.chunk`: Island chunk ownership tracking +- `island.warp`: Island warp management +- `island.bank`: Island money storage with transactions + +### Player System + +`SuperiorPlayer` wrappers (subclass `SSuperiorPlayer`) wrap Bukkit Players and offline data: +- Permission checks for island actions +- Personal statistics and missions +- Island membership state +- Chat and respawn preferences + +Players use builders (`SuperiorPlayerBuilderImpl`) for construction. NPC players handled separately via `SuperiorNPCPlayer` for compatibility with NPC plugins. + +### Database Abstraction + +`DatabaseBridge` interface abstracts persistence: +- **Modes**: Read-only, read-write, write-only (specified per database instance) +- **Operations**: `insertObject()`, `updateObject()`, `deleteObject()`, `getObject()` +- **Bridges**: Dedicated bridge classes (GridDatabaseBridge, IslandsDatabaseBridge, PlayersDatabaseBridge) handle specific entity persistence +- **SQL implementation**: `SQLDatabaseBridge` backed by HikariCP connection pooling + +ObjectPools (ObjectsPools) provide pooled reuse of DBColumn and Batch objects for allocation efficiency. + +### NMS (Native Minecraft Server) Abstraction + +Supports 18 Minecraft versions (v1_8_R3 through v26_2, including Paper variants): + +- **Strategy**: Each version gets its own Gradle subproject under `/NMS/v*/` +- **Code generation**: Templates in `/NMS/src/main/templates/` are processed with version-specific properties to generate implementation classes (AbstractNMSAlgorithms, AbstractNMSChunks, etc.) +- **Version registration**: NMSLoader (external common library) dynamically selects correct NMS handler at runtime based on server version +- **NMS facades** (in `/src/main/java/com/bgsoftware/superiorskyblock/nms/`): + - NMSAlgorithms, NMSChunks, NMSEntities, NMSWorld, NMSPlayers, NMSTags, NMSHolograms, NMSDragonFight + - These route to version-specific implementations and hide Minecraft internals + +Version-specific modules use PaperWeight (for 1.17+) or Spigot mappings for compilation. Conditional compilation controlled via `gradle.properties` (e.g., `nms.compile_v1_21=true`). + +### NMS Template System + +Shared NMS code is written once as `.template` files and stamped into each version's source tree at build time, avoiding copy-paste across 18+ versions. + +**How it works:** + +1. **Templates** (`NMS/src/main/templates/**/*.template`): Java source files with `${KEY}` placeholders for anything that differs between Minecraft versions — package names, class paths, method signatures, etc. +2. **Properties files** (`NMS//properties`): Each NMS subproject contains a plain-text `properties` file with key=value pairs that fill in the placeholders for that version. +3. **`generateNmsSources` task** (`NMS/build.gradle`): Defined on every NMS subproject. At build time it: + - Reads the subproject's `properties` file + - Iterates all `*.template` files under `NMS/src/main/templates/` + - Replaces every `${KEY}` occurrence with the matching value + - Writes the result to `$buildDir/generated/sources/nms/` (stripping the `.template` extension, preserving directory structure) +4. **Source set wiring**: Generated sources are added to the `main` Java source set alongside hand-written sources in `src/main/java/`. `compileJava` depends on `generateNmsSources`, so generation always runs first. + +**Common template variables** (defined per version in `properties`): +- `NMS_VERSION` — version identifier used in package names (e.g. `v1_21_7`) +- `CRAFTBUKKIT_PACKAGE` — CraftBukkit package, versioned pre-1.20.5, unversioned after +- `COMMON_NMS_PACKAGE` — base NMS package shared by a version family (e.g. `v1_20_3` code reused by `v1_21_7`) +- `REGISTRY_CLASS`, `CHUNK_STATUS_CLASS`, `SERVER_LEVEL_RANDOM_TYPE` — NMS class paths that moved between versions +- `ABSTRACT_MINECART_SUBPACKAGE`, `STAR_LIGHT_INTERFACE_CLASS`, etc. — other version-specific class references + +**When to edit:** +- To fix a bug that affects all NMS versions: edit the `.template` file. +- To fix a bug that is version-specific: edit the hand-written source in that subproject's `src/main/java/`, and if it should propagate, add a new placeholder + property entry. +- To add a new NMS version: create a new subproject directory with a `properties` file, a `build.gradle`, and a `src/main/java/` for any hand-written overrides. + +### External Integrations (Hooks) + +40+ optional plugin hooks in `/Hooks` use a **provider pattern**: +- Each hook detects the target plugin's presence at runtime +- Implements a provider interface (e.g., EconomyProvider for Vault) +- ProvidersManager dynamically loads compatible providers +- Seamless fallback if plugin is absent + +Examples: PlaceholderAPI, Vault economy, LuckPerms permissions, WorldEdit, Slimefun, various spawner plugins. + +### Module System + +**Builtin modules** (loaded automatically): +- **Generators**: Custom block generators (e.g., cobblestone with custom rates) +- **Missions**: Repeatable island challenges with rewards +- **Bank**: Island-wide money storage separate from player accounts +- **Upgrades**: Island stat upgrades with leveling + +External modules can be placed in `/plugins/SuperiorSkyblock2/modules/` as JAR files. ModulesManager dynamically loads and registers them via reflection. + +### Service Layer + +ServicesHandler registers and retrieves internal services that other components depend on: +- PlaceholdersService, HologramsService, DragonBattleService, BossBarsService +- MessagesService, PortalsService, RegionManagerService, StackedBlocksService, WorldRecordService + +Services implement `IService` interface and are registered with Bukkit's ServiceManager (ServicePriority.Normal). + +### Event System + +Custom plugin events (in `core.events.plugin.PluginEventsFactory`) abstract Bukkit/Paper events: +- PluginEventsDispatcher fires domain events (IslandJoinEvent, IslandUpgradeEvent, etc.) +- EventCallbacks allow plugins to hook into lifecycle events +- Platform abstraction: GameEventsDispatcher bridges to Bukkit events +- Event args passed through PluginEventArgs utility + +### Key Design Patterns Used + +1. **Manager**: Base Manager + concrete implementations (GridManagerImpl, PlayersManagerImpl, etc.) +2. **Builder**: IslandBuilder, PlayerBuilder, SchematicBuilder, ItemBuilder for complex object construction +3. **Factory**: DefaultIslandsFactory, DefaultPlayersFactory, etc. for object creation +4. **Strategy**: IslandCreationAlgorithm implementations for pluggable generation logic +5. **Bridge**: DatabaseBridge abstraction layer for persistence +6. **Template Method**: NMS abstract classes with template generation for version-specific code +7. **Container**: IslandsContainer, PlayersContainer for data storage and retrieval +8. **Service Locator**: ServicesHandler for central service registry +9. **Observer**: Custom event system with callback registrations +10. **Adapter**: Provider wrappers for external plugin integration (PlaceholderAPI, Vault, etc.) + +## Module Structure + +### Root Build + +`build.gradle` orchestrates subprojects: +- Configures shadow JAR relocation (BStats, common libraries) +- Defines collectArtifacts task (final JAR placement to `/target`) +- Includes subproject builds in shadowJar (NMS modules embedded in nms/ subdirectory, mission modules in modules/missions/) + +### API Module + +Published separately as `com.bgsoftware:SuperiorSkyblockAPI` to Maven repo (https://repo.bg-software.com/repository/api/). + +291 Java files defining: +- Core interfaces: SuperiorSkyblock, Island, SuperiorPlayer, GridManager, etc. +- Event types: 30+ plugin-specific events extending Bukkit events +- Data layer: DatabaseBridge, DatabaseFilter abstractions +- Handlers: Interface contracts for all managers +- Enums and domain objects + +**Backwards compatibility is mandatory.** Third-party plugins depend on this API, and breaking changes silently break those plugins at runtime. Rules: + +- **Never remove or rename** an existing API method, class, or enum constant. +- **Never change a method signature** (parameter types, parameter count, return type). +- **Never change observable behaviour** of an existing API method — if the semantics must change, add a new method instead. +- **Extend, don't replace**: add new methods alongside the old ones. Have the old method delegate to the new one so existing callers continue to work unchanged. +- **`@Deprecated` is not removal** — mark old methods `@Deprecated` when a better alternative exists, but keep them functional and delegating. + +Example pattern when behaviour needs to change: + +```java +// Old method — keep it, delegate to new +@Deprecated +Island getIsland(UUID uuid); + +// New method with improved/extended behaviour +Island getIsland(UUID uuid, boolean includeArchived); +``` + +**Prefer `Enumerable` classes over Java `enum` for extensible constants.** Java enums are sealed — third-party plugins cannot add new values. When a concept needs to be extendable through the API (new privileges, new flags, new types), use the Enumerable pattern instead. + +The pattern (`IslandPrivilege`, `IslandFlag`, etc.): +- The class implements `com.bgsoftware.superiorskyblock.api.objects.Enumerable` (provides `ordinal()` for efficient array-based lookups). +- A private static `Map` holds all registered instances; a private `static int ordinalCounter` assigns sequential ordinals. +- The constructor is **private** — callers cannot instantiate directly. +- A public static `register(String name, ...)` method creates and stores a new instance, enforcing uniqueness. +- Public static `values()` and `getByName(String)` mirror the standard enum API. + +```java +public class IslandPrivilege implements Enumerable { + private static final Map registry = new HashMap<>(); + private static int ordinalCounter = 0; + + private final String name; + private final int ordinal; + + private IslandPrivilege(String name) { + this.name = name.toUpperCase(Locale.ENGLISH); + this.ordinal = ordinalCounter++; + } + + @Override public int ordinal() { return ordinal; } + public String getName() { return name; } + + public static void register(String name) { + name = name.toUpperCase(Locale.ENGLISH); + Preconditions.checkState(!registry.containsKey(name), "Already registered: " + name); + registry.put(name, new IslandPrivilege(name)); + } + + public static IslandPrivilege getByName(String name) { /* lookup */ return registry.get(name.toUpperCase(Locale.ENGLISH)); } + public static Collection values() { return registry.values(); } +} +``` + +Use this pattern (not `enum`) whenever you add a new extensible constant type to the API. + +**Use `EnumerateMap` and `EnumerateSet` for collections keyed by `Enumerable` types.** Both classes live in `core.collections` and replace `HashMap`/`HashSet` when the key is an `Enumerable`. They back storage with a plain array indexed by `ordinal()`, giving O(1) get/contains with no hashing overhead. + +- `EnumerateMap` — array-backed map; `get(key)` reads `values[key.ordinal()]` directly. +- `EnumerateSet` — array-backed set backed by `boolean[]`; `contains(key)` reads `values[key.ordinal()]` directly. +- Both auto-expand their backing array when a newly registered `Enumerable` has a higher ordinal than the current capacity. +- Construct with the full `Collection` of known instances so the array is pre-sized correctly: `new EnumerateMap<>(IslandPrivilege.values())`. + +Use these instead of `HashMap`/`HashSet` anywhere the key is an `Enumerable` (privileges, flags, upgrades, dimensions, etc.). + +### Implementation (Main Plugin) + +798 Java files under `/src/main/java/com/bgsoftware/superiorskyblock/`: + +Key packages: +- `config/`: SettingsManagerImpl, configuration loaders, section-based config structure +- `core/`: Manager base, utilities (ObjectsPools, LazyReference, Counter, etc.), error handling +- `database/`: SQL bridge implementation, DBColumn, result mapping +- `island/`: Island implementation, builders, privilege system, upgrades, warps, cache +- `player/`: Player wrappers, permissions, respawn logic, inventory management +- `commands/`: Command system with admin/player command hierarchy +- `listener/`: Event listeners for Bukkit events +- `external/`: Provider implementations for external plugins +- `service/`: Internal service implementations +- `module/`: Module system and builtin module implementations +- `world/`: World generation, chunk management, schematics +- `nms/`: NMS facades routing to version-specific implementations + +## Important Configuration Notes + +- **gradle.properties**: Controls which NMS and hook modules compile. Set to `false` to skip expensive version compilations (e.g., `nms.compile_v1_21=false`). +- **plugin.yml**: Contains 50+ permission nodes for commands; API version 1.13+; soft dependencies on 25+ common plugins +- Database configuration: SQLite by default, but supports any JDBC database via config +- Block values: Loaded from YAML, updatable at runtime +- Schematics: Binary format stored in `/src/main/resources/schematics/` + +## Project Metadata + +- **Current version**: 2026.1 (active development) +- **License**: GNU GPL v3.0 +- **Author**: Ome_R (BG Software) +- **Project type**: Bukkit/Spigot/Paper plugin (Java) +- **Target audience**: Skyblock server administrators and developers + +## API Availability + +The plugin is designed as an API-first plugin. Other plugins should depend on `SuperiorSkyblockAPI` (not the implementation JAR) to avoid breaking changes. API methods are stable and documented; implementation changes occur without API modifications. + +Access the plugin instance via: `SuperiorSkyblockAPI.getSuperiorSkyblock()` after checking plugin availability. + From ac2692495a175d67fbaba2f707679b7c0bd36111 Mon Sep 17 00:00:00 2001 From: Ome_R Date: Sat, 13 Jun 2026 22:17:20 +0300 Subject: [PATCH 594/600] Fix getBiome registry lookup silently returning null on Paper 1.20.4 (#2943) --- .../nms/v1_19/NMSAlgorithmsImpl.java | 17 +++++++++++------ .../nms/v1_20_3/NMSAlgorithmsImpl.java | 17 +++++++++++------ .../nms/v1_20_4/NMSAlgorithmsImpl.java | 17 +++++++++++------ .../nms/v1_21/NMSAlgorithmsImpl.java | 17 +++++++++++------ .../nms/v1_21_10/NMSAlgorithmsImpl.java | 17 +++++++++++------ .../nms/v1_21_3/NMSAlgorithmsImpl.java | 17 +++++++++++------ .../nms/v1_21_4/NMSAlgorithmsImpl.java | 17 +++++++++++------ .../nms/v1_21_5/NMSAlgorithmsImpl.java | 17 +++++++++++------ .../nms/v1_21_7/NMSAlgorithmsImpl.java | 17 +++++++++++------ .../nms/v1_21_9/NMSAlgorithmsImpl.java | 17 +++++++++++------ .../nms/v26_1/NMSAlgorithmsImpl.java | 17 +++++++++++------ 11 files changed, 121 insertions(+), 66 deletions(-) diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java index cee04ee67d..482253eb7d 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSAlgorithmsImpl.java @@ -50,16 +50,21 @@ public double getCurrentTps() { @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); - if (key == null) { - return null; + if (key != null) { + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry != null) { + Biome biome = registry.get(key); + if (biome != null) { + return biome; + } + } } - Registry registry = Bukkit.getRegistry(Biome.class); - if (registry == null) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { return null; } - - return registry.get(key); } private static Enchantment initializeGlowEnchantment() { diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java index 330e424d55..a3296b7ae9 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSAlgorithmsImpl.java @@ -84,16 +84,21 @@ public double getCurrentTps() { @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); - if (key == null) { - return null; + if (key != null) { + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry != null) { + Biome biome = registry.get(key); + if (biome != null) { + return biome; + } + } } - Registry registry = Bukkit.getRegistry(Biome.class); - if (registry == null) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { return null; } - - return registry.get(key); } private static Enchantment initializeGlowEnchantment() { diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java index 4706f19432..e0a465aa09 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSAlgorithmsImpl.java @@ -78,16 +78,21 @@ public double getCurrentTps() { @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); - if (key == null) { - return null; + if (key != null) { + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry != null) { + Biome biome = registry.get(key); + if (biome != null) { + return biome; + } + } } - Registry registry = Bukkit.getRegistry(Biome.class); - if (registry == null) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { return null; } - - return registry.get(key); } } diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java index 1ba5175b8a..729139c0bb 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java @@ -84,16 +84,21 @@ public double getCurrentTps() { @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); - if (key == null) { - return null; + if (key != null) { + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry != null) { + Biome biome = registry.get(key); + if (biome != null) { + return biome; + } + } } - Registry registry = Bukkit.getRegistry(Biome.class); - if (registry == null) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { return null; } - - return registry.get(key); } } diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java index 6172b04c8c..9f5e99973d 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java @@ -100,16 +100,21 @@ public double getCurrentTps() { @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); - if (key == null) { - return null; + if (key != null) { + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry != null) { + Biome biome = registry.get(key); + if (biome != null) { + return biome; + } + } } - Registry registry = Bukkit.getRegistry(Biome.class); - if (registry == null) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { return null; } - - return registry.get(key); } } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java index f3e2853f77..7dadfff6c3 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java @@ -89,16 +89,21 @@ public double getCurrentTps() { @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); - if (key == null) { - return null; + if (key != null) { + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry != null) { + Biome biome = registry.get(key); + if (biome != null) { + return biome; + } + } } - Registry registry = Bukkit.getRegistry(Biome.class); - if (registry == null) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { return null; } - - return registry.get(key); } } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index 6167c50d1f..e91b8ff6c6 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -89,16 +89,21 @@ public double getCurrentTps() { @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); - if (key == null) { - return null; + if (key != null) { + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry != null) { + Biome biome = registry.get(key); + if (biome != null) { + return biome; + } + } } - Registry registry = Bukkit.getRegistry(Biome.class); - if (registry == null) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { return null; } - - return registry.get(key); } } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java index ebb9a8c27b..741a49287e 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java @@ -89,16 +89,21 @@ public double getCurrentTps() { @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); - if (key == null) { - return null; + if (key != null) { + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry != null) { + Biome biome = registry.get(key); + if (biome != null) { + return biome; + } + } } - Registry registry = Bukkit.getRegistry(Biome.class); - if (registry == null) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { return null; } - - return registry.get(key); } } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java index ad4f9c67c7..f490637060 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java @@ -100,16 +100,21 @@ public double getCurrentTps() { @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); - if (key == null) { - return null; + if (key != null) { + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry != null) { + Biome biome = registry.get(key); + if (biome != null) { + return biome; + } + } } - Registry registry = Bukkit.getRegistry(Biome.class); - if (registry == null) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { return null; } - - return registry.get(key); } } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java index d7f94d8039..d2de169f3c 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java @@ -100,16 +100,21 @@ public double getCurrentTps() { @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); - if (key == null) { - return null; + if (key != null) { + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry != null) { + Biome biome = registry.get(key); + if (biome != null) { + return biome; + } + } } - Registry registry = Bukkit.getRegistry(Biome.class); - if (registry == null) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { return null; } - - return registry.get(key); } } diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java index 71f2dbf5bc..7eef4f7997 100644 --- a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java @@ -100,16 +100,21 @@ public double getCurrentTps() { @Override public Biome getBiome(String biomeName) { NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); - if (key == null) { - return null; + if (key != null) { + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry != null) { + Biome biome = registry.get(key); + if (biome != null) { + return biome; + } + } } - Registry registry = Bukkit.getRegistry(Biome.class); - if (registry == null) { + try { + return Biome.valueOf(biomeName.toUpperCase(Locale.ENGLISH)); + } catch (IllegalArgumentException e) { return null; } - - return registry.get(key); } } From 27ed494bc79f1a6271173e7ec179b9a72bd778d6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Tue, 16 Jun 2026 22:00:24 +0300 Subject: [PATCH 595/600] Fix generated_schematics and unlocked_worlds columns created with types of INTEGER instead of TEXT (#2951) --- .../core/database/loader/sql/SQLDatabase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java index 6a76a6c30a..3d4abbbaa1 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/database/loader/sql/SQLDatabase.java @@ -81,8 +81,8 @@ private static void createIslandsTable() { new Column("ignored", "BOOLEAN"), new Column("name", "TEXT"), new Column("description", "TEXT"), - new Column("generated_schematics", "INTEGER"), - new Column("unlocked_worlds", "INTEGER"), + new Column("generated_schematics", "TEXT"), + new Column("unlocked_worlds", "TEXT"), new Column("last_time_updated", "BIGINT"), new Column("dirty_chunks", "LONGTEXT"), new Column("block_counts", "LONGTEXT"), From f85e4ae9ec8991425dc848a509096540bf52a634 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sat, 13 Jun 2026 13:47:42 +0300 Subject: [PATCH 596/600] Adds support to 26.2 --- .../templates/AbstractNMSChunks.java.template | 2 +- .../NMSDragonFightImpl.java.template | 2 +- NMS/src/main/templates/NMSUtils.java.template | 2 +- .../crops/CropsBlockEntity.java.template | 7 +- .../crops/CropsTickingMethod.java.template | 6 +- ...tractIslandEntityEnderDragon.java.template | 2 +- .../dragon/IslandEndDragonFight.java.template | 14 +- NMS/v1_17/properties | 4 +- .../nms/v1_17/NMSChunksImpl.java | 3 - NMS/v1_18/properties | 4 +- .../nms/v1_18/NMSChunksImpl.java | 3 - NMS/v1_19/properties | 4 +- .../nms/v1_19/NMSChunksImpl.java | 5 +- NMS/v1_20_3/properties | 4 +- .../nms/v1_20_3/NMSChunksImpl.java | 18 +- NMS/v1_20_4/properties | 4 +- .../nms/v1_20_4/NMSChunksImpl.java | 17 +- NMS/v1_21/properties | 4 +- .../nms/v1_21/NMSChunksImpl.java | 17 +- NMS/v1_21_10/properties | 4 +- .../nms/v1_21_10/NMSChunksImpl.java | 19 +- NMS/v1_21_3/properties | 4 +- .../nms/v1_21_3/NMSChunksImpl.java | 19 +- NMS/v1_21_4/properties | 4 +- .../nms/v1_21_4/NMSChunksImpl.java | 19 +- NMS/v1_21_5/properties | 4 +- .../nms/v1_21_5/NMSChunksImpl.java | 19 +- NMS/v1_21_7/properties | 4 +- .../nms/v1_21_7/NMSChunksImpl.java | 19 +- NMS/v1_21_9/properties | 4 +- .../nms/v1_21_9/NMSChunksImpl.java | 19 +- NMS/v26_1/properties | 4 +- .../nms/v26_1/NMSChunksImpl.java | 19 +- NMS/v26_2/build.gradle | 25 + NMS/v26_2/properties | 14 + .../nms/v26_2/NMSAlgorithmsImpl.java | 115 +++++ .../nms/v26_2/NMSChunksImpl.java | 367 ++++++++++++++ .../nms/v26_2/NMSEntitiesImpl.java | 24 + .../nms/v26_2/NMSTagsImpl.java | 152 ++++++ .../nms/v26_2/NMSWorldImpl.java | 145 ++++++ .../v26_2/dragon/EndDragonFightWrapper.java | 35 ++ .../v26_2/dragon/IslandEntityEnderDragon.java | 40 ++ .../nms/v26_2/hologram/EntityHologram.java | 64 +++ .../nms/v26_2/trial/IslandPlayerDetector.java | 56 +++ .../nms/v26_2/utils/NMSUtilsVersioned.java | 448 ++++++++++++++++++ .../v26_2/vibration/IslandVibrationUser.java | 90 ++++ .../v26_2/world/BlockLevelTicksTracker.java | 59 +++ .../CollectingNeighborUpdaterTracker.java | 44 ++ .../world/PropertiesMapperVersioned.java | 18 + build.gradle | 2 +- gradle.properties | 1 + settings.gradle | 3 +- .../superiorskyblock/core/ServerVersion.java | 1 + 53 files changed, 1885 insertions(+), 101 deletions(-) create mode 100644 NMS/v26_2/build.gradle create mode 100644 NMS/v26_2/properties create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSAlgorithmsImpl.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSChunksImpl.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSEntitiesImpl.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSTagsImpl.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSWorldImpl.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/dragon/EndDragonFightWrapper.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/dragon/IslandEntityEnderDragon.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/hologram/EntityHologram.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/trial/IslandPlayerDetector.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/utils/NMSUtilsVersioned.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/vibration/IslandVibrationUser.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/world/BlockLevelTicksTracker.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/world/CollectingNeighborUpdaterTracker.java create mode 100644 NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/world/PropertiesMapperVersioned.java diff --git a/NMS/src/main/templates/AbstractNMSChunks.java.template b/NMS/src/main/templates/AbstractNMSChunks.java.template index b100f0d06d..6d7b2aa933 100644 --- a/NMS/src/main/templates/AbstractNMSChunks.java.template +++ b/NMS/src/main/templates/AbstractNMSChunks.java.template @@ -292,7 +292,7 @@ public abstract class AbstractNMSChunks implements NMSChunks { } protected void removeEntities(LevelChunk levelChunk) { - ServerLevel serverLevel = levelChunk.level; + ServerLevel serverLevel = (ServerLevel) levelChunk.getLevel(); int chunkWorldCoordX = levelChunk.locX << 4; int chunkWorldCoordZ = levelChunk.locZ << 4; diff --git a/NMS/src/main/templates/NMSDragonFightImpl.java.template b/NMS/src/main/templates/NMSDragonFightImpl.java.template index d1cf666b3e..0596569d4f 100644 --- a/NMS/src/main/templates/NMSDragonFightImpl.java.template +++ b/NMS/src/main/templates/NMSDragonFightImpl.java.template @@ -44,7 +44,7 @@ public class NMSDragonFightImpl implements NMSDragonFight { private static boolean firstWorldPreparation = true; static { - ENTITY_TYPES_BUILDER.set(EntityType.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); + ENTITY_TYPES_BUILDER.set(${ENTITY_TYPE_VALUES_CLASS}.ENDER_DRAGON, (EntityType.EntityFactory) IslandEntityEnderDragon::fromEntityTypes); } @Override diff --git a/NMS/src/main/templates/NMSUtils.java.template b/NMS/src/main/templates/NMSUtils.java.template index 31997006e5..6af3c3df03 100644 --- a/NMS/src/main/templates/NMSUtils.java.template +++ b/NMS/src/main/templates/NMSUtils.java.template @@ -258,7 +258,7 @@ public class NMSUtils { public static BlockState setBlock(LevelChunk levelChunk, BlockPos blockPos, int combinedId, @Nullable CompoundTag statesTag, @Nullable CompoundTag tileEntity) { - ServerLevel serverLevel = levelChunk.level; + ServerLevel serverLevel = (ServerLevel) levelChunk.getLevel(); SetBlockContext setBlockContext = new SetBlockContext() { @Override diff --git a/NMS/src/main/templates/crops/CropsBlockEntity.java.template b/NMS/src/main/templates/crops/CropsBlockEntity.java.template index fd7fc352fa..0b6a6d26b1 100644 --- a/NMS/src/main/templates/crops/CropsBlockEntity.java.template +++ b/NMS/src/main/templates/crops/CropsBlockEntity.java.template @@ -8,7 +8,6 @@ import com.bgsoftware.superiorskyblock.nms.${NMS_VERSION}.NMSUtils; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.LevelChunk; @@ -30,11 +29,11 @@ public class CropsBlockEntity extends BlockEntity { private double cachedCropGrowthMultiplier; private CropsBlockEntity(Island island, LevelChunk levelChunk, BlockPos blockPos) { - super(BlockEntityType.COMMAND_BLOCK, blockPos, levelChunk.level.getBlockState(blockPos)); + super(${BLOCK_ENTITY_TYPE_VALUES_CLASS}.COMMAND_BLOCK, blockPos, levelChunk.getLevel().getBlockState(blockPos)); this.island = new WeakReference<>(island); this.chunk = new WeakReference<>(levelChunk); - setLevel(levelChunk.level); - levelChunk.level.addBlockEntityTicker(new CropsTickingBlockEntity(this)); + setLevel(levelChunk.getLevel()); + levelChunk.getLevel().addBlockEntityTicker(new CropsTickingBlockEntity(this)); this.cachedCropGrowthMultiplier = island.getCropGrowthMultiplier() - 1; } diff --git a/NMS/src/main/templates/crops/CropsTickingMethod.java.template b/NMS/src/main/templates/crops/CropsTickingMethod.java.template index 552673b70c..a5756899ab 100644 --- a/NMS/src/main/templates/crops/CropsTickingMethod.java.template +++ b/NMS/src/main/templates/crops/CropsTickingMethod.java.template @@ -68,7 +68,7 @@ public abstract class CropsTickingMethod { @Override protected void doTick(LevelChunk levelChunk, int tickSpeed) { - ServerLevel serverLevel = levelChunk.level; + ServerLevel serverLevel = (ServerLevel) levelChunk.getLevel(); LevelChunkSection[] sections = levelChunk.getSections(); int minSection = NMSUtilsVersioned.getMinSection(serverLevel); @@ -90,7 +90,7 @@ public abstract class CropsTickingMethod { continue; } - PalettedContainer states = levelChunkSection.states; + PalettedContainer states = levelChunkSection.getStates(); int offsetY = (sectionIndex + minSection) << 4; @@ -126,7 +126,7 @@ public abstract class CropsTickingMethod { @Override protected void doTick(LevelChunk levelChunk, int tickSpeed) { LevelChunkSection[] sections = levelChunk.getSections(); - ServerLevel serverLevel = levelChunk.level; + ServerLevel serverLevel = (ServerLevel) levelChunk.getLevel(); int chunkOffsetX = levelChunk.locX << 4; int chunkOffsetZ = levelChunk.locZ << 4; diff --git a/NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template b/NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template index 8fd4b14219..5d6812f0bb 100644 --- a/NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template +++ b/NMS/src/main/templates/dragon/AbstractIslandEntityEnderDragon.java.template @@ -39,7 +39,7 @@ public class AbstractIslandEntityEnderDragon extends EnderDragon { } protected AbstractIslandEntityEnderDragon(Level level) { - super(EntityType.ENDER_DRAGON, level); + super(${ENTITY_TYPE_VALUES_CLASS}.ENDER_DRAGON, level); this.serverLevel = (ServerLevel) level; this.dimension = plugin.getProviders().getWorldsProvider().getIslandsWorldDimension(level.getWorld()); } diff --git a/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template b/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template index 5cd799965e..0262d01a9c 100644 --- a/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template +++ b/NMS/src/main/templates/dragon/IslandEndDragonFight.java.template @@ -47,6 +47,7 @@ public class IslandEndDragonFight extends EndDragonFightWrapper { ${END_DRAGON_FIGHT_CLASS}.class, boolean.class, Modifier.PRIVATE, 3); private static final ReflectField WAS_DRAGON_KILLED = new ReflectField<>( ${END_DRAGON_FIGHT_CLASS}.class, boolean.class, Modifier.PRIVATE, 1); + private static final ReflectField DRAGON_UUID = initializeDragonUUIDField(); private static final ReflectField TICKS_SINCE_LAST_PLAYER_SCAN = new ReflectField<>( ${END_DRAGON_FIGHT_CLASS}.class, int.class, Modifier.PRIVATE, 4); @@ -203,7 +204,8 @@ public class IslandEndDragonFight extends EndDragonFightWrapper { NMSUtilsVersioned.addEntity(this.serverLevel, entityEnderDragon, CreatureSpawnEvent.SpawnReason.NATURAL); - this.dragonUUID = entityEnderDragon.getUUID(); + DRAGON_UUID.set(this, entityEnderDragon.getUUID()); + this.resetSpikeCrystals(); return entityEnderDragon; @@ -223,4 +225,14 @@ public class IslandEndDragonFight extends EndDragonFightWrapper { return dragonBattleField; } + private static ReflectField initializeDragonUUIDField() { + ReflectField dragonUUIDField = new ReflectField<>(${END_DRAGON_FIGHT_CLASS}.class, UUID.class, Modifier.PRIVATE, 1); + + if(!dragonUUIDField.isValid()) { + dragonUUIDField = new ReflectField<>(${END_DRAGON_FIGHT_CLASS}.class, UUID.class, Modifier.PUBLIC, 1); + } + + return dragonUUIDField; + } + } diff --git a/NMS/v1_17/properties b/NMS/v1_17/properties index 0a3a9fdabb..164e412616 100644 --- a/NMS/v1_17/properties +++ b/NMS/v1_17/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.light.StarLightInterface ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight -SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=SpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java index 561acfb78d..6be0b592a5 100644 --- a/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java +++ b/NMS/v1_17/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_17/NMSChunksImpl.java @@ -18,7 +18,6 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket; import net.minecraft.server.level.ServerLevel; @@ -78,7 +77,6 @@ public void onLoadedChunk(LevelChunk levelChunk) { Arrays.fill(biomes, biome); levelChunk.setUnsaved(true); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos.x, chunkPos.z); //noinspection deprecation ClientboundLevelChunkPacket levelChunkPacket = new ClientboundLevelChunkPacket(levelChunk); ClientboundLightUpdatePacket lightUpdatePacket = new ClientboundLightUpdatePacket(chunkPos, @@ -86,7 +84,6 @@ public void onLoadedChunk(LevelChunk levelChunk) { playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(lightUpdatePacket); serverPlayer.connection.send(levelChunkPacket); }); diff --git a/NMS/v1_18/properties b/NMS/v1_18/properties index b32acd70c2..7ead2fb56a 100644 --- a/NMS/v1_18/properties +++ b/NMS/v1_18/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterf ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight -SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=SpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java index e188f37f06..3837b5f89a 100644 --- a/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java +++ b/NMS/v1_18/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_18/NMSChunksImpl.java @@ -20,7 +20,6 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -79,13 +78,11 @@ public void onLoadedChunk(LevelChunk levelChunk) { levelChunk.setUnsaved(true); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos.x, chunkPos.z); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( levelChunk, levelChunk.level.getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } diff --git a/NMS/v1_19/properties b/NMS/v1_19/properties index d240d1c6c7..4adc7c4099 100644 --- a/NMS/v1_19/properties +++ b/NMS/v1_19/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterf ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight -SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=SpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java index 5dac3811f8..a509d5f47c 100644 --- a/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java +++ b/NMS/v1_19/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_19/NMSChunksImpl.java @@ -21,7 +21,6 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -81,13 +80,11 @@ public void onLoadedChunk(LevelChunk levelChunk) { levelChunk.setUnsaved(true); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos.x, chunkPos.z); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null, true); + levelChunk, levelChunk.getLevel().getLightEngine(), null, null, true); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); serverPlayer.connection.send(mapChunkPacket); }); } diff --git a/NMS/v1_20_3/properties b/NMS/v1_20_3/properties index e601ac463d..22507c5808 100644 --- a/NMS/v1_20_3/properties +++ b/NMS/v1_20_3/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterf ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight -SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=SpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java index d2eabe95e4..6a553da7f7 100644 --- a/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java +++ b/NMS/v1_20_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_3/NMSChunksImpl.java @@ -21,7 +21,8 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchFinishedPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchStartPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; @@ -54,6 +55,9 @@ public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_3.AbstractNMSChunks { + private static final ClientboundChunkBatchStartPacket CHUNK_BATCH_START_PACKET = new ClientboundChunkBatchStartPacket(); + private static final ClientboundChunkBatchFinishedPacket CHUNK_BATCH_FINISHED_PACKET = new ClientboundChunkBatchFinishedPacket(1); + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @@ -80,14 +84,18 @@ public void onLoadedChunk(LevelChunk levelChunk) { levelChunk.setUnsaved(true); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null, true); + levelChunk, levelChunk.getLevel().getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); - serverPlayer.connection.send(mapChunkPacket); + + try { + serverPlayer.connection.send(CHUNK_BATCH_START_PACKET); + serverPlayer.connection.send(mapChunkPacket); + } finally { + serverPlayer.connection.send(CHUNK_BATCH_FINISHED_PACKET); + } }); } diff --git a/NMS/v1_20_4/properties b/NMS/v1_20_4/properties index bfc67e1151..e26cd25610 100644 --- a/NMS/v1_20_4/properties +++ b/NMS/v1_20_4/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.starlight.common.light.StarLightInterf ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight -SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=SpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java index b63a38dacf..fa588e2695 100644 --- a/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java +++ b/NMS/v1_20_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_20_4/NMSChunksImpl.java @@ -21,7 +21,8 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchFinishedPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchStartPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -55,6 +56,8 @@ public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_20_4.AbstractNMSChunks { + private static final ClientboundChunkBatchFinishedPacket CHUNK_BATCH_FINISHED_PACKET = new ClientboundChunkBatchFinishedPacket(1); + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @@ -81,14 +84,18 @@ public void onLoadedChunk(LevelChunk levelChunk) { levelChunk.setUnsaved(true); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null, true); + levelChunk, levelChunk.getLevel().getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); - serverPlayer.connection.send(mapChunkPacket); + + try { + serverPlayer.connection.send(ClientboundChunkBatchStartPacket.INSTANCE); + serverPlayer.connection.send(mapChunkPacket); + } finally { + serverPlayer.connection.send(CHUNK_BATCH_FINISHED_PACKET); + } }); } diff --git a/NMS/v1_21/properties b/NMS/v1_21/properties index 3f84e339d7..4be0e6b2f6 100644 --- a/NMS/v1_21/properties +++ b/NMS/v1_21/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarL ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight -SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=SpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java index e9a0ced091..3ee8006e55 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSChunksImpl.java @@ -21,7 +21,8 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchFinishedPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchStartPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -55,6 +56,8 @@ public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21.AbstractNMSChunks { + private static final ClientboundChunkBatchFinishedPacket CHUNK_BATCH_FINISHED_PACKET = new ClientboundChunkBatchFinishedPacket(1); + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @@ -81,14 +84,18 @@ public void onLoadedChunk(LevelChunk levelChunk) { levelChunk.setUnsaved(true); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null, true); + levelChunk, levelChunk.getLevel().getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); - serverPlayer.connection.send(mapChunkPacket); + + try { + serverPlayer.connection.send(ClientboundChunkBatchStartPacket.INSTANCE); + serverPlayer.connection.send(mapChunkPacket); + } finally { + serverPlayer.connection.send(CHUNK_BATCH_FINISHED_PACKET); + } }); } diff --git a/NMS/v1_21_10/properties b/NMS/v1_21_10/properties index 5f03a6f719..79f63d3934 100644 --- a/NMS/v1_21_10/properties +++ b/NMS/v1_21_10/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarL ABSTRACT_MINECART_SUBPACKAGE=vehicle.minecart GET_RANDOM_TICK_SPEED_METHOD=get(net.minecraft.world.level.gamerules.GameRules.RANDOM_TICK_SPEED) END_DRAGON_FIGHT_CLASS=EndDragonFight -SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=SpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSChunksImpl.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSChunksImpl.java index 836913a9ad..7a6e8d7d5b 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSChunksImpl.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSChunksImpl.java @@ -21,7 +21,8 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchFinishedPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchStartPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -62,6 +63,8 @@ public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_10. private static final ReflectMethod>>> CONTAINER_FACTORY_BIOME_RW_CODEC = new ReflectMethod<>(PalettedContainerFactory.class, "biomeContainerCodecRW"); + private static final ClientboundChunkBatchFinishedPacket CHUNK_BATCH_FINISHED_PACKET = new ClientboundChunkBatchFinishedPacket(1); + private static final Logger LOGGER = LogUtils.getLogger(); public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { @@ -75,8 +78,6 @@ protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome b public void onLoadedChunk(LevelChunk levelChunk) { Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - ChunkPos chunkPos = levelChunk.getPos(); - LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; @@ -88,14 +89,18 @@ public void onLoadedChunk(LevelChunk levelChunk) { levelChunk.markUnsaved(); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null); + levelChunk, levelChunk.getLevel().getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); - serverPlayer.connection.send(mapChunkPacket); + + try { + serverPlayer.connection.send(ClientboundChunkBatchStartPacket.INSTANCE); + serverPlayer.connection.send(mapChunkPacket); + } finally { + serverPlayer.connection.send(CHUNK_BATCH_FINISHED_PACKET); + } }); } diff --git a/NMS/v1_21_3/properties b/NMS/v1_21_3/properties index 3e4b00f9d9..b45db24541 100644 --- a/NMS/v1_21_3/properties +++ b/NMS/v1_21_3/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarL ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight -SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=SpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java index 10eadc8087..4259f752e4 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSChunksImpl.java @@ -21,7 +21,8 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchFinishedPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchStartPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -56,6 +57,8 @@ public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_3.AbstractNMSChunks { + private static final ClientboundChunkBatchFinishedPacket CHUNK_BATCH_FINISHED_PACKET = new ClientboundChunkBatchFinishedPacket(1); + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @@ -68,8 +71,6 @@ public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - ChunkPos chunkPos = levelChunk.getPos(); - LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; @@ -82,14 +83,18 @@ public void onLoadedChunk(LevelChunk levelChunk) { levelChunk.markUnsaved(); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null, true); + levelChunk, levelChunk.getLevel().getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); - serverPlayer.connection.send(mapChunkPacket); + + try { + serverPlayer.connection.send(ClientboundChunkBatchStartPacket.INSTANCE); + serverPlayer.connection.send(mapChunkPacket); + } finally { + serverPlayer.connection.send(CHUNK_BATCH_FINISHED_PACKET); + } }); } diff --git a/NMS/v1_21_4/properties b/NMS/v1_21_4/properties index 8dbb058db2..eac086fef8 100644 --- a/NMS/v1_21_4/properties +++ b/NMS/v1_21_4/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarL ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight -SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=SpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java index a11517a25c..598e7eb00c 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSChunksImpl.java @@ -21,7 +21,8 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchFinishedPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchStartPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -56,6 +57,8 @@ public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_4.AbstractNMSChunks { + private static final ClientboundChunkBatchFinishedPacket CHUNK_BATCH_FINISHED_PACKET = new ClientboundChunkBatchFinishedPacket(1); + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @@ -68,8 +71,6 @@ public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - ChunkPos chunkPos = levelChunk.getPos(); - LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; @@ -82,14 +83,18 @@ public void onLoadedChunk(LevelChunk levelChunk) { levelChunk.markUnsaved(); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null, true); + levelChunk, levelChunk.getLevel().getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); - serverPlayer.connection.send(mapChunkPacket); + + try { + serverPlayer.connection.send(ClientboundChunkBatchStartPacket.INSTANCE); + serverPlayer.connection.send(mapChunkPacket); + } finally { + serverPlayer.connection.send(CHUNK_BATCH_FINISHED_PACKET); + } }); } diff --git a/NMS/v1_21_5/properties b/NMS/v1_21_5/properties index ed9c7d9895..d97995000d 100644 --- a/NMS/v1_21_5/properties +++ b/NMS/v1_21_5/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarL ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight -SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=SpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java index 1c417f8d18..54331f773f 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSChunksImpl.java @@ -21,7 +21,8 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchFinishedPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchStartPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -56,6 +57,8 @@ public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_5.AbstractNMSChunks { + private static final ClientboundChunkBatchFinishedPacket CHUNK_BATCH_FINISHED_PACKET = new ClientboundChunkBatchFinishedPacket(1); + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { super(plugin); } @@ -68,8 +71,6 @@ public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - ChunkPos chunkPos = levelChunk.getPos(); - LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; @@ -82,14 +83,18 @@ public void onLoadedChunk(LevelChunk levelChunk) { levelChunk.markUnsaved(); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null, true); + levelChunk, levelChunk.getLevel().getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); - serverPlayer.connection.send(mapChunkPacket); + + try { + serverPlayer.connection.send(ClientboundChunkBatchStartPacket.INSTANCE); + serverPlayer.connection.send(mapChunkPacket); + } finally { + serverPlayer.connection.send(CHUNK_BATCH_FINISHED_PACKET); + } }); } diff --git a/NMS/v1_21_7/properties b/NMS/v1_21_7/properties index 9bcdf8c242..221c34814f 100644 --- a/NMS/v1_21_7/properties +++ b/NMS/v1_21_7/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarL ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight -SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=SpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java index ef6f7b5603..ecacf308d1 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSChunksImpl.java @@ -22,7 +22,8 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchFinishedPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchStartPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -61,6 +62,8 @@ public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_7.AbstractNMSChunks { + private static final ClientboundChunkBatchFinishedPacket CHUNK_BATCH_FINISHED_PACKET = new ClientboundChunkBatchFinishedPacket(1); + private static final Logger LOGGER = LogUtils.getLogger(); public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { @@ -75,8 +78,6 @@ public void onLoadedChunk(LevelChunk levelChunk) { Registry biomesRegistry = levelChunk.level.registryAccess().lookupOrThrow(Registries.BIOME); Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - ChunkPos chunkPos = levelChunk.getPos(); - LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; @@ -89,14 +90,18 @@ public void onLoadedChunk(LevelChunk levelChunk) { levelChunk.markUnsaved(); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null, true); + levelChunk, levelChunk.getLevel().getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); - serverPlayer.connection.send(mapChunkPacket); + + try { + serverPlayer.connection.send(ClientboundChunkBatchStartPacket.INSTANCE); + serverPlayer.connection.send(mapChunkPacket); + } finally { + serverPlayer.connection.send(CHUNK_BATCH_FINISHED_PACKET); + } }); } diff --git a/NMS/v1_21_9/properties b/NMS/v1_21_9/properties index 431e8a567f..a43e0e42c0 100644 --- a/NMS/v1_21_9/properties +++ b/NMS/v1_21_9/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarL ABSTRACT_MINECART_SUBPACKAGE=vehicle GET_RANDOM_TICK_SPEED_METHOD=getInt(net.minecraft.world.level.GameRules.RULE_RANDOMTICKING) END_DRAGON_FIGHT_CLASS=EndDragonFight -SPIKE_FEATURE_CLASS=SpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=SpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java index 5378e7e18e..8296986872 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSChunksImpl.java @@ -21,7 +21,8 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchFinishedPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchStartPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -62,6 +63,8 @@ public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v1_21_9.A private static final ReflectMethod>>> CONTAINER_FACTORY_BIOME_RW_CODEC = new ReflectMethod<>(PalettedContainerFactory.class, "biomeContainerCodecRW"); + private static final ClientboundChunkBatchFinishedPacket CHUNK_BATCH_FINISHED_PACKET = new ClientboundChunkBatchFinishedPacket(1); + private static final Logger LOGGER = LogUtils.getLogger(); public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { @@ -75,8 +78,6 @@ protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome b public void onLoadedChunk(LevelChunk levelChunk) { Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - ChunkPos chunkPos = levelChunk.getPos(); - LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; @@ -88,14 +89,18 @@ public void onLoadedChunk(LevelChunk levelChunk) { levelChunk.markUnsaved(); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null); + levelChunk, levelChunk.getLevel().getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); - serverPlayer.connection.send(mapChunkPacket); + + try { + serverPlayer.connection.send(ClientboundChunkBatchStartPacket.INSTANCE); + serverPlayer.connection.send(mapChunkPacket); + } finally { + serverPlayer.connection.send(CHUNK_BATCH_FINISHED_PACKET); + } }); } diff --git a/NMS/v26_1/properties b/NMS/v26_1/properties index cfd4a71e95..b8520a07b2 100644 --- a/NMS/v26_1/properties +++ b/NMS/v26_1/properties @@ -9,4 +9,6 @@ STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarL ABSTRACT_MINECART_SUBPACKAGE=vehicle.minecart GET_RANDOM_TICK_SPEED_METHOD=get(net.minecraft.world.level.gamerules.GameRules.RANDOM_TICK_SPEED) END_DRAGON_FIGHT_CLASS=EnderDragonFight -SPIKE_FEATURE_CLASS=EndSpikeFeature \ No newline at end of file +SPIKE_FEATURE_CLASS=EndSpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityType +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityType \ No newline at end of file diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSChunksImpl.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSChunksImpl.java index d4a2c79b45..1ee6fa7c85 100644 --- a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSChunksImpl.java +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSChunksImpl.java @@ -21,7 +21,8 @@ import net.minecraft.nbt.ListTag; import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.Tag; -import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchFinishedPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchStartPacket; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; @@ -62,6 +63,8 @@ public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v26_1.Abs private static final ReflectMethod>>> CONTAINER_FACTORY_BIOME_RW_CODEC = new ReflectMethod<>(PalettedContainerFactory.class, "biomeContainerCodecRW"); + private static final ClientboundChunkBatchFinishedPacket CHUNK_BATCH_FINISHED_PACKET = new ClientboundChunkBatchFinishedPacket(1); + private static final Logger LOGGER = LogUtils.getLogger(); public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { @@ -75,8 +78,6 @@ protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome b public void onLoadedChunk(LevelChunk levelChunk) { Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); - ChunkPos chunkPos = levelChunk.getPos(); - LevelChunkSection[] chunkSections = levelChunk.getSections(); for (int i = 0; i < chunkSections.length; ++i) { LevelChunkSection currentSection = chunkSections[i]; @@ -88,14 +89,18 @@ public void onLoadedChunk(LevelChunk levelChunk) { levelChunk.markUnsaved(); - ClientboundForgetLevelChunkPacket forgetLevelChunkPacket = new ClientboundForgetLevelChunkPacket(chunkPos); ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( - levelChunk, levelChunk.level.getLightEngine(), null, null); + levelChunk, levelChunk.getLevel().getLightEngine(), null, null); playersToUpdate.forEach(player -> { ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); - serverPlayer.connection.send(forgetLevelChunkPacket); - serverPlayer.connection.send(mapChunkPacket); + + try { + serverPlayer.connection.send(ClientboundChunkBatchStartPacket.INSTANCE); + serverPlayer.connection.send(mapChunkPacket); + } finally { + serverPlayer.connection.send(CHUNK_BATCH_FINISHED_PACKET); + } }); } diff --git a/NMS/v26_2/build.gradle b/NMS/v26_2/build.gradle new file mode 100644 index 0000000000..833df5a338 --- /dev/null +++ b/NMS/v26_2/build.gradle @@ -0,0 +1,25 @@ +plugins { + id("io.papermc.paperweight.userdev") version "2.0.0-beta.21" +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(25)) + } +} + +paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.getMOJANG_PRODUCTION() + +group 'NMS:v26_2' + +dependencies { + paperweight.paperDevBundle("26.2.build.+") + compileOnly project(":NMS:Spigot-1_20_3") + compileOnly project(":NMS:Paper-1_20_3") + compileOnly project(":API") + compileOnly project(":") +} + +if (project.hasProperty('nms.compile_v26_2') && !Boolean.valueOf(project.findProperty("nms.compile_v26_2").toString())) { + project.tasks.all { task -> task.enabled = false } +} \ No newline at end of file diff --git a/NMS/v26_2/properties b/NMS/v26_2/properties new file mode 100644 index 0000000000..7df8c3d6dd --- /dev/null +++ b/NMS/v26_2/properties @@ -0,0 +1,14 @@ +NMS_VERSION=v26_2 +CRAFTBUKKIT_PACKAGE=org.bukkit.craftbukkit +COMMON_NMS_PACKAGE=com.bgsoftware.superiorskyblock.nms.v1_20_3 +PAPER_CHUNK_BLOCK_CONTROLLER_CLASS=io.papermc.paper.antixray.ChunkPacketBlockController +REGISTRY_CLASS=net.minecraft.core.registries.BuiltInRegistries +CHUNK_STATUS_CLASS=net.minecraft.world.level.chunk.status.ChunkStatus +SERVER_LEVEL_RANDOM_TYPE=net.minecraft.util.RandomSource +STAR_LIGHT_INTERFACE_CLASS=ca.spottedleaf.moonrise.patches.starlight.light.StarLightInterface +ABSTRACT_MINECART_SUBPACKAGE=vehicle.minecart +GET_RANDOM_TICK_SPEED_METHOD=get(net.minecraft.world.level.gamerules.GameRules.RANDOM_TICK_SPEED) +END_DRAGON_FIGHT_CLASS=EnderDragonFight +SPIKE_FEATURE_CLASS=EndSpikeFeature +ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.entity.EntityTypes +BLOCK_ENTITY_TYPE_VALUES_CLASS=net.minecraft.world.level.block.entity.BlockEntityTypes \ No newline at end of file diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSAlgorithmsImpl.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSAlgorithmsImpl.java new file mode 100644 index 0000000000..b6eaf62b6b --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSAlgorithmsImpl.java @@ -0,0 +1,115 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2; + +import com.bgsoftware.common.reflection.ReflectField; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.mojang.serialization.JsonOps; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.ComponentSerialization; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Biome; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.inventory.ItemRarity; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ArmorMeta; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.trim.ArmorTrim; +import org.bukkit.inventory.meta.trim.TrimMaterial; +import org.bukkit.inventory.meta.trim.TrimPattern; + +import java.lang.reflect.Modifier; +import java.util.Locale; + +public class NMSAlgorithmsImpl extends com.bgsoftware.superiorskyblock.nms.v26_2.AbstractNMSAlgorithms { + + public static final ReflectField SERVER_RECENT_TPS = new ReflectField<>(MinecraftServer.class, + double[].class, Modifier.PUBLIC | Modifier.FINAL, 1); + + private static final Gson COMPONENT_GSON = new GsonBuilder().disableHtmlEscaping().create(); + + @Override + public String parseSignLine(String original) { + RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(JsonOps.INSTANCE); + JsonElement jsonElement = ComponentSerialization.CODEC.encodeStart(context, CraftChatMessage.fromString(original)[0]) + .getOrThrow(JsonParseException::new); + return COMPONENT_GSON.toJson(jsonElement); + } + + @Override + public void setItemModel(ItemMeta itemMeta, String itemModel) { + itemMeta.setItemModel(NamespacedKey.fromString(itemModel)); + } + + @Override + public void setRarity(ItemMeta itemMeta, String rarity) { + itemMeta.setRarity(ItemRarity.valueOf(rarity)); + } + + @Override + public void setTrim(ItemMeta itemMeta, String trimMaterial, String trimPattern) { + if (itemMeta instanceof ArmorMeta armorMeta) { + Registry materialRegistry = Bukkit.getRegistry(TrimMaterial.class); + Registry patternRegistry = Bukkit.getRegistry(TrimPattern.class); + + if (materialRegistry == null || patternRegistry == null) { + return; + } + + TrimMaterial material = materialRegistry.get(NamespacedKey.minecraft(trimMaterial)); + TrimPattern pattern = patternRegistry.get(NamespacedKey.minecraft(trimPattern)); + + if (material == null) + throw new IllegalArgumentException("Couldn't convert " + trimMaterial.toUpperCase(Locale.ENGLISH) + + " into trim material, skipping..."); + if (pattern == null) + throw new IllegalArgumentException("Couldn't convert " + trimPattern.toUpperCase(Locale.ENGLISH) + + " into trim pattern, skipping..."); + + ArmorTrim armorTrim = new ArmorTrim(material, pattern); + armorMeta.setTrim(armorTrim); + } + } + + @Override + public void setHideTooltip(ItemMeta itemMeta) { + itemMeta.setHideTooltip(true); + } + + @Override + public String getMinecraftKey(ItemStack itemStack) { + return BuiltInRegistries.ITEM.getKey(CraftItemStack.asNMSCopy(itemStack).getItem()).toString(); + } + + @Override + public void makeItemGlow(ItemMeta itemMeta) { + itemMeta.setEnchantmentGlintOverride(true); + } + + @Override + public double getCurrentTps() { + return (SERVER_RECENT_TPS.isValid() ? SERVER_RECENT_TPS.get(MinecraftServer.getServer()) : Bukkit.getTPS())[0]; + } + + @Override + public Biome getBiome(String biomeName) { + NamespacedKey key = NamespacedKey.fromString(biomeName.toLowerCase(Locale.ENGLISH)); + if (key == null) { + return null; + } + + Registry registry = Bukkit.getRegistry(Biome.class); + if (registry == null) { + return null; + } + + return registry.get(key); + } + +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSChunksImpl.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSChunksImpl.java new file mode 100644 index 0000000000..dbffd4b7af --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSChunksImpl.java @@ -0,0 +1,367 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2; + +import com.bgsoftware.common.reflection.ReflectMethod; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.core.CalculatedChunk; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.collections.Chunk2ObjectMap; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.core.threads.Synchronized; +import com.bgsoftware.superiorskyblock.nms.v26_2.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v26_2.utils.NMSUtilsVersioned; +import com.bgsoftware.superiorskyblock.world.chunk.ChunkLoadReason; +import com.bgsoftware.superiorskyblock.world.generator.IslandsGenerator; +import com.mojang.logging.LogUtils; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; +import net.minecraft.network.protocol.game.ClientboundChunkBatchFinishedPacket; +import net.minecraft.network.protocol.game.ClientboundChunkBatchStartPacket; +import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.ProblemReporter; +import net.minecraft.util.datafix.DataFixers; +import net.minecraft.util.datafix.fixes.References; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerFactory; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.ValueInput; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Player; +import org.bukkit.generator.ChunkGenerator; +import org.slf4j.Logger; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +import static com.bgsoftware.superiorskyblock.nms.v26_2.utils.NMSUtilsVersioned.DEFAULT_PALETTED_CONTAINER_FACTORY; + +public class NMSChunksImpl extends com.bgsoftware.superiorskyblock.nms.v26_2.AbstractNMSChunks { + + private static final ReflectMethod>>> CONTAINER_FACTORY_BIOME_RW_CODEC = + new ReflectMethod<>(PalettedContainerFactory.class, "biomeContainerCodecRW"); + + private static final ClientboundChunkBatchFinishedPacket CHUNK_BATCH_FINISHED_PACKET = new ClientboundChunkBatchFinishedPacket(1); + + private static final Logger LOGGER = LogUtils.getLogger(); + + public NMSChunksImpl(SuperiorSkyblockPlugin plugin) { + super(plugin); + } + + @Override + protected NMSUtils.ChunkCallback getBiomesChunkCallback(org.bukkit.block.Biome bukkitBiome, Collection playersToUpdate) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.SET_BIOME, false) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); + + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + LevelChunkSection currentSection = chunkSections[i]; + if (currentSection != null) { + PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); + chunkSections[i] = new LevelChunkSection(currentSection.getStates(), biomesContainer); + } + } + + levelChunk.markUnsaved(); + + ClientboundLevelChunkWithLightPacket mapChunkPacket = new ClientboundLevelChunkWithLightPacket( + levelChunk, levelChunk.getLevel().getLightEngine(), null, null); + + playersToUpdate.forEach(player -> { + ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle(); + + try { + serverPlayer.connection.send(ClientboundChunkBatchStartPacket.INSTANCE); + serverPlayer.connection.send(mapChunkPacket); + } finally { + serverPlayer.connection.send(CHUNK_BATCH_FINISHED_PACKET); + } + }); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + + Holder biome = CraftBiome.bukkitToMinecraftHolder(bukkitBiome); + + PalettedContainer> biomesContainer = NMSUtilsVersioned.createBiomesContainer(biome); + DataResult dataResult = getBiomeContainerRWCodec() + .encodeStart(NbtOps.INSTANCE, biomesContainer); + Tag biomesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); + + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).ifPresent(compound -> compound.put("biomes", biomesCompound)); + } + + @Override + public void onFinish() { + // Do nothing. + } + }; + } + + @Override + protected NMSUtils.ChunkCallback getDeleteChunkCallback(Runnable onFinish) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.DELETE_CHUNK, false) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + LevelChunkSection[] chunkSections = levelChunk.getSections(); + for (int i = 0; i < chunkSections.length; ++i) { + chunkSections[i] = new LevelChunkSection(DEFAULT_PALETTED_CONTAINER_FACTORY); + } + + removeEntities(levelChunk); + removeBlockEntities(levelChunk); + removeBlocks(levelChunk); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + + ListTag tileEntities = new ListTag(); + + chunkCompound.put("Entities", new ListTag()); + chunkCompound.put("block_entities", tileEntities); + + if (serverLevel.generator instanceof IslandsGenerator) { + PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() + .encodeStart(NbtOps.INSTANCE, statesContainer); + Tag blockStatesCompound = dataResult.getOrThrow(); + + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); + for (int i = 0; i < sectionsList.size(); ++i) + sectionsList.getCompound(i).ifPresent(compound -> compound.put("block_states", blockStatesCompound)); + } else { + ProtoChunk protoChunk = NMSUtils.createProtoChunk(unloadedChunkCompound.chunkPos(), serverLevel); + + try { + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, serverLevel.generator, protoChunk); + } catch (Exception ignored) { + } + + LevelLightEngine lightEngine = serverLevel.getLightEngine(); + LevelChunkSection[] chunkSections = protoChunk.getSections(); + + ListTag sectionsList = new ListTag(); + + // Save blocks + for (int i = lightEngine.getMinLightSection(); i < lightEngine.getMaxLightSection(); ++i) { + int chunkSectionIndex = serverLevel.getSectionIndex(i); + + CompoundTag sectionCompound = new CompoundTag(); + + if (chunkSectionIndex >= 0 && chunkSectionIndex < chunkSections.length) { + LevelChunkSection levelChunkSection = chunkSections[chunkSectionIndex]; + + { + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.blockStatesContainerCodec() + .encodeStart(NbtOps.INSTANCE, levelChunkSection.getStates()); + sectionCompound.put("block_states", dataResult.getOrThrow()); + } + + { + DataResult dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerCodec() + .encodeStart(NbtOps.INSTANCE, levelChunkSection.getBiomes()); + sectionCompound.put("biomes", dataResult.getOrThrow()); + } + } + + if (!sectionCompound.isEmpty()) { + sectionCompound.putByte("Y", (byte) i); + sectionsList.add(sectionCompound); + } + } + + for (BlockPos blockEntityPos : protoChunk.blockEntities.keySet()) { + CompoundTag blockEntityCompound = protoChunk.getBlockEntityNbtForSaving(blockEntityPos, + MinecraftServer.getServer().registryAccess()); + if (blockEntityCompound != null) + tileEntities.add(blockEntityCompound); + } + + chunkCompound.put("sections", sectionsList); + } + } + + @Override + public void onFinish() { + if (onFinish != null) + onFinish.run(); + } + }; + } + + @Override + protected NMSUtils.ChunkCallback getCalculateChunkCallback(CompletableFuture> completableFuture, + Synchronized> unloadedChunksCache, + List allCalculatedChunks) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.BLOCKS_RECALCULATE, true) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + ServerLevel serverLevel = (ServerLevel) levelChunk.getLevel(); + ChunkPosition chunkPosition = ChunkPosition.of(serverLevel.getWorld(), levelChunk.locX, levelChunk.locZ, false); + allCalculatedChunks.add(calculateChunk(chunkPosition, serverLevel, levelChunk.getSections())); + + latchCountDown(); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + ChunkPosition chunkPosition = unloadedChunkCompound.chunkPosition(); + ServerLevel serverLevel = unloadedChunkCompound.serverLevel(); + CompoundTag chunkCompound = unloadedChunkCompound.chunkCompound(); + + LevelChunkSection[] chunkSections = new LevelChunkSection[serverLevel.getSectionsCount()]; + + ListTag sectionsList = chunkCompound.getListOrEmpty("sections"); + for (int i = 0; i < sectionsList.size(); ++i) { + CompoundTag sectionCompound = sectionsList.getCompoundOrEmpty(i); + byte yPosition = sectionCompound.getByteOr("Y", (byte) 0); + int sectionIndex = serverLevel.getSectionIndexFromSectionY(yPosition); + + if (sectionIndex >= 0 && sectionIndex < chunkSections.length) { + PalettedContainer blocksPalettedContainer; + Optional blockStatesCompound = sectionCompound.getCompound("block_states"); + if (blockStatesCompound.isPresent()) { + DataResult> dataResult = DEFAULT_PALETTED_CONTAINER_FACTORY + .blockStatesContainerCodec().parse(NbtOps.INSTANCE, blockStatesCompound.get()) + .promotePartial((sx) -> { + }); + blocksPalettedContainer = dataResult.getOrThrow(); + } else { + blocksPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + } + + PalettedContainer> biomesPalettedContainer; + Optional biomesCompound = sectionCompound.getCompound("biomes"); + if (biomesCompound.isPresent()) { + DataResult>> dataResult = getBiomeContainerRWCodec() + .parse(NbtOps.INSTANCE, biomesCompound.get()) + .promotePartial((sx) -> { + }); + biomesPalettedContainer = dataResult.getOrThrow(); + } else { + biomesPalettedContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBiomes(); + } + + chunkSections[sectionIndex] = new LevelChunkSection(blocksPalettedContainer, biomesPalettedContainer); + } + + } + + CalculatedChunk.Blocks calculatedChunk = calculateChunk(chunkPosition, serverLevel, chunkSections); + allCalculatedChunks.add(calculatedChunk); + unloadedChunksCache.write(m -> m.put(chunkPosition, calculatedChunk)); + + latchCountDown(); + } + + @Override + public void onFinish() { + completableFuture.complete(allCalculatedChunks); + } + }; + } + + @Override + protected NMSUtils.ChunkCallback getEntitiesChunkCallback(List allCalculatedChunks, + List unloadedChunkCompounds, + CompletableFuture> completableFuture) { + return new NMSUtils.ChunkCallback(ChunkLoadReason.ENTITIES_RECALCULATE, true) { + @Override + public void onLoadedChunk(LevelChunk levelChunk) { + ChunkPosition chunkPosition = ChunkPosition.of(levelChunk.getLevel().getWorld(), levelChunk.locX, levelChunk.locZ, false); + allCalculatedChunks.add(calculatedChunk(chunkPosition, levelChunk)); + + latchCountDown(); + } + + @Override + public void onUnloadedChunk(NMSUtils.UnloadedChunkCompound unloadedChunkCompound) { + unloadedChunkCompounds.add(unloadedChunkCompound); + + latchCountDown(); + } + + @Override + public void onFinish() { + BukkitExecutor.ensureMain(() -> { + for (NMSUtils.UnloadedChunkCompound unloadedChunkCompound : unloadedChunkCompounds) { + ListTag entitiesTag = unloadedChunkCompound.chunkCompound().getListOrEmpty("Entities"); + allCalculatedChunks.add(calculatedChunk(unloadedChunkCompound.chunkPosition(), + unloadedChunkCompound.serverLevel(), entitiesTag)); + } + + completableFuture.complete(allCalculatedChunks); + }); + } + }; + } + + @Override + protected Optional createEntityFromTag(CompoundTag compoundTag, ServerLevel serverLevel) { + int dataVersion = compoundTag.getIntOr("DataVersion", 0); + if (dataVersion < com.bgsoftware.superiorskyblock.nms.v26_2.AbstractNMSAlgorithms.DATA_VERSION) { + compoundTag = (CompoundTag) DataFixers.getDataFixer().update(References.ENTITY_CHUNK, + new Dynamic<>(NbtOps.INSTANCE, compoundTag), dataVersion, + com.bgsoftware.superiorskyblock.nms.v26_2.AbstractNMSAlgorithms.DATA_VERSION).getValue(); + } + + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(compoundTag::toString, LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverLevel.registryAccess(), compoundTag); + return EntityType.by(valueInput).flatMap(entityType -> + EntityType.create(entityType, valueInput, serverLevel, EntitySpawnReason.NATURAL)); + } + } + + private static void removeBlocks(ChunkAccess chunk) { + ServerLevel serverLevel = (ServerLevel) ((LevelChunk) chunk).getLevel(); + ChunkGenerator bukkitGenerator = serverLevel.getWorld().getGenerator(); + + if (bukkitGenerator == null || bukkitGenerator instanceof IslandsGenerator) + return; + + NMSUtilsVersioned.buildSurfaceForChunk(serverLevel, bukkitGenerator, chunk); + } + + private static Codec>> getBiomeContainerRWCodec() { + if (CONTAINER_FACTORY_BIOME_RW_CODEC.isValid()) { + return CONTAINER_FACTORY_BIOME_RW_CODEC.invoke(DEFAULT_PALETTED_CONTAINER_FACTORY); + } else { + return DEFAULT_PALETTED_CONTAINER_FACTORY.biomeContainerRWCodec(); + } + } + +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSEntitiesImpl.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSEntitiesImpl.java new file mode 100644 index 0000000000..d3bbb5f3e6 --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSEntitiesImpl.java @@ -0,0 +1,24 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2; + +import net.minecraft.tags.ItemTags; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.PortalProcessor; +import org.bukkit.craftbukkit.entity.CraftMinecartFurnace; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.minecart.PoweredMinecart; + +public class NMSEntitiesImpl extends com.bgsoftware.superiorskyblock.nms.v26_2.AbstractNMSEntities { + + @Override + public boolean isMinecartFuel(org.bukkit.inventory.ItemStack bukkitItem, PoweredMinecart minecart) { + return ((CraftMinecartFurnace) minecart).getHandle().fuel + 3600 <= 32000 && + CraftItemStack.asNMSCopy(bukkitItem).is(ItemTags.FURNACE_MINECART_FUEL); + } + + @Override + protected int getPortalTicks(Entity entity) { + PortalProcessor portalProcessor = entity.portalProcess; + return portalProcessor == null ? 0 : portalProcessor.getPortalTime(); + } + +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSTagsImpl.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSTagsImpl.java new file mode 100644 index 0000000000..c52296b1e6 --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSTagsImpl.java @@ -0,0 +1,152 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2; + +import com.bgsoftware.superiorskyblock.tag.CompoundTag; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.logging.LogUtils; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.ByteArrayTag; +import net.minecraft.nbt.IntArrayTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.NumericTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.RegistryOps; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.ProblemReporter; +import net.minecraft.util.Util; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.item.component.ResolvableProfile; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.ValueInput; +import org.bukkit.Location; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.slf4j.Logger; + +import java.util.Set; + +public class NMSTagsImpl extends com.bgsoftware.superiorskyblock.nms.v26_2.AbstractNMSTags { + + private static final Logger LOGGER = LogUtils.getLogger(); + + @Override + public org.bukkit.inventory.ItemStack getSkullWithTexture(org.bukkit.inventory.ItemStack bukkitItem, String texture) { + ItemStack itemStack = CraftItemStack.asNMSCopy(bukkitItem); + + Multimap properties = HashMultimap.create(); + properties.put("textures", new Property("textures", texture)); + + GameProfile gameProfile = new GameProfile(Util.NIL_UUID, "", new PropertyMap(properties)); + + ResolvableProfile resolvableProfile = ResolvableProfile.createResolved(gameProfile); + + itemStack.set(DataComponents.PROFILE, resolvableProfile); + + return CraftItemStack.asBukkitCopy(itemStack); + } + + @Override + protected CompoundTag setTagAndGetCompoundTag(ItemStack itemStack, String key, int value) { + RegistryOps context = MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); + + net.minecraft.nbt.CompoundTag tagCompound = (net.minecraft.nbt.CompoundTag) + ItemStack.CODEC.encodeStart(context, itemStack).getOrThrow(); + tagCompound.putInt("DataVersion", com.bgsoftware.superiorskyblock.nms.v26_2.AbstractNMSAlgorithms.DATA_VERSION); + + return CompoundTag.fromNBT(tagCompound); + } + + @Override + protected int getCompoundTagInt(net.minecraft.nbt.CompoundTag compoundTag, String key, int def) { + return compoundTag.getIntOr(key, def); + } + + @Override + protected ItemStack parseItemStack(net.minecraft.nbt.CompoundTag compoundTag) { + RegistryOps context = + MinecraftServer.getServer().registryAccess().createSerializationContext(NbtOps.INSTANCE); + + return ItemStack.CODEC.parse(context, compoundTag) + .resultOrPartial((itemId) -> LOGGER.error("Tried to load invalid item: '{}'", itemId)) + .orElseThrow(); + } + + @Override + protected void setItemStackCompoundTag(ItemStack itemStack, net.minecraft.nbt.CompoundTag compoundTag) { + itemStack.set(DataComponents.CUSTOM_DATA, CustomData.of(compoundTag)); + } + + @Override + protected void loadEntity(net.minecraft.nbt.CompoundTag compoundTag, ServerLevel serverLevel, Location location) { + try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(this::toString, LOGGER)) { + ValueInput input = TagValueInput.create(reporter, serverLevel.registryAccess(), compoundTag); + EntityType.loadEntityRecursive(input, serverLevel, EntitySpawnReason.NATURAL, entity -> { + entity.absSnapTo(location.getX(), location.getY(), location.getZ(), entity.getYRot(), entity.getXRot()); + return !serverLevel.addWithUUID(entity) ? null : entity; + }); + } + } + + @Override + public byte[] getNBTByteArrayValue(Object object) { + return ((ByteArrayTag) object).getAsByteArray(); + } + + @Override + public byte getNBTByteValue(Object object) { + return ((NumericTag) object).byteValue(); + } + + @Override + public Set getNBTCompoundValue(Object object) { + return ((net.minecraft.nbt.CompoundTag) object).keySet(); + } + + @Override + public double getNBTDoubleValue(Object object) { + return ((NumericTag) object).doubleValue(); + } + + @Override + public float getNBTFloatValue(Object object) { + return ((NumericTag) object).floatValue(); + } + + @Override + public int[] getNBTIntArrayValue(Object object) { + return ((IntArrayTag) object).getAsIntArray(); + } + + @Override + public int getNBTIntValue(Object object) { + return ((NumericTag) object).intValue(); + } + + @Override + public Object getNBTListIndexValue(Object object, int index) { + return ((net.minecraft.nbt.ListTag) object).get(index); + } + + @Override + public long getNBTLongValue(Object object) { + return ((NumericTag) object).longValue(); + } + + @Override + public short getNBTShortValue(Object object) { + return ((NumericTag) object).shortValue(); + } + + @Override + public String getNBTStringValue(Object object) { + return ((StringTag) object).value(); + } + +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSWorldImpl.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSWorldImpl.java new file mode 100644 index 0000000000..d0b7b0c122 --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSWorldImpl.java @@ -0,0 +1,145 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2; + +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.nms.v26_2.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v26_2.trial.IslandPlayerDetector; +import com.bgsoftware.superiorskyblock.nms.v26_2.vibration.IslandVibrationUser; +import com.bgsoftware.superiorskyblock.nms.v26_2.world.BlockLevelTicksTracker; +import com.bgsoftware.superiorskyblock.nms.v26_2.world.CollectingNeighborUpdaterTracker; +import com.bgsoftware.superiorskyblock.world.SignType; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.block.entity.SignBlockEntity; +import net.minecraft.world.level.block.entity.TrialSpawnerBlockEntity; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; +import net.minecraft.world.level.block.entity.trialspawner.TrialSpawner; +import net.minecraft.world.level.block.entity.vault.VaultBlockEntity; +import net.minecraft.world.level.block.entity.vault.VaultConfig; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.chunk.ChunkGenerator; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator; +import net.minecraft.world.level.levelgen.NoiseGeneratorSettings; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.data.type.HangingSign; +import org.bukkit.block.data.type.WallHangingSign; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; + +import java.lang.reflect.Modifier; + +public class NMSWorldImpl extends com.bgsoftware.superiorskyblock.nms.v26_2.AbstractNMSWorld { + + private static final ReflectField SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER = new ReflectField( + SculkSensorBlockEntity.class, VibrationSystem.User.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField COLLECTING_NEIGHBOR_UPDATER = new ReflectField( + Level.class, CollectingNeighborUpdater.class, Modifier.PROTECTED | Modifier.FINAL, 1).removeFinal(); + private static final ReflectField> BLOCK_TICKS = new ReflectField>( + ServerLevel.class, LevelTicks.class, Modifier.PRIVATE | Modifier.FINAL, 1).removeFinal(); + + public NMSWorldImpl(SuperiorSkyblockPlugin plugin) { + super(plugin); + } + + @Override + protected void lerpSizeBetween(WorldBorder worldBorder, double oldSize, double newSize) { + worldBorder.lerpSizeBetween(oldSize, newSize, Long.MAX_VALUE, worldBorder.world.getGameTime()); + } + + @Override + protected Component[] getSignBlockEntityText(SignBlockEntity signBlockEntity) { + return signBlockEntity.getFrontText().getMessages(false); + } + + @Override + protected ChunkGenerator getChunkGeneratorDelegate(CustomChunkGenerator chunkGenerator) { + return chunkGenerator.getDelegate(); + } + + @Override + protected FlatLevelSource createFlatLevelSource(FlatLevelSource original, int seaLevel) { + return new FlatLevelSource(original.settings()) { + @Override + public int getSeaLevel() { + return seaLevel; + } + }; + } + + @Override + protected NoiseGeneratorSettings getNoiseGeneratorSettings(NoiseBasedChunkGenerator noiseBasedChunkGenerator) { + return noiseBasedChunkGenerator.generatorSettings().value(); + } + + @Override + public void replaceTrialBlockPlayerDetector(Island island, Location location) { + BlockEntity blockEntity = NMSUtils.getBlockEntityAt(location, BlockEntity.class); + if (blockEntity == null) + return; + + if (blockEntity instanceof VaultBlockEntity vaultBlockEntity) { + VaultConfig vaultConfig = vaultBlockEntity.getConfig(); + + PlayerDetector playerDetector = vaultConfig.playerDetector(); + if (playerDetector instanceof IslandPlayerDetector) + return; + + VaultConfig newConfig = new VaultConfig( + vaultConfig.lootTable(), + vaultConfig.activationRange(), + vaultConfig.deactivationRange(), + vaultConfig.keyItem(), + vaultConfig.overrideLootTableToDisplay(), + IslandPlayerDetector.trialVaultPlayerDetector(island, playerDetector), + vaultConfig.entitySelector() + ); + + vaultBlockEntity.setConfig(newConfig); + } else if (blockEntity instanceof TrialSpawnerBlockEntity trialSpawnerBlockEntity) { + TrialSpawner trialSpawner = trialSpawnerBlockEntity.getTrialSpawner(); + PlayerDetector playerDetector = trialSpawner.getPlayerDetector(); + + if (playerDetector instanceof IslandPlayerDetector) + return; + + trialSpawnerBlockEntity.getTrialSpawner().setPlayerDetector(IslandPlayerDetector.trialSpawnerPlayerDetector(island, playerDetector)); + } + } + + @Override + public void replaceSculkSensorListener(Island island, Location location) { + SculkSensorBlockEntity sculkSensorBlockEntity = NMSUtils.getBlockEntityAt(location, SculkSensorBlockEntity.class); + if (sculkSensorBlockEntity == null || sculkSensorBlockEntity.getVibrationUser() instanceof IslandVibrationUser) + return; + + SCULK_SENSOR_BLOCK_ENTITY_VIBRATION_USER.set(sculkSensorBlockEntity, new IslandVibrationUser(island, sculkSensorBlockEntity)); + } + + @Override + public SignType getSignType(Object sign) { + if (sign instanceof HangingSign) + return SignType.HANGING_SIGN; + else if (sign instanceof WallHangingSign) + return SignType.HANGING_WALL_SIGN; + else + return super.getSignType(sign); + } + + @Override + public void listenBlockStateChanges(World world) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + COLLECTING_NEIGHBOR_UPDATER.set(serverLevel, new CollectingNeighborUpdaterTracker(serverLevel)); + BLOCK_TICKS.set(serverLevel, new BlockLevelTicksTracker(serverLevel)); + } + +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/dragon/EndDragonFightWrapper.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/dragon/EndDragonFightWrapper.java new file mode 100644 index 0000000000..84fea9846f --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/dragon/EndDragonFightWrapper.java @@ -0,0 +1,35 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2.dragon; + +import com.bgsoftware.superiorskyblock.nms.v26_2.dragon.EndWorldEndDragonFightHandler; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.dimension.end.EnderDragonFight; + +import java.util.List; +import java.util.Optional; + +public class EndDragonFightWrapper extends EnderDragonFight { + + public final EndWorldEndDragonFightHandler HANDLER = new EndWorldEndDragonFightHandler(); + + public EndDragonFightWrapper(ServerLevel serverLevel, BlockPos islandPos) { + super(true, false, false, Optional.empty(), 0, Optional.empty(), Optional.empty(), new ObjectArrayList(), List.of()); + init(serverLevel, serverLevel.getSeed(), islandPos); + } + + @Override + public void tick() { + HANDLER.tick(); + } + + protected BlockPos getPortalPos() { + return this.exitPortalLocation; + } + + protected void setPortalPos(BlockPos blockPos) { + this.exitPortalLocation = blockPos; + } + + +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/dragon/IslandEntityEnderDragon.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/dragon/IslandEntityEnderDragon.java new file mode 100644 index 0000000000..e01575200e --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/dragon/IslandEntityEnderDragon.java @@ -0,0 +1,40 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2.dragon; + +import com.bgsoftware.common.annotations.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.world.DifficultyInstance; +import net.minecraft.world.entity.EntitySpawnReason; +import net.minecraft.world.entity.SpawnGroupData; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.ServerLevelAccessor; +import net.minecraft.world.level.storage.ValueInput; + +public class IslandEntityEnderDragon extends com.bgsoftware.superiorskyblock.nms.v26_2.dragon.AbstractIslandEntityEnderDragon { + + public IslandEntityEnderDragon(Level level, BlockPos islandBlockPos) { + super(level, islandBlockPos); + } + + public IslandEntityEnderDragon(Level level) { + super(level); + } + + @Nullable + @Override + public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, + DifficultyInstance difficulty, + EntitySpawnReason spawnReason, + @Nullable SpawnGroupData entityData) { + if (this.islandBlockPos == null) + finalizeIslandEnderDragon(); + + return super.finalizeSpawn(world, difficulty, spawnReason, entityData); + } + + @Override + protected void readAdditionalSaveData(ValueInput input) { + super.readAdditionalSaveData(input); + finalizeIslandEnderDragon(); + } + +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/hologram/EntityHologram.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/hologram/EntityHologram.java new file mode 100644 index 0000000000..62598924e9 --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/hologram/EntityHologram.java @@ -0,0 +1,64 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2.hologram; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.level.storage.ValueOutput; +import net.minecraft.world.phys.Vec3; + +public class EntityHologram extends com.bgsoftware.superiorskyblock.nms.v26_2.hologram.AbstractEntityHologram { + + public EntityHologram(ServerLevel serverLevel, double x, double y, double z) { + super(serverLevel, x, y, z); + } + + @Override + protected void addAdditionalSaveData(ValueOutput output) { + // Do not save NBT. + } + + @Override + protected void addAdditionalSaveData(ValueOutput output, boolean includeAll) { + // Do not save NBT. + } + + @Override + protected void readAdditionalSaveData(ValueInput input) { + // Do not load NBT. + } + + @Override + public boolean saveAsPassenger(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { + // Do not save NBT. + return false; + } + + @Override + public boolean saveAsPassenger(ValueOutput output) { + // Do not save NBT. + return false; + } + + @Override + public void saveWithoutId(ValueOutput output, boolean includeAll, boolean includeNonSaveable, boolean forceSerialization) { + // Do not save NBT. + } + + @Override + public void saveWithoutId(ValueOutput output) { + // Do not save NBT. + } + + @Override + public void load(ValueInput input) { + // Do not load NBT. + } + + @Override + public InteractionResult interact(Player player, InteractionHand hand, Vec3 location) { + // Prevent stand being equipped + return InteractionResult.PASS; + } +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/trial/IslandPlayerDetector.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/trial/IslandPlayerDetector.java new file mode 100644 index 0000000000..5398318986 --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/trial/IslandPlayerDetector.java @@ -0,0 +1,56 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2.trial; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandPrivilege; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import com.bgsoftware.superiorskyblock.world.entity.BuiltinEntityCategory; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.entity.trialspawner.PlayerDetector; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; +import java.util.function.Supplier; + +public class IslandPlayerDetector implements PlayerDetector { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final PlayerDetector original; + private final Supplier requiredPrivilege; + + public static IslandPlayerDetector trialVaultPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, () -> IslandPrivileges.CONFIG_VAULT_INTERACT); + } + + public static IslandPlayerDetector trialSpawnerPlayerDetector(Island island, PlayerDetector original) { + return new IslandPlayerDetector(island, original, () -> BuiltinEntityCategory.MONSTER.getEntityCategory().getDamagePrivilege()); + } + + private IslandPlayerDetector(Island island, PlayerDetector original, Supplier requiredPrivilege) { + this.island = island; + this.original = original; + this.requiredPrivilege = requiredPrivilege; + } + + @Override + public List detect(ServerLevel serverLevel, EntitySelector entitySelector, BlockPos blockPos, double maxDistance, boolean requireLineOfSight) { + List players = this.original.detect(serverLevel, entitySelector, blockPos, maxDistance, requireLineOfSight); + IslandPrivilege requiredPrivilege = this.requiredPrivilege.get(); + if (requiredPrivilege != null && !players.isEmpty()) { + players = new LinkedList<>(players); + players.removeIf(uuid -> { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(uuid); + return !island.hasPermission(superiorPlayer, requiredPrivilege); + }); + players = Collections.unmodifiableList(players); + } + return players; + } + +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/utils/NMSUtilsVersioned.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/utils/NMSUtilsVersioned.java new file mode 100644 index 0000000000..4e528d2a13 --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/utils/NMSUtilsVersioned.java @@ -0,0 +1,448 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2.utils; + +import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; +import com.bgsoftware.common.annotations.Nullable; +import com.bgsoftware.common.reflection.ReflectField; +import com.bgsoftware.superiorskyblock.api.world.Dimension; +import com.bgsoftware.superiorskyblock.core.ChunkPosition; +import com.bgsoftware.superiorskyblock.core.Text; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.bgsoftware.superiorskyblock.core.threads.BukkitExecutor; +import com.bgsoftware.superiorskyblock.island.IslandUtils; +import com.bgsoftware.superiorskyblock.nms.v26_2.NMSUtils; +import com.bgsoftware.superiorskyblock.nms.v26_2.utils.TickingBlockList; +import com.google.gson.JsonParseException; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.PropertyMap; +import com.mojang.logging.LogUtils; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ChunkMap; +import net.minecraft.server.level.ClientInformation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.level.ThreadedLevelLightEngine; +import net.minecraft.server.level.WorldGenRegion; +import net.minecraft.util.ProblemReporter; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.LevelHeightAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.entity.SignText; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.PalettedContainer; +import net.minecraft.world.level.chunk.PalettedContainerFactory; +import net.minecraft.world.level.chunk.ProtoChunk; +import net.minecraft.world.level.chunk.Strategy; +import net.minecraft.world.level.chunk.UpgradeData; +import net.minecraft.world.level.chunk.status.ChunkPyramid; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.chunk.status.ChunkStep; +import net.minecraft.world.level.chunk.storage.EntityStorage; +import net.minecraft.world.level.chunk.storage.SimpleRegionStorage; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.dimension.end.EnderDragonFight; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import net.minecraft.world.level.storage.TagValueInput; +import net.minecraft.world.level.storage.TagValueOutput; +import net.minecraft.world.level.storage.ValueInput; +import net.minecraft.world.ticks.ProtoChunkTicks; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBiome; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.generator.CustomChunkGenerator; +import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.ChunkGenerator; +import org.slf4j.Logger; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.function.BiConsumer; + +public class NMSUtilsVersioned { + + private static final Logger LOGGER = LogUtils.getLogger(); + + private static final Component[] COMPONENT_ARRAY_TYPE = new Component[0]; + + private static final ReflectField> SERVER_LEVEL_ENTITY_MANAGER = new ReflectField<>( + ServerLevel.class, PersistentEntitySectionManager.class, Modifier.PUBLIC | Modifier.FINAL, 1); + private static final ReflectField ENTITY_STORAGE_REGION_STORAGE = new ReflectField<>( + EntityStorage.class, SimpleRegionStorage.class, Modifier.PRIVATE | Modifier.FINAL, 1); + + public static final PalettedContainerFactory DEFAULT_PALETTED_CONTAINER_FACTORY = PalettedContainerFactory.create( + MinecraftServer.getServer().registryAccess()); + + public static CompoundTag readChunk(ChunkMap chunkMap, ChunkPos chunkPos) { + return chunkMap.read(chunkPos).join().orElse(null); + } + + public static CompoundTag getChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ServerLevel serverLevel, ChunkPos chunkPos) { + return chunkMap.upgradeChunkTag(chunkCompoundTag); + } + + public static void saveChunkData(ChunkMap chunkMap, CompoundTag chunkCompoundTag, ChunkPos chunkPos) { + chunkMap.write(chunkPos, () -> chunkCompoundTag); + } + + public static BukkitExecutor.NestedTask runActionOnUnloadedEntityChunks( + Collection chunks, NMSUtils.ChunkCallback chunkCallback, CountDownLatch countDownLatch) { + if (SERVER_LEVEL_ENTITY_MANAGER.isValid()) { + return BukkitExecutor.createTask().runSync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + PersistentEntitySectionManager entityManager = SERVER_LEVEL_ENTITY_MANAGER.get(serverLevel); + SimpleRegionStorage regionStorage = ENTITY_STORAGE_REGION_STORAGE.get(entityManager.permanentStorage); + + ChunkPos chunkPos = new ChunkPos(chunkPosition.getX(), chunkPosition.getZ()); + + regionStorage.read(chunkPos).whenComplete((entityDataOptional, error) -> { + if (error != null) { + countDownLatch.countDown(); + throw new RuntimeException(error); + } else { + CompoundTag entityData = entityDataOptional.orElse(null); + if (entityData == null) { + chunkCallback.onChunkNotExist(chunkPosition); + } else { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + } + } + }); + }); + }); + } else { + return BukkitExecutor.createTask().runAsync(v -> { + chunks.forEach(chunkPosition -> { + ServerLevel serverLevel = ((CraftWorld) chunkPosition.getWorld()).getHandle(); + + try { + MoonriseRegionFileIO.RegionDataController regionDataController = + serverLevel.moonrise$getEntityChunkDataController(); + int chunkX = chunkPosition.getX(); + int chunkZ = chunkPosition.getZ(); + MoonriseRegionFileIO.RegionDataController.ReadData readData = + regionDataController.readData(chunkX, chunkZ); + if (readData != null) { + CompoundTag entityData = switch (readData.result()) { + case HAS_DATA -> regionDataController.finishRead(chunkX, chunkZ, readData); + case SYNC_READ -> readData.syncRead(); + default -> null; + }; + if (entityData != null) { + NMSUtils.UnloadedChunkCompound unloadedChunkCompound = new NMSUtils.UnloadedChunkCompound(chunkPosition, entityData); + chunkCallback.onUnloadedChunk(unloadedChunkCompound); + return; + } + } + + chunkCallback.onChunkNotExist(chunkPosition); + } catch (IOException error) { + countDownLatch.countDown(); + Log.error(error, "An unexpected error occurred while interacting with unloaded chunk ", chunkPosition, ":"); + } + }); + }); + } + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, + UpgradeData.EMPTY, + serverLevel, + DEFAULT_PALETTED_CONTAINER_FACTORY, + null); + } + + public static ProtoChunk createProtoChunk(ChunkPos chunkPos, LevelChunkSection[] chunkSections, + LevelHeightAccessor levelHeightAccessor, @Nullable ServerLevel serverLevel) { + return new ProtoChunk(chunkPos, UpgradeData.EMPTY, chunkSections, new ProtoChunkTicks<>(), + new ProtoChunkTicks<>(), levelHeightAccessor, DEFAULT_PALETTED_CONTAINER_FACTORY, null); + } + + public static boolean isBlockStateLiquid(BlockState blockState) { + return blockState.liquid(); + } + + public static boolean isLevelChunkSectionEmpty(LevelChunkSection levelChunkSection) { + return levelChunkSection.hasOnlyAir(); + } + + public static void loadBlockEntity(BlockEntity blockEntity, CompoundTag compoundTag) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "block_entity@" + blockEntity.getBlockPos(), LOGGER)) { + ValueInput valueInput = TagValueInput.create(scopedCollector, blockEntity.getLevel().registryAccess(), compoundTag); + blockEntity.loadWithComponents(valueInput); + } + } + + public static void relightChunks(ThreadedLevelLightEngine lightEngine, Set chunks) { + lightEngine.starlight$serverRelightChunks(chunks, chunkCallback -> { + }, completeCallback -> { + }); + } + + public static void rewriteSignLines(CompoundTag compoundTag) { + applySignTextLines(compoundTag, "front_text"); + applySignTextLines(compoundTag, "back_text"); + convertLegacySignTextLines(compoundTag); + } + + public static DimensionType getDimensionTypeFromDimension(Dimension dimension) { + ResourceKey resourceKey; + switch (dimension.getEnvironment()) { + case NETHER -> resourceKey = LevelStem.NETHER; + case THE_END -> resourceKey = LevelStem.END; + default -> resourceKey = LevelStem.OVERWORLD; + } + HolderLookup.RegistryLookup registry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.LEVEL_STEM); + return registry.getOrThrow(resourceKey).value().type().value(); + } + + public static void createChunkSections(@Nullable ServerLevel serverLevel, + LevelHeightAccessor levelHeightAccessor, + LevelChunkSection[] chunkSections, + Dimension dimension) { + Holder biome = CraftBiome.bukkitToMinecraftHolder(IslandUtils.getDefaultWorldBiome(dimension)); + + for (int i = 0; i < chunkSections.length; ++i) { + PalettedContainer> biomesContainer = createBiomesContainer(biome); + PalettedContainer statesContainer = DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + chunkSections[i] = new LevelChunkSection(statesContainer, biomesContainer); + } + } + + public static void buildSurfaceForChunk(ServerLevel serverLevel, ChunkGenerator bukkitGenerator, ChunkAccess chunkAccess) { + CustomChunkGenerator customChunkGenerator = new CustomChunkGenerator(serverLevel, + serverLevel.getChunkSource().getGenerator(), bukkitGenerator); + + ChunkStep surfaceStep = ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.SURFACE); + + // Unsafe: we do not provide chunks cache, even tho it is required. + // Should be fine in normal flow, as the only method that access the chunks cache + // is WorldGenRegion#getChunk. Mimic`ing the cache seems to result an error: + // https://github.com/BG-Software-LLC/SuperiorSkyblock2/issues/2121 + WorldGenRegion region = new WorldGenRegion(serverLevel, null, surfaceStep, chunkAccess); + + customChunkGenerator.buildSurface(region, + serverLevel.structureManager().forWorldGenRegion(region), + serverLevel.getChunkSource().randomState(), + chunkAccess); + } + + public static PalettedContainer createEmptyPlattedContainerStates() { + return DEFAULT_PALETTED_CONTAINER_FACTORY.createForBlockStates(); + } + + public static PalettedContainer copyPalettedContainer(PalettedContainer original) { + return original.copy(); + } + + public static CompoundTag saveBlockEntity(BlockEntity blockEntity) { + return blockEntity.saveWithFullMetadata(MinecraftServer.getServer().registryAccess()); + } + + public static CompoundTag saveEntity(Entity entity) { + try (ProblemReporter.ScopedCollector scopedCollector = + new ProblemReporter.ScopedCollector(() -> "cached_entity@" + entity.getUUID(), LOGGER)) { + TagValueOutput valueOutput = TagValueOutput.createWithContext(scopedCollector, entity.level().registryAccess()); + entity.save(valueOutput); + return valueOutput.buildResult(); + } + } + + public static Material getMaterialFromBlock(Block block) { + return CraftMagicNumbers.getMaterial(block); + } + + public static ServerPlayer createServerPlayer(ServerLevel serverLevel, GameProfile gameProfile) { + return new ServerPlayer(MinecraftServer.getServer(), serverLevel, gameProfile, ClientInformation.createDefault()); + } + + public static TickingBlockList getTickingBlockList(LevelChunkSection levelChunkSection) { + return new TickingBlockList() { + @Override + public int size() { + return levelChunkSection.moonrise$getTickingBlockList().size(); + } + + @Override + public int getRaw(int index) { + return (int) levelChunkSection.moonrise$getTickingBlockList().getRaw(index); + } + }; + } + + public static void addEntity(ServerLevel serverLevel, Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) { + serverLevel.addFreshEntity(entity, spawnReason); + } + + public static PropertyMap getProfileProperties(GameProfile gameProfile) { + return gameProfile.properties(); + } + + public static String getPropertyValue(com.mojang.authlib.properties.Property property) { + return property.value(); + } + + public static EnderDragonFight getEndDragonFight(ServerLevel serverLevel) { + return serverLevel.getDragonFight(); + } + + public static void moveEntity(Entity entity, double x, double y, double z, float yaw, float pitch) { + entity.absSnapTo(x, y, z, yaw, pitch); + } + + public static int getMinSection(ServerLevel serverLevel) { + return serverLevel.getMinSectionY(); + } + + public static int getMinBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMinY(); + } + + public static int getMaxBuildHeight(ServerLevel serverLevel) { + return serverLevel.getMaxY(); + } + + public static void markUnsaved(LevelChunk levelChunk) { + levelChunk.markUnsaved(); + } + + public static PalettedContainer> createBiomesContainer(Holder biome) { + Registry biomesRegistry = MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME); + Strategy> biomesStrategy = Strategy.createForBiomes(biomesRegistry.asHolderIdMap()); + return new PalettedContainerFactory( + null, + null, + null, + biomesStrategy, + biome, + null, + null + ).createForBiomes(); + } + + public static Optional loadPlayerData(ServerPlayer serverPlayer) { + try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(serverPlayer.problemPath(), LOGGER)) { + return MinecraftServer.getServer().getPlayerList().loadPlayerData(serverPlayer.nameAndId()) + .map(playerData -> { + ValueInput valueInput = TagValueInput.create(scopedCollector, serverPlayer.registryAccess(), playerData); + serverPlayer.load(valueInput); + return playerData; + }); + } + } + + public static long getCompoundTagLong(net.minecraft.nbt.CompoundTag compoundTag, String key, long def) { + return compoundTag.getLongOr(key, def); + } + + private static void applySignTextLines(CompoundTag blockEntityCompound, String key) { + blockEntityCompound.getCompound(key).ifPresent(textCompound -> { + ListTag messages = textCompound.getListOrEmpty("messages"); + List textLines = new ArrayList<>(); + for (net.minecraft.nbt.Tag lineTag : messages) { + try { + textLines.add(CraftChatMessage.fromJSON(lineTag.asString().orElseThrow())); + } catch (JsonParseException error) { + textLines.add(CraftChatMessage.fromString(lineTag.asString().orElseThrow())[0]); + } + } + + for (int i = 0; i < 4; i++) { + if (textLines.get(i) == null) + textLines.set(i, Component.empty()); + } + + Component[] textLinesArray = textLines.toArray(COMPONENT_ARRAY_TYPE); + + SignText signText = new SignText(textLinesArray, textLinesArray, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(nbt -> blockEntityCompound.put(key, nbt)); + }); + } + + private static void convertLegacySignTextLines(CompoundTag blockEntityCompound) { + Component[] signLines = new Component[4]; + Arrays.fill(signLines, Component.empty()); + boolean hasAnySignLines = false; + // We try to convert old text sign lines + for (int i = 1; i <= 4; ++i) { + if (blockEntityCompound.contains("SSB.Text" + i)) { + String signLine = blockEntityCompound.getString("SSB.Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromString(signLine)[0]; + hasAnySignLines = true; + } + } else { + String signLine = blockEntityCompound.getString("Text" + i).orElse(null); + if (!Text.isBlank(signLine)) { + signLines[i - 1] = CraftChatMessage.fromJSON(signLine); + hasAnySignLines = true; + } + } + } + + if (hasAnySignLines) { + SignText signText = new SignText(signLines, signLines, DyeColor.BLACK, false); + SignText.DIRECT_CODEC.encodeStart(NbtOps.INSTANCE, signText).result() + .ifPresent(frontTextNBT -> blockEntityCompound.put("front_text", frontTextNBT)); + } + } + + public static BlockState getBlockState(org.bukkit.block.Block block) { + return ((CraftBlock) block).getBlockState(); + } + + public static boolean forEachProperty(BlockState blockState, BiConsumer, Comparable> consumer) { + int[] count = new int[]{0}; + + blockState.getValues().forEach(value -> { + ++count[0]; + consumer.accept(value.property(), value.value()); + }); + + return count[0] > 0; + } + + public static Identifier getBlockEntityTypeKey(BlockEntityType type) { + return BuiltInRegistries.BLOCK_ENTITY_TYPE.getKey(type); + } + + private NMSUtilsVersioned() { + + } + +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/vibration/IslandVibrationUser.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/vibration/IslandVibrationUser.java new file mode 100644 index 0000000000..b004584013 --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/vibration/IslandVibrationUser.java @@ -0,0 +1,90 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2.vibration; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.wrappers.SuperiorPlayer; +import com.bgsoftware.superiorskyblock.island.privilege.IslandPrivileges; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.block.entity.SculkSensorBlockEntity; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.gameevent.PositionSource; +import net.minecraft.world.level.gameevent.vibrations.VibrationSystem; + +import javax.annotation.Nullable; + +public class IslandVibrationUser implements VibrationSystem.User { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Island island; + private final VibrationSystem.User original; + + public IslandVibrationUser(Island island, SculkSensorBlockEntity sculkSensorBlockEntity) { + this.island = island; + this.original = sculkSensorBlockEntity.getVibrationUser(); + } + + @Override + public int getListenerRadius() { + return this.original.getListenerRadius(); + } + + @Override + public PositionSource getPositionSource() { + return this.original.getPositionSource(); + } + + @Override + public boolean canReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, GameEvent.Context context) { + if (!this.original.canReceiveVibration(serverLevel, blockPos, holder, context)) + return false; + + if (context.sourceEntity() instanceof Player player) { + SuperiorPlayer superiorPlayer = plugin.getPlayers().getSuperiorPlayer(player.getBukkitEntity()); + return island.hasPermission(superiorPlayer, IslandPrivileges.SCULK_SENSOR); + } + + return true; + } + + @Override + public void onReceiveVibration(ServerLevel serverLevel, BlockPos blockPos, Holder holder, @Nullable Entity entity, @Nullable Entity entity1, float v) { + this.original.onReceiveVibration(serverLevel, blockPos, holder, entity, entity1, v); + } + + @Override + public TagKey getListenableEvents() { + return this.original.getListenableEvents(); + } + + @Override + public boolean canTriggerAvoidVibration() { + return this.original.canTriggerAvoidVibration(); + } + + @Override + public boolean requiresAdjacentChunksToBeTicking() { + return this.original.requiresAdjacentChunksToBeTicking(); + } + + @Override + public int calculateTravelTimeInTicks(float distance) { + return this.original.calculateTravelTimeInTicks(distance); + } + + @Override + public boolean isValidVibration(Holder gameEvent, GameEvent.Context context) { + return this.original.isValidVibration(gameEvent, context); + } + + @Override + public void onDataChanged() { + this.original.onDataChanged(); + } + +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/world/BlockLevelTicksTracker.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/world/BlockLevelTicksTracker.java new file mode 100644 index 0000000000..6693416d88 --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/world/BlockLevelTicksTracker.java @@ -0,0 +1,59 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventFlags; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.ticks.LevelTicks; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +import java.util.List; +import java.util.function.BiConsumer; + +public class BlockLevelTicksTracker extends LevelTicks { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final ServerLevel serverLevel; + + public BlockLevelTicksTracker(ServerLevel serverLevel) { + super(serverLevel::isPositionTickingWithEntitiesLoaded); + this.serverLevel = serverLevel; + } + + @Override + public void tick(long gameTime, int maxAllowedTicks, BiConsumer ticker) { + super.tick(gameTime, maxAllowedTicks, (blockPos, block) -> { + BlockState oldState = this.serverLevel.getBlockState(blockPos); + try { + // Only capture blocks related events + plugin.getGameEventsDispatcher().startCaptureEvents(GameEventFlags.BLOCK_EVENT | GameEventFlags.MAYBE_BLOCK_EVENT); + ticker.accept(blockPos, block); + } finally { + List> capturedEvents = plugin.getGameEventsDispatcher().stopCaptureEvents(); + // Remove BlockPhysicsEvent which we don't listen to + capturedEvents.removeIf(gameEvent -> gameEvent.getType() == GameEventType.BLOCK_PHYSICS_EVENT); + // We don't want to fire the BlockUpdateShapeEvent if another event was fired in the tick method. + // This is to prevent blocks from being considered updated twice. + if (!capturedEvents.isEmpty()) + return; + } + BlockState newState = this.serverLevel.getBlockState(blockPos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.serverLevel, blockPos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.serverLevel, blockPos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + }); + } +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/world/CollectingNeighborUpdaterTracker.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/world/CollectingNeighborUpdaterTracker.java new file mode 100644 index 0000000000..95419fabea --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/world/CollectingNeighborUpdaterTracker.java @@ -0,0 +1,44 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2.world; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.platform.event.GameEvent; +import com.bgsoftware.superiorskyblock.platform.event.GameEventPriority; +import com.bgsoftware.superiorskyblock.platform.event.GameEventType; +import com.bgsoftware.superiorskyblock.platform.event.args.GameEventArgs; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.redstone.CollectingNeighborUpdater; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockStates; + +public class CollectingNeighborUpdaterTracker extends CollectingNeighborUpdater { + + private static final SuperiorSkyblockPlugin plugin = SuperiorSkyblockPlugin.getPlugin(); + + private final Level level; + + public CollectingNeighborUpdaterTracker(Level level) { + super(level, MinecraftServer.getServer().getMaxChainedNeighborUpdates()); + this.level = level; + } + + @Override + public void shapeUpdate(Direction direction, BlockState state, BlockPos pos, BlockPos neighborPos, @Block.UpdateFlags int flags, int recursionLeft) { + BlockState oldState = this.level.getBlockState(pos); + super.shapeUpdate(direction, state, pos, neighborPos, flags, recursionLeft); + BlockState newState = this.level.getBlockState(pos); + if (oldState.getBlock() != newState.getBlock()) { + // Block was changed, let's call an update + GameEventArgs.BlockUpdateShapeEvent blockUpdateShapeEvent = new GameEventArgs.BlockUpdateShapeEvent(); + blockUpdateShapeEvent.block = CraftBlock.at(this.level, pos); + blockUpdateShapeEvent.oldState = CraftBlockStates.getBlockState(this.level, pos, oldState, null); + GameEvent gameEvent = GameEventType.BLOCK_UPDATE_SHAPE_EVENT.createEvent(blockUpdateShapeEvent); + plugin.getGameEventsDispatcher().onGameEvent(gameEvent, GameEventPriority.MONITOR); + } + } + +} diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/world/PropertiesMapperVersioned.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/world/PropertiesMapperVersioned.java new file mode 100644 index 0000000000..b46285272d --- /dev/null +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/world/PropertiesMapperVersioned.java @@ -0,0 +1,18 @@ +package com.bgsoftware.superiorskyblock.nms.v26_2.world; + +import net.minecraft.world.level.block.state.properties.BlockStateProperties; + +import java.util.Map; + +public class PropertiesMapperVersioned { + + public static void initializeFields(Map fieldsToNames) { + fieldsToNames.put(BlockStateProperties.AGE_4, "age4"); + fieldsToNames.put(BlockStateProperties.TEST_BLOCK_MODE, "test-block-mode"); + } + + private PropertiesMapperVersioned() { + + } + +} diff --git a/build.gradle b/build.gradle index f31e003881..27c0f9e69e 100644 --- a/build.gradle +++ b/build.gradle @@ -67,7 +67,7 @@ dependencies { implementation 'com.bgsoftware.common.executors:Executors:b3' implementation 'com.bgsoftware.common.shopsbridge:ShopsBridge:b11:all@jar' implementation 'com.bgsoftware.common.dependencies:DependenciesManager:b2' - implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b21' + implementation 'com.bgsoftware.common.nmsloader:NMSLoader:b22' implementation 'com.bgsoftware.common.databasebridge:DatabaseBridge:b2' implementation 'org.bstats:bstats-bukkit:3.0.0' diff --git a/gradle.properties b/gradle.properties index 99bb774c2e..b9ca2c397f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,6 +9,7 @@ nms.compile_v1_19=true nms.compile_v1_20=true nms.compile_v1_21=true nms.compile_v26_1=true +nms.compile_v26_2=true hook.compile_advancedspawners=true hook.compile_candcsilkspawners=true hook.compile_changeskin=true diff --git a/settings.gradle b/settings.gradle index 674e94e423..12d50ead43 100644 --- a/settings.gradle +++ b/settings.gradle @@ -84,4 +84,5 @@ include 'NMS:v1_21_5' include 'NMS:v1_21_7' include 'NMS:v1_21_9' include 'NMS:v1_21_10' -include 'NMS:v26_1' \ No newline at end of file +include 'NMS:v26_1' +include 'NMS:v26_2' \ No newline at end of file diff --git a/src/main/java/com/bgsoftware/superiorskyblock/core/ServerVersion.java b/src/main/java/com/bgsoftware/superiorskyblock/core/ServerVersion.java index 71481c7349..fd73d8ac06 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/core/ServerVersion.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/core/ServerVersion.java @@ -22,6 +22,7 @@ public enum ServerVersion { v1_20(120), v1_21(121), v26_1(261), + v26_2(262), UNKONWN(-1); From b464a4dd48e0a9974b79284aea26057a9ce10010 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Fri, 19 Jun 2026 16:12:43 +0300 Subject: [PATCH 597/600] Fix detection of soft explosions --- .../superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java | 7 +++++++ .../superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java | 7 +++++++ .../superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java | 7 +++++++ .../superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java | 7 +++++++ .../superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java | 7 +++++++ .../superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java | 7 +++++++ .../superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java | 7 +++++++ .../superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java | 7 +++++++ .../superiorskyblock/nms/v26_2/NMSAlgorithmsImpl.java | 7 +++++++ .../superiorskyblock/listener/BukkitEventsListener.java | 6 +----- .../com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java | 5 +++++ 11 files changed, 69 insertions(+), 5 deletions(-) diff --git a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java index 729139c0bb..b1e2bc76e3 100644 --- a/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java +++ b/NMS/v1_21/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21/NMSAlgorithmsImpl.java @@ -4,11 +4,13 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; +import org.bukkit.ExplosionResult; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; @@ -101,4 +103,9 @@ public Biome getBiome(String biomeName) { } } + @Override + public boolean isSoftExplosion(EntityExplodeEvent e) { + return e.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK; + } + } diff --git a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java index 9f5e99973d..47969a5699 100644 --- a/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_10/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_10/NMSAlgorithmsImpl.java @@ -11,11 +11,13 @@ import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; +import org.bukkit.ExplosionResult; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; @@ -117,4 +119,9 @@ public Biome getBiome(String biomeName) { } } + @Override + public boolean isSoftExplosion(EntityExplodeEvent e) { + return e.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK; + } + } diff --git a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java index 7dadfff6c3..c1d61972f7 100644 --- a/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_3/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_3/NMSAlgorithmsImpl.java @@ -4,11 +4,13 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; +import org.bukkit.ExplosionResult; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; @@ -106,4 +108,9 @@ public Biome getBiome(String biomeName) { } } + @Override + public boolean isSoftExplosion(EntityExplodeEvent e) { + return e.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK; + } + } diff --git a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java index e91b8ff6c6..bda3e3527f 100644 --- a/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_4/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_4/NMSAlgorithmsImpl.java @@ -4,11 +4,13 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; +import org.bukkit.ExplosionResult; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; @@ -106,4 +108,9 @@ public Biome getBiome(String biomeName) { } } + @Override + public boolean isSoftExplosion(EntityExplodeEvent e) { + return e.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK; + } + } diff --git a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java index 741a49287e..698a33d162 100644 --- a/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_5/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_5/NMSAlgorithmsImpl.java @@ -4,11 +4,13 @@ import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; +import org.bukkit.ExplosionResult; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; @@ -106,4 +108,9 @@ public Biome getBiome(String biomeName) { } } + @Override + public boolean isSoftExplosion(EntityExplodeEvent e) { + return e.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK; + } + } diff --git a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java index f490637060..a80ab2a849 100644 --- a/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_7/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_7/NMSAlgorithmsImpl.java @@ -10,11 +10,13 @@ import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; +import org.bukkit.ExplosionResult; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; @@ -117,4 +119,9 @@ public Biome getBiome(String biomeName) { } } + @Override + public boolean isSoftExplosion(EntityExplodeEvent e) { + return e.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK; + } + } diff --git a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java index d2de169f3c..e47fa9c4a0 100644 --- a/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java +++ b/NMS/v1_21_9/src/main/java/com/bgsoftware/superiorskyblock/nms/v1_21_9/NMSAlgorithmsImpl.java @@ -11,11 +11,13 @@ import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; +import org.bukkit.ExplosionResult; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; @@ -117,4 +119,9 @@ public Biome getBiome(String biomeName) { } } + @Override + public boolean isSoftExplosion(EntityExplodeEvent e) { + return e.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK; + } + } diff --git a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java index 7eef4f7997..3313e4672b 100644 --- a/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java +++ b/NMS/v26_1/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_1/NMSAlgorithmsImpl.java @@ -11,11 +11,13 @@ import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; +import org.bukkit.ExplosionResult; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; @@ -117,4 +119,9 @@ public Biome getBiome(String biomeName) { } } + @Override + public boolean isSoftExplosion(EntityExplodeEvent e) { + return e.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK; + } + } diff --git a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSAlgorithmsImpl.java b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSAlgorithmsImpl.java index b6eaf62b6b..8de830204f 100644 --- a/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSAlgorithmsImpl.java +++ b/NMS/v26_2/src/main/java/com/bgsoftware/superiorskyblock/nms/v26_2/NMSAlgorithmsImpl.java @@ -11,11 +11,13 @@ import net.minecraft.resources.RegistryOps; import net.minecraft.server.MinecraftServer; import org.bukkit.Bukkit; +import org.bukkit.ExplosionResult; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Biome; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftChatMessage; +import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.inventory.ItemRarity; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ArmorMeta; @@ -112,4 +114,9 @@ public Biome getBiome(String biomeName) { return registry.get(key); } + @Override + public boolean isSoftExplosion(EntityExplodeEvent e) { + return e.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK; + } + } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java index a9fb5c9a74..abf9a635cf 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/listener/BukkitEventsListener.java @@ -108,10 +108,6 @@ public class BukkitEventsListener implements Listener { ProjectileHitEvent.class, "getHitEntity"); private static final ReflectMethod PROJECTILE_HIT_EVENT_TARGET_BLOCK = new ReflectMethod<>( ProjectileHitEvent.class, "getHitBlock"); - @Nullable - private static final EntityType WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "WIND_CHARGE"); - @Nullable - private static final EntityType BREEZE_WIND_CHARGE = EnumHelper.getEnum(EntityType.class, "BREEZE_WIND_CHARGE"); private final SuperiorSkyblockPlugin plugin; @@ -473,7 +469,7 @@ private GameEvent createGameEvent(GameEventTyp GameEventArgs.EntityExplodeEvent entityExplodeEvent = new GameEventArgs.EntityExplodeEvent(); entityExplodeEvent.entity = e.getEntity(); entityExplodeEvent.blocks = e.blockList(); - entityExplodeEvent.isSoftExplosion = e.getEntityType() == WIND_CHARGE || e.getEntityType() == BREEZE_WIND_CHARGE; + entityExplodeEvent.isSoftExplosion = plugin.getNMSAlgorithms().isSoftExplosion(e); return eventType.createEvent(entityExplodeEvent); } diff --git a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java index 23e2d1cc92..69ddd738d3 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/nms/NMSAlgorithms.java @@ -12,6 +12,7 @@ import org.bukkit.command.defaults.BukkitCommand; import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Minecart; +import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; @@ -106,6 +107,10 @@ default BukkitEventsListener.GameEventCreator getGenericGameCreator() { throw new UnsupportedOperationException("Not supported in this version"); } + default boolean isSoftExplosion(EntityExplodeEvent e) { + return false; + } + interface EnumBridge { T[] getValues(); From 7e70777d8d106c47845e1ffe0d47345224af3c16 Mon Sep 17 00:00:00 2001 From: Djoey Date: Fri, 19 Jun 2026 19:21:19 +0200 Subject: [PATCH 598/600] Fix RoseStacker's PreStackedSpawnerSpawnEvent not detected (#2950) --- Hooks/RoseStacker1_5/build.gradle | 19 +++ .../SpawnersProvider_RoseStacker1_5.java | 118 ++++++++++++++++++ settings.gradle | 1 + .../external/ProvidersManagerImpl.java | 15 ++- 4 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 Hooks/RoseStacker1_5/build.gradle create mode 100644 Hooks/RoseStacker1_5/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker1_5.java diff --git a/Hooks/RoseStacker1_5/build.gradle b/Hooks/RoseStacker1_5/build.gradle new file mode 100644 index 0000000000..0f0f959869 --- /dev/null +++ b/Hooks/RoseStacker1_5/build.gradle @@ -0,0 +1,19 @@ +group 'Hooks:RoseStacker1_5' + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +dependencies { + compileOnly 'dev.rosewood:RoseStacker:1.5.33' + compileOnly "org.spigotmc:v1_8_R3-Taco:latest" + compileOnly project(":API") + compileOnly project(":") +} + +if (project.hasProperty('hook.compile_rosestacker') && + !Boolean.valueOf(project.findProperty("hook.compile_rosestacker").toString())) { + project.tasks.all { task -> task.enabled = false } +} diff --git a/Hooks/RoseStacker1_5/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker1_5.java b/Hooks/RoseStacker1_5/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker1_5.java new file mode 100644 index 0000000000..71ba5e3da3 --- /dev/null +++ b/Hooks/RoseStacker1_5/src/main/java/com/bgsoftware/superiorskyblock/external/spawners/SpawnersProvider_RoseStacker1_5.java @@ -0,0 +1,118 @@ +package com.bgsoftware.superiorskyblock.external.spawners; + +import com.bgsoftware.superiorskyblock.SuperiorSkyblockPlugin; +import com.bgsoftware.superiorskyblock.api.entity.EntityCategory; +import com.bgsoftware.superiorskyblock.api.island.Island; +import com.bgsoftware.superiorskyblock.api.island.IslandFlag; +import com.bgsoftware.superiorskyblock.api.key.Key; +import com.bgsoftware.superiorskyblock.api.objects.Pair; +import com.bgsoftware.superiorskyblock.core.key.Keys; +import com.bgsoftware.superiorskyblock.core.logging.Log; +import com.google.common.base.Preconditions; +import dev.rosewood.rosestacker.api.RoseStackerAPI; +import dev.rosewood.rosestacker.event.PreStackedSpawnerSpawnEvent; +import dev.rosewood.rosestacker.event.SpawnerStackEvent; +import dev.rosewood.rosestacker.event.SpawnerUnstackEvent; +import dev.rosewood.rosestacker.stack.StackedSpawner; +import dev.rosewood.rosestacker.utils.ItemUtils; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.EntityType; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; + +import java.util.List; + +public class SpawnersProvider_RoseStacker1_5 implements SpawnersProvider_AutoDetect { + + private final SuperiorSkyblockPlugin plugin; + + public SpawnersProvider_RoseStacker1_5(SuperiorSkyblockPlugin plugin) { + this.plugin = plugin; + Bukkit.getPluginManager().registerEvents(new StackerListener(), plugin); + Log.info("Using RoseStacker as a spawners provider."); + } + + @Override + public Pair getSpawner(Location location) { + Preconditions.checkNotNull(location, "location parameter cannot be null."); + + int blockCount = -1; + + if (Bukkit.isPrimaryThread()) { + StackedSpawner stackedSpawner = RoseStackerAPI.getInstance().getStackedSpawner(location.getBlock()); + blockCount = stackedSpawner == null ? 1 : stackedSpawner.getStackSize(); + } + + return new Pair<>(blockCount, null); + } + + @Override + public String getSpawnerType(ItemStack itemStack) { + Preconditions.checkNotNull(itemStack, "itemStack parameter cannot be null."); + EntityType entityType = ItemUtils.getStackedItemEntityType(itemStack); + return entityType == null ? null : entityType.name(); + } + + @SuppressWarnings("unused") + private class StackerListener implements Listener { + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onSpawnerStack(SpawnerStackEvent e) { + Location location = e.getStack().getLocation(); + Island island = plugin.getGrid().getIslandAt(location); + if (island != null) { + Key blockKey = Keys.of(e.getStack().getBlock()); + + int increaseAmount = e.getStack().getStackSize() + e.getIncreaseAmount() > e.getStack().getStackSettings().getMaxStackSize() ? + e.getStack().getStackSettings().getMaxStackSize() - e.getStack().getStackSize() : e.getIncreaseAmount(); + int newBlocksCount = e.isNew() ? Math.max(1, increaseAmount - 1) : increaseAmount; + + if (island.hasReachedBlockLimit(blockKey, newBlocksCount)) { + e.setCancelled(true); + } else { + island.handleBlockPlace(blockKey, newBlocksCount); + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onSpawnerUnstack(SpawnerUnstackEvent e) { + Location location = e.getStack().getLocation(); + Island island = plugin.getGrid().getIslandAt(location); + if (island != null) { + island.handleBlockBreak(Keys.of(e.getStack().getBlock()), e.getDecreaseAmount()); + } + } + + @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) + public void onStackedSpawnerSpawn(PreStackedSpawnerSpawnEvent e) { + StackedSpawner stackedSpawner = e.getStack(); + Location location = stackedSpawner.getLocation(); + + Island island = plugin.getGrid().getIslandAt(location); + if (island == null) + return; + + if (!plugin.getSettings().getSpawn().isProtected() && island.isSpawn()) + return; + + EntityType spawnedType = stackedSpawner.getSpawnerTile().getSpawnedType(); + if (spawnedType == null) + return; + + List entityCategories = plugin.getSettings().getEntityCategoriesMap().getCategories(Keys.of(spawnedType)); + for (EntityCategory entityCategory : entityCategories) { + IslandFlag islandFlag = entityCategory.getSpawnerSpawningIslandFlag(); + if (islandFlag != null && !island.hasSettingsEnabled(islandFlag)) { + e.setCancelled(true); + return; + } + } + } + + } + +} diff --git a/settings.gradle b/settings.gradle index 12d50ead43..92524612e5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -37,6 +37,7 @@ include 'Hooks:PlaceholderAPI' include 'Hooks:ProtocolLib' include 'Hooks:PvpingSpawners' include 'Hooks:RoseStacker' +include 'Hooks:RoseStacker1_5' include 'Hooks:SkinsRestorer' include 'Hooks:SkinsRestorer14' include 'Hooks:SkinsRestorer15' diff --git a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java index 3f0910bd2d..310229f1de 100644 --- a/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java +++ b/src/main/java/com/bgsoftware/superiorskyblock/external/ProvidersManagerImpl.java @@ -567,7 +567,11 @@ private void registerSpawnersProvider() { listenToSpawnerChanges = false; } else if (canRegisterHook("RoseStacker") && (auto || configSpawnersProvider.equalsIgnoreCase("RoseStacker"))) { - spawnersProvider = createInstance("spawners.SpawnersProvider_RoseStacker"); + if (hasRoseStackerPreSpawnEventSupport()) { + spawnersProvider = createInstance("spawners.SpawnersProvider_RoseStacker1_5"); + } else { + spawnersProvider = createInstance("spawners.SpawnersProvider_RoseStacker"); + } listenToSpawnerChanges = false; } @@ -739,6 +743,15 @@ private static boolean hasMiniMessageSupport() { } } + private static boolean hasRoseStackerPreSpawnEventSupport() { + try { + Class.forName("dev.rosewood.rosestacker.event.PreStackedSpawnerSpawnEvent"); + return true; + } catch (ClassNotFoundException error) { + return false; + } + } + private Optional createInstance(String className) { try { Class clazz = Class.forName("com.bgsoftware.superiorskyblock.external." + className); From 92a3e5eea276f5fc36ccec724012e7b5de8f876b Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 28 Jun 2026 23:04:44 +0300 Subject: [PATCH 599/600] API version 17 --- .../bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java b/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java index f31e70db8a..23a38c77ac 100644 --- a/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java +++ b/API/src/main/java/com/bgsoftware/superiorskyblock/api/SuperiorSkyblockAPI.java @@ -71,7 +71,7 @@ public static void setPluginInstance(SuperiorSkyblock plugin) { * Everytime a change is made to the API, the version of it changes. */ public static int getAPIVersion() { - return 16; + return 17; } /* From e1ac5f2200efd1571dc35e8b50145fd7e88b9db6 Mon Sep 17 00:00:00 2001 From: OmerBenGera Date: Sun, 28 Jun 2026 23:07:59 +0300 Subject: [PATCH 600/600] Version 2026.2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 27c0f9e69e..8063ef7d74 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group 'SuperiorSkyblock' -version = "2026.1" +version = "2026.2" project.ext { targetFolder = file("target/")
  2. X<1V3yY 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